跳到主要内容

WebRTC:浏览器为什么能点对点音视频通话?ICE、STUN、TURN、SDP 分别是什么?

面试速答(30 秒版 TL;DR)

  • WebRTC 是浏览器端实时通信方案,核心能力是:音视频采集、点对点传输、数据通道
  • 真正负责连接的是 RTCPeerConnection;真正负责采集的是 getUserMedia;真正负责网络穿透的是 ICE + STUN + TURN;真正负责协商媒体参数的是 SDP offer/answer
  • 面试最核心的链路是:采集媒体 -> 建立 PeerConnection -> 交换 offer/answer -> 交换 ICE candidate -> 建链 -> 传输音视频/数据
  • WebRTC 不是“完全不需要服务器”,至少还需要 信令服务器 来交换协商信息。

心智模型:媒体传输是 P2P,但建链离不开信令

很多人对 WebRTC 的第一误解是:

  • “既然点对点,那就不需要服务端”

实际上服务端至少常承担两件事:

  • 信令(signaling):交换 offer、answer、ICE candidate
  • TURN 中继:P2P 打不通时兜底转发

所以更准确的说法是:

  • WebRTC 的媒体链路尽量 P2P
  • 但建链过程和兜底链路通常离不开服务器

一、最核心的几个对象

API作用
navigator.mediaDevices.getUserMedia()获取摄像头/麦克风媒体流
RTCPeerConnection建立点对点连接
RTCDataChannel建立数据通道
MediaStream / MediaStreamTrack承载音视频轨道

二、最小链路:先拿本地媒体

const localStream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
});

videoEl.srcObject = localStream;

这一步只解决:

  • 设备权限
  • 音视频采集

还没开始和对端通信。


三、RTCPeerConnection 做了什么

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

它负责:

  • 媒体协商
  • 网络候选收集
  • 建立安全传输通道
  • 发送/接收音视频与数据

把本地轨道加进去:

for (const track of localStream.getTracks()) {
pc.addTrack(track, localStream);
}

四、Offer / Answer 是什么

这是 WebRTC 高频核心题。

主叫方

const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// 通过信令服务器把 offer 发给对端

被叫方

await pc.setRemoteDescription(offer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
// 通过信令服务器把 answer 回给主叫方

主叫方收到 answer

await pc.setRemoteDescription(answer);

面试口径:

  • offer/answer 是协商双方能力和传输参数的描述文本
  • 这份描述通常使用 SDP 格式

五、SDP 是什么

SDP(Session Description Protocol)里通常描述:

  • 支持的音视频编码
  • 媒体轨道方向
  • 网络相关参数
  • 连接所需信息

你不需要背 SDP 文本格式,但要说清:

  • SDP 负责“谈判媒体会话长什么样”
  • 它不是“最终媒体数据本身”

六、ICE、STUN、TURN 各解决什么问题

ICE

  • 候选地址收集与连接尝试机制
  • 会尝试各种可能路径,看哪条能打通

STUN

  • 帮你知道“我在公网看来是谁”
  • 常用于 NAT 场景下发现自己的公网映射地址

TURN

  • 当双方直连打不通时,走中继服务器转发

一句话背诵:

  • STUN 用来找地址,TURN 用来做中继,ICE 用来组织候选和试连。

七、ICE candidate 怎么交换

本地收集候选:

pc.onicecandidate = (event) => {
if (event.candidate) {
signaling.send({ type: "candidate", candidate: event.candidate });
}
};

收到远端候选:

await pc.addIceCandidate(remoteCandidate);

这一步为什么必要:

  • 对端得知道有哪些网络路径可以试
  • 双方不断补充 candidate,直到连上或宣告失败

八、远端媒体怎么接收

pc.ontrack = (event) => {
remoteVideo.srcObject = event.streams[0];
};

也就是说:

  • 对方把轨道加进连接
  • 你这边通过 ontrack 收到远端媒体流

九、数据通道 RTCDataChannel

WebRTC 不只能传音视频,也能传业务数据。

const channel = pc.createDataChannel("chat");
channel.onmessage = (e) => {
console.log(e.data);
};
channel.send("hello");

适合:

  • 实时聊天
  • 白板坐标同步
  • 小文件/控制消息

十、为什么 WebRTC 适合低延迟实时场景

因为它的设计目标就是:

  • 低延迟
  • 实时互动
  • 浏览器原生支持媒体与网络协商

但也要知道边界:

  • 并不是所有网络环境都能稳定直连
  • 大规模多人房间往往会引入 SFU/MCU 架构,而不是纯网状 P2P

十一、多人通话为什么常用 SFU

如果 10 个人全做 Mesh 网状互连:

  • 每个人都要同时发给 9 个人
  • 上行带宽和浏览器负担都很重

所以工程上常用:

  • SFU(Selective Forwarding Unit):服务端转发媒体流,但不做重编码

面试答到这里通常已经足够加分。


典型题 & 标准答法

Q1:WebRTC 建链流程怎么说?

标准答法:

  1. getUserMedia 获取本地媒体
  2. 创建 RTCPeerConnection
  3. addTrack
  4. 创建 offer / answer 并通过信令服务器交换
  5. 交换 ICE candidate
  6. 建立连接并通过 ontrack 接收远端流

Q2:STUN 和 TURN 有什么区别?

  • STUN:帮助发现公网映射地址
  • TURN:直连失败时做中继

Q3:为什么说 WebRTC 不是完全“去服务器化”?

因为至少还需要信令服务器,而复杂网络环境下通常还需要 TURN,很多多人通话还会用 SFU。


易错点/坑

  • 以为 WebRTC 不需要服务端。
  • 把 SDP 当成媒体数据本身。
  • 忽略 NAT 穿透和 TURN 成本。
  • 认为多人通话直接 Mesh 就能扩展到大规模。

速记要点(可背诵)

  • 采集:getUserMedia
  • 建链:RTCPeerConnection
  • 协商:SDP offer/answer
  • 穿透:ICE + STUN + TURN
  • 多人场景常上 SFU