Android Audio System 之二:AudioFlinger

來源:互聯網
上載者:User
引言

    AudioFlinger是Android音頻系統的兩大服務之一,另一個服務是AudioPolicyService,這兩大服務都在系統啟動時有MediaSever載入,載入的代碼位於:frameworks/base/media/mediaserver/main_mediaserver.cpp。AudioPolicyService的相關內容請參考另一編文章:《Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager 》

http://blog.csdn.net/DroidPhone/archive/2010/10/18/5949280.aspx

 

    本文主要介紹AudioFlinger,AudioFlinger向下訪問AudioHardware,實現輸出音頻資料,控制音頻參數。同時,AudioFlinger向上通過IAudioFinger介面提供服務。所以,AudioFlinger在Android的音頻系統架構中起著承上啟下的作用,地位相當重要。AudioFlinger的相關代碼主要在:frameworks/base/libs/audioflinger,也有部分相關的代碼在frameworks/base/media/libmedia裡。

AudioFlinger的類結構

下面的圖示描述了AudioFlinger類的內部結構和關係:

 

                                                             圖一   AudioFlinger的類結構

不知道各位是否和我一樣,第一次看到AudioFlinger類的定義的時候都很鬱悶--這個類實在是龐大和臃腫,可是當你理清他的關係以後,你會覺得相當合理。下面我們一一展開討論。

  • IAudioFlinger介面

    這是AudioFlinger向外提供服務的介面,例如openOutput,openInput,createTrack,openRecord等等,應用程式或者其他service通過ServiceManager可以獲得該介面。該介面通過繼承BnAudioFlinger得到。

  • ThreadBase

    在AudioFlinger中,Android為每一個放音/錄音裝置均建立一個處理線程,負責音頻資料的I/O和合成,ThreadBase是這些線程的基類,所有的播放和錄音線程都派生自ThreadBase

  • TrackBase

    應用程式每建立一個音軌(AudioTrack/AudioRecord),在AudioFlinger中都會建立一個對應的Track執行個體,TrackBase就是這些Track的基類,他的衍生類別有:

  •  

    • PlaybackTread::Track    // 用於普通播放,對應於應用程式層的AudioTrack
    • PlaybackThread::OutputTrack    // 用於多重裝置輸出,當藍芽播放開啟時使用
    • RecordThread::RecordTrack    // 用於錄音,對應於應用程式層的AudioRecord
  • 播放

    預設的播放線程是MixerThread,它由AudioPolicyManager建立,在AudioPolicyManager的建構函式中,有以下代碼:

mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,<br /> &outputDesc->mSamplingRate,<br /> &outputDesc->mFormat,<br /> &outputDesc->mChannels,<br /> &outputDesc->mLatency,<br /> outputDesc->mFlags);

最終會進入AudioFlinger的openOut函數:

......<br />thread = new MixerThread(this, output, ++mNextThreadId);<br />......<br />mPlaybackThreads.add(mNextThreadId, thread);<br />......<br />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://blog.csdn.net/DroidPhone/archive/2010/10/14/5941344.aspx

createTrack會調用PlaybackThread類的createTrack_l函數:

track = thread->createTrack_l(client, streamType, sampleRate, format,<br /> channelCount, frameCount, sharedBuffer, &lStatus);

再跟入createTrack_l函數中,可以看到建立了PlaybackThread::Track類,然後加入播放線程的track列表mTracks中。

track = thread->createTrack_l(client, streamType, sampleRate, format,<br /> channelCount, frameCount, sharedBuffer, &lStatus);<br />......<br />mTracks.add(track);

在createTrack的最後,建立了TrackHandle類並返回,TrackHandle繼承了IAudioTrack介面,以後,createTrack的調用者可以通過IAudioTrack介面與AudioFlinger中對應的Track執行個體互動。

trackHandle = new TrackHandle(track);<br />......<br />return trackHandle;

 最後,在系統運行時,AudioFlinger中的線程和Track的結構大致如所示:它會擁有多個背景工作執行緒,每個線程擁有多個Track。

                                          圖二     AudioFlinger的線程結構

播放線程實際上是MixerThread的一個執行個體,MixerThread的threadLoop()中,會把該線程中的各個Track進行混合,必要時還要進行ReSample(重採樣)的動作,轉換為統一的採樣率(44.1K),然後通過音頻系統的AudioHardware層輸出音頻資料。

  • 錄音

     錄音的流程和放音差不多,只不過資料流動的方向相反,錄音線程變成RecordThread,Track變成了RecordTrack,openRecord返回RecordHandle,詳細的暫且不表。

  • DuplicatingThread

    AudioFlinger中有一個特殊的線程類:DuplicatingThread,從圖一可以知道,它是MixerThread的子類。當系統中有兩個裝置要同時輸出時,DuplicatingThread將被建立,通過IAudioFlinger的openDuplicateOutput方法建立DuplicatingThread。

int AudioFlinger::openDuplicateOutput(int output1, int output2)<br />{<br /> Mutex::Autolock _l(mLock);<br /> MixerThread *thread1 = checkMixerThread_l(output1);<br /> MixerThread *thread2 = checkMixerThread_l(output2);<br /> ......<br /> DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);<br /> thread->addOutputTrack(thread2);<br /> mPlaybackThreads.add(mNextThreadId, thread);<br /> return mNextThreadId;<br />}

    建立 DuplicatingThread時,傳入2個需要同時輸出的目標線程Id,openDuplicateOutput先從mPlaybackThreads中根據Id取得相應輸出線程的執行個體,然後為每個線程建立一個虛擬AudioTrack----OutputTrack,然後把這個虛擬AudioTrack加入到目標線程的mTracks列表中,DuplicatingThread在它的threadLoop()中,把Mixer好的資料同時寫入兩個虛擬OutputTrack中,因為這兩個OutputTrack已經加入到目標線程的mTracks列表,所以,兩個目標線程會同時輸出DuplicatingThread的聲音。

    實際上,建立DuplicatingThread的工作是有AudioPolicyService中的AudioPolicyManager裡發起的。主要是當藍芽耳機和本機輸出都開啟時,AudioPolicyManager會做出以下動作:

  • 首先開啟(或建立)藍芽輸出線程A2dpOutput
  • 以HardwareOutput和A2dpOutput作為參數,調用openDuplicateOutput,建立DuplicatingThread
  • 把屬於STRATEGY_MEDIA類型的Track移到A2dpOutput中
  • 把屬於STRATEGY_DTMF類型的Track移到A2dpOutput中
  • 把屬於STRATEGY_SONIFICATION類型的Track移到DuplicateOutput中

結果是,音樂和DTMF只會在藍芽耳機中輸出,而按鍵音和鈴聲等提示音會同時在本機和藍芽耳機中輸出。

                                                                           圖三  本機播放時的Thread和Track

 

 

 

 

 

 

 

 

 

                                                                        圖四   藍芽播放時的Thread和Track

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.