安卓音視頻基礎:AudioRecord和AudioTrack的簡單使用

在之前的文章安卓實現錄音/播放/暫停/繼續的功能中介紹了通過MediaRecorder和MediaPlayer實現簡單的錄音和播放功能,但相比於安卓二次封裝後的API,AudioRecord和AudioTrack更接近底層,可通過獲取的PCM數據,進行二次的算法處理,實現更加接近需求的聲音。

1. AudioRecord

AndioRecord類的主要功能是讓各種JAVA應用能夠管理音頻資源,以便它們通過此類能夠錄製聲音相關的硬件所收集的聲音。此功能的實現就是通過”pulling”(讀取)AudioRecord對象的聲音數據來完成的。在錄音過程中,應用所需要做的就是通過後面三個類方法中的一個去及時地獲取AudioRecord對象的錄音數據. AudioRecord類提供的三個獲取聲音數據的方法分別是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int). 無論選擇使用那一個方法都必須事先設定方便用戶的聲音數據的存儲格式。

AudioRecord的使用比較簡單,獲取音頻緩衝區buffer後創建AudioRecord對象,buffer用來保存新的錄像數據,該buffer是通過api獲取的與設備硬件、設置的參數等相關,如果過大導致超過整個錄像的數據,過小導致構造AudioRecord對象失敗。
使用流程:

  1. 獲取緩衝buffer,構建AudioRecord對象;
  2. 創建一個文件的輸出流,用於存儲buffer數據;
  3. 開始錄像;
  4. 暫停/停止錄音,釋放資源。

下面結合代碼分析流程

1. 獲取緩衝buffer,構建AudioRecord對象對象;

 BufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_HERTZ,
                    CHANNEL_CONFIG, AUDIO_FORMAT);
  mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    SAMPLE_RATE_HERTZ, CHANNEL_CONFIG, AUDIO_FORMAT, BufferSize);

其中構建AudioRecord對象的對象參數意義如下:

  • audioSource:音頻的輸入源,包括DEFAULT、MIC、VOICE_x和CAMCORDER等
  • sampleRateInHz:音頻採樣率,是指1s內對音頻信號的採樣次數,採樣率越高,聲音的還原度越高,主流的採集卡的採樣頻率一般共分爲22.05KHz、44.1KHz、48KHz三個等級。
  • channelConfig:聲道數,包括單聲道(CHANNEL_IN_MONO)和雙聲道(立體聲)(CHANNEL_IN_STEREO),其中CHANNEL_IN_MONO一般是可以兼容其他設備能夠使用的。
  • audioFormat:採樣位數(量化精度),是指聲卡處理聲音的解析度,該值越大聲音的還原越真實,常見的包括8bit、16bit和32bit,通俗理解爲每幀採集的聲音大小,類似視頻的分辨率。
  • bufferSizeInBytes:通過以上三個參數,調用getMinBufferSize獲取音頻的緩存區數據。

除了上面介紹的幾個概念外,還有一個常見的名稱:比特率,又稱碼率,是指每秒傳輸的數據大小,單位爲bps(Bit Per Second),該值越大,說明包括的音視頻數據越多,音視頻質量越好,基本的計算公式爲:

基本的算法是:【碼率】(kbps)=【文件大小】(字節)X8/【時間】(秒)× 1000

2. 創建一個文件的輸出流,用於存儲buffer數據;

FileOutputStream PcmFos = new FileOutputStream(new File(path));

3. 開始錄像;

			//開始錄製
                mAudioRecord.startRecording();
			//不斷讀取音頻緩衝區的數據
                while (true == isRecord && !isInterrupted()) {
                    int read = mAudioRecord.read(bytes, 0, bytes.length);
              //若讀取數據沒有出現錯誤,將數據寫入文件
                    if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                        PcmFos.write(bytes, 0, read);
                        PcmFos.flush();
                    }
                }

4. 暫停/停止錄音,釋放資源

 mAudioRecord.stop();//暫停錄製,如果是單獨調用該方法,表示暫停錄製操作
 mAudioRecord.release();//停止錄製
 PcmFos.close();//關流

在執行停止或暫停操作時,可通過getState()獲取當前的運行狀態。

2. AudioTrack

對於通過AudioRecord獲取的音頻數據是不經過編解碼處理的數據,因此不能被常見的音頻播放器播放,可通過AdobeAudition軟件播放,同樣安卓調用時需要通過AudioTrack播放,常見的MediaPlayer也無法正常播放,下面講解一下AudioTrack的使用。
與AudioRecord類似,也需要先獲取播放緩衝區,然後構建AudioTrack對象,主要流程如下:

  1. 獲取緩衝buffer,構建AudioTrack對象;
  2. 讀取pcm文件,調用AudioTrack的write開始播放;
  3. 暫停、停止或釋放操作
    流程分析如下:

1. 獲取緩衝buffer,構建AudioTrack對象;

 BufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_HERTZ,
                    AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT);
 mAudioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_ALARM)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setEncoding(AUDIO_FORMAT)
                            .setSampleRate(SAMPLE_RATE_HERTZ)
                            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                            .build())
                    .setBufferSizeInBytes(BufferSize)
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .build();                    

這裏需要注意以下幾點:

  • 調用getMinBufferSize時,添加的三個參數要與AudioRecord設置的參數一致,否則無法正常播放;
  • 獲取AudioTrack通過Builder的方式,設置Attributes和Format兩種屬性,其中Format同樣需要與AudioRecord的設置一致,也可以直接通過new的方式構建對象;
  • 通過setTransferMode設置播放方式,包括 MODE_STATIC 或者 MODE_STREAM,其中 MODE_STATIC是預先將播放的數據讀取到緩衝區buffer中,然後開始播放,因此需要先調用write方法,然後調用play方法,適用於播放鈴聲等短小的聲音,MODE_STREAM是邊讀邊播的方式,也是默認的方式,由於需要邊讀邊播,因此會有一定的延時。

2. 讀取pcm文件,調用AudioTrack的write開始播放

	FileInputStream fis = new FileInputStream(autoFile);
    mAudioTrack.play();
    byte[] bytes = new byte[BufferSize];

        while (true == isRecord) {
                int read = fis.read(bytes);
                //若讀取有錯則跳過
                    if (AudioTrack.ERROR_INVALID_OPERATION == read
                            || AudioTrack.ERROR_BAD_VALUE == read) {
                        continue;
                    }

       if (read != 0 && read != -1) {
              mAudioTrack.write(bytes, 0, BufferSize);
        } else {
                isRecord = false;
        }

獲取到音頻的pcm文件後,開始根據buffer的大小讀取文件數據,寫入到AudioTrack進行播放,該過程可通過添加狀態變量isRecord 來循環遍歷讀取播放。

3. 暫停、停止或釋放操作

mAudioTrack.pause();//暫停
mAudioTrack.stop();//停止
mAudioTrack.release();//釋放資源
fis.close();//關流
//狀態獲取
int state = mAudioTrack.getState();

3. PCM轉WAV

PCM(Pulse Code Modulation—-脈碼調製錄音)。所謂PCM錄音就是將聲音等模擬信號變成符號化的脈衝列,再予以記錄。PCM信號是由[1]、[0]等符號構成的數字信號,而未經過任何編碼和壓縮處理。與模擬信號比,它不易受傳送系統的雜波及失真的影響。動態範圍寬,可得到音質相當好的影響效果。也就是說,PCM就是沒有壓縮的編碼方式,PCM文件就是採用PCM這種沒有壓縮的編碼方式編碼的音頻數據文件。
WAV爲微軟公司(Microsoft)開發的一種聲音文件格式,它符合RIFF(Resource Interchange File Format)文件規範,用於保存Windows平臺的音頻信息資源,被Windows平臺及其應用程序所廣泛支持,該格式也支持MSADPCM,CCITT A LAW等多種壓縮運算法,支持多種音頻數字,取樣頻率和聲道,標準格式化的WAV文件和CD格式一樣,也是44.1K的取樣頻率,16位量化數字,因此在聲音文件質量和CD相差無幾!

PCM是一種直接記錄數字信號(0或1)的無損壓縮方式,而WAV是通過在PCM的基礎上增加其特有的頭文件形成的一種音頻格式。其添加方法可參考河北-寶哥

4. 常見的錄音和播放比較

API 優點 缺點
AudioRecord 獲取最底層的音頻數據,使用更加靈活,可針對獲取的音頻數據進行處理,例如壓縮、網傳或算法處理 常見的播放器無法正常播放,數據量較大
MediaRecorder android在AudioRecord基礎上二次封裝的API,便於應用層的開發,使用簡單方便,適用於常見的音頻播放器 無法實施音頻處理
AudioTrack 可播放延遲要求低,無須解碼的pcm數據 無法播放需要解碼的音頻文件
MediaPlayer 可播放需要解碼的常見音頻文件,例如MP3、AAC和WAV等數據 資源佔用較高,需要解碼處理,延時較高

本文涉及的demo鏈接

參考鏈接:
1、https://www.jianshu.com/p/1f78c4211ab7?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
2、https://blog.csdn.net/haovip123/article/details/52356024

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章