跳到主要内容

L5-AI增强会议

把 AI 能力插入实时音视频管道。本项目演示三个最有价值的能力:实时字幕虚拟背景降噪。全部跑在客户端 / 端侧,不依赖云端

1. 学习目标

  • 理解 Insertable Streams API:在编码 / 解码前后插入自定义处理。
  • 用 onnxruntime-web 在浏览器跑 ONNX 模型。
  • 用 MediaPipe / Selfie Segmentation 做虚拟背景。
  • 用 RNNoise / DeepFilterNet 做降噪。
  • 用 Whisper streaming 做实时字幕。
  • 把 ML 推理和 RTC 帧率解耦,避免阻塞媒体路径。

2. 架构

3. Insertable Streams 模板

// 视频
const processor = new MediaStreamTrackProcessor({ track: videoTrack });
const generator = new MediaStreamTrackGenerator({ kind: 'video' });

const transformer = new TransformStream({
async transform(frame, controller) {
const newFrame = await applyVirtualBackground(frame);
controller.enqueue(newFrame);
frame.close();
},
});

processor.readable.pipeThrough(transformer).pipeTo(generator.writable);

// 把处理过的 generator track 替代原 track 推流
const sender = pc.getSenders().find(s => s.track?.kind === 'video');
await sender.replaceTrack(generator);

4. 虚拟背景(MediaPipe + WebGPU)

import { ImageSegmenter, FilesetResolver } from '@mediapipe/tasks-vision';

const fileset = await FilesetResolver.forVisionTasks('/mp');
const segmenter = await ImageSegmenter.createFromOptions(fileset, {
baseOptions: { modelAssetPath: '/models/selfie_segmenter.tflite', delegate: 'GPU' },
runningMode: 'VIDEO',
outputCategoryMask: true,
});

async function applyVirtualBackground(frame) {
const ts = performance.now();
const result = segmenter.segmentForVideo(frame, ts);
const bitmap = composeWithMask(frame, result.categoryMask, backgroundImage);
return new VideoFrame(bitmap, { timestamp: frame.timestamp });
}

性能要点:

  • 用 WebGPU 而不是 WebGL(吞吐高 30%+)。
  • 模型选 Selfie Segmenter Lite(10MB 内)。
  • ML 推理与 30fps 视频流解耦:模型跑 15fps,缺帧用上一帧 mask 复用。

5. 降噪(RNNoise WASM)

import RNNoise from '@shiguredo/rnnoise-wasm';

class DenoiseProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.rnnoise = new RNNoise();
}
process(inputs, outputs) {
const inp = inputs[0][0];
const out = outputs[0][0];
this.rnnoise.process(inp, out);
return true;
}
}
registerProcessor('denoise', DenoiseProcessor);

接入:

const audioCtx = new AudioContext({ sampleRate: 48000 });
await audioCtx.audioWorklet.addModule('/denoise-worklet.js');
const src = audioCtx.createMediaStreamSource(micStream);
const node = new AudioWorkletNode(audioCtx, 'denoise');
const dest = audioCtx.createMediaStreamDestination();
src.connect(node).connect(dest);
const cleanTrack = dest.stream.getAudioTracks()[0];
await audioSender.replaceTrack(cleanTrack);

6. 实时字幕(Whisper Streaming)

import { pipeline } from '@xenova/transformers';

const transcriber = await pipeline(
'automatic-speech-recognition',
'Xenova/whisper-tiny',
{ device: 'webgpu' },
);

// 每 1s PCM 切片 → ASR
async function transcribeChunk(pcm) {
const result = await transcriber(pcm, {
chunk_length_s: 30,
stride_length_s: 5,
return_timestamps: true,
});
showCaption(result.text);
}

延迟模型:

  • 真正"流式"的 Whisper 需要 streaming patch(如 whisper.cpp + KV cache)。
  • 浏览器端可用 whisper-tiny + 1s 切片,端到端 1~2s 延迟。
  • 高质量需求建议云端 ASR(火山 / 讯飞 / Deepgram),通过 WebSocket 把音频流推过去。

7. 性能预算

模块CPU/GPU 占用备注
Selfie SegmentationGPU 15%WebGPU,30fps
RNNoiseCPU 单核 5%WASM SIMD
Whisper-tinyGPU 30%tiny 端到端可接受

总和:现代笔记本可同时跑 30~50% GPU + 15% CPU 而不影响通话。

8. 目录结构

L5-AI增强会议/
├── client/
│ ├── src/
│ │ ├── pipeline.js # Insertable Streams 编排
│ │ ├── vbg.js # 虚拟背景
│ │ ├── denoise.js # AudioWorklet 降噪
│ │ ├── caption.js # 字幕显示
│ │ └── asr-worker.js # ASR Web Worker
│ └── public/models/ # ONNX / TFLite 模型
└── server/ # 复用 L2 SFU

9. 验收 Checklist

  • 虚拟背景在 30fps 不掉帧
  • 降噪开启后 SNR 提升 ≥ 10dB(用 sox 测)
  • 字幕端到端延迟 ≤ 2s
  • 笔记本 CPU 占用 < 50%、GPU < 60%
  • 关闭 ML 时管道立即降级,不影响通话

10. 参考资料