Web Audio:浏览器为什么能做音频处理?AudioContext、节点图、AudioWorklet 怎么理解?
面试速答(30 秒版 TL;DR)
- Web Audio API 是浏览器里的音频处理图(audio graph)系统,核心入口是
AudioContext。 - 它的模型不是“播一段音频文件就完了”,而是把音频数据放进一张 节点图:来源节点 -> 处理节点 -> 输出节点。
- 高频节点要会:
AudioBufferSourceNode、MediaElementAudioSourceNode、MediaStreamAudioSourceNode、GainNode、AnalyserNode、BiquadFilterNode、AudioDestinationNode。 - 高频追问是:为什么需要用户手势恢复音频、
AudioBufferSourceNode为什么通常只能播一次、AudioWorklet为什么比ScriptProcessorNode更现代。
心智模型:音频不是“一个播放器”,而是一张可编排的处理链
如果你只把 Web Audio 理解成“播放 mp3”,会答浅了。
更准确的理解是:
- 浏览器提供了一套音频节点系统
- 不同节点负责采集、生成、滤波、增益、分析、输出
- 把它们连起来,就形成音频处理图
一、入口:AudioContext
const audioContext = new AudioContext();
它负责:
- 管理音频时钟
- 创建音频节点
- 驱动整张音频图运行
注意:
- 现代浏览器经常要求 用户手势 后才能真正开始播放声音
- 所以常见写法是点击按钮后
resume()
button.addEventListener("click", async () => {
await audioContext.resume();
});
二、最小例子:振荡器发声
const ctx = new AudioContext();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.frequency.value = 440;
gain.gain.value = 0.1;
osc.connect(gain);
gain.connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 1);
这段代码说明了最核心的图结构:
OscillatorNode产生声音GainNode控制音量destination输出到扬声器
三、常见音频来源节点
| 节点 | 来源 |
|---|---|
AudioBufferSourceNode | 内存中的音频 buffer |
MediaElementAudioSourceNode | <audio> / <video> 元素 |
MediaStreamAudioSourceNode | 麦克风 / WebRTC 流 |
OscillatorNode | 程序生成波形 |
AudioBufferSourceNode 常见用法
const buf = await fetchAudioBuffer();
const source = ctx.createBufferSource();
source.buffer = buf;
source.connect(ctx.destination);
source.start();
高频点:
AudioBufferSourceNode通常是 一次性节点- 播完想再播,通常要重新创建一个新的 source
四、常见处理节点
| 节点 | 作用 |
|---|---|
GainNode | 调整音量 |
AnalyserNode | 做频谱/波形分析 |
BiquadFilterNode | 滤波 |
DelayNode | 延迟效果 |
DynamicsCompressorNode | 压缩动态范围 |
StereoPannerNode | 左右声道平移 |
频谱可视化为什么常用 AnalyserNode
因为它能拿到:
- 时域波形数据
- 频域频谱数据
于是可用于:
- 音频可视化
- 音量条
- 语音活跃度粗略检测
五、解码音频文件:decodeAudioData
const arrayBuffer = await fetch("/demo.mp3").then((r) => r.arrayBuffer());
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
这一步把压缩音频文件解码成:
- 浏览器可处理的 PCM 音频缓冲数据
六、为什么说 Web Audio 适合做“处理”,而 <audio> 更像“播放”
| 维度 | <audio> 元素 | Web Audio |
|---|---|---|
| 目标 | 媒体播放 | 音频处理与编排 |
| 上手难度 | 低 | 更高 |
| 可编程性 | 有限 | 很强 |
| 适合 | 普通播放控件 | 效果器、可视化、音频编辑、合成器 |
面试口径:
- 纯播放 UI 用
<audio>就够 - 要做音量图、滤波、混音、实时分析,Web Audio 更合适
七、和麦克风 / WebRTC 结合
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = ctx.createMediaStreamSource(stream);
const analyser = ctx.createAnalyser();
source.connect(analyser);
analyser.connect(ctx.destination);
这适合:
- 实时语音可视化
- 降噪前后分析
- 语音处理链路
八、AudioWorklet 为什么比 ScriptProcessorNode 更现代
老方案 ScriptProcessorNode 的问题:
- 延迟更高
- 设计较旧
- 主线程参与更多,稳定性更差
AudioWorklet 的优势:
- 更现代
- 更适合低延迟自定义音频处理
- 运行模型更接近实时音频处理要求
面试答法:
- 需要自定义、低延迟、可持续维护的音频 DSP 逻辑时,优先
AudioWorklet。
九、自动播放限制为什么常被追问
现代浏览器通常不允许页面一加载就自动出声。
原因:
- 避免骚扰用户
- 节制媒体自动播放
所以常见做法:
- 用户点击“播放/开始”按钮后再
resume()
这也是为什么你经常看到:
await audioContext.resume();
十、典型使用场景
1) 音频可视化
- 波形图
- 频谱图
2) 音效处理
- 均衡器
- 延迟
- 混响
3) 语音与实时音频
- 麦克风采集
- 实时分析
- WebRTC 前后处理
4) 游戏与交互音效
- 短音效触发
- 3D / 空间音频
典型题 & 标准答法
Q1:Web Audio 的核心模型是什么?
AudioContext管理一张音频节点图- 来源节点产生音频,处理节点加工音频,最终输出到
destination
Q2:为什么 AudioBufferSourceNode 通常只能播放一次?
因为它更像“一次性播放节点”,播放完成后一般要重新创建新的 source,再挂同一个 buffer。
Q3:为什么音频播放常要求用户点击后才生效?
因为浏览器有自动播放策略,通常要求用户手势激活音频上下文。
Q4:AudioWorklet 为什么比 ScriptProcessorNode 更好?
因为它更现代,更适合低延迟和稳定的自定义音频处理。
易错点/坑
- 页面加载就直接播放,忽略自动播放限制。
AudioBufferSourceNode重复start(),以为能多次复用同一节点。- 把 Web Audio 当成单纯播放器,忽略其“节点图”本质。
- 在主线程做过重音频处理,导致卡顿。
速记要点(可背诵)
- 入口:
AudioContext - 模型:来源节点 -> 处理节点 -> 输出节点
- 高频处理节点:
GainNode、AnalyserNode、BiquadFilterNode - 自定义低延迟处理优先
AudioWorklet