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

一目的

上回我們說了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)

{

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

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

    //先假設我們使用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了。真繞。

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;

//目前可用的輸入設備,內置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<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使用的是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

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

}

好了,回到

[---->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方面,我們還只是看了看它的代碼,還沒有一個實際例子來體會。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章