17、WebRTC与AI结合:实时语音识别、人脸特效、背景替换
说实话,WebRTC 本身只是个传输管道。真正让实时通信变得「聪明」的,是 AI。
我最早接触这个方向,是在一个远程会议项目里。客户说:「能不能把背景换成海滩?」我当时心想,这不就是绿幕抠像吗?但后来发现,在浏览器里做实时背景替换,坑比想象中多得多。
这一章,我们就聊聊 WebRTC 和 AI 怎么结合。重点放在三个方向:实时语音识别、人脸特效、背景替换。这些都是我在实际项目中踩过坑、也填过坑的地方。
17.1 实时语音识别:让机器听懂你在说什么
实时语音识别,说白了就是把麦克风采集到的音频流,一边传一边转成文字。
在 WebRTC 里,音频流通常通过 MediaStream 获取。然后我们可以把它喂给语音识别引擎。
17.1.1 浏览器原生方案:Web Speech API
最简单的做法,是用浏览器自带的 SpeechRecognition API。它不需要额外引入 SDK,开箱即用。
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = 'zh-CN';
recognition.interimResults = true;
recognition.continuous = true;
recognition.onresult = (event) => {
for (let i = event.resultIndex; i < event.results.length; i++) {
const transcript = event.results[i][0].transcript;
console.log('识别结果:', transcript);
}
};
// 从 WebRTC 获取音频流
navigator.mediaDevices.getUserMedia({ audio: true })
.then((stream) => {
// 注意:SpeechRecognition 默认使用麦克风,不需要手动传 stream
recognition.start();
});
我在一个教育类项目里用过这个方案。当时学生端需要实时转写老师说的话。结果发现,如果网络延迟高,识别结果会滞后好几秒。嗯,这里要注意:实时性要求高的场景,建议用 WebSocket 对接专门的语音识别服务。
17.1.2 服务端方案:WebSocket + ASR
更靠谱的做法,是把音频流通过 WebSocket 发送到服务端,由 ASR(自动语音识别)引擎处理。
// 客户端:通过 WebRTC 获取音频,然后发送到服务端
const peerConnection = new RTCPeerConnection();
const audioTrack = localStream.getAudioTracks()[0];
peerConnection.addTrack(audioTrack, localStream);
// 同时,把音频数据通过 WebSocket 发送
const socket = new WebSocket('wss://your-asr-server.com/ws');
const mediaRecorder = new MediaRecorder(localStream, { mimeType: 'audio/webm' });
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
socket.send(event.data);
}
};
mediaRecorder.start(100); // 每 100ms 发送一次
AudioContext 在浏览器端先解码再编码。
17.2 人脸特效:给视频流加点「魔法」
人脸特效,比如加个兔子耳朵、戴个墨镜,本质上是对视频帧做实时图像处理。
在 WebRTC 里,我们需要拦截视频轨道,逐帧处理,再放回去。
17.2.1 核心流程:MediaStream -> Canvas -> 替换轨道
基本思路是这样的:
- 从
getUserMedia获取原始视频流 - 用
Canvas或WebGL逐帧绘制,叠加特效 - 把 Canvas 的流通过
captureStream()转换成新的 MediaStream - 用新流替换掉原始流
const video = document.createElement('video');
video.srcObject = localStream;
video.play();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
function processFrame() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// 在这里叠加特效,比如画个眼镜
drawGlasses(ctx);
requestAnimationFrame(processFrame);
}
processFrame();
const processedStream = canvas.captureStream(30);
// 替换掉原始视频轨道
const sender = peerConnection.getSenders().find(s => s.track.kind === 'video');
sender.replaceTrack(processedStream.getVideoTracks()[0]);
face-api.js 或 MediaPipe。我建议用 MediaPipe,它支持 WebGL 加速,性能更好。
17.2.2 避坑指南:性能与延迟
我曾经在一个直播项目里做美颜特效。一开始用纯 Canvas 逐帧处理,结果 CPU 直接拉满,帧率掉到 10fps 以下。
后来改用 WebGL 着色器,性能提升了好几倍。说白了,图像处理一定要走 GPU。
17.3 背景替换:从绿幕到 AI 抠图
背景替换,早期靠绿幕。现在靠 AI 语义分割。
最流行的方案是 MediaPipe Selfie Segmentation。它能在浏览器里实时分割出人像区域。
17.3.1 实现步骤
- 加载 MediaPipe 模型
- 对每一帧视频做分割,得到人像蒙版
- 用蒙版合成新背景
// 使用 @mediapipe/selfie_segmentation
const selfieSegmentation = new SelfieSegmentation({
locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`
});
selfieSegmentation.setOptions({
modelSelection: 1, // 0: 通用, 1: 景观(效果更好但更慢)
});
selfieSegmentation.onResults((results) => {
// results.segmentationMask 是蒙版
// 用蒙版合成背景
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(results.image, 0, 0);
ctx.globalCompositeOperation = 'destination-in';
ctx.drawImage(results.segmentationMask, 0, 0);
// 再绘制新背景
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(backgroundImage, 0, 0);
});
17.3.2 我踩过的坑
有一次,用户反馈背景替换后,边缘有「毛刺」。我排查了半天,发现是蒙版分辨率太低。
解决办法:把蒙版放大到和视频同尺寸,再做边缘羽化。嗯,这个细节很容易被忽略。
17.4 知识体系总览
下面这张图,概括了 WebRTC + AI 的核心逻辑。你可以把它当作一个参考框架。
17.5 总结与建议
WebRTC 和 AI 的结合,其实就三件事:拿流、处理、放回去。
但真正落地时,性能、延迟、兼容性,每一个都是硬骨头。
我个人建议,先从简单的特效开始,比如加个滤镜。等熟悉了 Canvas 和 MediaStream 的交互,再上人脸检测和背景替换。
如果你在项目中遇到问题,可以回头看看这一章的避坑指南。很多坑,我都替你踩过了。
公众号:蓝海资料掘金营,微信deep3321