跳到主要内容

Web Audio:浏览器为什么能做音频处理?AudioContext、节点图、AudioWorklet 怎么理解?

面试速答(30 秒版 TL;DR)

  • Web Audio API 是浏览器里的音频处理图(audio graph)系统,核心入口是 AudioContext
  • 它的模型不是“播一段音频文件就完了”,而是把音频数据放进一张 节点图:来源节点 -> 处理节点 -> 输出节点。
  • 高频节点要会:AudioBufferSourceNodeMediaElementAudioSourceNodeMediaStreamAudioSourceNodeGainNodeAnalyserNodeBiquadFilterNodeAudioDestinationNode
  • 高频追问是:为什么需要用户手势恢复音频、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
  • 模型:来源节点 -> 处理节点 -> 输出节点
  • 高频处理节点:GainNodeAnalyserNodeBiquadFilterNode
  • 自定义低延迟处理优先 AudioWorklet