1. WebRTC 全景概览:它到底是什么?

WebRTC,全称 Web Real-Time Communication。说白了,就是让浏览器之间能直接通话、传文件、共享屏幕的一套标准。不需要装插件,不需要第三方软件,打开网页就能用。

我记得 2017 年第一次接触这个技术时,心里还挺震撼的。以前做 VoIP 要用 SIP 协议栈、要处理 NAT 穿透、要自己写音视频编解码……WebRTC 把这些全封装好了。你调几个 API,就能跑起一个实时通话。

核心价值: 浏览器原生支持,无需安装,端到端延迟可控制在 200ms 以内。

1.1 为什么低延迟这么重要?

实时通话,延迟就是生命线。你想想看,两个人打电话,你说完一句话,对方 3 秒后才听到。这种体验,没人能接受。

我做过一个在线教育项目,客户反馈说“老师说话和学生听到之间总有半秒延迟”。半秒!在实时互动里已经非常明显了。后来排查发现是音频缓冲区设得太大,调整后延迟降到了 120ms,体验立刻不一样了。

业内公认的标准是这样的:

延迟范围 用户体验 适用场景
0 - 150ms 优秀,几乎无感知 实时通话、在线教学
150 - 300ms 可接受,略有延迟感 视频会议、远程协作
300 - 500ms 明显延迟,影响交流 直播互动(勉强可用)
500ms 以上 无法正常对话 不适合实时场景

WebRTC 的设计目标,就是把端到端延迟控制在 200ms 以内。为了实现这个目标,它用了 UDP 而不是 TCP,用了自适应抖动缓冲,用了 FEC(前向纠错)……这些后面章节会细讲。

1.2 三大核心 API,你必须掌握

WebRTC 的 API 其实不多,但每个都很关键。我按使用频率排个序:

1.2.1 getUserMedia — 获取音视频流

这是最基础的 API。你要通话,总得先拿到摄像头和麦克风的数据吧?

// 获取摄像头和麦克风
const stream = await navigator.mediaDevices.getUserMedia({
  video: true,
  audio: true
});

// 把视频流挂到页面上
const video = document.getElementById('localVideo');
video.srcObject = stream;

这里有个坑,我踩过好几次。getUserMedia 必须在 HTTPS 或 localhost 下才能调用。你如果在 HTTP 页面里调,浏览器直接拒绝。曾经有个同事调试了半天,最后发现是协议问题……

注意: getUserMedia 需要用户授权。如果用户拒绝,会抛出一个 NotAllowedError。一定要做好异常处理。

1.2.2 RTCPeerConnection — 建立点对点连接

这才是 WebRTC 的核心。它负责把两端的音视频流传过去,还要处理网络穿透、编解码协商、带宽自适应……

const pc = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' }
  ]
});

// 把本地流添加到连接
stream.getTracks().forEach(track => {
  pc.addTrack(track, stream);
});

// 监听远端流
pc.ontrack = (event) => {
  const remoteVideo = document.getElementById('remoteVideo');
  remoteVideo.srcObject = event.streams[0];
};

我个人习惯把 RTCPeerConnection 的配置单独抽出来,方便调试。特别是 ICE 服务器列表,生产环境至少配两个 STUN 和一个 TURN,不然 NAT 穿透会出问题。

1.2.3 RTCDataChannel — 传输任意数据

很多人以为 WebRTC 只能传音视频。其实它还能传任意二进制数据,比如文件、文本、游戏状态同步。

// 创建数据通道
const dc = pc.createDataChannel('chat', {
  ordered: false,      // 允许乱序到达
  maxRetransmits: 0    // 不重传
});

dc.onopen = () => {
  dc.send('Hello from peer!');
};

dc.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

这里有个技巧:如果你传的是实时游戏指令,把 ordered 设为 false,maxRetransmits 设为 0。这样延迟最低,丢包就丢包,不等待重传。如果是传文件,那就用 ordered: true,保证数据完整。

1.3 整体架构长什么样?

我把 WebRTC 的核心流程画了张图,你看一眼就明白了:

WebRTC 核心架构与通话流程 发送端 (Peer A) getUserMedia 编码 + 打包 ICE + DTLS 接收端 (Peer B) 渲染/播放 解码 + 抖动缓冲 ICE + DTLS 网络 (UDP / ICE / TURN) 信令通道 (WebSocket / HTTP) 信令通道只交换 SDP 和 ICE Candidate,不传音视频数据 音视频走 UDP 直连,延迟最低

流程其实不复杂:

  1. 获取媒体流 — 用 getUserMedia 拿到摄像头和麦克风数据
  2. 建立连接 — 通过信令通道交换 SDP 和 ICE Candidate
  3. 传输数据 — 音视频走 UDP,数据通道走 SCTP
  4. 接收渲染 — 远端流解码后挂到 video/audio 标签上
我的建议: 刚开始学 WebRTC,别急着看信令细节。先跑通一个最简单的点对点 demo,把 getusermedia 和 RTCPeerConnection 调通,你就有信心了。

1.4 本章小结

WebRTC 不是什么黑魔法。它就是一套标准化的实时通信 API。三个核心接口各司其职:getUserMedia 负责采集,RTCPeerConnection 负责传输,RTCDataChannel 负责数据。

低延迟是 WebRTC 的灵魂。200ms 以内是目标,超过 300ms 就要开始排查问题了。后面章节我会带你一步步定位延迟、回声、丢包这些实战问题。

嗯,第一章就到这里。记住这三个 API 的名字和用途,后面全是围绕它们展开的。