按照前文所介绍的内容可知,AudioTrack在调用createTrack时,会传入一个audio_handle_t,这个值表示AF中某个工作线程的索引号,而它又是从APS中得到的。那么,这中间又有哪些曲折的经历呢?
先回顾一下AudioTrack的set函数。
1. 重回set
先来看相应的代码,如下所示:
**AudioTrack.cpp**
~~~
status_t AudioTrack::set(int streamType,uint32_tsampleRate,int format,
int channels,intframeCount,uint32_t flags,
callback_t cbf,void*user,int notificationFrames,
constsp<IMemory>& sharedBuffer, bool threadCanCallJava)
{
......
//得到AF中一个工作线程的索引号
audio_io_handle_toutput = AudioSystem::getOutput(
(AudioSystem::stream_type)streamType,
sampleRate,format, channels,
(AudioSystem::output_flags)flags);
......
//创建Track,最终会调到AF的createTrack
status_t status = createTrack(streamType,sampleRate, format, channelCount,
frameCount,flags, sharedBuffer, output);
~~~
再看AudioSystem是如何实现getOutput的,代码如下所示:
**AudioSystem.cpp**
~~~
audio_io_handle_tAudioSystem::getOutput(stream_type stream,
uint32_tsamplingRate,
uint32_tformat,
uint32_tchannels,
output_flagsflags)
{
audio_io_handle_t output = 0;
......
if(output == 0) {
const sp<IAudioPolicyService>& aps =
AudioSystem::get_audio_policy_service();
if(aps == 0) return 0;
//调用AP的getOutput函数
output = aps->getOutput(stream, samplingRate, format, channels,flags);
if((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
Mutex::Autolock _l(gLock);
//把这个stream和output的对应关系保存到map中
AudioSystem::gStreamOutputMap.add(stream, output);
}
}
returnoutput;
}
~~~
这里调用了AP的getOutput,来看:
**AudioPolicyService.cpp**
~~~
audio_io_handle_t AudioPolicyService::getOutput(
AudioSystem::stream_typestream, uint32_t samplingRate,
uint32_tformat,uint32_t channels,
AudioSystem::output_flagsflags)
{
//和硬件厂商的实现相关,所以交给AudioPolicyInterface处理
//这里将由AudioPolicyManagerBase处理
Mutex::Autolock _l(mLock);
returnmpPolicyManager->getOutput(stream, samplingRate, format, channels,
flags);
}
~~~
**AudioPolicyManagerBase.cpp**
~~~
audio_io_handle_tAudioPolicyManagerBase::getOutput(
AudioSystem::stream_typestream, uint32_t samplingRate,
uint32_t format,uint32_tchannels,
AudioSystem::output_flagsflags)
{
audio_io_handle_t output = 0;
uint32_tlatency = 0;
//根据流类型得到对应的路由策略,这个我们已经见过了,MUSIC类型返回MUSIC策略
routing_strategystrategy = getStrategy((AudioSystem::stream_type)stream);
//根据策略得到使用这个策略的输出设备(指扬声器之类的),以后再看这个函数
uint32_tdevice = getDeviceForStrategy(strategy);
......
//看这个设备是不是与蓝牙的A2DP相关
uint32_ta2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP;
if(AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) {
#ifdef WITH_A2DP
//对于有A2DP支持,a2dpUsedForSonification函数直接返回true
if (a2dpUsedForSonification() &&a2dpDevice != 0) {
//和DuplicatingThread相关,以后再看
output = mDuplicatedOutput;
} else
#endif
{
output = mHardwareOutput; //使用非蓝牙的混音输出线程
}
} else{
#ifdef WITH_A2DP
if(a2dpDevice != 0) {
//使用蓝牙的混音输出线程
output = mA2dpOutput;
}else
#endif
{
output = mHardwareOutput;
}
}
returnoutput;
}
~~~
终于明白了!原来,AudioSystem的getOutput就是想找到AF中的一个工作线程。为什么这个线程号会由AP返回呢?是因为Audio系统需要:
- 根据流类型找到对应的路由策略。
- 根据该策略找到合适的输出device(指扬声器、听筒之类的)。
- 根据device选择AF中合适的工作线程,例如是蓝牙的MixerThread,还是DSP的MixerThread,或者是DuplicatingThread。
- AT根据得到的工作线程索引号,最终将在对应的工作线程中创建一个Track。之后,AT的数据将由该线程负责处理。
下面用图7-15来回顾一下上面AT、AF、AP之间的交互关系。
:-: ![](http://img.blog.csdn.net/20150802160955740?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图7-15 Audio三巨头的交互关系
图7-15充分展示了AT、AF和AP之间复杂微妙的关系。关系虽复杂,但目的却单纯。读者在分析时一定要明确目的。下面从目的开始,反推该流程:
- AT的目的是把数据发送给对应的设备,例如是蓝牙、DSP等。
- 代表输出设备的HAL对象由MixerThread线程持有,所以要找到对应的MixerThread。
- AP维护流类型和输出设备(耳机、蓝牙耳机、听筒等)之间的关系,不同的输出设备使用不同的混音线程。
- AT根据自己的流类型,向AudioSystem查询,希望得到对应的混音线程号。
这样,三者精妙配合,便达到了预期目的。
2. 重回start
现在要分析的就是start函数。AT的start虽没有直接与AP交互,但在AF的start中却和AP有着交互关系。其代码如下所示:
**AudioFlinger.cpp**
~~~
status_tAudioFlinger::PlaybackThread::Track::start()
{
status_t status = NO_ERROR;
sp<ThreadBase> thread = mThread.promote();
......
if(!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread->mLock.unlock();
//调用AudioSystem的startOutput
status = AudioSystem::startOutput(thread->id(),
(AudioSystem::stream_type)mStreamType);
thread->mLock.lock();
}
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
playbackThread->addTrack_l(this);//把这个Track加入到活跃Track数组中
returnstatus;
}
~~~
下面来看AudioSystem的startOutput,代码如下所示:
**AudioSystem.cpp**
~~~
status_tAudioSystem::startOutput(audio_io_handle_t output,
AudioSystem::stream_typestream)
{
constsp<IAudioPolicyService>& aps =
AudioSystem::get_audio_policy_service();
if (aps== 0) return PERMISSION_DENIED;
//调用AP的startOutput,最终由AMB完成实际功能
returnaps->startOutput(output, stream);
}
~~~
**AudioPolicyManagerBase.cpp**
~~~
status_tAudioPolicyManagerBase::startOutput(audio_io_handle_t output,
AudioSystem::stream_typestream)
{
//根据output找到对应的AudioOutputDescriptor
ssize_t index = mOutputs.indexOfKey(output);
AudioOutputDescriptor*outputDesc = mOutputs.valueAt(index);
//找到对应流使用的路由策略
routing_strategy strategy =getStrategy((AudioSystem::stream_type)stream);
//增加outputDesc中该流的使用计数,1表示增加1
outputDesc->changeRefCount(stream, 1);
//getNewDevice将得到一个设备,setOutputDevice将使用这个设备进行路由切换。
//至于setOutputDevice,我们在分析耳机插入事件时再来讲解
setOutputDevice(output, getNewDevice(output));
//设置音量,读者可自行分析
checkAndSetVolume(stream,mStreams[stream].mIndexCur, output,
outputDesc->device());
returnNO_ERROR;
}
~~~
再看getNewDevice,它和音频流的使用计数有关系:
**AudioPolicyManagerBase.cpp**
~~~
uint32_tAudioPolicyManagerBase::getNewDevice(audio_io_handle_t output,
bool fromCache)
{
uint32_t device = 0;
AudioOutputDescriptor*outputDesc = mOutputs.valueFor(output);
/*
isUsedByStrategy判断某个策略是否正在被使用,之前曾通过changeRefCount为
MUSIC流使用计数增加了1,所以使用MUSIC策略的个数至少为1,这表明,此设备正在使用该策略。
一旦得到当前outputDesc使用的策略,便可根据该策略找到对应的设备。
注意if和else的顺序,它代表了系统优先使用的策略,以第一个判断为例,
假设系统已经插上耳机,并且处于通话状态时,而且强制使用了扬声器,那么声音都从扬声器出。
这时,如果想听音乐的话,则应首先使用STRATEGY_PHONE的对应设备,此时就是扬声器。
所以音乐将从扬声器出来,而不是耳机。上面仅是举例,具体的情况还要综合考虑Audio
系统中的其他信息。另外如果fromCache为true,将直接从内部保存的旧信息中得到设备,
关于这个问题,在后面的耳机插入事件处理中再做分析
*/
if(mPhoneState == AudioSystem::MODE_IN_CALL ||
outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}
returndevice;
}
~~~
这里,有一个问题需要关注:
* **为什么startOutput函数会和设备切换有关系呢?**
仅举一个例子,帮助理解这一问题。AudioTrack创建时可设置音频流类型,假设第一个AT创建时使用的是MUSIC类型,那么它将使用耳机出声(假设耳机已经连接上)。这时第二个AT创建了,它使用的是RING类型,它对应的策略应是SONIFACATION,这个策略的优先级比MUSIC要高(因为getNewDevice的判断语句首先会判断isUsedByStrategy(STRATEGY_SONIFICATION)),所以这时需要把设备切换为耳机加扬声器(假设这种类型的声音需要从耳机和扬声器同时输出)。startOutput的最终结果,是这两路的Track声音都将从耳机和扬声器中听到。当第二路AT调用stop时,对应音频流类型使用计数会减一,这会导致新的路由切换,并重新回到只有耳机的情况,这时第一路AT的声音会恢复为只从耳机输出。
>[warning] **提醒**:读者可自行分析stop的处理方式,基本上是start的逆向处理过程。
3. 本节小结
这一节主要讲解了AudioTrack和AP之间的交互,总结为以下两点:
- AT通过AP获取AF中的工作线程索引号,这决定了数据传输的最终目标是谁,比如是音频DSP或是蓝牙。
- AT的start和stop会影响Audio系统的路由切换。
读完这一节,读者可能只会对与工作线程索引有关的内容印象较深刻,毕竟这个决定了数据传输的目的地。至于与路由切换有关的知识,可能就还不太了解了。下面,通过分析一个应用场景来启发、加深对它的理解。
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结