3. AudioRecord录制麦克风音频
任务说明
本案例在 Android 车载应用中使用 AudioRecord 采集麦克风 PCM 数据,写入 .pcm 文件,并通过文件大小与采样参数校验录音是否成功。核心参数:采样率 16000Hz、单声道、16bit PCM。
权限与依赖
在 AndroidManifest.xml 中声明录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Android 6.0+ 需在运行时申请 RECORD_AUDIO。车载系统若为系统应用,也可通过 privapp-permissions 预授权。
核心实现
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class MicPcmRecorder {
private static final String TAG = "MicPcmRecorder";
private static final int SAMPLE_RATE = 16000;
private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;
private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord audioRecord;
private volatile boolean recording = false;
private Thread recordThread;
/** 开始录音,PCM 数据写入 outputFile */
public boolean start(File outputFile) {
int minBuf = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL, ENCODING);
if (minBuf == AudioRecord.ERROR || minBuf == AudioRecord.ERROR_BAD_VALUE) {
Log.e(TAG, "getMinBufferSize failed");
return false;
}
int bufferSize = minBuf * 2;
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC,
SAMPLE_RATE, CHANNEL, ENCODING, bufferSize);
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "AudioRecord init failed");
audioRecord.release();
audioRecord = null;
return false;
}
recording = true;
audioRecord.startRecording();
recordThread = new Thread(() -> writePcm(outputFile, bufferSize));
recordThread.start();
return true;
}
private void writePcm(File outputFile, int bufferSize) {
byte[] buffer = new byte[bufferSize];
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
while (recording) {
int read = audioRecord.read(buffer, 0, buffer.length);
if (read > 0) {
fos.write(buffer, 0, read);
}
}
fos.flush();
} catch (IOException e) {
Log.e(TAG, "write pcm failed", e);
}
}
/** 停止录音并释放资源 */
public void stop() {
recording = false;
if (recordThread != null) {
try { recordThread.join(1000); } catch (InterruptedException ignored) {}
recordThread = null;
}
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
}
}
调用与验证
File pcm = new File(getExternalFilesDir(null), "mic_test.pcm");
MicPcmRecorder recorder = new MicPcmRecorder();
if (recorder.start(pcm)) {
// 录制 3 秒
new android.os.Handler().postDelayed(recorder::stop, 3000);
}
验证方法:录制 3 秒后检查 mic_test.pcm 文件大小。理论字节数 = 16000 × 2 × 3 = 96000 字节(单声道 16bit)。实际大小接近该值即说明采集与写入正常。可用 adb pull 导出后通过 Audacity「导入原始数据」选择 16000Hz / 单声道 / 16bit 试听。
常见问题
- 文件为 0 字节:多为未授予
RECORD_AUDIO或getState()未初始化。 - 播放为噪声:采样率或声道数不匹配,导入时需与代码参数一致。
- 录音断续:
bufferSize过小,建议取getMinBufferSize的 2 倍以上。