25、WebRTC与AI结合:人脸检测、语音识别、实时字幕生成

说实话,WebRTC 做到一定程度,你会发现一个瓶颈——画面和声音是传过去了,但机器看不懂。我最早做视频会议项目时,客户提了个需求:“能不能自动把发言人框出来?” 当时我第一反应是“这得加个 AI 模块吧?” 后来真做起来才发现,WebRTC 和 AI 的结合,其实比想象中要顺滑得多。

今天我们就聊聊三个最实用的方向:人脸检测语音识别实时字幕生成。说白了,就是让 WebRTC 的流里跑点“脑子”。

25.1 为什么要在 WebRTC 里塞 AI?

你想想看,WebRTC 本身只负责传输音视频流。它不关心画面里有没有人,也不管对方说了什么。但实际业务中,这些信息太重要了。

  • 人脸检测:自动聚焦发言人、美颜、背景虚化
  • 语音识别:会议纪要、关键词提醒、实时翻译
  • 实时字幕:听障辅助、嘈杂环境、多语言沟通

我在项目中遇到过最典型的场景:一个跨国会议,有人网络差,声音断断续续。如果有了实时字幕,哪怕音频丢包,文字还能补全信息。这就是 AI 的价值。

核心思路:WebRTC 提供流,AI 消费流。两者通过 MediaStream 和 MediaStreamTrack 桥接。

25.2 整体架构:AI 模块怎么插进去?

先看一张图,你就明白了。

WebRTC 采集 摄像头 / 麦克风 MediaStream AI 处理层 人脸检测 (TensorFlow.js) 语音识别 (Web Speech API) 字幕生成 (Canvas 覆盖) 处理结果 渲染输出 视频 + 人脸框 音频 + 字幕 RTCPeerConnection

嗯,这里要注意:AI 处理不能阻塞主线程。我早期犯过一个错——直接在 ontrack 回调里跑模型推理,结果画面卡成 PPT。后来改用 OffscreenCanvasWeb Worker,才把帧率稳住。

25.3 人脸检测实战

人脸检测在 WebRTC 里最常见的用法是:在本地视频上画框,然后只发送框内区域。这样可以节省带宽,也能保护隐私。

25.3.1 技术选型

方案 优点 缺点
TensorFlow.js + FaceMesh 纯前端,无需后端 CPU 占用高
MediaPipe 性能好,支持 GPU 需要额外加载 WASM
OpenCV.js 经典算法,轻量 准确率一般

我个人习惯用 MediaPipe。为什么?因为它能跑在 Web Worker 里,不卡主线程。我在一个远程医疗项目里用过,1080p 30fps 的视频,检测延迟控制在 20ms 以内。

25.3.2 核心代码示例

// 1. 获取本地视频流
const stream = await navigator.mediaDevices.getUserMedia({ video: true });

// 2. 初始化 MediaPipe Face Detection
const faceDetector = new FaceDetection({
  locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/${file}`
});

faceDetector.setOptions({
  modelSelection: 1, // 0: 短距离, 1: 全距离
  minDetectionConfidence: 0.7
});

// 3. 每帧检测
const video = document.createElement('video');
video.srcObject = stream;
await video.play();

async function detectLoop() {
  const results = await faceDetector.send({ image: video });
  if (results.detections.length > 0) {
    // 在 canvas 上画框
    drawFaceBox(results.detections);
    // 可选:裁剪人脸区域发送
    cropAndSendFace(results.detections[0]);
  }
  requestAnimationFrame(detectLoop);
}
detectLoop();

避坑指南:我曾经把 faceDetector.send() 放在 requestAnimationFrame 里直接跑,结果发现每帧都要等模型推理完才渲染。后来改成 setInterval 每 100ms 检测一次,渲染和检测分离,流畅度提升明显。

25.4 语音识别与实时字幕

语音识别这块,浏览器其实已经给了我们一个好东西——Web Speech API。它支持实时语音识别,而且不需要额外模型。但有个坑:它只能识别麦克风输入,不能直接识别 WebRTC 的远端音频。

25.4.1 识别远端音频的解决方案

我当时的做法是:把远端音频流通过 AudioContext 重新采样,再喂给 SpeechRecognition。说白了就是“偷梁换柱”。

// 1. 获取远端音频流
const remoteStream = peerConnection.getRemoteStreams()[0];
const audioTrack = remoteStream.getAudioTracks()[0];

// 2. 创建 AudioContext 并连接
const audioCtx = new AudioContext();
const source = audioCtx.createMediaStreamSource(new MediaStream([audioTrack]));
const dest = audioCtx.createMediaStreamDestination();
source.connect(dest);

// 3. 用 dest.stream 作为 SpeechRecognition 的输入
const recognition = new webkitSpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = 'zh-CN';

// 注意:SpeechRecognition 默认用麦克风,这里需要 hack
// 实际项目中可以用 AudioWorklet 或 MediaStreamTrackProcessor
recognition.onresult = (event) => {
  for (let i = event.resultIndex; i < event.results.length; i++) {
    const transcript = event.results[i][0].transcript;
    if (event.results[i].isFinal) {
      appendSubtitle(transcript); // 最终结果
    } else {
      showInterimSubtitle(transcript); // 临时结果
    }
  }
};

recognition.start();

注意:Web Speech API 的 start() 必须在用户交互事件(如点击)中调用,否则会被浏览器拦截。我踩过这个坑,调试了半天才发现是自动播放策略的问题。

25.4.2 字幕渲染

字幕渲染我推荐用 Canvas 覆盖层,而不是 DOM 元素。因为 Canvas 可以跟视频帧同步,不会出现字幕和画面错位的情况。

function renderSubtitle(text, isFinal) {
  const canvas = document.getElementById('subtitleCanvas');
  const ctx = canvas.getContext('2d');
  
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 背景
  ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
  ctx.roundRect(10, canvas.height - 60, canvas.width - 20, 50, 10);
  ctx.fill();
  
  // 文字
  ctx.fillStyle = isFinal ? '#ffffff' : '#aaaaaa';
  ctx.font = '24px sans-serif';
  ctx.textAlign = 'center';
  ctx.fillText(text, canvas.width / 2, canvas.height - 25);
}

25.5 性能优化:别让 AI 拖垮 WebRTC

AI 加进来之后,最头疼的就是性能。我总结了几条经验:

  • 降分辨率:人脸检测不需要 4K,320x240 足够。用 canvas.drawImage 缩放到小尺寸再送检。
  • 跳帧处理:不必每帧都跑 AI,15fps 的检测频率已经够用。
  • 分离线程:AI 推理放到 Web Worker,渲染留在主线程。
  • 硬件加速:MediaPipe 支持 WebGL 后端,记得开启。

我的经验:在一个在线教育项目里,我们同时跑了人脸检测和语音识别。一开始 CPU 飙到 90%,后来把检测分辨率降到 160x120,帧率降到 10fps,CPU 直接降到 30%。用户根本感觉不到差异。

25.6 完整流程总结

来,我们把今天的内容串一下:

  1. 采集:getUserMedia 获取本地流,RTCPeerConnection 获取远端流
  2. 人脸检测:MediaPipe 或 TensorFlow.js,在 Canvas 上画框
  3. 语音识别:Web Speech API + AudioContext 重采样
  4. 字幕生成:Canvas 覆盖层,实时渲染文字
  5. 发送:处理后的视频/音频通过 WebRTC 发送

说白了,WebRTC 和 AI 的结合,就是让流变得“聪明”。你不需要成为 AI 专家,只要知道怎么把模型接进来、怎么优化性能就够了。剩下的,交给浏览器和 GPU。

最后一个小建议:如果你刚开始做,先从语音识别入手。它最简单,效果也最直观。人脸检测涉及 Canvas 绘制和坐标转换,稍微复杂一点。但不管哪个方向,记住一句话——先跑通,再优化


公众号:蓝海资料掘金营,微信deep3321