Android 音頻開發 目錄
- Android音頻開發(1):音頻相關知識
- Android音頻開發(2):使用AudioRecord錄制pcm格式音頻
- Android音頻開發(3):使用AudioRecord實現錄音的暫停和恢復
- Android音頻開發(4):PCM轉WAV格式音頻
- Android音頻開發(5):Mp3的錄制 - 編譯Lame源碼
- Android音頻開發(6):Mp3的錄制 - 使用Lame實時錄制MP3格式音頻
- Android音頻開發(7):音樂可視化-FFT頻譜圖
項目地址
https://github.com/zhaolewei/ZlwAudioRecorder
一、AudioRecord類的介紹
- 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)
- getMinBufferSize()
/** * 獲取AudioRecord所需的最小緩沖區大小 * @param sampleRateInHz: 采樣率 * @param channelConfig:聲道數 * @param audioFormat: 采樣位數. */ public static int getMinBufferSize (int sampleRateInHz, int channelConfig, int audioFormat)
- getRecordingState()
/** * 獲取AudioRecord當前的錄音狀態 * @see AudioRecord#RECORDSTATE_STOPPED * @see AudioRecord#RECORDSTATE_RECORDING */ public int getRecordingState()
- startRecording()
/** * 開始錄制 */ public int startRecording()
- startRecording()
/** * 停止錄制 */ public int stop()
- 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的功能,下一篇再繼續完善。
- 需要錄音及文件處理的動態權限