1 分析思路 1. Thread如何創建? AudioPolicyService是策略的制定者,AudioFlinger是策略的執行者, 所以: AudioPolicyService根據配置文件使喚AudioFlinger來創建Thread 2. Thread對應output, output對應哪些 ...
1 分析思路
Thread如何創建?
AudioPolicyService是策略的制定者,AudioFlinger是策略的執行者,
所以: AudioPolicyService根據配置文件使喚AudioFlinger來創建ThreadThread對應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
audio.primary.$(TARGET_DEVICE) : device/friendly-arm/common/libaudio/AudioHardware.cpp libhardware_legacy libhardware_legacy : hardware/libhardware_legacy/audio/audio_hw_hal.cpp
- 載入哪個so文件? 文件名是什麼? 文件名從何而來?
- 對硬體的封裝:
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.outputTemp臨時BUFFER中
調用總的mState.hook即可, 它會再去調用每一個mState.tracks[x].hook
然後轉換格式後存入 thread.mMixerBuffer- memcpy_by_audio_format :
把數據從thread.mMixerBuffer或thread.mEffectBuffer複製到thread.mSinkBuffer - threadLoop_write:
把thread.mSinkBuffer寫到音效卡上 threadLoop_exit