2、前端技术选型:Web Audio API vs WebRTC、AudioWorklet vs ScriptProcessor、浏览器兼容性分析

做 VAD 前端部署,第一步就是选对工具。说白了,你得想清楚:音频从哪来?怎么处理?跑在哪个线程?

我刚开始做这个方向时,也踩过不少坑。今天就把这些经验拆开揉碎了讲给你听。

2.1 音频采集:Web Audio API vs WebRTC

这两个都能拿到麦克风音频流。但它们的定位完全不同。

对比维度 Web Audio API WebRTC (getUserMedia + MediaStream)
核心用途 音频处理、合成、分析 实时通信、媒体流传输
获取音频方式 通过 AudioContext.createMediaStreamSource() 通过 getUserMedia() 获取 MediaStream
采样率控制 由 AudioContext 的 sampleRate 决定 由浏览器和硬件决定,无法直接控制
延迟特性 低延迟,适合实时处理 中等延迟,为网络传输优化
VAD 适用性 ⭐⭐⭐⭐⭐ 首选 ⭐⭐⭐ 需要额外转换

我的建议:VAD 场景下,直接用 Web Audio API。它原生支持音频图(Audio Graph),方便你把麦克风节点、处理节点、分析节点串起来。WebRTC 的 MediaStream 虽然也能用,但多一层转换,没必要。

举个例子。你拿到 MediaStream 后,想喂给 VAD 模型,得先转成 AudioBuffer 或 Float32Array。Web Audio API 直接就能输出 AudioBuffer,省掉中间步骤。

// 推荐方式:Web Audio API
const audioContext = new AudioContext({ sampleRate: 16000 });
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = audioContext.createMediaStreamSource(stream);
// source 直接接入 AudioWorklet 或 ScriptProcessor

小技巧:创建 AudioContext 时,显式指定 sampleRate: 16000。VAD 模型通常用 16kHz 采样率,省去后续重采样步骤。我在项目中吃过这个亏——默认 48kHz,还得手动降采样,多了一堆代码。

2.2 音频处理:AudioWorklet vs ScriptProcessor

拿到音频流后,你需要一个「处理节点」来跑 VAD 算法。这里有两个选择。

2.2.1 ScriptProcessor(已废弃,但还能用)

ScriptProcessor 是 Web Audio API 早期的处理方案。它运行在主线程,通过 onaudioprocess 事件回调处理音频。

const processor = audioContext.createScriptProcessor(1024, 1, 1);
processor.onaudioprocess = (event) => {
  const inputData = event.inputBuffer.getChannelData(0);
  // 在这里跑 VAD 算法
  const isSpeech = vadModel.process(inputData);
};

注意:ScriptProcessor 在主线程运行。如果你的 VAD 算法计算量大,会卡 UI。我曾在项目里用 ScriptProcessor 跑一个轻量 VAD,结果页面滚动都掉帧。后来果断换了 AudioWorklet。

2.2.2 AudioWorklet(推荐)

AudioWorklet 是 Web Audio API 的现代方案。它在独立线程(AudioWorkletGlobalScope)中运行,不阻塞主线程。

// 1. 注册 Worklet
await audioContext.audioWorklet.addModule('vad-processor.js');

// 2. 创建节点
const vadNode = new AudioWorkletNode(audioContext, 'vad-processor');

// 3. 连接
source.connect(vadNode);
vadNode.connect(audioContext.destination);

// 4. 接收结果
vadNode.port.onmessage = (event) => {
  const { isSpeech, confidence } = event.data;
  updateUI(isSpeech, confidence);
};

在 vad-processor.js 中:

class VADProcessor extends AudioWorkletProcessor {
  process(inputs, outputs, parameters) {
    const input = inputs[0];
    if (input.length > 0) {
      const channelData = input[0];
      const result = runVAD(channelData);
      this.port.postMessage(result);
    }
    return true; // 保持处理器活跃
  }
}
registerProcessor('vad-processor', VADProcessor);
对比维度 ScriptProcessor AudioWorklet
运行线程 主线程 独立音频线程
延迟 较高(至少 2 个 buffer 长度) 极低(1 个 buffer 长度)
稳定性 可能被 UI 任务阻塞 稳定,不受主线程影响
浏览器支持 所有浏览器(已标记废弃) Chrome 66+, Firefox 76+, Safari 14.1+
VAD 推荐度 ❌ 不推荐 ✅ 强烈推荐

核心结论:新项目直接用 AudioWorklet。ScriptProcessor 已经是历史遗留产物了。如果你需要兼容非常老的浏览器(比如 Chrome 66 之前),才考虑 ScriptProcessor 作为 fallback。

2.3 浏览器兼容性分析

做前端部署,最头疼的就是兼容性。我整理了一份主流浏览器的支持情况。

特性 Chrome Firefox Safari Edge
Web Audio API ✅ 全支持 ✅ 全支持 ✅ 全支持 ✅ 全支持
getUserMedia ✅ 全支持 ✅ 全支持 ✅ 11+ ✅ 全支持
AudioWorklet ✅ 66+ ✅ 76+ ✅ 14.1+ ✅ 79+
ScriptProcessor ✅ 全支持(废弃) ✅ 全支持(废弃) ✅ 全支持(废弃) ✅ 全支持(废弃)
AudioContext.sampleRate ✅ 全支持 ✅ 全支持 ⚠️ 部分限制 ✅ 全支持

避坑指南:我曾经在 Safari 上栽过跟头。Safari 14.1 以下不支持 AudioWorklet,而且 AudioContext 的 sampleRate 不能随意指定——它只支持设备原生采样率。如果你需要 16kHz,得手动重采样。建议在代码里加一个特性检测:

function isAudioWorkletSupported() {
  return 'audioWorklet' in AudioContext.prototype;
}

function getSupportedSampleRate() {
  const ctx = new AudioContext();
  return ctx.sampleRate;
}

2.4 整体技术选型流程图

下面这张图,帮你理清整个选型逻辑。

VAD 前端技术选型流程图 VAD 前端技术选型决策流程 音频采集需求 需要实时处理还是仅采集? 实时处理 仅采集 Web Audio API getUserMedia 需要低延迟? MediaStream → AudioBuffer AudioWorklet ScriptProcessor (fallback) 💡 选型建议 优先 AudioWorklet + Web Audio API;Safari 14.1 以下降级到 ScriptProcessor

2.5 我的最终推荐方案

说了这么多,直接给结论吧。

  1. 音频采集:用 getUserMedia 获取 MediaStream,然后通过 AudioContext.createMediaStreamSource() 接入 Web Audio API 的音频图。
  2. 音频处理:用 AudioWorklet 跑 VAD 算法。如果目标浏览器不支持,降级到 ScriptProcessor。
  3. 采样率:创建 AudioContext 时指定 sampleRate: 16000。如果浏览器不支持(比如 Safari),手动重采样。
  4. 兼容性检测:运行时检测 audioWorklet 和 sampleRate 支持情况,动态选择方案。

个人经验:我做过一个跨平台 VAD SDK,覆盖 Chrome、Firefox、Safari、Edge 以及内置浏览器。最终方案是:AudioWorklet 为主,ScriptProcessor 为 fallback,Safari 单独处理采样率。这套方案跑了半年,线上崩溃率低于 0.1%。