一、WebRTC 是什么
WebRTC,全称 Web Real-Time Communication,是浏览器提供的一套实时音视频和点对点数据通信能力。它允许网页在不安装插件的情况下,直接采集摄像头、麦克风、屏幕内容,并在浏览器、移动端、桌面端之间进行低延迟传输。
WebRTC 常见应用包括:
- 音视频通话
- 在线会议
- 直播连麦
- 屏幕共享
- 在线教育
- 远程面试
- 远程协助
- 浏览器 P2P 文件传输
- 低延迟互动游戏
- 实时白板和协同编辑
一句话概括:WebRTC 是浏览器原生的实时通信基础设施。
二、WebRTC 解决了什么问题
传统 Web 应用如果要做音视频通信,通常需要插件、客户端、Flash 或专门的原生应用。WebRTC 把实时通信能力下沉到了浏览器,让网页可以直接完成音视频采集、编码、传输、解码和播放。
它主要解决以下问题。
1. 浏览器直接采集媒体
通过 getUserMedia,网页可以在用户授权后访问摄像头和麦克风。
2. 低延迟实时传输
WebRTC 基于 UDP、RTP、SRTP、DTLS、ICE 等技术,目标是降低端到端延迟。
3. 点对点通信
在网络允许的情况下,两个浏览器可以直接建立 P2P 连接,不必让所有音视频流都经过业务服务器。
4. NAT 穿透
现实网络中,大多数设备都在路由器、防火墙或 NAT 后面。WebRTC 通过 ICE、STUN、TURN 尝试建立可用连接。
5. 安全传输
WebRTC 默认要求加密传输,媒体流通常通过 SRTP 保护,数据通道通过 DTLS 保护。
三、WebRTC 的核心 API
WebRTC 前端开发主要围绕几个核心 API 展开。
| API | 作用 |
|---|---|
navigator.mediaDevices.getUserMedia |
获取摄像头和麦克风 |
navigator.mediaDevices.getDisplayMedia |
获取屏幕共享流 |
RTCPeerConnection |
建立点对点连接,传输音视频 |
RTCDataChannel |
点对点传输任意数据 |
MediaStream |
表示媒体流,由多个 Track 组成 |
MediaStreamTrack |
表示单条音频轨或视频轨 |
RTCSessionDescription |
表示 SDP offer 或 answer |
RTCIceCandidate |
表示 ICE 候选连接地址 |
四、WebRTC 的整体架构
WebRTC 并不是只有浏览器之间的直接连接。一个完整系统通常还需要业务服务器和信令服务器。
典型架构包括:
- 前端页面:采集、播放、协商、连接管理。
- 信令服务器:交换 offer、answer、ICE candidate 等协商信息。
- STUN 服务器:帮助发现公网地址。
- TURN 服务器:P2P 不通时转发媒体流。
- 业务服务器:房间、用户、权限、录制、计费、日志等业务能力。
需要注意:信令服务器不属于 WebRTC 标准的一部分,WebRTC 只规定浏览器实时通信能力,如何交换协商消息由业务自行实现。常见信令通道可以是 WebSocket、Socket.IO、HTTP 轮询、MQTT 等。
五、媒体采集:getUserMedia
1. 获取摄像头和麦克风
js
async function startLocalMedia() {
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true
});
const video = document.querySelector('#localVideo');
video.srcObject = stream;
}
浏览器会弹出权限确认。只有用户授权后,页面才能获得媒体流。
2. 指定采集约束
js
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
},
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 30 },
facingMode: 'user'
}
});
常见视频约束包括分辨率、帧率、前后摄像头等。常见音频约束包括回声消除、降噪、自动增益。
3. 获取设备列表
js
const devices = await navigator.mediaDevices.enumerateDevices();
const cameras = devices.filter(device => device.kind === 'videoinput');
const microphones = devices.filter(device => device.kind === 'audioinput');
用户授权前,浏览器可能隐藏设备名称。
4. 切换摄像头
js
async function switchCamera(deviceId) {
return navigator.mediaDevices.getUserMedia({
audio: true,
video: { deviceId: { exact: deviceId } }
});
}
切换后需要替换本地预览和 PeerConnection 中发送的视频轨。
六、屏幕共享:getDisplayMedia
屏幕共享使用 getDisplayMedia。
js
async function startScreenShare() {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
});
document.querySelector('#screenVideo').srcObject = stream;
}
常见用途:
- 在线会议共享桌面。
- 在线教育共享课件。
- 远程协助查看用户屏幕。
- 产品演示和直播推流。
监听用户停止共享:
js
const [track] = stream.getVideoTracks();
track.addEventListener('ended', () => {
console.log('用户停止了屏幕共享');
});
七、RTCPeerConnection 是什么
RTCPeerConnection 是 WebRTC 的核心对象,负责:
- 管理媒体轨道。
- 生成 SDP offer 和 answer。
- 收集 ICE candidate。
- 建立 P2P 或中继连接。
- 发送和接收音视频流。
- 统计连接质量。
- 管理 DataChannel。
创建连接:
js
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{
urls: 'turn:turn.example.com:3478',
username: 'user',
credential: 'password'
}
]
});
iceServers 用于配置 STUN 和 TURN 服务器,帮助双方找到可用连接路径。
八、WebRTC 建连核心流程
WebRTC 建连可以理解为:采集媒体、创建连接、交换 SDP、交换 ICE、建立媒体通道。
1. 发起方创建 Offer
js
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
signaling.send({
type: 'offer',
sdp: offer
});
2. 接收方处理 Offer 并创建 Answer
js
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
signaling.send({
type: 'answer',
sdp: answer
});
3. 发起方处理 Answer
js
await peerConnection.setRemoteDescription(answer);
4. 双方交换 ICE Candidate
js
peerConnection.onicecandidate = event => {
if (event.candidate) {
signaling.send({
type: 'candidate',
candidate: event.candidate
});
}
};
收到远端 candidate:
js
await peerConnection.addIceCandidate(candidate);
九、什么是 SDP
SDP,全称 Session Description Protocol,用来描述媒体会话能力。WebRTC 中的 offer 和 answer 本质上都是 SDP。
SDP 会描述:
- 支持的音视频编码格式。
- 媒体方向,例如 sendrecv、sendonly、recvonly。
- 音频和视频轨信息。
- 网络传输参数。
- DTLS 指纹。
- ICE 用户名片段和密码。
- 带宽、扩展头、编解码参数等。
示意:
txt
v=0
o=- 46117326 2 IN IP4 127.0.0.1
s=-
t=0 0
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=rtpmap:111 opus/48000/2
m=video 9 UDP/TLS/RTP/SAVPF 96
a=rtpmap:96 VP8/90000
前端通常不需要手写 SDP,但需要理解它是双方协商媒体能力的载体。
十、什么是 ICE、STUN、TURN
现实网络中,两个浏览器通常都在 NAT 或防火墙后面,不能简单地直接连接。ICE、STUN、TURN 就是为了解决连接路径问题。
1. ICE
ICE,全称 Interactive Connectivity Establishment,是一套连接候选路径收集、交换、检测和选择机制。
ICE 会尝试多种候选地址:
- Host Candidate:本机局域网地址。
- Server Reflexive Candidate:通过 STUN 发现的公网映射地址。
- Relay Candidate:通过 TURN 中继服务器转发的地址。
2. STUN
STUN 用于帮助客户端发现自己在公网侧看到的地址和端口。
它不转发媒体,只帮助发现地址。
3. TURN
TURN 是中继服务器。当 P2P 连接无法建立时,音视频流会通过 TURN 转发。
TURN 成本更高,因为它要承载真实媒体流量。
十一、媒体轨道与流
WebRTC 中常见两个概念:
MediaStream:媒体流容器,可以包含多个轨道。MediaStreamTrack:具体的一条音频轨或视频轨。
js
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
const audioTracks = stream.getAudioTracks();
const videoTracks = stream.getVideoTracks();
把本地轨道添加到连接:
js
stream.getTracks().forEach(track => {
peerConnection.addTrack(track, stream);
});
接收远端媒体:
js
peerConnection.ontrack = event => {
const [remoteStream] = event.streams;
remoteVideo.srcObject = remoteStream;
};
十二、静音、关闭摄像头和停止采集
1. 静音
js
const [audioTrack] = localStream.getAudioTracks();
audioTrack.enabled = false;
enabled = false 表示仍保留轨道,但发送静音数据。
2. 关闭摄像头
js
const [videoTrack] = localStream.getVideoTracks();
videoTrack.enabled = false;
远端通常会看到黑屏或冻结画面,具体取决于浏览器和播放处理。
3. 停止采集
js
localStream.getTracks().forEach(track => track.stop());
stop() 会真正停止设备采集。如果之后要恢复,需要重新调用 getUserMedia。
十三、替换媒体轨道
视频通话中经常需要切换摄像头、切换屏幕共享、恢复摄像头。推荐使用 RTCRtpSender.replaceTrack()。
js
async function replaceVideoTrack(peerConnection, newTrack) {
const sender = peerConnection
.getSenders()
.find(item => item.track && item.track.kind === 'video');
if (sender) {
await sender.replaceTrack(newTrack);
}
}
使用 replaceTrack 通常不需要重新协商,体验更平滑。
十四、RTCDataChannel
除了音视频,WebRTC 还支持点对点数据通道 RTCDataChannel。它可以传输文本、二进制、文件分片、游戏状态、白板操作等数据。
创建 DataChannel:
js
const channel = peerConnection.createDataChannel('chat');
channel.onopen = () => {
channel.send('hello');
};
channel.onmessage = event => {
console.log('收到消息', event.data);
};
接收远端 DataChannel:
js
peerConnection.ondatachannel = event => {
const channel = event.channel;
channel.onmessage = messageEvent => {
console.log(messageEvent.data);
};
};
DataChannel 适合:
- P2P 聊天。
- 文件传输。
- 游戏状态同步。
- 实时白板操作。
- 协同编辑操作广播。
- 远程控制指令。
十五、信令服务器的作用
WebRTC 浏览器之间要通信,首先需要交换协商信息。但两个浏览器在连接建立前无法直接通信,所以需要信令服务器。
信令服务器负责交换:
- 房间加入和离开消息。
- 用户在线状态。
- SDP offer。
- SDP answer。
- ICE candidate。
- 通话控制消息,例如邀请、拒绝、挂断。
- 业务消息,例如角色、权限、会议状态。
信令服务器不一定传输音视频流。大多数一对一 WebRTC 场景中,音视频流建立后可以走 P2P 或 TURN。
十六、一对一通话完整示例
下面是一个简化的一对一流程,省略了信令实现细节。
js
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
const localStream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true
});
localVideo.srcObject = localStream;
localStream.getTracks().forEach(track => {
pc.addTrack(track, localStream);
});
pc.ontrack = event => {
remoteVideo.srcObject = event.streams[0];
};
pc.onicecandidate = event => {
if (event.candidate) {
signaling.send({ type: 'candidate', candidate: event.candidate });
}
};
发起方:
js
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
signaling.send({ type: 'offer', sdp: offer });
接收方:
js
await pc.setRemoteDescription(remoteOffer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
signaling.send({ type: 'answer', sdp: answer });
发起方收到 answer:
js
await pc.setRemoteDescription(remoteAnswer);
双方收到 candidate:
js
await pc.addIceCandidate(remoteCandidate);
十七、多人通话架构
一对一通话可以 P2P,但多人会议要复杂得多。常见架构有 Mesh、SFU、MCU。
1. Mesh 架构
每个用户都和其他所有用户建立 P2P 连接。
优点:实现相对简单,不需要媒体服务器转发。
缺点:人数增加后连接数和上行带宽爆炸。
2. SFU 架构
SFU,全称 Selective Forwarding Unit。每个用户把媒体流上传到 SFU,SFU 选择性转发给其他用户。
优点:适合多人会议,延迟较低,客户端压力可控。
缺点:需要部署媒体服务器。
3. MCU 架构
MCU,全称 Multipoint Control Unit。服务器接收所有媒体流,进行混流、转码,再输出合成后的流。
优点:客户端压力小,兼容传统会议系统。
缺点:服务器成本高,延迟更高,扩展压力大。
十八、WebRTC 与直播、连麦
WebRTC 适合低延迟互动直播和连麦,但传统大规模直播通常使用 HLS、FLV、DASH、RTMP 等链路。
常见组合:
- 主播到服务器使用 WebRTC 推流。
- 连麦用户使用 WebRTC 互动。
- 观众大规模观看使用 HLS、FLV 或低延迟 HLS。
- 服务器把 WebRTC 流转封装为直播流。
如果追求超低延迟互动,WebRTC 更合适。如果追求百万级分发,CDN 直播协议更成熟。
十九、WebRTC 质量控制
实时音视频不是只要连上就行,还要关注质量。
常见指标:
- RTT:往返延迟。
- Jitter:抖动。
- Packet Loss:丢包率。
- Bitrate:码率。
- Frame Rate:帧率。
- Resolution:分辨率。
- Freeze Count:卡顿次数。
- Audio Level:音量。
- CPU 使用率。
获取统计信息:
js
const stats = await peerConnection.getStats();
stats.forEach(report => {
if (report.type === 'outbound-rtp' && report.kind === 'video') {
console.log(report.bytesSent, report.framesEncoded);
}
});
根据质量动态调整:
- 网络差时降低分辨率。
- 网络差时降低码率。
- 丢包严重时关闭视频保音频。
- 弱设备降低帧率。
- 大房间中只订阅活跃说话人视频。
二十、常见错误和状态
RTCPeerConnection 有多个状态可以监听。
js
pc.onconnectionstatechange = () => {
console.log('connectionState', pc.connectionState);
};
pc.oniceconnectionstatechange = () => {
console.log('iceConnectionState', pc.iceConnectionState);
};
pc.onsignalingstatechange = () => {
console.log('signalingState', pc.signalingState);
};
常见状态含义:
| 状态 | 说明 |
|---|---|
new |
刚创建,还未连接 |
connecting |
正在建立连接 |
connected |
已连接 |
disconnected |
连接暂时断开,可能恢复 |
failed |
连接失败,需要重连或重建 |
closed |
连接已关闭 |
常见问题:
- 用户拒绝摄像头权限。
- 设备被其他应用占用。
- HTTPS 环境不满足。
- STUN 或 TURN 配置错误。
- 信令消息顺序错误。
- Candidate 在 remoteDescription 设置前被添加。
- NAT 严格导致必须走 TURN。
- 移动端切后台导致连接中断。
二十一、重连与异常恢复
WebRTC 通话中断时,不能只依赖浏览器自动恢复。业务层通常需要设计重连机制。
基本策略:
- 监听连接状态。
- 短暂
disconnected可以等待自动恢复。 failed后尝试 ICE restart。- ICE restart 失败后重建 PeerConnection。
- 信令断开后重连 WebSocket。
- 重连期间保持 UI 状态提示。
ICE restart 示例:
js
const offer = await pc.createOffer({ iceRestart: true });
await pc.setLocalDescription(offer);
signaling.send({ type: 'offer', sdp: offer });
二十二、安全与隐私
WebRTC 直接涉及摄像头、麦克风、屏幕和网络地址,安全与隐私非常重要。
1. 必须用户授权
摄像头、麦克风、屏幕共享必须经过用户授权,页面不能静默开启。
2. 推荐 HTTPS
getUserMedia 通常要求安全上下文,线上环境必须使用 HTTPS。
3. 防止误共享屏幕
屏幕共享 UI 要明确提示当前正在共享,并提供停止入口。
4. TURN 凭证要临时化
TURN 服务器成本高,凭证泄露可能被滥用。建议使用短期动态凭证。
5. 不要泄露敏感信令
SDP 和 ICE 信息不应随意写入公开日志,尤其要注意内网地址、设备信息、用户标识。
6. 权限和房间校验放在服务端
进入房间、发起通话、发布媒体、订阅媒体等权限不能只靠前端控制。
二十三、前端工程实践
1. 封装连接管理类
复杂项目不建议把 WebRTC 逻辑散落在组件中。可以封装为连接管理模块:
- 创建和销毁 PeerConnection。
- 管理本地流。
- 管理远端流。
- 处理信令消息。
- 管理连接状态。
- 处理重连和错误。
- 暴露事件给 UI 层。
2. 明确信令协议
建议定义清晰的信令消息类型:
ts
type SignalingMessage =
| { type: 'join'; roomId: string; userId: string }
| { type: 'offer'; from: string; to: string; sdp: RTCSessionDescriptionInit }
| { type: 'answer'; from: string; to: string; sdp: RTCSessionDescriptionInit }
| { type: 'candidate'; from: string; to: string; candidate: RTCIceCandidateInit }
| { type: 'leave'; roomId: string; userId: string };
3. 处理 Candidate 缓存
有时 candidate 先于 remoteDescription 到达,直接添加会报错。可以先缓存,等设置远端描述后再批量添加。
js
const pendingCandidates = [];
async function handleCandidate(candidate) {
if (pc.remoteDescription) {
await pc.addIceCandidate(candidate);
} else {
pendingCandidates.push(candidate);
}
}
async function flushCandidates() {
while (pendingCandidates.length > 0) {
await pc.addIceCandidate(pendingCandidates.shift());
}
}
4. 页面生命周期处理
需要处理:
- 页面刷新。
- 组件卸载。
- 用户离开房间。
- 浏览器切后台。
- 移动端锁屏。
- 网络从 Wi-Fi 切到蜂窝。
离开时应关闭连接和采集:
js
function cleanup() {
localStream?.getTracks().forEach(track => track.stop());
pc?.getSenders().forEach(sender => sender.track?.stop());
pc?.close();
}
二十四、WebRTC 应用场景详解
1. 在线会议
核心能力:多人音视频、屏幕共享、静音、摄像头开关、成员列表、活跃说话人、网络质量提示、录制。
推荐架构:多人会议通常使用 SFU。
2. 在线教育
核心能力:老师推流、学生连麦、课件共享、白板互动、举手、录制回放。
常见组合:WebRTC 负责低延迟互动,普通直播协议负责大规模旁路观看。
3. 远程面试
核心能力:一对一音视频、屏幕共享、代码编辑器协同、录制、设备检测。
重点关注稳定性、权限提示和异常恢复。
4. 远程协助
核心能力:屏幕共享、鼠标轨迹、键盘指令、文件传输、权限确认。
可结合 DataChannel 传输控制指令。
5. P2P 文件传输
核心能力:DataChannel、文件切片、进度展示、断点续传、哈希校验。
适合小规模点对点文件发送,不适合完全替代大文件分发系统。
6. 实时协同白板
核心能力:DataChannel 或信令通道传输绘图操作、WebRTC 音视频同步沟通、服务端持久化白板数据。
二十五、WebRTC 与 WebSocket 的区别
WebRTC 和 WebSocket 经常一起出现,但它们不是替代关系。
| 对比项 | WebRTC | WebSocket |
|---|---|---|
| 通信模式 | 可 P2P,也可经 TURN 或媒体服务器 | 客户端到服务器 |
| 主要用途 | 实时音视频、P2P 数据 | 信令、聊天、业务消息 |
| 传输内容 | 音视频、二进制、文本 | 文本、二进制 |
| 延迟 | 音视频场景低延迟优化 | 取决于服务器链路 |
| NAT 穿透 | 内置 ICE 机制 | 不需要 P2P 穿透 |
| 复杂度 | 较高 | 较低 |
典型搭配:WebSocket 做信令,WebRTC 做媒体和 P2P 数据传输。
二十六、WebRTC 与 WebTransport、HLS 的区别
1. WebRTC 与 HLS
HLS 适合大规模直播分发,但延迟通常较高。WebRTC 适合低延迟互动,但大规模分发成本更高。
2. WebRTC 与 WebTransport
WebTransport 提供基于 HTTP/3 的低延迟双向传输能力,但它不直接提供摄像头采集、音视频编解码、回声消除、抖动缓冲等实时音视频完整能力。
3. 如何选择
- 一对一音视频:WebRTC。
- 多人互动会议:WebRTC 加 SFU。
- 大规模直播观看:HLS、DASH、FLV 或低延迟直播方案。
- 低延迟自定义数据传输:可评估 WebTransport。
- 浏览器 P2P 文件传输:WebRTC DataChannel。
二十七、调试 WebRTC
1. 浏览器内部页面
Chrome 可以使用:
txt
chrome://webrtc-internals
可以查看 SDP、ICE 状态、码率、丢包、延迟、轨道信息等。
2. 控制台日志
建议记录:
- 信令消息收发。
signalingState。iceConnectionState。connectionState。iceGatheringState。- 本地和远端 SDP。
- Candidate 类型。
- getStats 关键指标。
3. 排查流程
二十八、常见面试题
1. WebRTC 是否不需要服务器
不是。WebRTC 的媒体流在理想情况下可以 P2P,但仍然需要信令服务器交换协商信息;复杂网络下还需要 TURN 服务器;多人会议通常还需要 SFU 或 MCU。
2. STUN 和 TURN 有什么区别
STUN 只帮助发现公网映射地址,不转发媒体。TURN 在无法 P2P 时负责中继媒体流,成本更高。
3. Offer 和 Answer 是什么
Offer 和 Answer 是双方基于 SDP 的媒体能力协商。Offer 表示发起方的能力和意图,Answer 表示接收方接受后的协商结果。
4. 为什么有时本地测试能通,线上用户不通
本地网络可能 NAT 简单,线上用户可能处于公司防火墙、对称 NAT、弱网或运营商复杂网络下。缺少可用 TURN 是常见原因。
5. WebRTC 能不能做万人直播
单纯浏览器 P2P 不适合万人直播。大规模直播通常需要媒体服务器、转码、CDN 分发。WebRTC 可以用于主播推流和低延迟连麦。
6. DataChannel 和 WebSocket 怎么选
如果需要客户端和服务器稳定通信,选 WebSocket。如果需要浏览器之间 P2P 传输数据,选 WebRTC DataChannel。实际 WebRTC 项目中常用 WebSocket 做信令,DataChannel 做点对点业务数据。
二十九、最佳实践清单
1. 媒体采集
- 采集前做设备检测。
- 用户授权失败要给出明确提示。
- 移动端注意前后摄像头切换。
- 停止通话时释放摄像头和麦克风。
2. 信令设计
- 消息类型清晰。
- 带上房间 ID、用户 ID、目标用户 ID。
- 处理乱序、重复和延迟消息。
- Candidate 到达过早时先缓存。
3. 网络穿透
- 线上必须配置可靠 TURN。
- TURN 凭证使用短期动态凭证。
- 监控 TURN 使用比例和流量成本。
4. 连接稳定性
- 监听连接状态。
- 支持 ICE restart。
- 支持重建 PeerConnection。
- 信令断开要自动重连。
- UI 上提示重连状态。
5. 音视频质量
- 使用
getStats采集质量指标。 - 网络差时动态降级。
- 多人会议使用 SFU。
- 大房间避免订阅所有高清视频。
6. 安全隐私
- 全站 HTTPS。
- 房间权限放在服务端校验。
- 屏幕共享提供明显状态提示。
- 不在公开日志中记录敏感 SDP 和 ICE 信息。
三十、总结
WebRTC 是现代前端实时通信的重要基础能力。它让浏览器可以直接完成音视频采集、实时传输、P2P 数据通信和屏幕共享。
理解 WebRTC 可以抓住五条主线:
- 媒体采集:
getUserMedia和getDisplayMedia。 - 协商建连:
RTCPeerConnection、Offer、Answer、SDP。 - 网络穿透:ICE、STUN、TURN、Candidate。
- 媒体传输:Track、Stream、RTP、SRTP。
- 工程应用:信令、重连、质量监控、多人架构、安全隐私。
如果只做一对一通话,核心是 PeerConnection 加信令交换。如果做多人会议,重点会转向 SFU、订阅策略和质量控制。如果做直播连麦,重点是 WebRTC 与媒体服务器、CDN、转码链路的协作。
WebRTC 的复杂点不在 API 数量,而在网络环境、媒体质量、状态同步和异常恢复。真正稳定的 WebRTC 应用,需要把前端 API、信令服务、媒体服务器、网络穿透和监控体系一起设计。