4、音频采集:音频约束详解(sampleRate、channelCount、echoCancellation)、获取麦克风音频流。
好,咱们接着聊音频采集。上一节我们把摄像头搞定了,画面有了,但光有画面没声音,那叫默片。今天咱们就深入聊聊音频约束,把麦克风的声音也抓进来。
说实话,音频这块儿坑比视频还多。视频顶多是卡顿、模糊,音频要是出了问题,那就是刺啦刺啦的噪音,或者干脆没声。我在项目里就吃过这个亏,后面会跟大家细说。
音频约束的核心参数
调用 getUserMedia 的时候,我们传一个 audio: true 就能拿到音频流。但这样拿到的,是浏览器的「默认配置」。这个默认配置,往往不是最优的。
我们需要用更精细的约束对象来控制它。就像这样:
const constraints = {
audio: {
sampleRate: 48000,
channelCount: 2,
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
};
这几个参数,我一个个拆开讲。
sampleRate:采样率
采样率,说白了就是一秒钟采集多少个声音样本。单位是 Hz。
常见的值有:
| 采样率 | 常见场景 | 我的建议 |
|---|---|---|
| 8000 Hz | 传统电话 | 别用,音质太差 |
| 16000 Hz | VoIP、语音通话 | 够用,省带宽 |
| 44100 Hz | CD 音质 | 音乐场景可用 |
| 48000 Hz | 专业音频、WebRTC 默认 | 我推荐用这个 |
为什么我推荐 48000 Hz?因为 WebRTC 内部处理音频时,默认就是 48000 Hz。你设成 16000 Hz,浏览器还得做一次重采样,多一道转换就多一分延迟和损耗。
MediaDevices.getSupportedConstraints() 查一下。不过大部分现代设备都支持 48000 Hz。
channelCount:声道数
声道数,就是同时录几个声道。
- 1(单声道):所有声音混成一个轨道。省带宽,适合语音通话。
- 2(立体声):左右声道分开。音质好,但数据量翻倍。
我个人习惯,做语音通话用单声道就够了。为什么?因为 WebRTC 的音频处理模块(比如回声消除、降噪)都是基于单声道设计的。你传立体声进去,它反而要混成单声道再处理,多此一举。
但如果你在做音乐直播、远程乐器演奏,那就必须用立体声。这个看场景。
echoCancellation:回声消除
这个参数,我愿称之为「音频采集的灵魂」。
回声是怎么来的?你想想看:对方说话的声音,从你的扬声器放出来,又被你的麦克风录进去,再传回给对方。对方就听到了自己的回声,烦不烦?
echoCancellation: true 就是让浏览器帮你把这个回声干掉。它通过分析扬声器播放的声音和麦克风采集的声音,把重复的部分抵消掉。
另外两个参数:noiseSuppression(降噪)和 autoGainControl(自动增益控制),我一般也设为 true。降噪能滤掉风扇声、键盘声;自动增益能保证你离麦克风远一点时,声音不会太小。
获取麦克风音频流
参数讲完了,咱们写代码。获取音频流和获取视频流,套路是一样的:
async function getAudioStream() {
try {
const constraints = {
audio: {
sampleRate: 48000,
channelCount: 1,
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
console.log('音频流获取成功', stream);
// 把音频流挂到 audio 元素上播放(本地监听)
const audioElement = document.querySelector('audio');
audioElement.srcObject = stream;
audioElement.play();
return stream;
} catch (err) {
console.error('获取音频流失败:', err);
// 常见的错误:NotAllowedError(用户拒绝)、NotFoundError(没麦克风)
}
}
这里有个细节:本地监听。你把麦克风的声音直接播出来,会听到自己的声音,而且可能产生啸叫。所以调试的时候,建议戴耳机。
stream.getAudioTracks() 的长度。如果为 0,说明没拿到音频轨道。我在项目中遇到过,用户系统里明明有麦克风,但浏览器就是识别不到——后来发现是权限被系统安全软件拦截了。
音频约束的整体逻辑
为了让大家更直观地理解,我画了一张图:
从图里能看出来,约束参数就是一道关卡。你设得好,拿到的音频流质量高、延迟低。设得不好,后面做再多的处理也白搭。
避坑指南
最后,分享几个我踩过的坑:
- 别设死值:比如你设
sampleRate: { exact: 48000 },如果设备不支持,直接报错。用ideal或者直接给数值,让浏览器自己选。 - 检查轨道设置:拿到流之后,用
track.getSettings()看看浏览器实际用了什么参数。有时候你设了 48000,它给你降到 44100,你都不知道。 - 移动端注意:手机上的麦克风,采样率可能被系统锁定。我在 Android 上遇到过,设 48000 没用,实际只有 16000。这时候别纠结,能用就行。
嗯,音频约束这块儿就这些。说白了就是几个参数,但每个参数背后都有讲究。你把它调明白了,音频采集就稳了。