Android音频系统之AudioPolicyService
地址:http://blog.csdn.net/edmond999/article/details/18599327
1.1 AudioPolicy Service
?
在AudioFlinger小節,我們反復強調它只是策略的執行者,而AudioPolicyService則是策略的制定者。這種分離方式有效地降低了整個系統的藕合性,而且為各個模塊獨立擴展功能提供了保障。
1.1.1 AudioPolicyService概述
漢語中有很多與策略有關聯的俗語,比如“因地制宜”、“具體問題具體分析”;戰爭中只遵照兵書制定戰術的行為也被我們稱為是“紙上談兵”、死讀書。這些都告訴我們,了解策略的執行環境是非常重要的,只有清晰地界定出“問題是什么”,才能有的放矢的制定出正確的Policy來解決問題。
Android系統中聲音的種類有很多種,具體分類如下所示:
??? /*AudioManager.java*/???
??? public static final intSTREAM_VOICE_CALL = 0; /* 通話聲音*/
??? public static final intSTREAM_SYSTEM = 1; /* 系統聲音*/
?? ?public static final int STREAM_RING = 2; /* 電話鈴聲和短信提示 */???
??? 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提供的接口完成了整個音頻系統的部署,從而為后面上層應用使用音頻設備提供了底層支撐。下一小節我們就看下上層應用具體是如何使用這一框架來播放音頻的。
?
?
?
?
轉自:http://blog.csdn.net/xuesen_lin/article/details/8805108
轉載于:https://www.cnblogs.com/senior-engineer/p/4976716.html
總結
以上是生活随笔為你收集整理的Android音频系统之AudioPolicyService的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站三级分销数据库如何设计,简单案例
- 下一篇: 5道经典基础编程题让你入门C语言