深入浅出安卓AudioRecord

8 阅读4分钟

深入浅出安卓AudioRecord

一、AudioRecord是什么?

想象AudioRecord就像你手机里的"录音笔",专门用来录制原始音频数据。和手机自带的录音APP不同,它提供的是"原材料"(PCM数据),而不是"成品"(MP3/WAV文件)。你可以对这些原材料进行加工处理,比如:

  • 实时语音识别
  • 音频特效处理
  • 语音通话应用
  • 声音分析(如分贝检测)

二、录音的基本流程

1. 配置录音参数 - 相当于设置录音笔

// 常用参数配置
int sampleRate = 44100; // 采样率(CD音质)
int channelConfig = AudioFormat.CHANNEL_IN_MONO; // 单声道
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位深度

// 计算最小缓冲区大小
int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);

参数解释

  • 采样率:每秒采集多少次声音(Hz),越高音质越好但体积越大
  • 声道配置:单声道(CHANNEL_IN_MONO)或立体声(CHANNEL_IN_STEREO)
  • 音频格式:一般用16位的PCM(ENCODING_PCM_16BIT)

2. 创建AudioRecord对象 - 买录音笔

AudioRecord audioRecord = new AudioRecord(
    MediaRecorder.AudioSource.MIC, // 使用麦克风
    sampleRate,
    channelConfig,
    audioFormat,
    minBufferSize * 2 // 实际缓冲区大小(建议是最小值的2倍)
);

注意

  • 需要检查录音权限(Manifest.permission.RECORD_AUDIO
  • Android 6.0+需要动态申请权限

3. 开始录音 - 按下录音键

audioRecord.startRecording();

4. 读取音频数据 - 获取录音内容

byte[] audioData = new byte[minBufferSize];
while (isRecording) {
    int readResult = audioRecord.read(audioData, 0, minBufferSize);
    // 处理audioData(可以保存、传输或实时处理)
}

5. 停止和释放 - 关闭录音笔

audioRecord.stop();
audioRecord.release(); // 非常重要!释放资源

三、关键问题与解决方案

1. 为什么录音有杂音/声音小?

可能原因

  • 缓冲区大小不合适
  • 没有使用合适的音频源

解决方案

// 尝试使用VOICE_RECOGNITION音频源(针对语音优化)
new AudioRecord(
    MediaRecorder.AudioSource.VOICE_RECOGNITION,
    sampleRate,
    channelConfig,
    audioFormat,
    bufferSize
);

2. 如何保存为WAV文件?

PCM是原始数据,需要加WAV头才能播放:

// 添加WAV文件头的方法
private void writeWavHeader(FileOutputStream out, long totalAudioLen) throws IOException {
    long totalDataLen = totalAudioLen + 36;
    byte[] header = new byte[44];
    
    // 标准的WAV文件头填充代码...
    out.write(header);
}

3. 实时处理音频数据(示例:实时音量计算)

while (isRecording) {
    int readResult = audioRecord.read(audioData, 0, bufferSize);
    double sum = 0;
    for (int i = 0; i < readResult; i += 2) {
        short sample = (short)((audioData[i+1] << 8) | audioData[i]);
        sum += sample * sample;
    }
    double rms = Math.sqrt(sum / (readResult/2)); // 均方根值
    updateVolumeUI(rms); // 更新UI显示音量
}

四、进阶技巧

1. 音频源类型选择

音频源常量用途
MIC主麦克风
VOICE_COMMUNICATION语音通话(会启用降噪)
VOICE_RECOGNITION语音识别优化
CAMCORDER相机关联的麦克风

2. 低延迟配置(Android 8.0+)

// 在创建AudioRecord前设置低延迟模式
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.setProperty("android.media.property.OUTPUT_FRAMES_PER_BUFFER", "256");

// 使用高性能采样率
int sampleRate = 48000; // 专业音频设备常用采样率

3. 处理音频焦点(避免和其他APP冲突)

AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.requestAudioFocus(
    focusChange -> { /* 处理焦点变化 */ },
    AudioManager.STREAM_MUSIC,
    AudioManager.AUDIOFOCUS_GAIN
);

五、常见坑与填坑指南

  1. 报错:startRecording() failed - invalid operation

    • 检查是否已经调用了prepare()release()
    • 确认权限已获取
  2. 录音数据全是0

    • 检查麦克风是否被其他应用占用
    • 尝试不同的音频源(如VOICE_RECOGNITION)
  3. 延迟太高

    • 减小缓冲区大小(但不能小于getMinBufferSize返回值)
    • 使用低延迟配置(见第四节)
  4. 不同手机效果差异大

    • 测试主流机型
    • 提供设置选项让用户调整采样率/缓冲区

六、完整示例代码框架

public class AudioRecorder {
    private AudioRecord audioRecord;
    private boolean isRecording;
    private Thread recordingThread;
    
    public void startRecording(File outputFile) {
        // 1. 配置参数
        int sampleRate = 44100;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int minBufferSize = AudioRecord.getMinBufferSize(...);
        
        // 2. 创建AudioRecord
        audioRecord = new AudioRecord(
            MediaRecorder.AudioSource.MIC,
            sampleRate,
            channelConfig,
            audioFormat,
            minBufferSize * 2
        );
        
        // 3. 开始录音
        audioRecord.startRecording();
        isRecording = true;
        
        // 4. 启动数据读取线程
        recordingThread = new Thread(() -> {
            FileOutputStream fos = new FileOutputStream(outputFile);
            writeWavHeader(fos, 0); // 先写入空头
            
            byte[] buffer = new byte[minBufferSize];
            while (isRecording) {
                int bytesRead = audioRecord.read(buffer, 0, buffer.length);
                fos.write(buffer, 0, bytesRead);
                // 可以在这里添加实时处理逻辑
            }
            
            // 录音结束,更新WAV头
            updateWavHeader(fos);
            fos.close();
        });
        recordingThread.start();
    }
    
    public void stopRecording() {
        isRecording = false;
        try {
            recordingThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        audioRecord.stop();
        audioRecord.release();
    }
}

七、总结

AudioRecord使用三步走:

  1. 准备阶段:配置参数 → 创建对象
  2. 运行阶段:开始录音 → 循环读取数据
  3. 收尾阶段:停止录音 → 释放资源

关键要点:

  • 录音参数要根据实际需求调整(不是越高越好)
  • 记得检查权限和释放资源
  • PCM数据需要处理才能播放(加WAV头或转码)
  • 实时处理时注意性能问题

就像专业录音师需要了解设备特性一样,用好AudioRecord需要理解它的参数和行为。现在,你可以开始打造自己的音频处理APP了!