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 Segmentation | GPU 15% | WebGPU,30fps |
| RNNoise | CPU 单核 5% | WASM SIMD |
| Whisper-tiny | GPU 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. 参考资料
- W3C Insertable Streams: https://w3c.github.io/webrtc-encoded-transform/
- MediaPipe Vision: https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter
- RNNoise: https://jmvalin.ca/demo/rnnoise/
- transformers.js: https://huggingface.co/docs/transformers.js/
- 上一级 实战项目总览