Android深入浅出之Audio第三部分Audio Policy[1]

农历新年快来到了,我希望能把android这个系列写完。

今天这篇帖子是农历年最后一篇了。大家如果有什么想了解的,可以回帖或者站内短消息,我们共同来分析Android。

目的

上回我们说了 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<ProcessState> proc(ProcessState::self());

    sp<IServiceManager> sm = defaultServiceManager();

    // 先创建AF

AudioFlinger::instantiate();

    // 再创建APS

AudioPolicyService::instantiate();

 

    ProcessState::self()->startThreadPool();

    IPCThreadState::self()->joinThreadPool();

}

2.1 new AudioFlinger

前面说过, instantiate 内部会实例化一个对象,那直接看 AF 的构造函数。

AudioFlinger::AudioFlinger()

    : BnAudioFlinger(),// 基类构造函数

        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)

{

  注意mAudioHardwaremNextThreadId

  mHardwareStatus = AUDIO_HW_IDLE;

// 创建audioHAL 代表

    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 吧。

2.2 new AudioPolicyService

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);

    // 先假设我们使用GenericAudio 设备吧。

#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 了。真绕。

2.3 AudioPolicyManagerBase

代码位置在 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,

AudioSystem.FORCE_SPEAKER);

            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;

        } else {

            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,

AudioSystem.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;

// 目前可用的输入设备,内置MICmAvailableInputDevices0x4000 ,不过我们不关注input

  mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;

  

  ...

  下面东西就很少了,我们一气呵成。

// 创建一个AudioOutputDescriptor ,并设置它的device 为外设0x2

AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();

outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;

 

// 调用APSopenOutput ,得到一个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<IAudioFlinger> 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) {

// 走哪个分支?我把答案告诉大家吧。

// 刚才那个mAudioHardware->openOutputStream 确实会更改指针对应的value

// 当然,我们说了,AF 使用的是GENERICAudio 硬件。大家有兴趣可以去看看它的实现。

// 我待会再贴出它的内容。反正到这里。

// 那几个值变成:formatPCM_16_BITchannels2samplingRate44100

// 这样的话,那只能走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 来表示它想要的就可以了。例如GenericAudio 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

//deviceAudioSystem::DEVICE_OUT_SPEAKER

// forcetruedelayMs 用默认值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;

popCount2 ,因为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)

{

  //  fromCachefalse

// 放眼望去,这个函数好像涉及到很对策略方面的事情。

// 我们大概讲解下,至于系统为什么要这么做,问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 下,DTMFPHONE 用一个策略

    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

            // FALL THROUGH

       // 我们还记得强制设置那里吗?对了,此时都是FORCE_NONE

      // 而且,mAvailableOutputDevices0X3 ( 外放| 耳机)

        default:    // FORCE_NONE

            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;

            if (device) break;

            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;

             if (device) break;

   // 看,下面这句会成立。啥意思?如果有耳机的话,那么输出设备就是耳机

// 太正确了。实际手机是不是就是这样的呢?

            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;

            break;

     // 再验证下我们刚才说的,如果强制使用外放的话,

        case AudioSystem::FORCE_SPEAKER:

            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_SPEAKER;

            break;

        }

    break;

    case STRATEGY_SONIFICATION:// 分析方法同上,我不说了。

        if (mPhoneState == AudioSystem::MODE_IN_CALL) {

            device = getDeviceForStrategy(STRATEGY_PHONE, false);

            break;

        }

        device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;

// 同样没有break ,说明SONIFICATIONMEDIA 策略影响。

    case STRATEGY_MEDIA: {

        uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;

        if (device2 == 0) {

            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;

        }

        if (device2 == 0) {

            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;

        }

   // 可惜,上面那些高级设备我们都没有

        if (device2 == 0) {

            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;

        }

  // 假设我们没有从SONIFICATION 下来,那么device 最终会= DEVICE_OUT_SPEAKER

// 假设我们从SONIFICATION 下来,那么device 还是等于DEVICE_OUT_SPEAKER

// 奇怪,如果有耳机的话为何会走外放呢?普通耳机和线控耳机还能区分?

        device |= device2;

        } break;

 

    default:

        break;

    }

    return device;

}

好了,回到

[---->AudioPolicyManagerBase::updateDeviceForStrategy()]

void AudioPolicyManagerBase::updateDeviceForStrategy()

{

    for (int i = 0; i < NUM_STRATEGIES; i++) {

        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);

    }

}

这个函数完了,表明各种策略下使用的对应设备也准备好了。

真爽,一路回去, APS 的构造就完了。

留个纪念:

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)

{

  ....

updateDeviceForStrategy();

}

AudioPolicyService::AudioPolicyService()

: BnAudioPolicyService() , mpPolicyManager(NULL)

{

  #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)

    mpPolicyManager = new AudioPolicyManagerBase(this);

LOGV("build for GENERIC_AUDIO - using generic audio policy");

  ...

#endif

property_get("ro.camera.sound.forced", value, "0");

mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);

}

 

2.4 总结

总结下吧, AF,APS 都创建完了,得到什么了吗?下面按先后顺序说说。

l          AF 创建了一个代表 HAL 对象的东西

l          APS 创建了两个 AudioCommandThread ,一个用来处理命令,一个用来播放 tone 。我们还没看。

l          APS 同时会创建 AudioManagerBase ,做为系统默认的音频管理

l          AMB 集中管理了策略上面的事情,同时会在 AF openOutput 中创建一个混音线程。同时, AMB 会更新一些策略上的安排。

另外,我们分析的 AMB Generic 的,但不同厂商可以实现自己的策略。例如我可以设置只要有耳机,所有类型声音都从耳机出。

上面关于 AMB 方面,我们还只是看了看它的代码,还没有一个实际例子来体会。

你可能感兴趣的:(thread,android,Stream,audio,Descriptor,output)