Android音頻開發(2):使用AudioRecord錄製pcm格式音頻

Android 音頻開發 目錄

  1. Android音頻開發(1):音頻相關知識
  2. Android音頻開發(2):使用AudioRecord錄製pcm格式音頻
  3. Android音頻開發(3):使用AudioRecord實現錄音的暫停和恢復
  4. Android音頻開發(4):PCM轉WAV格式音頻
  5. Android音頻開發(5):Mp3的錄製 - 編譯Lame源碼
  6. Android音頻開發(6):Mp3的錄製 - 使用Lame實時錄製MP3格式音頻
  7. Android音頻開發(7):音樂可視化-FFT頻譜圖

項目地址

https://github.com/zhaolewei/ZlwAudioRecorder


一、AudioRecord類的介紹

  1. AudioRecord構造函數:
     /**
     * @param audioSource :錄音源
     * 這裏選擇使用麥克風:MediaRecorder.AudioSource.MIC
     * @param sampleRateInHz: 採樣率
     * @param channelConfig:聲道數  
     * @param audioFormat: 採樣位數.
     *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
     * @param bufferSizeInBytes: 音頻錄製的緩衝區大小
     *   See {@link #getMinBufferSize(int, int, int)}  
     */
    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes)
    
  2. getMinBufferSize()
    /**
    * 獲取AudioRecord所需的最小緩衝區大小
    * @param sampleRateInHz: 採樣率
    * @param channelConfig:聲道數  
    * @param audioFormat: 採樣位數.
    */
    public static int getMinBufferSize (int sampleRateInHz, 
                int channelConfig, 
                int audioFormat)
    
  3. getRecordingState()
    /**
    * 獲取AudioRecord當前的錄音狀態 
    *   @see AudioRecord#RECORDSTATE_STOPPED    
    *   @see AudioRecord#RECORDSTATE_RECORDING
    */
    public int getRecordingState()
    
  4. startRecording()
     /**
     * 開始錄製
     */
     public int startRecording()
    
  5. startRecording()
     /**
     * 停止錄製
     */
     public int stop()
    
  6. read()
    /**
     * 從錄音設備中讀取音頻數據
     * @param audioData 音頻數據寫入的byte[]緩衝區
     * @param offsetInBytes 偏移量
     * @param sizeInBytes 讀取大小
     * @return 返回負數則表示讀取失敗
     *      see {@link #ERROR_INVALID_OPERATION} -3 : 初始化錯誤
            {@link #ERROR_BAD_VALUE}  -3: 參數錯誤
            {@link #ERROR_DEAD_OBJECT} -6: 
            {@link #ERROR}  
     */
    public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) 
    
    
    
    
    

二、實現

  • 實現過程就是調用上面的API的方法,構造AudioRecord實例後再調用startRecording(),開始錄音,並通過read()方法不斷獲取錄音數據記錄下來,生成PCM文件。涉及耗時操作,所以最好在子線程中進行。
/**
 * @author zhaolewei on 2018/7/10.
 */
public class RecordHelper {
    //0.此狀態用於控制線程中的循環操作,應用volatile修飾,保持數據的一致性
    private volatile RecordState state = RecordState.IDLE;
    private AudioRecordThread audioRecordThread;
    private File tmpFile = null;

    public void start(String filePath, RecordConfig config) {
        if (state != RecordState.IDLE) {
            Logger.e(TAG, "狀態異常當前狀態: %s", state.name());
            return;
        }
        recordFile = new File(filePath);
        String tempFilePath = getTempFilePath();
        Logger.i(TAG, "tmpPCM File: %s", tempFilePath);
        tmpFile = new File(tempFilePath);
        //1.開啓錄音線程並準備錄音
        audioRecordThread = new AudioRecordThread();
        audioRecordThread.start();
    }

    public void stop() {
        if (state == RecordState.IDLE) {
            Logger.e(TAG, "狀態異常當前狀態: %s", state.name());
            return;
        }

        state = RecordState.STOP;
    }

    private class AudioRecordThread extends Thread {
        private AudioRecord audioRecord;
        private int bufferSize;

        AudioRecordThread() {
            //2.根據錄音參數構造AudioRecord實體對象
            bufferSize = AudioRecord.getMinBufferSize(currentConfig.getFrequency(),
                    currentConfig.getChannel(), currentConfig.getEncoding()) * RECORD_AUDIO_BUFFER_TIMES;
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, currentConfig.getFrequency(),
                    currentConfig.getChannel(), currentConfig.getEncoding(), bufferSize);
        }

        @Override
        public void run() {
            super.run();
            state = RecordState.RECORDING;
            Logger.d(TAG, "開始錄製");
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(tmpFile);
                audioRecord.startRecording();
                byte[] byteBuffer = new byte[bufferSize];

                while (state == RecordState.RECORDING) {
                    //3.不斷讀取錄音數據並保存至文件中
                    int end = audioRecord.read(byteBuffer, 0, byteBuffer.length);
                    fos.write(byteBuffer, 0, end);
                    fos.flush();
                }
                //4.當執行stop()方法後state != RecordState.RECORDING,終止循環,停止錄音
                audioRecord.stop();
            } catch (Exception e) {
                Logger.e(e, TAG, e.getMessage());
            } finally {
                try {
                    if (fos != null) {
                        fos.close();
                    }
                } catch (IOException e) {
                    Logger.e(e, TAG, e.getMessage());
                }
            }
            state = RecordState.IDLE;
            Logger.d(TAG, "錄音結束");
        }
    }
}

三、其他

  • 這裏實現了PCM音頻的錄製,AudioRecord API中只有開始和停止的方法,在實際開發中可能還需要暫停/恢復的操作,以及PCM轉WAV的功能,下一篇再繼續完善。
  • 需要錄音及文件處理的動態權限
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章