AudioTrack與AudioFlinger交換音頻資料

來源:互聯網
上載者:User

AudioTrack與AudioFlinger交換音頻資料(一)

轉載自:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=98290

      Android Framework的音頻子系統中,每一個音頻流對應著一個AudioTrack類的一個執行個體,每個AudioTrack會在建立時註冊到 AudioFlinger中,由AudioFlinger把所有的AudioTrack進行混合(Mixer),然後輸送到AudioHardware中進行播放,目前Android的Froyo版本設定了同時最多可以建立32個音頻流,也就是說,Mixer最多會同時處理32個AudioTrack的資料流。

       如何使用AudioTrack
       AudioTrack的主要代碼位於 frameworks/base/media/libmedia/audiotrack.cpp中。現在先通過一個例子來瞭解一下如何使用 AudioTrack,ToneGenerator是android中產生電話撥號音和其他音調波形的一個實現,我們就以它為例子:

       ToneGenerator的初始化函數:

bool ToneGenerator::initAudioTrack() { // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size mpAudioTrack = new AudioTrack(); mpAudioTrack->set (mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this , 0, 0, mThreadCanCallJava); if (mpAudioTrack->initCheck() != NO_ERROR) { LOGE("AudioTrack->initCheck failed" ); goto initAudioTrack_exit; } mpAudioTrack->setVolume(mVolume, mVolume); mState = TONE_INIT; } 

  可見,建立步驟很簡單,先new一個AudioTrack的執行個體,然後調用set成員函數完成參數的設定並註冊到AudioFlinger中,然後可以調用其他諸如設定音量等函數進一步設定音頻參數。其中,一個重要的參數是audioCallback,audioCallback是一個回呼函數,負責響應
AudioTrack的通知,例如填充資料、迴圈播放、播放位置觸發等等。回呼函數的寫法通常像這樣:

void ToneGenerator::audioCallback(int event , void * user, void *info) { if (event != AudioTrack::EVENT_MORE_DATA) return ; AudioTrack::Buffer *buffer = static_cast<AudioTrack::Buffer *>(info); ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user); short *lpOut = buffer->i16; unsigned int lNumSmp = buffer->size/sizeof (short ); const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc; if (buffer->size == 0) return ; // Clear output buffer: WaveGenerator accumulates into lpOut buffer memset(lpOut, 0, buffer->size); // 以下是產生音調資料的代碼,略.... } 

 該函數首先判斷事件的類型是否是EVENT_MORE_DATA,如果是,則後續的代碼會填充相應的音頻資料後返回,當然你可以處理其他事件,以下是可用的事件類型

java代碼:

enum event_type { EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer. EVENT_UNDERRUN = 1, // PCM buffer underrun occured. EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0. EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()). EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()). EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer. }; 

 關於開始播放和停止播放 ,只要簡單的調用start() ,stop()即可mpAudioTrack->start(); 

系列之AudioTrack與AudioFlinger交換音頻資料(二)的文章連結http://www.eoeandroid.com/thread-98297-1-1.html

AudioTrack與AudioFlinger交換音頻資料(二)

通常,AudioTrack和AudioFlinger並不在同一個進程中,它們通過android中的binder機制建立聯絡。
        AudioFlinger是android中的一個service,在android啟動時就已經被載入。

        我們可以這樣理解:
        audio_track_cblk_t實現了一個環形FIFO;
        AudioTrack是FIFO的資料生產者;
        AudioFlinger是FIFO的資料消費者。

        建立聯絡的過程
        解釋一下過程:
        Framework或者Java層通過JNI,new AudioTrack();
        根據StreamType等參數,通過一系列的調用getOutput();
        如有必要,AudioFlinger根據StreamType開啟不同硬體裝置;
        AudioFlinger為該輸出裝置建立混音線程: MixerThread(),並把該線程的id作為getOutput()的傳回值返回給

        AudioTrack;
        AudioTrack通過binder機制調用AudioFlinger的createTrack();
        AudioFlinger註冊該AudioTrack到MixerThread中;
        AudioFlinger建立一個用於控制的TrackHandle,並以IAudioTrack這一介面作為createTrack()的傳回值;
        AudioTrack通過IAudioTrack介面,得到在AudioFlinger中建立的FIFO(audio_track_cblk_t);
        AudioTrack建立自己的監控線程:AudioTrackThread;

        自此,AudioTrack建立了和AudioFlinger的全部聯絡工作,接下來,AudioTrack可以:
        通過IAudioTrack介面控制該音軌的狀態,例如start,stop,pause等等;
        通過對FIFO的寫入,實現連續的音頻播放;
        監控線程監控事件的發生,並通過audioCallback回呼函數與使用者程式進行互動;

        FIFO的管理
        audio_track_cblk_t
        audio_track_cblk_t這個結構是FIFO實現的關鍵,該結構是在createTrack的時候,由AudioFlinger申請相應的記憶體,然後通過IMemory介面返回AudioTrack的,這樣AudioTrack和AudioFlinger管理著同一個 audio_track_cblk_t,通過它實現了環形FIFO,AudioTrack向FIFO中寫入音頻資料,AudioFlinger從FIFO
中讀取音頻資料,經Mixer後送給AudioHardware進行播放。

       audio_track_cblk_t的主要資料成員:
       user             -- AudioTrack當前的寫位置的位移
       userBase     -- AudioTrack寫位移的基準位置,結合user的值方可確定真實的FIFO地址指標
       server          -- AudioFlinger當前的讀位置的位移
       serverBase  -- AudioFlinger讀位移的基準位置,結合server的值方可確定真實的FIFO地址指標
       frameCount -- FIFO的大小,以音頻資料的幀為單位,16bit的音頻每幀的大小是2位元組
       buffers         -- 指向FIFO的起始地址
       out               -- 音頻流的方向,對於AudioTrack,out=1,對於AudioRecord,out=0

       audio_track_cblk_t的主要成員函數:
       framesAvailable_l()和framesAvailable()用於擷取FIFO中可寫的空閑空間的大小,只是加鎖和不加鎖的區別。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.