編輯:Android開發實例
AudioFlinger是Android音頻系統的兩大服務之一,另一個服務是AudioPolicyService,這兩大服務都在系統啟動時有MediaSever加載,加載的代碼位於:frameworks\base\media\mediaserver\main_mediaserver.cpp。AudioPolicyService的相關內容請參考另一編文章:《Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager 》
http://www.fengfly.com/plus/view-192719-1.html
本文主要介紹AudioFlinger,AudioFlinger向下訪問AudioHardware,實現輸出音頻數據,控制音頻參數。同時,AudioFlinger向上通過IAudioFinger接口提供服務。所以,AudioFlinger在Android的音頻系統框架中起著承上啟下的作用,地位相當重要。AudioFlinger的相關代碼主要在:frameworks\base\libs\audioflinger,也有部分相關的代碼在frameworks\base\media\libmedia裡。
下面的圖示描述了AudioFlinger類的內部結構和關系:
圖一 AudioFlinger的類結構
不知道各位是否和我一樣,第一次看到AudioFlinger類的定義的時候都很郁悶--這個類實在是龐大和臃腫,可是當你理清他的關系以後,你會覺得相當合理。下面我們一一展開討論。
這是AudioFlinger向外提供服務的接口,例如openOutput,openInput,createTrack,openRecord等等,應用程序或者其他service通過ServiceManager可以獲得該接口。該接口通過繼承BnAudioFlinger得到。
在AudioFlinger中,Android為每一個放音/錄音設備均創建一個處理線程,負責音頻數據的I/O和合成,ThreadBase是這些線程的基類,所有的播放和錄音線程都派生自ThreadBase
應用程序每創建一個音軌(AudioTrack/AudioRecord),在AudioFlinger中都會創建一個對應的Track實例,TrackBase就是這些Track的基類,他的派生類有:
默認的播放線程是MixerThread,它由AudioPolicyManager創建,在AudioPolicyManager的構造函數中,有以下代碼:
- mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
- &outputDesc->mSamplingRate,
- &outputDesc->mFormat,
- &outputDesc->mChannels,
- &outputDesc->mLatency,
- outputDesc->mFlags);
最終會進入AudioFlinger的openOut函數:
- ......
- thread = new MixerThread(this, output, ++mNextThreadId);
- ......
- mPlaybackThreads.add(mNextThreadId, thread);
- ......
- return mNextThreadId;
可以看到,創建好的線程會把該線程和它的Id保存在AudioFlinger的成員變量mPlaybackThreads中,mPlaybackThreads是一個Vector,AudioFlinger創建的線程都會保存在裡面,最後,openOutput返回該線程的Id,該Id也就是所謂的audio_io_handle_t,AudioFlinger的調用者這能看到這個audio_io_handle_t,當需要訪問時傳入該audio_io_handle_t,AudioFlinger會通過mPlaybackThreads,得到該線程的指針。
要播放聲音,應用程序首先要通過IAudioFlinger接口,調用createTrack(),關於createTrack的流程,可以參看我的另一篇文章:
http://www.fengfly.com/plus/view-192718-1.html
createTrack會調用PlaybackThread類的createTrack_l函數:
- track = thread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
再跟入createTrack_l函數中,可以看到創建了PlaybackThread::Track類,然後加入播放線程的track列表mTracks中。
- track = thread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- ......
- mTracks.add(track);
在createTrack的最後,創建了TrackHandle類並返回,TrackHandle繼承了IAudioTrack接口,以後,createTrack的調用者可以通過IAudioTrack接口與AudioFlinger中對應的Track實例交互。
- trackHandle = new TrackHandle(track);
- ......
- return trackHandle;
最後,在系統運行時,AudioFlinger中的線程和Track的結構大致如下圖所示:它會擁有多個工作線程,每個線程擁有多個Track。
圖二 AudioFlinger的線程結構
播放線程實際上是MixerThread的一個實例,MixerThread的threadLoop()中,會把該線程中的各個Track進行混合,必要時還要進行ReSample(重采樣)的動作,轉換為統一的采樣率(44.1K),然後通過音頻系統的AudioHardware層輸出音頻數據。
錄音的流程和放音差不多,只不過數據流動的方向相反,錄音線程變成RecordThread,Track變成了RecordTrack,openRecord返回RecordHandle,詳細的暫且不表。
AudioFlinger中有一個特殊的線程類:DuplicatingThread,從圖一可以知道,它是MixerThread的子類。當系統中有兩個設備要同時輸出時,DuplicatingThread將被創建,通過IAudioFlinger的openDuplicateOutput方法創建DuplicatingThread。
- int AudioFlinger::openDuplicateOutput(int output1, int output2)
- {
- Mutex::Autolock _l(mLock);
- MixerThread *thread1 = checkMixerThread_l(output1);
- MixerThread *thread2 = checkMixerThread_l(output2);
- ......
- DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
- thread->addOutputTrack(thread2);
- mPlaybackThreads.add(mNextThreadId, thread);
- return mNextThreadId;
- }
創建 DuplicatingThread時,傳入2個需要同時輸出的目標線程Id,openDuplicateOutput先從mPlaybackThreads中根據Id取得相應輸出線程的實例,然後為每個線程創建一個虛擬的AudioTrack----OutputTrack,然後把這個虛擬的AudioTrack加入到目標線程的mTracks列表中,DuplicatingThread在它的threadLoop()中,把Mixer好的數據同時寫入兩個虛擬的OutputTrack中,因為這兩個OutputTrack已經加入到目標線程的mTracks列表,所以,兩個目標線程會同時輸出DuplicatingThread的聲音。
實際上,創建DuplicatingThread的工作是有AudioPolicyService中的AudioPolicyManager裡發起的。主要是當藍牙耳機和本機輸出都開啟時,AudioPolicyManager會做出以下動作:
結果是,音樂和DTMF只會在藍牙耳機中輸出,而按鍵音和鈴聲等提示音會同時在本機和藍牙耳機中輸出。
圖三 本機播放時的Thread和Track
圖四 藍牙播放時的Thread和Track
引言 程序猿們,是否還在為你的老板辛辛苦苦的打工而拿著微薄的薪水呢,還是不知道如何用自己的應用或游戲來賺錢呢! 在這裡IQuick將教您如何同過自己的應用
本文實例講述了Android實現仿通訊錄側邊欄滑動SiderBar效果代碼。分享給大家供大家參考,具體如下: 之前看到某些應用的側邊欄做得不錯,想想自己也弄一個出
篇幅較長遂分成上下兩篇,上一篇我們已經快要一氣呵成了,但是美中不足的是,這個界面並不能討得美工MM的歡心,美工MM曾寄希望於您,卻交出這麼作出這麼一副死型樣,我都
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放