一 目的
我们提供的服务有:做网站、网站制作、微信公众号开发、网站优化、网站认证、精河ssl等。为近千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的精河网站制作公司
上回我们说了AudioFlinger(AF),总感觉代码里边有好多东西没说清楚,心里发毛。就看了看AF的流程,我们敢说自己深入了解了Android系统吗?AudioPolicyService(APS)是个什么东西?为什么要有它的存在?下层的Audio HAL层又是怎么结合到Android中来的?更有甚者,问个实在问题:插入耳机后,声音又怎么从最开始的外放变成从耳机输出了?调节音量的时候到底是调节Music的还是调节来电音量呢?这些东西,我们在AF的流程中统统都没讲到。但是这些他们又是至关重要的。从我个人理解来看,策略(Policy)比流程更复杂和难懂。
当然,遵循我们的传统分析习惯,得有一个切入点,否则我们都不知道从何入手了。
这里的切入点将是:
l AF和APS系统第一次起来后,到底干了什么。
l 检测到耳机插入事件后,AF和APS的处理。
大家跟着我一步步来看,很快就发现,啊哈,APS也不是那么难嘛。
另外,这次代码分析的格式将参考《Linux内核情景分析》的样子,函数调用的解析将采用深度优先的办法,即先解释所调用的函数,然后再出来继续讲。
我曾经数度放弃分析APS,关键原因是我没找到切入点,只知道代码从头看到尾!
二 AF和APS的诞生
这个东西,已经说得太多了。在framework/base/media/MediaServer/Main_MediaServer中。
我们看看。
- int main(int argc, char** argv)
- {
- sp
proc(ProcessState::self()); - sp
sm = defaultServiceManager(); - //先创建AF
- AudioFlinger::instantiate();
- //再创建APS
- AudioPolicyService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
前面说过,instantiate内部会实例化一个对象,那直接看AF的构造函数。
- AudioFlinger::AudioFlinger()
- : BnAudioFlinger(),//基类构造函数
- mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
- {
注意mAudioHardware和mNextThreadId
mHardwareStatus = AUDIO_HW_IDLE;
//创建audio的HAL代表
mAudioHardware = AudioHardwareInterface::create();
mHardwareStatus = AUDIO_HW_INIT;
//下面这些不至于会使用APS吧?APS还没创建呢!
- if (mAudioHardware->initCheck() == NO_ERROR) {
- setMode(AudioSystem::MODE_NORMAL);
- setMasterVolume(1.0f);
- setMasterMute(false);
- }
感觉上,AF的构造函数就是创建了一个最重要的AudioHardWare的HAL代表。
其他好像是没干什么策略上的事情。
不过:AF创建了一个AudioHardware的HAL对象。注意整个系统就这一个AudioHardware了。也就是说,不管是线控耳机,蓝牙耳机,麦克,外放等等,最后都会由这一个HAL统一管理。
再看APS吧。
- AudioPolicyService::AudioPolicyService()
- : BnAudioPolicyService() , mpPolicyManager(NULL)
- {
- // mpPolicyManager?策略管理器?可能很重要
- char value[PROPERTY_VALUE_MAX];
- // TonePlayback?播放铃声的?为什么放在这里?以后来看看
- mTonePlaybackThread = new AudioCommandThread(String8(""));
- // Audio Command?音频命令?看到Command,我就想到设计模式中的Command模式了
- //Android尤其是MediaPlayerService中大量使用了这种模式。
- mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
- #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
- //注意AudioPolicyManagerBase的构造函数,把this传进去了。
- mpPolicyManager = new AudioPolicyManagerBase(this);
- //先假设我们使用Generic的Audio设备吧。
- #else
- ...
- #endif
// 根据系统属性来判断摄像机是否强制使用声音。这个...为什么会放在这里?
//手机带摄像机好像刚出来的时候,为了防止偷拍,强制按快门的时候必须发出声音
//就是这个目的吧?
- property_get("ro.camera.sound.forced", value, "0");
- mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
- }
so easy!,不至于吧?我们不应该放过任何一个疑问!这么多疑问,先看哪个呢?这里分析的是Audio Policy,而构造函数中又创建了一个AudioPolicyManagerBase,而且不同厂商还可以实现自己的AudioPolicyManager,看来这个对于音频策略有至关重要的作用了。
不得不说的是,Android代码中的这些命名在关键地方上还是比较慎重和准确的。
另外,AudioPolicyManagerBase的构造函数可是把APS传进去了,看来又会有一些回调靠APS了。真绕。
代码位置在framework/base/libs/audioflinger/AudioPolicyManagerBase.cpp中
- AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
- :
- mPhoneState(AudioSystem::MODE_NORMAL), ---->这里有电话的状态?
- mRingerMode(0),
- mMusicStopTime(0),
- mLimitRingtoneVolume(false)
- {
- [--->mPhoneState(AudioSystem::MODE_NORMAL)]
AudioSystem其实是窥视Android如何管理音频系统的好地方。位置在
framework/base/include/media/AudioSystem.h中,定义了大量的枚举之类的东西来表达Google对音频系统的看法。我们只能见招拆招了。
下面是audio_mode的定义。这里要注意一个地方:
这些定义都和SDK中的JAVA层定义类似。实际上应该说先有C++层的定义,然后再反映到JAVA层中。但是C++层的定义一般没有解释说明,而SDK中有。所以我们不能不面对的一个痛苦现实就是:常常需要参考SDK的说明才能搞明白到底是什么。
关于C++的AudioSystem这块,SDK的说明在AudioManager中。
- enum audio_mode {
- //解释参考SDK说明,以下不再说明
- MODE_INVALID = -2, //无效mode
- MODE_CURRENT = -1,//当前mode,和音频设备的切换(路由)有关
- MODE_NORMAL = 0,//正常mode,没有电话和铃声
- MODE_RINGTONE,//收到来电信号了,此时会有铃声
- MODE_IN_CALL,//电话mode,这里表示已经建立通话了
- NUM_MODES // Android大量采用这种技巧来表示枚举结束了。
- };
好,继续:
- ...
- mPhoneState(AudioSystem::MODE_NORMAL), ---->这里有电话的状态?
- mRingerMode(0),
- mMusicStopTime(0),
- mLimitRingtoneVolume(false)
- {
- mpClientInterface = clientInterface;//BT,保存APS对象。
- //forceUse?这是个什么玩意儿?
- for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
- mForceUse[i] = AudioSystem::FORCE_NONE;
- }
[---->AudioSystem::FORCE_NONE和AudioSystem::NUM_FORCE_USE]
注意,这里有两个枚举,太无耻了。先看看FORCE_NONE这个
- enum forced_config {强制_配置,看名字好像是强制使用设备吧,比如外放,耳机,蓝牙等
- FORCE_NONE,
- FORCE_SPEAKER,
- FORCE_HEADPHONES,
- FORCE_BT_SCO,
- FORCE_BT_A2DP,
- FORCE_WIRED_ACCESSORY,
- FORCE_BT_CAR_DOCK,
- FORCE_BT_DESK_DOCK,
- NUM_FORCE_CONFIG,
- FORCE_DEFAULT = FORCE_NONE //这个,太无聊了。
- };
再看看AudioSystem::NUM_FORCE_USE这个
- enum force_use {
- FOR_COMMUNICATION,//这里是for_xxx,不是force_xxx。
- FOR_MEDIA,
- FOR_RECORD,
- FOR_DOCK,
- NUM_FORCE_USE
- };
不懂,两个都不懂。为何?能猜出来什么吗?也不行。因为我们没找到合适的场景!那好吧,我们去SDK找找。恩
我看到AudioManager这个函数setSpeakerphoneOn (boolean on)。好吧,我
这么调用
setSpeakerphoneOn(true),看看实现。
这次我没再浪费时间了,我用一个新的工具coolfind,把搜索framework目录,寻找*.java文件,匹配字符串setSpeakerphone。终于,我在
- framework/base/media/java/android/media/AudioService.java中找到了。
- public void setSpeakerphoneOn(boolean on){
- if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
- return;
- }
- if (on) {
//看到这里,是不是明白十之八九了?下面这个调用是:
//强制通话使用speaker!原来是这么个意思!
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,
- ioSystem.FORCE_SPEAKER);
- mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
- } else {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,
- ioSystem.FORCE_NONE);
- mForcedUseForComm = AudioSystem.FORCE_NONE;
- }
- }
好了,说点题外话,既然Android源码都放开给我们了,有什么理由我们不去多搜搜呢?上网google也是搜,查源代码也是一样吗。不过我们要有目的:就是找到一个合适的使用场景。
force_use和force_config就不用我再解释了吧?
- [--->AudioPolicyManagerBase::AudioPolicyManagerBase]
- ...
//下面这个意思就是把几种for_use的情况使用的设备全部置为NONE。
//比如设置FOR_MEDIA的场景,使用的设备就是FORCE_NONE
- for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
- mForceUse[i] = AudioSystem::FORCE_NONE;
- }
// 目前可以的输出设备,耳机和外放
- mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
- AudioSystem::DEVICE_OUT_SPEAKER;
- //目前可用的输入设备,内置MIC
- mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
- 又得来看看AudioSystem是怎么定义输入输出设备的了。
- [--->mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE]
- enum audio_devices {
- // output devices
- DEVICE_OUT_EARPIECE = 0x1,
- DEVICE_OUT_SPEAKER = 0x2,
- DEVICE_OUT_WIRED_HEADSET = 0x4,
- DEVICE_OUT_WIRED_HEADPHONE = 0x8,
- DEVICE_OUT_BLUETOOTH_SCO = 0x10,
- DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
- DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
- DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
- DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
- DEVICE_OUT_AUX_DIGITAL = 0x400,
- DEVICE_OUT_DEFAULT = 0x8000,
- DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER |
- DEVICE_OUT_WIRED_HEADSET | DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
- DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
- DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
- DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- // input devices
- DEVICE_IN_COMMUNICATION = 0x10000,
- DEVICE_IN_AMBIENT = 0x20000,
- DEVICE_IN_BUILTIN_MIC = 0x40000,
- DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
- DEVICE_IN_WIRED_HEADSET = 0x100000,
- DEVICE_IN_AUX_DIGITAL = 0x200000,
- DEVICE_IN_VOICE_CALL = 0x400000,
- DEVICE_IN_BACK_MIC = 0x800000,
- DEVICE_IN_DEFAULT = 0x80000000,
- DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT |
- DEVICE_IN_BUILTIN_MIC |DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET |
- DEVICE_IN_AUX_DIGITAL | DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC |
- DEVICE_IN_DEFAULT)
- };
一些比较容易眼花的东西我标成红色的了。这么多东西,不过没什么我们不明白的了。
得嘞,继续走。
[--->AudioPolicyManagerBase::AudioPolicyManagerBase]
// 目前可以的输出设备,又有耳机又有外放,配置很强悍啊。
//注意这里是OR操作符,最终mAvailableOutputDevices = 0X3
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
AudioSystem::DEVICE_OUT_SPEAKER;
//目前可用的输入设备,内置MIC,mAvailableInputDevices为0x4000,不过我们不关注input
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
下面东西就很少了,我们一气呵成。
//创建一个AudioOutputDescriptor,并设置它的device为外设0x2
- AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
- outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
//调用APS的openOutput,得到一个mHardwareOutput东东。这是个int型
//不过保不准是一个指针也不一定喔。
//而且,下面的参数都是指针类型(flags除外),难道?有人会改value吗?
- mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
- &outputDesc->mSamplingRate,
- &outputDesc->mFormat,
- &outputDesc->mChannels,
- &outputDesc->mLatency,
- outputDesc->mFlags);
//这个...估计是把int和指针加入到一个map了,方便管理。
addOutput(mHardwareOutput, outputDesc);
//不知道干嘛,待会看。
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
//不知道干嘛,待会看。
updateDeviceForStrategy();
好了,上面还有一系列函数,等着我们调用呢。我们一个一个看。
提前说一下,这块可是AudioManagerBase的核心喔。
[---->AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor()]
AudioOutputDescriptor是个什么?我不是神,我也得看注释。
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
明白了么?大概意思就是它,是这么一个东西:
l 描述audio输出的,可以用来保存一些配置信息。
l 跟踪音频stream类型使用这个output的一些情况。
没明白吧?以后碰到场景就明白了。
它的构造函数干了如下勾当:
- AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
- : mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
- mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0)
- {}
//很好,统统都置零了。上面这些东西不用我解释了吧?命名规则也可以看出来。
OK,go on.
[--->mHardwareOutput = mpClientInterface->openOutput()]:
这里调用的是APS的openOutput,看看去:
- [--->AudioPolicyService::openOutput]
- audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- uint32_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- AudioSystem::output_flags flags)
- {
- sp
af = AudioSystem::get_audio_flinger(); - //娘希匹,搞到AF去了
- return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels,
- pLatencyMs, flags);
- }
- [----->AudioFlinger::openOutput]
- int AudioFlinger::openOutput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- uint32_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- uint32_t flags)
- {
- //我们思考下传进来的值吧
- //*pDevices=0x2,代表外放
- //其他都是0。 嘿嘿,有了值,这不就知道下面该怎么走了吗?
- status_t status;
- PlaybackThread *thread = NULL;
- mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
- uint32_t format = pFormat ? *pFormat : 0;
- uint32_t channels = pChannels ? *pChannels : 0;
- uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
- Mutex::Autolock _l(mLock);
- //HAL对象得到一个AudioStreamOut,传进去的值会改吗?
- AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
- (int *)&format,
- &channels,
- &samplingRate,
- &status);
- mHardwareStatus = AUDIO_HW_IDLE;
- if (output != 0) {
#p#
//走哪个分支?我把答案告诉大家吧。
//刚才那个mAudioHardware->openOutputStream确实会更改指针对应的value。
//当然,我们说了,AF使用的是GENERIC的Audio硬件。大家有兴趣可以去看看它的实现。
//我待会再贴出它的内容。反正到这里。
//那几个值变成:format为PCM_16_BIT,channels为2,samplingRate为44100
//这样的话,那只能走else分支了。
- if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
- (format != AudioSystem::PCM_16_BIT) ||
- (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
- thread = new DirectOutputThread(this, output, ++mNextThreadId);
- } else {
//还记得前两节分析的同学,看到这里是不是明白了?恩,原来
//open一个Output,就会在AF中创建一个混音线程。设计得真好。
//想象下,所有设置为外放的程序,它的输出都是这个外放stream混音线程来工作
//所有设置为耳机的程序,它的输出都是这个耳机stream混音线程来完成。
//为什么对stream特加强调呢,没看见
//我们调用的是mAudioHardware->openOutputStream(0x2,,,)嘛。返回的
//是一个AudioStreamOut,可不是设备喔。Android把这些个东西都交给HAL层去实现了。
//不用自己来管理系统上有什么耳机,外设,蓝牙真实设备之类的东东,它反正用AudioStreamOut来表示它想要的就可以了。例如Generic的Audio Hal只支持一个OutputStream。--> only my opinion
thread = new MixerThread(this, output, ++mNextThreadId);
}
//好了,又多得了一个线程,
- mPlaybackThreads.add(mNextThreadId, thread);
- if (pSamplingRate) *pSamplingRate = samplingRate;
- if (pFormat) *pFormat = format;
- if (pChannels) *pChannels = channels;
- if (pLatencyMs) *pLatencyMs = thread->latency();
//从这里返回的是混音线程的索引。
return mNextThreadId;
return 0;//如果没创建成功线程,则返回零。
}
好,我们回到AudioManagerBase中。
- [--->AudioPolicyManagerBase::AudioPolicyManagerBase]
- mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
- &outputDesc->mSamplingRate,
- &outputDesc->mFormat,
- &outputDesc->mChannels,
- &outputDesc->mLatency,
- outputDesc->mFlags);
//上面实际就返回一个线程index。我有点疑惑,难道APS就只这么一个实际是线程index的东西就就行了吗?虽然它把这个index当成hardware的标识了。
//这个...估计是把int和指针加入到一个map了,方便管理。不看了。
addOutput(mHardwareOutput, outputDesc);
//不知道干嘛,待会看。
- setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
- [--->setOutputDevice(mHardwareOutput,...)]
这个函数,很重要!另外,再传点技巧。不要老在source insight中后退后退了,直接找到window菜单,里边列出了最近打开的文件,找到我们的AudioManagerBase.cpp,不就行了吗?
void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
{
//注意我们的参数:
// output = 1,
//device为AudioSystem::DEVICE_OUT_SPEAKER
// force为true,delayMs用默认值0
//map吧?刚才通过addOutput已经加进去了
- AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
- setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
- setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
- return;
- }
//还记得addOutput前设置的device吗?对了,为0X3,外放|耳机
- uint32_t prevDevice = (uint32_t)outputDesc->device();
- 现在设置的是外设,
- if ((device == 0 || device == prevDevice) && !force) {
- return;
- }
- //喔,设置这个outputDesc为外放
- outputDesc->mDevice = device;
- popCount为2,因为device=0x2=0010
//另外,我对下面这个output== mHardwareOutput尤其感兴趣。还记得我们刚才的疑问吗?
// mHardwareOutput实际上是AF返回的一个线程索引,那AMB怎么根据这样一个东西来
//管理所有的线程呢?果然,这里就比较了output是不是等于最初创建的线程索引
//这就表明。虽然只有这么一个mHardwareOutput,但实际上还是能够操作其他output的!
- if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) {
- setStrategyMute(STRATEGY_MEDIA, true, output);
- usleep(outputDesc->mLatency*2*1000);
- }
// 晕,又冒出来一个AudioParameter,不过意思却很明白
//说我们要设置路由,新的输出设备为外放
//等我们以后讲由外放切换到耳机,再来看这个问题。
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)device);
- mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);
- // update stream volumes according to new device
- applyStreamVolumes(output, device, delayMs);
// if changing from a combined headset + speaker route, unmute media streams
if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) {
//这里说,把media的音量置为0。以后再说。
setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
}
}
好了,返回了。
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
这个调研,更新了mHardwareOutput对应的输出路由设备,而且还发了一个命令给APS,说你给我更新对应混音线程的输出路由设备。
- [--->AudioPolicyManagerBase::AudioPolicyManagerBase]
- .....
- addOutput(mHardwareOutput, outputDesc);
- setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,
- true);
//只剩下最后一个函数了
- updateDeviceForStrategy();
- [----->updateDeviceForStrategy()]
- void AudioPolicyManagerBase::updateDeviceForStrategy()
- {
- for (int i = 0; i < NUM_STRATEGIES; i++) {
- mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);
- }
- }
晕,又出来一个枚举。我们看看
- [---->for (int i = 0; i < NUM_STRATEGIES; i++)]
- NUM_STRATEGIES在hardware/libhardware_legacy/include/hardware_legacy/
- AudioPolicyManagerBase.h中定义。
- enum routing_strategy {
- //好像很好理解
- STRATEGY_MEDIA,
- STRATEGY_PHONE,//通话音吗?
- STRATEGY_SONIFICATION,//除了其他三个外的,可以是铃声,提醒声等。
- STRATEGY_DTMF,//好像是拨号音
- NUM_STRATEGIES
- };
这个,反正我在SDK上没找到对应说明,我们待到以后看看会不会柳暗花明呢?
[----->getDeviceForStrategy((routing_strategy)i, false)]
看这个函数名的意思是,为各种策略找到它对应的设备。
uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
{
// fromCache为false
//放眼望去,这个函数好像涉及到很对策略方面的事情。
//我们大概讲解下,至于系统为什么要这么做,问Google吧。
- uint32_t device = 0;
- switch (strategy) {
- case STRATEGY_DTMF:
- if (mPhoneState != AudioSystem::MODE_IN_CALL) {
- //如果在打电话过程中,你再按按键,则和MEDIA走一个设备
- device = getDeviceForStrategy(STRATEGY_MEDIA, false);
- break;
- }
//注意这里没有break,所以在其他mode下,DTMF和PHONE用一个策略
case STRATEGY_PHONE:
//还得判断用户是不是强制使用了输出设备。
- switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
- case AudioSystem::FORCE_BT_SCO:
- if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
- device = mAvailableOutputDevices &
- AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- if (device) break;
- }
- device = mAvailableOutputDevices &
- AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
- if (device) break;
- // if SCO device is requested but no SCO device is available, fall back to default
- // case&n
标题名称:Android深入浅出之Audio第三部分AudioPolicy
分享网址:http://www.shufengxianlan.com/qtweb/news16/138166.html网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联