第28章 录制与效果:AudioRecord与效果处理、实时监听与效果反馈、回声消除与噪声抑制
各位同学,今天我们来聊聊录制过程中的效果处理。很多人觉得录音就是把麦克风的声音存下来,其实没那么简单。你想想看,如果录的是K歌,没点混响效果,那干巴巴的声音谁受得了?如果是视频通话,回声和噪声不处理,对方听着也难受。
我个人习惯把录制效果处理分成三个层次:基础录制、实时效果、环境优化。今天我们就一层层把它讲透。
28.1 AudioRecord与效果处理的基本流程
先看最基础的东西。Android里用AudioRecord采集音频,流程其实很固定:
// 1. 配置参数
int sampleRate = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
// 2. 创建AudioRecord实例
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelConfig, audioFormat, bufferSize);
// 3. 开始录制
recorder.startRecording();
// 4. 循环读取数据
byte[] buffer = new byte[bufferSize];
while (isRecording) {
int bytesRead = recorder.read(buffer, 0, buffer.length);
// 这里可以对buffer做效果处理
processAudioEffect(buffer, bytesRead);
// 写入文件或发送网络
fileOutputStream.write(buffer, 0, bytesRead);
}
// 5. 停止释放
recorder.stop();
recorder.release();
嗯,这里要注意一点:getMinBufferSize返回的值不一定是最优的。我在项目中遇到过,某些低端机用最小值会导致频繁的音频断流。我建议你在这个值基础上乘以2或4,留点余量。
28.2 实时监听与效果反馈
什么叫实时监听?说白了就是「边录边听」。比如你在K歌软件里唱歌,耳机里能听到带混响的自己声音,这就是实时监听。
实现方式有两种:
- 直接路由法:用AudioRecord读数据,直接写到AudioTrack播放。延迟最低,但没法做效果处理。
- 处理路由法:读数据→做效果→写AudioTrack。延迟稍高,但能加混响、均衡器等。
我一般用第二种。代码大概长这样:
// 创建AudioTrack用于监听输出
AudioTrack track = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize,
AudioTrack.MODE_STREAM);
track.play();
// 录制循环中加入监听
while (isRecording) {
int bytesRead = recorder.read(buffer, 0, buffer.length);
// 做效果处理(比如加个简单的混响)
applyReverb(buffer, bytesRead);
// 写入文件
fileOutputStream.write(buffer, 0, bytesRead);
// 同时送到监听输出
track.write(buffer, 0, bytesRead);
}
28.3 回声消除与噪声抑制
这部分是录制效果里最头疼的。回声怎么来的?你想想看,扬声器放出来的声音又被麦克风收回去,再传给对方,对方就听到了自己的回声。噪声就更不用说了,风扇声、空调声、马路声,全进来了。
Android提供了两种处理方式:
| 方式 | API | 适用场景 | 优缺点 |
|---|---|---|---|
| 硬件AEC | MediaRecorder.AudioSource.VOICE_COMMUNICATION | VoIP、视频通话 | 系统自带,延迟低,但效果因厂商而异 |
| 软件AEC | WebRTC AEC模块 | 自定义录制、直播 | 可控性强,但需要集成第三方库 |
我个人更推荐用WebRTC的方案。为什么?因为硬件AEC在不同手机上表现天差地别。我记得有一次测试,某款手机用VOICE_COMMUNICATION源录制,回声是没了,但声音变得像在水缸里说话一样。后来换成WebRTC的AEC,调了几个参数就好了。
WebRTC的AEC集成大概是这样:
// 初始化WebRTC音频处理模块
AudioProcessing ap = AudioProcessing.create();
ap.setExtCaptureSampleRate(sampleRate);
ap.setExtRenderSampleRate(sampleRate);
// 配置回声消除
ap.echo_cancellation().setEnable(true);
ap.echo_cancellation().setSuppressionLevel(EchoCancellation.SuppressionLevel.HIGH);
// 配置噪声抑制
ap.noise_suppression().setEnable(true);
ap.noise_suppression().setLevel(NoiseSuppression.Level.HIGH);
// 在录制循环中处理
while (isRecording) {
// 读取麦克风数据
recorder.read(captureBuffer, 0, captureBuffer.length);
// 读取扬声器参考数据(用于回声消除)
// 这里需要从AudioTrack的回调中获取renderBuffer
// 处理音频
ap.processStream(captureBuffer, renderBuffer);
// 处理后的数据在captureBuffer中
fileOutputStream.write(captureBuffer, 0, captureBuffer.length);
}
28.4 知识体系总览
说了这么多,我们来画个图,把整个录制效果框架串起来。这样你脑子里就有个全局概念了。
从这张图你能看到,整个流程是串行的:麦克风→AudioRecord→效果处理+环境优化→输出。其中效果处理和环境优化是并行的,可以同时做。我个人习惯先做环境优化(降噪、消回声),再做效果处理(混响、变声),这样效果更干净。
28.5 实战中的几个关键点
- 延迟控制:实时监听最怕延迟。我建议buffer size不要超过100ms的数据量,否则人耳能明显感觉到「慢半拍」。
- 线程模型:AudioRecord的读取和AudioTrack的写入要在不同线程。我曾经图省事放一个线程里,结果卡得不行。
- 参数调优:回声消除的抑制级别别拉太高。HIGH级别虽然消得干净,但容易把正常语音也削掉。我一般用MODERATE。
- 兼容性测试:不同手机的麦克风灵敏度、扬声器音量都不一样。建议在设置里加个「回声测试」功能,让用户自己调。
好了,这一章的内容就到这里。录制效果处理说难不难,说简单也不简单,关键是把基础流程走通,再根据场景选对方案。下一章我们会聊更高级的音频处理技巧,到时候再见。
公众号:蓝海资料掘金营,微信deep3321