跳到主要内容WebRTC 架构全景解析:从浏览器 API 到 libwebrtc | 极客日志JavaScriptNode.js大前端算法
WebRTC 架构全景解析:从浏览器 API 到 libwebrtc
WebRTC 架构涉及浏览器 API 层与底层引擎 libwebrtc。通过 getUserMedia 获取媒体流,RTCPeerConnection 管理 P2P 连接,信令流程负责 SDP 与 ICE 协商。底层包含音频视频处理模块及拥塞控制算法。理解此架构有助于优化实时通信性能与稳定性。
云间漫步15 浏览 WebRTC 在浏览器中的架构
整体架构图
┌─────────────────────────────────────────────────────────────────────────┐
│ Web Application │
│ (JavaScript / HTML) │
└─────────────────────────────────────────────────────────────────────────┘
│ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ WebRTC JavaScript API │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ getUserMedia() │ │RTCPeerConnection│ │ RTCDataChannel │ │
│ │ getDisplayMedia │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ WebRTC Native C++ API │
│ (libwebrtc / webrtc.org) │
├─────────────────────────────────────────────────────────────────────────┤
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Session Management │
│ │ (Offe/Answer, ICE, SRTP Key Exchange) │
│ └───────────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Voice Engine │ Video Engine │
│ │ ┌─────────────────┐ │ │ ┌─────────────────────┐ │
│ │ │ Audio Codecs │ │ │ Video Codecs │ │
│ │ │ (Opus, G.711) │ │ │ (VP8, VP9, H.264) │ │
│ │ ├─────────────────┤ │ ├─────────────────────┤ │
│ │ │ Echo Cancel │ │ │ Video Processing │ │
│ │ │ Noise Suppress │ │ │ (Scaling, FEC) │ │
│ │ ├─────────────────┤ │ ├─────────────────────┤ │
│ │ │ Jitter Buffer │ │ │ Jitter Buffer │ │
│ │ └─────────────────┘ │ └─────────────────────┘ │
│ └─────────────────────────┘ └─────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Transport Layer │
│ │ (ICE / STUN / TURN / DTLS / SRTP / SCTP) │
│ └───────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Operating System │
│ (Audio/Video Capture, Network Socket, etc.) │
└─────────────────────────────────────────────────────────────────────────┘
架构层次说明
第一层:Web 应用层
开发者编写的 JavaScript 代码,通过 WebRTC API 实现实时通信功能。
const pc = (config);
stream = navigator..({: });
stream.().( pc.(track, stream));
new
RTCPeerConnection
const
await
mediaDevices
getUserMedia
video
true
getTracks
forEach
track =>
addTrack
第二层:WebRTC JavaScript API
浏览器暴露给 JavaScript 的标准 API,由 W3C 定义:
| API | 职责 |
|---|
navigator.mediaDevices.getUserMedia() | 获取摄像头/麦克风 |
navigator.mediaDevices.getDisplayMedia() | 获取屏幕共享 |
RTCPeerConnection | 建立和管理 P2P 连接 |
RTCDataChannel | 传输任意数据 |
MediaStream / MediaStreamTrack | 管理媒体流和轨道 |
第三层:WebRTC Native C++ API
这是 libwebrtc 提供的 C++ 接口层,主要包含:
- PeerConnectionFactory:创建 PeerConnection 的工厂类
- PeerConnection:核心连接管理类
- MediaStreamInterface:媒体流接口
- DataChannelInterface:数据通道接口
第四层:核心引擎层
- Session Management:会话管理(SDP 协商、ICE 候选收集与交换、DTLS 密钥交换)
- Voice Engine:音频引擎(音频编解码、回声消除、噪声抑制、自动增益控制、抖动缓冲)
- Video Engine:视频引擎(视频编解码、视频处理、前向纠错、抖动缓冲)
第五层:传输层
┌─────────────────────────────────────────┐
│ Application │
├─────────────────────────────────────────┤
│ SRTP (媒体) │ SCTP (数据) │
├─────────────────────────────────────────┤
│ DTLS (加密) │
├─────────────────────────────────────────┤
│ ICE (NAT 穿透) │
├─────────────────────────────────────────┤
│ STUN / TURN (服务器) │
├─────────────────────────────────────────┤
│ UDP / TCP │
└─────────────────────────────────────────┘
浏览器实现差异
| 浏览器 | 底层实现 | 特点 |
|---|
| Chrome | libwebrtc | 最完整、更新最快 |
| Firefox | 自研 + libwebrtc 部分 | 独立实现,兼容性好 |
| Safari | 基于 libwebrtc | 更新较慢,部分功能缺失 |
| Edge | Chromium 内核 | 与 Chrome 一致 |
API 体系详解
getUserMedia / getDisplayMedia
getUserMedia - 获取摄像头和麦克风
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 },
frameRate: { ideal: 30, max: 60 },
facingMode: 'user',
deviceId: { exact: 'specific-camera-id' }
},
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
sampleRate: 48000,
channelCount: 2
}
});
getDisplayMedia - 屏幕共享
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: {
cursor: 'always',
displaySurface: 'monitor'
},
audio: true
});
枚举设备
const devices = await navigator.mediaDevices.enumerateDevices();
devices.forEach(device => {
console.log(`${device.kind}: ${device.label} (${device.deviceId})`);
});
RTCPeerConnection
RTCPeerConnection 是 WebRTC 的核心 API,负责建立和管理 P2P 连接。
构造函数与配置
const configuration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'turn:turn.example.com:3478', username: 'user', credential: 'password' }
],
iceTransportPolicy: 'all',
bundlePolicy: 'max-bundle',
rtcpMuxPolicy: 'require',
certificates: [certificate]
};
const pc = new RTCPeerConnection(configuration);
核心方法
const offer = await pc.createOffer({
offerToReceiveAudio: true,
offerToReceiveVideo: true,
iceRestart: false
});
const answer = await pc.createAnswer();
await pc.setLocalDescription(offer);
await pc.setRemoteDescription(remoteAnswer);
await pc.addIceCandidate(candidate);
const sender = pc.addTrack(track, stream);
pc.removeTrack(sender);
const senders = pc.getSenders();
const receivers = pc.getReceivers();
const transceivers = pc.getTransceivers();
const transceiver = pc.addTransceiver('video', { direction: 'sendrecv' });
const dataChannel = pc.createDataChannel('myChannel', { ordered: true, maxRetransmits: 3 });
pc.close();
const stats = await pc.getStats();
核心事件
pc.onicecandidate = (event) => {
if (event.candidate) {
sendToRemote({ type: 'candidate', candidate: event.candidate });
}
};
pc.oniceconnectionstatechange = () => {
console.log('ICE state:', pc.iceConnectionState);
};
pc.onconnectionstatechange = () => {
console.log('Connection state:', pc.connectionState);
};
pc.onsignalingstatechange = () => {
console.log('Signaling state:', pc.signalingState);
};
pc.ontrack = (event) => {
const [remoteStream] = event.streams;
remoteVideo.srcObject = remoteStream;
};
pc.ondatachannel = (event) => {
const dataChannel = event.channel;
dataChannel.onmessage = (e) => console.log(e.data);
};
pc.onnegotiationneeded = async () => {
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
sendToRemote({ type: 'offer', sdp: offer.sdp });
};
RTCDataChannel
DataChannel 提供了在 P2P 连接上传输任意数据的能力。
const dataChannel = pc.createDataChannel('chat', {
ordered: true,
maxRetransmits: 3,
protocol: 'json',
negotiated: false,
id: 0
});
dataChannel.onopen = () => {
console.log('Data channel opened');
dataChannel.send('Hello!');
};
dataChannel.onclose = () => {
console.log('Data channel closed');
};
dataChannel.onmessage = (event) => {
console.log('Received:', event.data);
};
dataChannel.onerror = (error) => {
console.error('Data channel error:', error);
};
dataChannel.send('text message');
dataChannel.send(new ArrayBuffer(1024));
dataChannel.send(new Blob(['binary data']));
if (dataChannel.bufferedAmount < dataChannel.bufferedAmountLowThreshold) {
dataChannel.send(moreData);
}
pc.ondatachannel = (event) => {
const receiveChannel = event.channel;
receiveChannel.onmessage = (e) => {
console.log('Received:', e.data);
};
};
WebRTC 信令流程概览
什么是信令?
信令(Signaling) 是 WebRTC 建立连接前的协商过程,用于交换:
- 会话描述(SDP):媒体能力、编解码器、传输参数
- 网络候选(ICE Candidates):可用的网络路径
⚠️ WebRTC 标准不定义信令协议,开发者需要自行实现。
常见信令方案
| 方案 | 优点 | 缺点 |
|---|
| WebSocket | 实时、双向 | 需要维护长连接 |
| HTTP 轮询 | 简单 | 延迟高、效率低 |
| Socket.IO | 易用、自动重连 | 额外依赖 |
| Firebase | 无需服务器 | 依赖第三方 |
| MQTT | 适合 IoT | 复杂度较高 |
完整信令流程
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Caller │ │ Signaling │ │ Callee │
│ (发起方) │ │ Server │ │ (接收方) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
│ 1. 获取本地媒体流 │ │ │
│ getUserMedia() │ │ │
│ │ │ │
│ 2. 创建 PeerConnection │ │ │
│ new RTCPeerConnection │ │ │
│ │ │ │
│ 3. 添加本地轨道 │ │ │
│ addTrack() │ │ │
│ │ │ │
│ 4. 创建 Offer │ │ │
│ createOffer() │ │ │
│ │ │ │
│ 5. 设置本地描述 │ │ │
│ setLocalDescription() │ │ │
│ │ │ │
│ 6. 发送 Offer ─────────>│ │ │
│ 7. 转发 Offer ─────────>│ │ │
│ │ │ │
│ 8. 获取本地媒体流 │ getUserMedia() │ │
│ 9. 创建 PeerConnection │ new RTCPeerConnection │ │
│ │ │ │
│ 10. 设置远端描述 │ setRemoteDescription() │ │
│ │ │ │
│ 11. 添加本地轨道 │ addTrack() │ │
│ │ │ │
│ 12. 创建 Answer │ createAnswer() │ │
│ │ │ │
│ 13. 设置本地描述 │ setLocalDescription() │ │
│ │ │ │
│<───────── 14. 发送 Answer │<───────── 15. 转发 Answer│ │
│ │ │ │
│ ═══════════ 17. ICE 候选交换 (双向) ═══════════ │
│ onicecandidate ──────>│<─────── onicecandidate │
│<────── addIceCandidate │ addIceCandidate ──────>│
│ │ │ │
│ ═══════════════ 18. P2P 连接建立 ═══════════════│
│<═══════════════════════════════════════════════>│
│ │ │ │
│ ═══════════════ 19. 媒体流传输 ═════════════════│
│<═══════════════════════════════════════════════>│
│ │ │
SDP 详解
SDP(Session Description Protocol)描述了会话的媒体能力。
SDP 示例
v=0 o=- 4611731400430051336 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE 0 1 a=extmap-allow-mixed a=msid-semantic: WMS stream_id m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:abcd a=ice-pwd:efghijklmnopqrstuvwxyz a=ice-options:trickle a=fingerprint:sha-256 AA:BB:CC:DD:... a=setup:actpass a=mid:0 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=sendrecv a=rtcp-mux a=rtpmap:111 opus/48000/2 a=fmtp:111 minptime=10;useinbandfec=1 ... m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:abcd a=ice-pwd:efghijklmnopqrstuvwxyz a=fingerprint:sha-256 AA:BB:CC:DD:... a=setup:actpass a=mid:1 a=sendrecv a=rtcp-mux a=rtcp-rsize a=rtpmap:96 VP8/90000 a=rtpmap:97 rtx/90000 a=fmtp:97 apt=96 a=rtpmap:98 VP9/90000 ...
SDP 关键字段
| 字段 | 含义 |
|---|
v= | 协议版本 |
o= | 会话发起者信息 |
s= | 会话名称 |
t= | 会话时间 |
m= | 媒体描述(audio/video) |
a=rtpmap: | RTP 负载类型映射 |
a=fmtp: | 格式参数 |
a=ice-ufrag: | ICE 用户名片段 |
a=ice-pwd: | ICE 密码 |
a=fingerprint: | DTLS 证书指纹 |
a=candidate: | ICE 候选 |
ICE 候选类型
{
candidate: "candidate:842163049 1 udp 1677729535 192.168.1.100 54321 typ srflx raddr 10.0.0.1 rport 12345 generation 0",
sdpMid: "0",
sdpMLineIndex: 0
}
| 类型 | 说明 | 优先级 |
|---|
host | 本地 IP 地址 | 最高 |
srflx | Server Reflexive(STUN 获取的公网地址) | 中 |
prflx | Peer Reflexive(对端发现的地址) | 中 |
relay | TURN 中继地址 | 最低 |
媒体引擎结构(libwebrtc 概览)
libwebrtc 简介
libwebrtc 是 Google 开源的 WebRTC 实现,也是 Chrome、Firefox(部分)、Safari 等浏览器的底层实现。
目录结构
src/
├── api/ # 公共 API 接口
│ ├── audio_codecs/ # 音频编解码器接口
│ ├── video_codecs/ # 视频编解码器接口
│ ├── peer_connection_interface.h
│ └── ...
├── audio/ # 音频处理
│ ├── audio_send_stream.cc
│ ├── audio_receive_stream.cc
│ └── ...
├── video/ # 视频处理
│ ├── video_send_stream.cc
│ ├── video_receive_stream.cc
│ └── ...
├── call/ # 呼叫管理
├── media/ # 媒体引擎
│ ├── engine/
│ │ ├── webrtc_voice_engine.cc
│ │ └── webrtc_video_engine.cc
│ └── ...
├── modules/ # 核心模块
│ ├── audio_coding/ # 音频编解码
│ ├── audio_processing/ # 音频处理(AEC、NS、AGC)
│ ├── video_coding/ # 视频编解码
│ ├── rtp_rtcp/ # RTP/RTCP 协议
│ ├── congestion_controller/ # 拥塞控制
│ └── ...
├── pc/ # PeerConnection 实现
│ ├── peer_connection.cc
│ ├── sdp_offer_answer.cc
│ └── ...
├── p2p/ # P2P 连接
│ ├── base/
│ │ ├── stun.cc
│ │ ├── turn_port.cc
│ │ └── ...
│ └── client/
│ └── basic_port_allocator.cc
├── rtc_base/ # 基础库
│ ├── thread.cc
│ ├── async_socket.cc
│ └── ...
└── sdk/ # 平台 SDK
├── android/
├── objc/ # iOS/macOS
└── ...
核心模块详解
音频处理模块 (Audio Processing Module, APM)
┌─────────────────────────────────────────────────────────────┐
│ Audio Processing Module │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ AEC │ │ NS │ │ AGC │ │
│ │ (回声消除) │ │ (噪声抑制) │ │ (自动增益控制) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ VAD │ │ Beamform │ │ Level Estimator │ │
│ │ (语音检测) │ │ (波束成形) │ │ (电平估计) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
| 组件 | 功能 | 文件位置 |
|---|
| AEC3 | 回声消除(第三代) | modules/audio_processing/aec3/ |
| NS | 噪声抑制 | modules/audio_processing/ns/ |
| AGC2 | 自动增益控制 | modules/audio_processing/agc2/ |
| VAD | 语音活动检测 | modules/audio_processing/vad/ |
视频编解码模块
┌─────────────────────────────────────────────────────────────┐
│ Video Coding Module │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Encoders │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ VP8 │ │ VP9 │ │ H.264 │ │ AV1 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Decoders │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ VP8 │ │ VP9 │ │ H.264 │ │ AV1 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Video Processing │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Scaling │ │ FEC │ │ Jitter Buf │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
RTP/RTCP 模块
┌─────────────────────────────────────────────────────────────┐
│ RTP/RTCP Module │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ RTP Sender │ │
│ │ • 打包媒体数据 │ │
│ │ • 添加 RTP 头部 │ │
│ │ • 处理重传请求 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ RTP Receiver │ │
│ │ • 解析 RTP 包 │ │
│ │ • 处理丢包 │ │
│ │ • 抖动缓冲 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ RTCP Handler │ │
│ │ • SR/RR (发送/接收报告) │ │
│ │ • NACK (丢包重传请求) │ │
│ │ • PLI/FIR (关键帧请求) │ │
│ │ • REMB (带宽估计) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
拥塞控制模块
WebRTC 使用 GCC(Google Congestion Control) 算法进行带宽估计和拥塞控制。
┌─────────────────────────────────────────────────────────────┐
│ Congestion Controller │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Send-side BWE (发送端带宽估计) │ │
│ │ • 基于延迟梯度 │ │
│ │ • Transport-wide CC │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Receive-side BWE (接收端带宽估计) │ │
│ │ • REMB 反馈 │ │
│ │ • 基于丢包率 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Pacer (发送节奏控制) │ │
│ │ • 平滑发送 │ │
│ │ • 避免突发 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
线程模型
┌─────────────────────────────────────────────────────────────┐
│ Thread Architecture │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Signaling │ 信令线程:处理 API 调用、SDP 协商 │
│ │ Thread │ │
│ └─────────────────┘ │
│ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Worker │ 工作线程:媒体处理、编解码 │
│ │ Thread │ │
│ └─────────────────┘ │
│ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Network │ 网络线程:网络 I/O、ICE 处理 │
│ │ Thread │ │
│ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Audio │ │ Video │ │
│ │ Device Thread │ │ Capture Thread │ 设备线程 │
│ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
总结
架构要点回顾
| 层次 | 内容 |
|---|
| 应用层 | JavaScript 代码,调用 WebRTC API |
| API 层 | getUserMedia、RTCPeerConnection、RTCDataChannel |
| 引擎层 | 音频引擎、视频引擎、会话管理 |
| 传输层 | ICE、DTLS、SRTP、SCTP |
API 体系总结
| API | 职责 |
|---|
getUserMedia() | 获取摄像头/麦克风 |
getDisplayMedia() | 屏幕共享 |
RTCPeerConnection | P2P 连接管理 |
RTCDataChannel | 任意数据传输 |
信令流程要点
- Offer/Answer 模型:发起方创建 Offer,接收方回复 Answer
- SDP 交换:描述媒体能力和传输参数
- ICE 候选交换:发现可用的网络路径
- 信令协议自定义:WebRTC 不规定信令协议
参考资料
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online