3. WebRTC 核心架构解析:PeerConnection、SDP 协商流程、ICE/STUN/TURN 协议栈、数据通道与媒体通道的区别
这一章,我们直接切入 WebRTC 的“心脏”。
很多做嵌入式移植的朋友,一开始就被 PeerConnection、SDP、ICE 这些术语搞懵了。说实话,我当年第一次看 WebRTC 源码时,也觉得这东西像个黑盒子。但后来在 ARM Cortex-A 平台上调通第一路视频通话后,我才真正理解——WebRTC 的核心架构,其实就三件事:建立连接、协商参数、传输数据。
3.1 PeerConnection:通话的“总指挥”
PeerConnection 是整个 WebRTC 的顶层对象。你可以把它理解成一个“通话管家”。
它负责管理:
- 本地媒体流的采集与发送
- 远端媒体流的接收与渲染
- 网络连接的建立与维护
- 编解码器的协商与切换
在嵌入式系统里,我习惯把 PeerConnection 看作一个状态机。它的生命周期大致是:
- 创建:new RTCPeerConnection(configuration)
- 添加流:addTrack() / addTransceiver()
- 创建 Offer:createOffer()
- 设置本地描述:setLocalDescription()
- 接收远端描述:setRemoteDescription()
- ICE 连接建立:iceConnectionState 变为 connected
- 通话中:媒体流双向传输
- 关闭:close()
关键点:在嵌入式平台上,PeerConnection 的配置参数需要特别关注。比如 iceServers 列表、iceCandidatePoolSize、bundlePolicy 等,这些直接影响连接建立的速度和稳定性。
3.2 SDP 协商流程:双方“握手”的协议
SDP(Session Description Protocol)不是传输协议,它只是一个描述格式。说白了,就是通话双方互相告诉对方:“我能支持什么编码?我的 IP 和端口是多少?”
完整的 SDP 协商流程是这样的:
- A 创建 Offer:A 调用 createOffer(),生成一个包含 A 端媒体能力、网络信息的 SDP
- A 设置本地描述:A 调用 setLocalDescription(offer)
- A 发送 Offer 给 B:通过信令通道(WebSocket、MQTT 等)
- B 设置远端描述:B 调用 setRemoteDescription(offer)
- B 创建 Answer:B 调用 createAnswer(),生成应答 SDP
- B 设置本地描述:B 调用 setLocalDescription(answer)
- B 发送 Answer 给 A:通过信令通道
- A 设置远端描述:A 调用 setRemoteDescription(answer)
嗯,这里要注意:SDP 协商是“先 Offer 后 Answer”的严格顺序。我在调试一个嵌入式摄像头项目时,曾经因为信令通道延迟导致 Offer 和 Answer 乱序,结果 PeerConnection 一直卡在 “have-remote-offer” 状态。后来加了序列号校验才解决。
嵌入式优化建议:在资源受限的嵌入式设备上,SDP 可以预先“裁剪”。比如去掉不支持的编解码器、减少 ICE candidate 数量,能显著降低协商耗时。
3.3 ICE / STUN / TURN 协议栈:穿透 NAT 的“三剑客”
这是 WebRTC 里最绕的部分,也是嵌入式移植的难点。
先看一张我画的协议栈关系图:
简单解释一下:
- STUN:帮你找到自己的公网 IP 和端口。我遇到过 STUN 请求被防火墙拦截的情况,后来改用 TCP 封装的 STUN 才解决。
- TURN:当 STUN 直连失败(比如对称 NAT),TURN 服务器作为中继转发数据。代价是延迟增加、带宽消耗翻倍。
- ICE:一个“连接管理器”。它收集所有可能的 candidate(本地、STUN、TURN),然后按优先级排序,逐个尝试连接。
嵌入式避坑指南:我曾经在 ESP32 上跑 WebRTC,发现 ICE 连接建立耗时超过 10 秒。原因是默认的 ICE candidate 收集超时太长。建议将 iceCandidatePoolSize 设为 0,并手动控制 candidate 的收集时机。
3.4 数据通道 vs 媒体通道:两条“车道”
很多初学者搞不清这两者的区别。我打个比方:
- 媒体通道:走的是“高速公路”,专门跑音视频数据。使用 SRTP/SCTP 协议,有 QoS 保障。
- 数据通道:走的是“普通公路”,传输任意二进制数据。使用 SCTP over DTLS,可靠或不可靠模式可选。
它们的核心差异如下:
| 对比维度 | 媒体通道 | 数据通道 |
|---|---|---|
| 传输内容 | 音频/视频流 | 任意二进制数据 |
| 底层协议 | SRTP / SCTP | SCTP over DTLS |
| 可靠性 | 部分可靠(丢包可容忍) | 可靠或不可靠(可配置) |
| 延迟要求 | 极低(< 100ms) | 低(可配置) |
| 典型用途 | 实时音视频通话 | 文件传输、游戏指令、传感器数据 |
| 嵌入式适配难度 | 高(需要硬件编解码) | 中(纯软件处理) |
在嵌入式场景下,我建议优先使用数据通道做控制信令的传输。比如摄像头云台控制、传感器状态上报等,用数据通道比单独建一个 WebSocket 连接更省资源。
实战技巧:数据通道支持“部分可靠”模式(partial reliability)。在嵌入式设备上,如果传输的是非关键数据(如日志),可以设置 maxPacketLifetime 为 100ms,这样超过 100ms 还没发出去的数据就直接丢弃,避免阻塞通道。
3.5 本章小结
这一章我们拆解了 WebRTC 的四大核心模块:
- PeerConnection:通话的“总指挥”,管理连接生命周期
- SDP 协商:双方“握手”,确定媒体参数和网络信息
- ICE/STUN/TURN:穿透 NAT 的“三剑客”,确保连接可达
- 数据通道 vs 媒体通道:两条“车道”,各司其职