音頻采集:Android基于AudioRecord的實現

前言

這篇文章簡單介紹下移動端Android系統下利用AudioRecord進行音頻采集方法。

按照慣例開始前先提供一份源碼 AudioRecordLib
AudioRecord采集的核心實現在于 AudioRecordCore.java 這個文件。

權限申請

想要使用AudioRecord這個API,需要在AndroidManifest.xml的配置文件里面增加錄音權限:

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

初始化

AudioRecord的初始化需要先創建一個AudioRecord實例。
構造函數原型如下:

public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig,
 int audioFormat,int bufferSizeInBytes)

具體參數說明:

  • audioSource 這個參數指的是音頻采集的輸入源,接受的值定義在MediaRecorder.AudioSource里面,一般來說使用DEFAULT或者MIC即可。
  • sampleRateInHz 指定采集音頻的采樣頻率,比較通用的是44100(44.1kHz),這個值是科學家們通過奈葵斯特采樣定理得出的一個人能接受最佳的采樣頻率值。
  • channelConfig 指定AudioRecord采集幾個聲道的聲音,預設值定義在AudioFormat中,常用值有 CHANNEL_CONFIGURATION_MONO(單聲道) 和 CHANNEL_CONFIGURATION_STEREO(雙聲道)。
  • audioFormat 指定采樣PCM數據的采樣格式,預設值定義在也AudioFormat中,常用值有 ENCODING_PCM_8BIT、ENCODING_PCM_16BIT和ENCODING_PCM_FLOAT,值得強調的是ENCODING_PCM_16BIT可以保證兼容大部分Andorid手機。
  • bufferSizeInBytes 配置AudioRecord內部的音頻數據緩沖區,一般來說緩存區越小,產生的音頻延遲也越小;值得注意的是,我們可以利用AudioRecord.getMinBufferSize()這個方法幫我們算出最小的緩存區大小,這個數值最好不要自己計算,畢竟不同廠商可能有不同的緩存區采集實現。

檢測AudioRecord當前狀態

由于可能存在權限問題導致配置AudioRecord失敗,所以我們需要在開始采集前檢查一下AudioRecord的狀態:

if (mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
    //todo start
}

如果getState()不等于AudioRecord.STATE_INITIALIZED說明創建AudioRecord失敗,這時候應該給用戶反饋信息。

完整代碼如下:

//獲取最低AudioRecord內部音視頻緩沖區大小,此大小依賴于各產商實現,最好不要自己計算
mRecordBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
//初始化AudioRecord實例
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, mRecordBufSize);
//檢測AudioRecord初始化是否成功
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
    mAudioRecord = null;
    mRecordBufSize = 0;
    return false;
}
else {
    //創建一個位置用于存放后續的PCM數據
    mPcmData = new byte[mRecordBufSize];
    mState = INIT;
    return true;
}

開始采集

創建好了AudioRecord實例,調用如下的方法即可開始麥克風采集:

mAudioRecord.startRecording();

提取數據

調用了開始采集后,我們需要另起一條線程進行PCM數據提取。
我們需要循環不斷從AudioRecord的緩沖區里面將數據讀取出來,值得注意的是這個過程一定要及時,不然會出現“overrun”的錯誤,也就是沒有及時取走音頻數據導致音頻緩存區溢出了。

private Thread mReadDataThread = new Thread() {
    @Override
    public void run() {
        int read;
        while (mState == RECORDING) {
            //讀取mRecordBufSize長度的音頻數據存入mPcmData中
            read = mAudioRecord.read(mPcmData, 0, mRecordBufSize);
            //如果讀取音頻數據沒有出現錯誤 ===> read 大于0
            if (read >= AudioRecord.SUCCESS) {
                synchronized (AudioRecordRecord.class){
                    if (mCallback != null)
                        mCallback.onPCMDataAvailable(mPcmData, read);
                }
            }
        }
    }
};

停止采集,釋放資源

停止錄音我們可以調用AudioRecord的stop方法來實現。

mAudioRecord.stop();

但是我們存在采集(音頻提取)線程,所以我們需要更改一個狀態變量讓線程結束

mState = INIT;

使得 while (mState == RECORDING) 退出循環邏輯。
接著我們需要釋放錄制器的資源,以便設備的其他應用可以正常使用錄音器,我們可以調用AudioRecord的release方法。

mAudioRecord.release();

這樣就完整的結束了AudioRecord的采集業務。

播放PCM文件

Audacity這個工具可以導入pcm原始文件,并且提供了波形圖查看和播放功能。
操作流程是:
文件 => 導入 => 原始數據 => 設置PCM數據格式 => 導入
具體效果圖如下:

p1.png

結語

下一篇博客會介紹一下Android利用OpenSL ES進行錄音導出PCM數據。
本文同步發布于簡書CSDN

End!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容