Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android Audio System 之二:AudioFlinger

Android Audio System 之二:AudioFlinger

編輯: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類的定義的時候都很郁悶--這個類實在是龐大和臃腫,可是當你理清他的關系以後,你會覺得相當合理。下面我們一一展開討論。

  • 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的構造函數中,有以下代碼:

 

  1. mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,  
  2.                                     &outputDesc->mSamplingRate,  
  3.                                     &outputDesc->mFormat,  
  4.                                     &outputDesc->mChannels,  
  5.                                     &outputDesc->mLatency,  
  6.                                     outputDesc->mFlags); 
 

 

最終會進入AudioFlinger的openOut函數:

 

  1. ......  
  2. thread = new MixerThread(this, output, ++mNextThreadId);  
  3. ......  
  4. mPlaybackThreads.add(mNextThreadId, thread);  
  5. ......  
  6. 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函數:

 

  1. track = thread->createTrack_l(client, streamType, sampleRate, format,  
  2.                 channelCount, frameCount, sharedBuffer, &lStatus); 
 

 

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

 

  1. track = thread->createTrack_l(client, streamType, sampleRate, format,  
  2.                 channelCount, frameCount, sharedBuffer, &lStatus);  
  3. ......  
  4. mTracks.add(track); 
 

 

在createTrack的最後,創建了TrackHandle類並返回,TrackHandle繼承了IAudioTrack接口,以後,createTrack的調用者可以通過IAudioTrack接口與AudioFlinger中對應的Track實例交互。

 

  1. trackHandle = new TrackHandle(track);  
  2. ......  
  3. 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。

 

  1. int AudioFlinger::openDuplicateOutput(int output1, int output2)  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     MixerThread *thread1 = checkMixerThread_l(output1);  
  5.     MixerThread *thread2 = checkMixerThread_l(output2);  
  6.     ......  
  7.     DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);  
  8.     thread->addOutputTrack(thread2);  
  9.     mPlaybackThreads.add(mNextThreadId, thread);  
  10.     return mNextThreadId;  
 

 

    創建 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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved