1 分析思路
-
Thread如何創建?
AudioPolicyService是策略的制定者,AudioFlinger是策略的執行者,
所以: AudioPolicyService根據配置文件使喚AudioFlinger來創建Thread -
Thread對應output, output對應哪些設備節點?
-
AudioTrack和Track的創建過程: AudioTrack對應哪一個Thread, 對應哪一個output?
-
AudioTrack如何傳輸數據給Thread?
-
AudioTrack如何播放、暫停、關閉?

2 以例子說明幾個重要概念
stream type, strategy, device, output, profile, module : policy
out flag : 比如對於某個專業APP, 它只從HDMI播放聲音, 這時就可以指定out flag為AUDIO_OUTPUT_FLAG_DIRECT,這會導致最終的聲音無需混音即直接輸出到對應的device
Android系統里使用hardware module來訪問硬件, 比如聲卡
聲卡上有喇叭、耳機等等,稱為device
為了便於管理, 把一個設備上具有相同參數的一組device稱為output,
一個module能支持哪些output,一個output能支持哪些device,使用配置文件/system/etc/audio_policy.conf來描述
app要播放聲音, 要指定聲音類型: stream type有那么多的類型, 來來來, 先看它屬於哪一類(策略): strategy
根據strategy確定要用什么設備播放: device, 喇叭、耳機還是藍牙?
根據device確定output, 進而知道對應的playbackthread,
把聲音數據傳給這個thread
一個stream如何最終選擇到一個device,這些stream如何互相影響(一個高優先級的聲音會使得其他聲音靜音),等等等, 統稱為policy (政策)
輸出、輸入設備:
https://blog.csdn.net/zzqhost/article/details/7711935
3 所涉及文件形象講解
系統服務APP:
frameworks/av/media/mediaserver/main_mediaserver.cpp
AudioFlinger :
AudioFlinger.cpp
(frameworks/av/services/audioflinger/AudioFlinger.cpp)
Threads.cpp (frameworks/av/services/audioflinger/Threads.cpp)
Tracks.cpp (frameworks/av/services/audioflinger/Tracks.cpp)
audio_hw_hal.cpp (hardware/libhardware_legacy/audio/Audio_hw_hal.cpp)
AudioHardware.cpp (device/friendly-arm/common/libaudio/AudioHardware.cpp)
AudioPolicyService:
AudioPolicyService.cpp (frameworks/av/services/audiopolicy/AudioPolicyService.cpp)
AudioPolicyClientImpl.cpp (frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp)
AudioPolicyInterfaceImpl.cpp(frameworks/av/services/audiopolicy/AudioPolicyInterfaceImpl.cpp)
AudioPolicyManager.cpp (device/friendly-arm/common/libaudio/AudioPolicyManager.cpp)
AudioPolicyManager.h (device/friendly-arm/common/libaudio/AudioPolicyManager.h)
AudioPolicyManagerBase.cpp (hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp)
堪誤: 上面3個文件被以下文件替代
AudioPolicyManager.cpp (frameworks/av/services/audiopolicy/AudioPolicyManager.cpp)
應用程序APP所用文件:
AudioTrack.java (frameworks/base/media/java/android/media/AudioTrack.java)
android_media_AudioTrack.cpp (frameworks/base/core/jni/android_media_AudioTrack.cpp)
AudioTrack.cpp (frameworks/av/media/libmedia/AudioTrack.cpp)
AudioSystem.cpp (frameworks/av/media/libmedia/AudioSystem.cpp)

4 AudioPolicyService啟動過程分析
比如一部典型的手機,它既有聽筒、耳機接口,還有藍牙設備。假設默認情況下播放音樂是通過聽筒喇叭輸出的,那么當用戶插入耳機時,這個策略就會改變——從耳機輸出,而不再是聽筒;又比如在機器插着耳機時,播放音樂不應該從喇叭輸出,但是當有來電鈴聲時,就需要同時從喇叭和耳機輸出音頻。這些“音頻策略”的制定,主導者就是AudioPolicyService
在AudioFlinger小節,我們反復強調它只是策略的執行者,而AudioPolicyService則是策略的制定者。這種分離方式有效地降低了整個系統的藕合性,而且為各個模塊獨立擴展功能提供了保障。
- 加載解析
/vendor/etc/audio_policy.conf或/system/etc/audio_policy.conf- 對於配置文件里的每一個module項, new HwModule(name), 放入mHwModules數組;
- 對於module里的每一個output, new IOProfile,放入module的mOutputProfiles
- 對於module里的每一個input, new IOProfile, 放入module的mInputProfiles
- 根據module的name加載廠家提供的so文件(通過AudioFlinger來加載)
- 打開對應的output(通過AudioFlinger來open output)

為了讓大家對AudioPolicyService有個感性的認識,我們以下圖來形象地表示它與AudioTrack及AudioFlinger間的關系:

5 AudioFlinger啟動過程分析
- 注冊AudioFlinger服務
- 被AudioPolicyService調用以打開廠家提供的so文件
- 加載哪個so文件? 文件名是什么? 文件名從何而來?
名字從/system/etc/audio_policy.conf得到 : primary
所以so文件就是 :audio.primary.XXX.so, eg.audio.primary.tiny4412.so - 該so文件由什么源文件組成? 查看
Android.mk
- 加載哪個so文件? 文件名是什么? 文件名從何而來?
audio.primary.$(TARGET_DEVICE) : device/friendly-arm/common/libaudio/AudioHardware.cpp
libhardware_legacy
libhardware_legacy : hardware/libhardware_legacy/audio/audio_hw_hal.cpp
- 對硬件的封裝:
AudioFlinger : AudioHwDevice (放入mAudioHwDevs數組中)
audio_hw_hal.cpp : audio_hw_device
廠家 : AudioHardware (派生自: AudioHardwareInterface)
AudioHwDevice是對audio_hw_device的封裝,audio_hw_device中函數的實現要通過AudioHardware類對象

6 AudioTrack創建過程概述
- 體驗測試程序:
frameworks/base/media/tests/audiotests/shared_mem_test.cpp
frameworks/base/media/tests/mediaframeworktest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
播放聲音時都要創建AudioTrack對象,java的AudioTrack對象創建時會導致c++的AudioTrack對象被創建;
所以分析的核心是c++的AudioTrack類,創建AudioTrack時涉及一個重要函數: set()函數
-
猜測創建過程的主要工作
- 使用AudioTrack的屬性, 根據AudioPolicy找到對應的output、playbackThread
- 在playbackThread中創建對應的track
- APP的AudioTrack 和 playbackThread的mTracks中的track之間建立共享內存
-
源碼時序圖

7 AudioTrack創建過程_Track和共享內存
回顧:
- APP創建AudioTrack AudioFlinger中PlaybackThread創建對應的Track
b. APP給AudioTrack提供音頻數據有2種方式: 一次性提供(MODE_STATIC)、邊播放邊提供(MODE_STREAM)
問:
- 音頻數據存在buffer中, 這個buffer由誰提供? APP 還是 PlaybackThread ?
- APP提供數據, PlaybackThread消耗數據, 如何同步?

8 音頻數據的傳遞
- APP創建AudioTrack, playbackThread創建對應的Track
它們之間通過共享內存傳遞音頻數據 - APP有2種使用共享內存的方式:
- MODE_STATIC:
APP創建共享內存, APP一次性填充數據 - MODE_STREAM:
APP使用obtainBuffer獲得空白內存, 填充數據后使用releaseBuffer釋放內存
- MODE_STATIC:
- playbackThread使用obtainBuffer獲得含有數據的內存, 使用數據后使用releaseBuffer釋放內存
- AudioTrack中含有mProxy, 它被用來管理共享內存, 里面含有obtainBuffer, releaseBuffer函數。Track中含有mServerProxy, 它被用來管理共享內存, 里面含有obtainBuffer, releaseBuffer函數。對於不同的MODE, 這些Proxy指向不同的對象
- 對於MODE_STREAM, APP和playbackThread使用環型緩沖區的方式傳遞數據

9 PlaybackThread處理流程
-
prepareTracks_l :
確定enabled track, disabled track
對於enabled track, 設置mState.tracks[x]中的參數 -
threadLoop_mix : 處理數據(比如重采樣)、混音
確定hook:
逐個分析mState.tracks[x]的數據, 根據它的格式確定tracks[x].hook
再確定總的mState.hook調用hook:
調用總的mState.hook即可, 它會再去調用每一個mState.tracks[x].hook混音后的數據會放在mState.outputTemp臨時BUFFER中
然后轉換格式后存入 thread.mMixerBuffer -
memcpy_by_audio_format :
把數據從thread.mMixerBuffer或thread.mEffectBuffer復制到thread.mSinkBuffer -
threadLoop_write:
把thread.mSinkBuffer寫到聲卡上 -
threadLoop_exit

