按照前文所介紹的內容可知,AudioTrack在調用createTrack時,會傳入一個audio_handle_t,這個值表示AF中某個工作線程的索引號,而它又是從APS中得到的。那么,這中間又有哪些曲折的經歷呢?
先回顧一下AudioTrack的set函數。
1. 重回set
先來看相應的代碼,如下所示:
**AudioTrack.cpp**
~~~
status_t AudioTrack::set(int streamType,uint32_tsampleRate,int format,
int channels,intframeCount,uint32_t flags,
callback_t cbf,void*user,int notificationFrames,
constsp<IMemory>& sharedBuffer, bool threadCanCallJava)
{
......
//得到AF中一個工作線程的索引號
audio_io_handle_toutput = AudioSystem::getOutput(
(AudioSystem::stream_type)streamType,
sampleRate,format, channels,
(AudioSystem::output_flags)flags);
......
//創建Track,最終會調到AF的createTrack
status_t status = createTrack(streamType,sampleRate, format, channelCount,
frameCount,flags, sharedBuffer, output);
~~~
再看AudioSystem是如何實現getOutput的,代碼如下所示:
**AudioSystem.cpp**
~~~
audio_io_handle_tAudioSystem::getOutput(stream_type stream,
uint32_tsamplingRate,
uint32_tformat,
uint32_tchannels,
output_flagsflags)
{
audio_io_handle_t output = 0;
......
if(output == 0) {
const sp<IAudioPolicyService>& aps =
AudioSystem::get_audio_policy_service();
if(aps == 0) return 0;
//調用AP的getOutput函數
output = aps->getOutput(stream, samplingRate, format, channels,flags);
if((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
Mutex::Autolock _l(gLock);
//把這個stream和output的對應關系保存到map中
AudioSystem::gStreamOutputMap.add(stream, output);
}
}
returnoutput;
}
~~~
這里調用了AP的getOutput,來看:
**AudioPolicyService.cpp**
~~~
audio_io_handle_t AudioPolicyService::getOutput(
AudioSystem::stream_typestream, uint32_t samplingRate,
uint32_tformat,uint32_t channels,
AudioSystem::output_flagsflags)
{
//和硬件廠商的實現相關,所以交給AudioPolicyInterface處理
//這里將由AudioPolicyManagerBase處理
Mutex::Autolock _l(mLock);
returnmpPolicyManager->getOutput(stream, samplingRate, format, channels,
flags);
}
~~~
**AudioPolicyManagerBase.cpp**
~~~
audio_io_handle_tAudioPolicyManagerBase::getOutput(
AudioSystem::stream_typestream, uint32_t samplingRate,
uint32_t format,uint32_tchannels,
AudioSystem::output_flagsflags)
{
audio_io_handle_t output = 0;
uint32_tlatency = 0;
//根據流類型得到對應的路由策略,這個我們已經見過了,MUSIC類型返回MUSIC策略
routing_strategystrategy = getStrategy((AudioSystem::stream_type)stream);
//根據策略得到使用這個策略的輸出設備(指揚聲器之類的),以后再看這個函數
uint32_tdevice = getDeviceForStrategy(strategy);
......
//看這個設備是不是與藍牙的A2DP相關
uint32_ta2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP;
if(AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) {
#ifdef WITH_A2DP
//對于有A2DP支持,a2dpUsedForSonification函數直接返回true
if (a2dpUsedForSonification() &&a2dpDevice != 0) {
//和DuplicatingThread相關,以后再看
output = mDuplicatedOutput;
} else
#endif
{
output = mHardwareOutput; //使用非藍牙的混音輸出線程
}
} else{
#ifdef WITH_A2DP
if(a2dpDevice != 0) {
//使用藍牙的混音輸出線程
output = mA2dpOutput;
}else
#endif
{
output = mHardwareOutput;
}
}
returnoutput;
}
~~~
終于明白了!原來,AudioSystem的getOutput就是想找到AF中的一個工作線程。為什么這個線程號會由AP返回呢?是因為Audio系統需要:
- 根據流類型找到對應的路由策略。
- 根據該策略找到合適的輸出device(指揚聲器、聽筒之類的)。
- 根據device選擇AF中合適的工作線程,例如是藍牙的MixerThread,還是DSP的MixerThread,或者是DuplicatingThread。
- AT根據得到的工作線程索引號,最終將在對應的工作線程中創建一個Track。之后,AT的數據將由該線程負責處理。
下面用圖7-15來回顧一下上面AT、AF、AP之間的交互關系。
:-: 
圖7-15 Audio三巨頭的交互關系
圖7-15充分展示了AT、AF和AP之間復雜微妙的關系。關系雖復雜,但目的卻單純。讀者在分析時一定要明確目的。下面從目的開始,反推該流程:
- AT的目的是把數據發送給對應的設備,例如是藍牙、DSP等。
- 代表輸出設備的HAL對象由MixerThread線程持有,所以要找到對應的MixerThread。
- AP維護流類型和輸出設備(耳機、藍牙耳機、聽筒等)之間的關系,不同的輸出設備使用不同的混音線程。
- AT根據自己的流類型,向AudioSystem查詢,希望得到對應的混音線程號。
這樣,三者精妙配合,便達到了預期目的。
2. 重回start
現在要分析的就是start函數。AT的start雖沒有直接與AP交互,但在AF的start中卻和AP有著交互關系。其代碼如下所示:
**AudioFlinger.cpp**
~~~
status_tAudioFlinger::PlaybackThread::Track::start()
{
status_t status = NO_ERROR;
sp<ThreadBase> thread = mThread.promote();
......
if(!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread->mLock.unlock();
//調用AudioSystem的startOutput
status = AudioSystem::startOutput(thread->id(),
(AudioSystem::stream_type)mStreamType);
thread->mLock.lock();
}
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
playbackThread->addTrack_l(this);//把這個Track加入到活躍Track數組中
returnstatus;
}
~~~
下面來看AudioSystem的startOutput,代碼如下所示:
**AudioSystem.cpp**
~~~
status_tAudioSystem::startOutput(audio_io_handle_t output,
AudioSystem::stream_typestream)
{
constsp<IAudioPolicyService>& aps =
AudioSystem::get_audio_policy_service();
if (aps== 0) return PERMISSION_DENIED;
//調用AP的startOutput,最終由AMB完成實際功能
returnaps->startOutput(output, stream);
}
~~~
**AudioPolicyManagerBase.cpp**
~~~
status_tAudioPolicyManagerBase::startOutput(audio_io_handle_t output,
AudioSystem::stream_typestream)
{
//根據output找到對應的AudioOutputDescriptor
ssize_t index = mOutputs.indexOfKey(output);
AudioOutputDescriptor*outputDesc = mOutputs.valueAt(index);
//找到對應流使用的路由策略
routing_strategy strategy =getStrategy((AudioSystem::stream_type)stream);
//增加outputDesc中該流的使用計數,1表示增加1
outputDesc->changeRefCount(stream, 1);
//getNewDevice將得到一個設備,setOutputDevice將使用這個設備進行路由切換。
//至于setOutputDevice,我們在分析耳機插入事件時再來講解
setOutputDevice(output, getNewDevice(output));
//設置音量,讀者可自行分析
checkAndSetVolume(stream,mStreams[stream].mIndexCur, output,
outputDesc->device());
returnNO_ERROR;
}
~~~
再看getNewDevice,它和音頻流的使用計數有關系:
**AudioPolicyManagerBase.cpp**
~~~
uint32_tAudioPolicyManagerBase::getNewDevice(audio_io_handle_t output,
bool fromCache)
{
uint32_t device = 0;
AudioOutputDescriptor*outputDesc = mOutputs.valueFor(output);
/*
isUsedByStrategy判斷某個策略是否正在被使用,之前曾通過changeRefCount為
MUSIC流使用計數增加了1,所以使用MUSIC策略的個數至少為1,這表明,此設備正在使用該策略。
一旦得到當前outputDesc使用的策略,便可根據該策略找到對應的設備。
注意if和else的順序,它代表了系統優先使用的策略,以第一個判斷為例,
假設系統已經插上耳機,并且處于通話狀態時,而且強制使用了揚聲器,那么聲音都從揚聲器出。
這時,如果想聽音樂的話,則應首先使用STRATEGY_PHONE的對應設備,此時就是揚聲器。
所以音樂將從揚聲器出來,而不是耳機。上面僅是舉例,具體的情況還要綜合考慮Audio
系統中的其他信息。另外如果fromCache為true,將直接從內部保存的舊信息中得到設備,
關于這個問題,在后面的耳機插入事件處理中再做分析
*/
if(mPhoneState == AudioSystem::MODE_IN_CALL ||
outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
} elseif (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}
returndevice;
}
~~~
這里,有一個問題需要關注:
* **為什么startOutput函數會和設備切換有關系呢?**
僅舉一個例子,幫助理解這一問題。AudioTrack創建時可設置音頻流類型,假設第一個AT創建時使用的是MUSIC類型,那么它將使用耳機出聲(假設耳機已經連接上)。這時第二個AT創建了,它使用的是RING類型,它對應的策略應是SONIFACATION,這個策略的優先級比MUSIC要高(因為getNewDevice的判斷語句首先會判斷isUsedByStrategy(STRATEGY_SONIFICATION)),所以這時需要把設備切換為耳機加揚聲器(假設這種類型的聲音需要從耳機和揚聲器同時輸出)。startOutput的最終結果,是這兩路的Track聲音都將從耳機和揚聲器中聽到。當第二路AT調用stop時,對應音頻流類型使用計數會減一,這會導致新的路由切換,并重新回到只有耳機的情況,這時第一路AT的聲音會恢復為只從耳機輸出。
>[warning] **提醒**:讀者可自行分析stop的處理方式,基本上是start的逆向處理過程。
3. 本節小結
這一節主要講解了AudioTrack和AP之間的交互,總結為以下兩點:
- AT通過AP獲取AF中的工作線程索引號,這決定了數據傳輸的最終目標是誰,比如是音頻DSP或是藍牙。
- AT的start和stop會影響Audio系統的路由切換。
讀完這一節,讀者可能只會對與工作線程索引有關的內容印象較深刻,畢竟這個決定了數據傳輸的目的地。至于與路由切換有關的知識,可能就還不太了解了。下面,通過分析一個應用場景來啟發、加深對它的理解。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結