Android音頻系統之AudioPolicyService

http://blog.csdn.net/xuesen_lin/article/details/8805108算法

1.1 AudioPolicy Service

在AudioFlinger小節,咱們反覆強調它只是策略的執行者,而AudioPolicyService則是策略的制定者。這種分離方式有效地下降了整個系統的藕合性,並且爲各個模塊獨立擴展功能提供了保障。數組

1.1.1 AudioPolicyService概述

漢語中有不少與策略有關聯的俗語,好比「因地制宜」、「具體問題具體分析」;戰爭中只遵守兵書制定戰術的行爲也被咱們稱爲是「紙上談兵」、死讀書。這些都告訴咱們,瞭解策略的執行環境是很是重要的,只有清晰地界定出「問題是什麼」,纔能有的放矢的制定出正確的Policy來解決問題。網絡

Android系統中聲音的種類有不少種,具體分類以下所示:框架

    /*AudioManager.Java*/   函數

    public static final intSTREAM_VOICE_CALL = 0; /* 通話聲音*/this

    public static final intSTREAM_SYSTEM = 1; /* 系統聲音*/spa

    public static final int STREAM_RING = 2; /* 電話鈴聲和短信提示 */   .net

    public static final intSTREAM_MUSIC = 3; /* 音樂播放 */   插件

    public static final intSTREAM_ALARM = 4; /* 鬧鈴 */   設計

public static final intSTREAM_NOTIFICATION = 5; /* 通知聲音 */

 

    /*下面幾個是隱藏類型,不對上層應用開放*/

    public static final intSTREAM_BLUETOOTH_SCO = 6; /*當鏈接藍牙時的通話*/   

public static final intSTREAM_SYSTEM_ENFORCED = 7; /* 強制的系統聲音,好比有的國家強制要求

                                                   攝像頭拍照時有聲音,以防止偷拍*/  

    public static final intSTREAM_DTMF = 8; /* DTMF聲音 */

    public static final intSTREAM_TTS = 9; /* 即text tospeech (TTS) */

針對這麼多類型的音頻,AudioPolicyService至少面臨着以下幾個問題:

l  上述類型的聲音須要輸出到哪些對應的硬件設備

好比一部典型的手機,它既有聽筒、耳機接口,還有藍牙設備。假設默認狀況下播放音樂是經過聽筒喇叭輸出的,那麼當用戶插入耳機時,這個策略就會改變——從耳機輸出,而再也不是聽筒;又好比在機器插着耳機時,播放音樂不該該從喇叭輸出,可是當有來電鈴聲時,就須要同時從喇叭和耳機輸出音頻。這些「音頻策略」的制定,主導者就是AudioPolicyService

l  聲音的路由策略

若是把一個音樂播放實例(好比用MediaPlayer播放一首SD卡中的歌曲)比做源IP,那麼上一步中找到的音頻播放設備就是目標IP。在TCP/IP體系中,從源IP最終到達目標IP一般須要通過若干個路由器節點,由各路由器根據必定的算法來決定下一個匹配的節點是什麼,從而制定出一條最佳的路由路徑,以下圖所示:

 

圖 13‑16 路由器示意圖

AudioPolicyService所要解決的問題與路由器相似。由於系統中極可能存在多個audiointerface,每個audio interface包含若干output,而每一個output又同時支持若干種音頻設備,這就意味着從播放實例到終端設備,須要通過audiointerface和output的選擇,咱們稱之爲AudioPolicyService的路由功能。

 

l  每種類型音頻的音量調節

不一樣類型的音頻,其音量的可調節範圍是不同的,好比有的是0-15,而有的則是1-20。並且它們的默認值也是有差異的,咱們看AudioManager中的定義:

    public static final int[]  DEFAULT_STREAM_VOLUME = new int[] {

        4,  // STREAM_VOICE_CALL

        7,  // STREAM_SYSTEM

        5,  // STREAM_RING

        11, // STREAM_MUSIC

        6,  // STREAM_ALARM

        5,  // STREAM_NOTIFICATION

        7,  // STREAM_BLUETOOTH_SCO

        7,  // STREAM_SYSTEM_ENFORCED

        11, // STREAM_DTMF

        11  // STREAM_TTS

    };

音量的調節部分後面咱們有專門的小節來介紹。

爲了讓你們對AudioPolicyService有個感性的認識,咱們如下圖來形象地表示它與AudioTrack及AudioFlinger間的關係:

 

圖 13‑17 AudioPolicyService與AudioTrack和AudioFlinger的關係

 

這個圖中的元素包括AudioPolicyService、AudioTrack、AudioFlinger、PlaybackThread以及兩音頻設備(喇叭、耳機)。它們之間的關係以下(特別注意,本例的目的只是說明這些元素的關係,並不表明圖中的策略就是Android系統所採用的):

l  一個PlaybackThread的輸出對應了一種設備

好比圖中有兩個設備,就有兩個PlaybackThread與之對應。左邊的Thread最終混音後輸出到喇叭,而右邊的則輸出到耳機

l  在特定的時間,同一類型音頻對應的輸出設備是統一的

也就是說,若是當前STREAM_MUSIC對應的是喇叭,那麼全部該類型的音頻都會輸出到喇叭。結合上一點,咱們還能夠得出一個結論,即同一類型音頻對應的PlaybackThread也是同樣的

l  AudioPolicyService起到了路由的做用

AudioPolicyService在整個選擇過程當中的做用有點相似於網絡路由器,它有權決定某一個AudioTrack所產生的音頻流最終會走向哪一個設備,就像路由器能夠根據必定的算法來決定發送者的包應該傳遞給哪一個節點同樣

接下來咱們從三個方面來了解AudioPolicyService。

首先,從啓動過程來看AudioPolicyService的工做方式。

其次,咱們結合上面的關係圖詳細分析AudioPolicyService是如何完成「路由功能」的。

最後,咱們來分析Android系統下默認的「路由策略」是怎樣的。

1.1.2 AudioPolicyService的啓動過程

還記得前面咱們在分析AudioFlinger的啓動時,曾經看到過AudioPolicyService的影子嗎?沒錯,它和AudioFlinger是駐留在同一個程序中的,以下所示:

/*frameworks/av/media/mediaserver/Main_mediaserver.cpp*/

int main(int argc, char** argv)

{   …

   AudioFlinger::instantiate();

    …

   AudioPolicyService::instantiate();

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

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

}

於是從理論上來說,AudioFlinger和AudioPolicyService是能夠直接進行函數調用的。不過實際上它們仍然採用標準的Binder進行通訊。

AudioPolicyService的啓動方式和AudioFlinger也是相似的,咱們這裏就不贅述,直接來看它的構造函數:

AudioPolicyService::AudioPolicyService()

    : BnAudioPolicyService() ,mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL)

{

    charvalue[PROPERTY_VALUE_MAX];

    const struct hw_module_t*module;

    int forced_val;

    int rc;

    …

    rc =hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);//Step 1.

    …

    rc =audio_policy_dev_open(module, &mpAudioPolicyDev);//Step 2.

    …

    rc =mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,

                                               &mpAudioPolicy);//Step3.

    …

    rc =mpAudioPolicy->init_check(mpAudioPolicy); //Step 4.

//Step 5

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

    forced_val = strtol(value,NULL, 0);

mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy,!forced_val);

//Step 6.

    if(access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {

       loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);

    } else if(access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {

        loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);

    }

}

咱們將上述代碼段分爲6個步驟來說解。

Step1@ AudioPolicyService::AudioPolicyService. 獲得Audio Policy的hw_module_t,原生態系統中Policy的實現有兩個地方,即Audio_policy.c和Audio_policy_hal.cpp,默認狀況下系統選擇的是後者(對應的庫是libaudiopolicy_legacy)

Step2@ AudioPolicyService::AudioPolicyService. 經過上一步獲得的hw_module_t打開Audio Policy設備(這並非一個傳統意義的硬件設備,而是把Policy虛擬成了一種設備。這樣子的實現方式讓音頻硬件廠商在制定本身的音頻策略時多了很多靈活性)。原生態代碼中audio_policy_dev_open調用的是legacy_ap_dev_open@Audio_policy_hal.cpp,最終生成的Policy Device實現是legacy_ap_device

Step 3@ AudioPolicyService::AudioPolicyService. 經過上述的Audio Policy設備來產生一個策略,其對應的具體實現方法是create_legacy_ap@Audio_policy_hal.cpp。這個函數首先生成的一個legacy_audio_policy@Audio_policy_hal.cpp,而mpAudioPolicy對應的則是legacy_audio_policy::policy。除此以外,legacy_audio_policy還包含以下重要成員變量:

struct legacy_audio_policy {

    structaudio_policy policy;

    void *service;

    structaudio_policy_service_ops *aps_ops;

   AudioPolicyCompatClient *service_client;

   AudioPolicyInterface *apm;

};

其中aps_ops是由AudioPolicyService提供的函數指針(aps_ops),這裏面的函數是AudioPolicyService與外界溝通的接口,後面還會常常遇到。

最後一個apm是AudioPolicyManager的簡寫,AudioPolicyInterface是其基類,apm在原生態實現上是一個AudioPolicyManagerDefault對象,它是在create_legacy_ap中建立的:

static int create_legacy_ap(const struct audio_policy_device*device,

                            structaudio_policy_service_ops *aps_ops,

                           void *service,

                           struct audio_policy **ap)

{

    struct legacy_audio_policy*lap;

                …

                lap->apm =createAudioPolicyManager(lap->service_client);

…}

函數createAudioPolicyManager默認狀況下對應的是AudioPolicyManagerDefault.cpp中的實現,因此它將返回一個AudioPolicyManagerDefault。

是否是以爲Policy相關的類愈來愈多了?那爲何須要這麼多類呢?咱們先來看一下它們之間的關係:

圖 13‑18 Audio Policy相關類的關係

看起來很複雜,其實概況起來就如下幾點:

l  AudioPolicyService持有的只是一個相似於接口類的對象,即audio_policy。換句話說,AudioPolicyService是一個「殼」,而audio_policy則是一個符合要求的插件。插件與殼之間的接口是固定不變的,而內部實現卻能夠根據廠商本身的需求來作

l  咱們知道,audio_policy其實是一個C語言中的struct類型,內部包含了各類函數指針,好比get_output、start_output等等。這些函數指針在初始化時,須要指向具體的函數實現,這就是Audio_policy_hal中的ap_get_output、ap_start_output等等

l  上面提到的各數據類型更多的只是一個「殼」,而真正的實現者是AudioPolicyManager。與此相關的又有三個類:AudioPolicyInterface是它們的基類,AudioPolicyManagerBase實現了一些基礎的策略,而AudioPolicyManagerDefault則是最終的實現類。除了AudioPolicyService,後面這兩個類也是咱們研究Audio Policy的重點

 

Step 4@ AudioPolicyService::AudioPolicyService. 進行初始化檢測,原生態的實現直接返回0

Step 5@ AudioPolicyService::AudioPolicyService. 判斷是否強制執行相機拍照聲音

Step 6@ AudioPolicyService::AudioPolicyService. 加載音頻效果文件(若是存在的話),文件路徑以下:

 AUDIO_EFFECT_DEFAULT_CONFIG_FILE"/system/etc/audio_effects.conf"

 AUDIO_EFFECT_VENDOR_CONFIG_FILE"/vendor/etc/audio_effects.conf"

 這樣AudioPolicyService就完成了構造,它在ServiceManager中的註冊名稱爲"media.audio_policy"。其中包含的mpAudioPolicy變量是實際的策略制定者,而它也是由HAL層建立的,換句話說是根據硬件廠商本身的「意願」來執行策略的。

1.1.3 AudioPolicyService加載音頻設備

在AudioFlinger的「設備管理」小節,咱們曾簡單說起AudioPolicyService將經過解析配置文件來加載當前系統中的音頻設備。具體而言,當AudioPolicyService構造時建立了一個Audio PolicyDevice(mpAudioPolicyDev)並由此打開一個AudioPolicy(mpAudioPolicy)——這個Policy默認狀況下的實現是legacy_audio_policy::policy(數據類型audio_policy)。同時legacy_audio_policy還包含了一個AudioPolicyInterface成員變量,它會被初始化爲一個AudioPolicyManagerDefault,這些都是咱們在前一個小節分析過的。

那麼AudioPolicyService在何時去加載音頻設備呢?

除了後期的動態添加外,另一個重要途徑是經過AudioPolicyManagerDefault的父類,即AudioPolicyManagerBase的構造函數。

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface*clientInterface)…

{   mpClientInterface= clientInterface;

    …

    if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR){

        if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {

            defaultAudioPolicyConfig();

        }

    }

    for (size_t i = 0; i < mHwModules.size();i++) {

       mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);

        if(mHwModules[i]->mHandle == 0) {

            continue;

        }

        for (size_t j = 0; j< mHwModules[i]->mOutputProfiles.size(); j++)

        {

            const IOProfile*outProfile = mHwModules[i]->mOutputProfiles[j];

            if(outProfile->mSupportedDevices & mAttachedOutputDevices) {

                AudioOutputDescriptor*outputDesc = new AudioOutputDescriptor(outProfile);

               outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &

                                                           outProfile->mSupportedDevices);

                audio_io_handle_t output =mpClientInterface->openOutput(…);

                                …              

}

不一樣的Android產品在音頻的設計上一般是有差別的,利用配置文件的形式(audio_policy.conf)可使廠商方便地描述其產品中所包含的音頻設備,這個文件的存放路徑有兩處:

#define AUDIO_POLICY_VENDOR_CONFIG_FILE  "/vendor/etc/audio_policy.conf"

#define AUDIO_POLICY_CONFIG_FILE"/system/etc/audio_policy.conf"

若是audio_policy.conf不存在的話,則系統將使用默認的配置,具體實如今defaultAudioPolicyConfig中。經過配置文件能夠讀取以下信息:

·        有哪些audiointerface,好比有沒有「primary」、「a2dp」、「usb」

·        每一個audiointerface的屬性。好比支持的sampling_rates、formats、支持哪些device等等。這些屬性是在loadOutput@AudioPolicyManagerBase中讀取的,並存儲到HwModule->mOutputProfiles中。每個audiointerface下可能有若干個output和input,而每一個output/input下又有若干具體的支持屬性,關係以下圖所示:

 

圖 13‑19 audio_policy.conf中各元素關係圖

 

你們能夠本身打開一個audio_policy.conf來具體瞭解這個文件的格式要求,咱們這裏就不作深刻講解了。

讀取了相關配置後,接下來就要打開這些設備了。AudioPolicyService只是策略制定者,而非執行者,那麼是由誰來完成這些具體的工做呢?沒錯,必定是AudioFlinger。咱們能夠看到上述函數段中有一個mpClientInterface變量,它是否和AudioFlinger有聯繫?能夠先來分析下這個變量是如何來的。

很明顯的mpClientInterface這個變量在AudioPolicyManagerBase構造函數的第一行進行了初始化,再回溯追蹤,能夠發現它的根源在AudioPolicyService的構造函數中,對應的代碼語句以下:

rc =mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this, &mpAudioPolicy);                           

在這個場景下,函數create_audio_policy對應的是create_legacy_ap,並將傳入的aps_ops組裝到一個AudioPolicyCompatClient對象中,也就是mpClientInterface所指向的那個對象。

換句話說,mpClientInterface->loadHwModule實際上調用的就是aps_ops->loadHwModule,即:

static audio_module_handle_t  aps_load_hw_module(void*service,const char *name)

{

    sp<IAudioFlinger> af= AudioSystem::get_audio_flinger();

    …

    returnaf->loadHwModule(name);

}

AudioFlinger終於出現了,一樣的狀況也適用於mpClientInterface->openOutput,代碼以下:

static audio_io_handle_t  aps_open_output(…)

{

    sp<IAudioFlinger> af= AudioSystem::get_audio_flinger();

    …

    return  af->openOutput((audio_module_handle_t)0,pDevices, pSamplingRate, pFormat, pChannelMask,

                         pLatencyMs, flags);

}

再回到AudioPolicyManagerBase的構造函數中來,for循環的目標有兩個:

Ø  利用loadHwModule來加載從audio_policy.conf中解析出的audio interface,即mHwModules數組中的元素

Ø  利用openOutput來打開各audio interface中包含的全部Output

關於AudioFlinger中這兩個函數的實現,咱們在前一個小節已經分析過了,這裏終於把它們串起來了。經過AudioPolicyManagerBase,AudioPolicyService解析出了設置中的音頻配置,並利用AudioFlinger提供的接口完成了整個音頻系統的部署,從而爲後面上層應用使用音頻設備提供了底層支撐。下一小節咱們就看下上層應用具體是如何使用這一框架來播放音頻的。

相關文章
相關標籤/搜索