AudioPolicy流程分析

转载自:
UML顺序图:
AudioPolicy.svg

切入点:

AF和APS系统第一次起来后,到底干了什么。

检测到耳机插入事件后,AF和APS的处理。

1 AudioFlinger-instantiate

AF和APS的诞生

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

AudioHardwareInterface-create

AudioFlinger::AudioFlinger()
    : BnAudioFlinger(),//基类构造函数
      mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
{
    mHardwareStatus = AUDIO_HW_IDLE;
    //创建audio的HAL代表
    mAudioHardware = AudioHardwareInterface::create();
    mHardwareStatus = AUDIO_HW_INIT;
    if (mAudioHardware->initCheck() == NO_ERROR) {
        setMode(AudioSystem::MODE_NORMAL);
        setMasterVolume(1.0f);
        setMasterMute(false);
    }
}

AF创建了一个AudioHardware的HAL对象。注意整个系统就这一个AudioHardware了。也就是说,不管是线控耳机,蓝牙耳机,麦克,外放等等,最后都会由这一个HAL统一管理。

3 AudioPolicyService-instantiate

AudioPolicyService::AudioPolicyService()
    : BnAudioPolicyService() , mpPolicyManager(NULL)
{
    // mpPolicyManager 策略管理器
    char value[PROPERTY_VALUE_MAX];
    mTonePlaybackThread = new AudioCommandThread(String8(""));
    mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
    #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
        // 注意AudioPolicyManagerBase的构造函数,把this传进去了。
        mpPolicyManager = new AudioPolicyManagerBase(this);
    #else
        ...
    #endif
    // 根据系统属性来判断摄像机是否强制使用声音。这个...为什么会放在这里?
    // 手机带摄像机好像刚出来的时候,为了防止偷拍,强制按快门的时候必须发出声音
    property_get("ro.camera.sound.forced", value, "0");
    mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}

AudioPolicyManagerBase的构造函数可是把APS传进去了,看来又会有一些回调靠APS了。

4 new AudioPolicyManagerBase

这是重点!

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
: mPhoneState(AudioSystem::MODE_NORMAL), ---->这里有电话的状态?
mRingerMode(0),
mMusicStopTime(0),
mLimitRingtoneVolume(false)
{
    mpClientInterface = clientInterface;    //BT,保存APS对象。
    for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
        mForceUse[i] = AudioSystem::FORCE_NONE;
    }
    ...
    // 下面这个意思就是把几种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;
    // 注意这里是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();
}

下面是audio_mode的定义。

enum audio_mode {
        MODE_INVALID = -2, //无效mode
        MODE_CURRENT = -1,//当前mode,和音频设备的切换(路由)有关
        MODE_NORMAL = 0,//正常mode,没有电话和铃声
        MODE_RINGTONE,//收到来电信号了,此时会有铃声
        MODE_IN_CALL,//电话mode,这里表示已经建立通话了
        NUM_MODES  // Android大量采用这种技巧来表示枚举结束了。
};

forced_config,强制_配置,看名字好像是强制使用设备吧,比如外放,耳机,蓝牙等。

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 
};
enum force_use {
        FOR_COMMUNICATION,    //这里是for_xxx,不是force_xxx。
        FOR_MEDIA,
        FOR_RECORD,
        FOR_DOCK,
        NUM_FORCE_USE
};

来看看AudioSystem是怎么定义输入输出设备:

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

5 mForceUse[i] = AudioSystem-FORCE_NONE

6 new AudioOutputDescriptor

AudioOutputDescriptor:

描述audio输出的,可以用来保存一些配置信息。跟踪音频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)
{}

7 mpClientInterface-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();
    return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
}

8 AudioSystem-get_audio_flinger

9 af-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) {
         // 那几个值变成: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来表示它想要的就可以了。
               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;
}

10 mAudioHardware-openOutputStream

11 new MixerThread

12 setOutputDevice

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
    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
    if (outputDesc->isDuplicated()) {
        setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
        setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
        return;
    }
    // prevDevice: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 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);
    }
}

这个调用,更新了mHardwareOutput对应的输出路由设备,而且还发了一个命令给APS,要更新对应混音线程的输出路由设备。

13 mpClientInterface-setParameters

14 setStrategyMute

15 updateDeviceForStrategy

void AudioPolicyManagerBase::updateDeviceForStrategy()
{
    for (int i = 0; i < NUM_STRATEGIES; i++) {
        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);
    }
}

表明各种策略下使用的对应设备也准备好了。

NUM_STRATEGIES在hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h中定义。

enum routing_strategy {
            STRATEGY_MEDIA,
            STRATEGY_PHONE,    //通话音
            STRATEGY_SONIFICATION,//除了其他三个外的,可以是铃声,提醒声等。
            STRATEGY_DTMF,     //拨号音
            NUM_STRATEGIES
};

16 getDeviceForStrategy

为各种策略找到它对应的设备。

uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
{
    // fromCache为false
    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
            // FALL THROUGH
            // 我们还记得强制设置那里吗?对了,此时都是FORCE_NONE。而且,mAvailableOutputDevices是0X3 (外放|耳机)
        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,说明SONIFICATION受MEDIA策略影响。
    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;
}

AudioPolicy总结:

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

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

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

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

另外,我们分析的AMB是Generic的,但不同厂商可以实现自己的策略。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值