AudioTrack

由于AudioTrack是Android SDK層提供的最底層的音頻播放API,因此只允許輸入裸數(shù)據(jù)。和MediaPlayer相比,對于一個壓縮的音頻文件(比如MP3、AAC等文件),它需要自行實現(xiàn)解碼操作和緩沖區(qū)控制。

首先來看一下AudioTrack的工作流程,具體如下。
1)根據(jù)音頻參數(shù)信息,配置出一個AudioTrack的實例。
2)調(diào)用play方法,將AudioTrack切換到播放狀態(tài)。
3)啟動播放線程,循環(huán)向AudioTrack的緩沖區(qū)中寫入音頻數(shù)據(jù)。
4)當數(shù)據(jù)寫完或者停止播放的時候,停止播放線程,并且釋放所有資源。
根據(jù)AudioTrack的上述工作流程,本節(jié)將以4個小部分分別介紹每個流程的詳細步驟。

1.配置AudioTrack
先來看一下AudioTrack的參數(shù)配置,要想構(gòu)造出一個AudioTrack類型的實例,必須先了解其構(gòu)造函數(shù)原型,代碼如下所示:

public AudioTrack(int streamType, int sampleRateInHz, int channelConfig,int audioFormat, int bufferSizeInBytes, int mode);

其中構(gòu)造函數(shù)的參數(shù)說明如下。

  • streamType,Android手機上提供了多重音頻管理策略(按一下手機側(cè)邊的按鍵,可以看到有多個音量管理,這其實就是不同音頻策略的音量控制展示),當系統(tǒng)有多個進程需要播放音頻的時候,管理策略會決定最終的呈現(xiàn)效果,該參數(shù)的可選值將以常量的形式定義在類AudioManager中,主要包括以下內(nèi)容:
    STREAM_VOCIE_CALL:電話聲音
    STREAM_SYSTEM:系統(tǒng)聲音
    STREAM_RING:鈴聲
    STREAM_MUSCI:音樂聲
    STREAM_ALARM:警告聲
    STREAM_NOTIFICATION:通知聲
  • sampleRateInHz,采樣率,即播放的音頻每秒鐘會有多少次采樣,可選用的采樣頻率列表為:8000、16000、22050、24000、32000、44100、48000等,大家可以根據(jù)自己的應(yīng)用場景進行合理的選擇。
  • channelConfig,聲道數(shù)(通道數(shù))的配置,可選值以常量的形式配置在類AudioFormat中,常用的是CHANNEL_IN_MONO(單聲道)、CHANNEL_IN_STEREO(雙聲道),因為現(xiàn)在大多數(shù)手機的麥克風都是偽立體聲的采集,為了性能考慮,筆者建議使用單聲道進行采集,而轉(zhuǎn)變?yōu)榱Ⅲw聲的過程可以在聲音的特效處理階段來完成。
  • audioFormat,該參數(shù)是用來配置“數(shù)據(jù)位寬”的,即采樣格式,可選值以常量的形式定義在類AudioFormat中,分別為ENCODING_PCM_16BIT(16bit)ENCODING_PCM_8BIT(8bit),
    注意,前者是可以兼容所有Android手機的。
  • bufferSizeInBytes,其配置的是AudioTrack內(nèi)部的音頻緩沖區(qū)的大小,AudioTrack類提供了一個幫助開發(fā)者確定bufferSizeInBytes的函數(shù),其原型具體如下:
int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);

在實際開發(fā)中,強烈建議由該函數(shù)計算出需要傳入的bufferSizeInBytes,而不是自己手動計算。

  • mode,AudioTrack提供了兩種播放模式,可選的值以常量的形式定義在類AudioTrack中,一個是MODE_STATIC,需要一次性將所有的數(shù)據(jù)都寫入播放緩沖區(qū)中,簡單高效,通常用于播放鈴聲、系統(tǒng)提醒的音頻片段;另一個是MODE_STREAM,需要按照一定的時間間隔不間
    斷地寫入音頻數(shù)據(jù),理論上它可以應(yīng)用于任何音頻播放的場景。

2.將AudioTrack切換到播放狀態(tài)
首先判斷AudioTrack實例是否初始化成功,如果當前狀態(tài)處于初始成功的狀態(tài),那么就調(diào)用它的play方法,并切換到播放狀態(tài),代碼如下:

if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
{
    audioTrack.play();
}

3.開啟播放線程
首先創(chuàng)建一個播放線程,代碼如下:

playerThread = new Thread(new PlayerThread(), "playerThread");
playerThread.start();

接下來看看該線程中執(zhí)行的任務(wù),代碼如下:

class PlayerThread implements Runnable {
    private short[] samples;
    public void run() {
       samples = new short[minBufferSize];
        while(!isStop) {
            int actualSize = decoder.readSamples(samples);
            audioTrack.write(samples, actualSize);
        }
    }
}

線程中的minBufferSize是在初始化AudioTrack的時候獲得的緩沖區(qū)大小,會對其進行換算,即以2個字節(jié)表示一個采樣的大小,也就是2倍的關(guān)系(因為初始化的時候是以字節(jié)為單位的);decoder是一個解碼器,假設(shè)已經(jīng)初始化成功,最后將調(diào)用write方法把從解碼器中獲得的PCM采樣數(shù)據(jù)寫入AudioTrack的緩沖區(qū)中,注意此方法是阻塞的方法,比如:一般要寫入200ms的音頻數(shù)據(jù)需要執(zhí)行接近200ms的時間。

4.銷毀資源
首先停止AudioTrack,代碼如下:

if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
{
    audioTrack.stop();
}

然后停止線程:

isStop = true;
if (null != playerThread) {
    playerThread.join();
    playerThread = null;
}

最后釋放AudioTrack:

audioTrack.release();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容