3. WebRTC架构:整体架构图、Native层与Web层、核心模块介绍
WebRTC 的架构,说白了就是一套「浏览器也能做实时音视频」的底层基础设施。我刚开始接触时也觉得它很神秘,后来拆开一看,其实就三层:Web API 层、Native C++ 层、以及底层的硬件抽象层。今天咱们就把它掰开揉碎,看看里面到底长什么样。
核心认知:WebRTC 不是单一库,而是一套完整的实时通信框架。它把音频采集、视频编码、网络传输、拥塞控制全部打包好了。你只需要调用几个 API,就能在浏览器里做视频通话。
3.1 WebRTC 整体架构图
先上一张我手绘的架构图。这张图我每次培训都会用,因为它把 WebRTC 的「三明治结构」讲得很清楚。
这张图我画了不下十版。你注意看,核心引擎层是 WebRTC 的心脏,VoiceEngine、VideoEngine、Session Management 三个模块各司其职。Web API 层只是「窗户」,真正的活儿都在 Native 层干。
3.2 Native 层与 Web 层
很多初学者会问:为什么 WebRTC 要分两层?直接给 JavaScript 不就行了?
嗯,这里有个关键点——性能。音视频处理是计算密集型任务,JavaScript 跑不动。所以 WebRTC 的设计哲学是:Web 层只做 API 暴露,Native 层做重活。
| 对比维度 | Web 层(JS) | Native 层(C++) |
|---|---|---|
| 运行环境 | 浏览器主线程 / Worker | 浏览器底层进程 |
| 主要职责 | API 调用、事件回调、信令交互 | 编解码、网络传输、音视频处理 |
| 性能要求 | 低(毫秒级延迟可接受) | 极高(微秒级) |
| 内存管理 | V8 垃圾回收 | 手动管理 / 智能指针 |
| 跨平台 | 浏览器兼容性 | Android/iOS/Windows/Mac/Linux |
我的经验:做 Web 端开发时,你只需要关注 RTCPeerConnection、getUserMedia 这些 API。但一旦要定制编码参数或做低延迟优化,就必须深入 Native 层。我曾经在 iOS 端用 Native API 把编码延迟从 30ms 降到了 8ms,Web 层根本做不到。
3.3 核心模块介绍
3.3.1 VoiceEngine
VoiceEngine 是音频处理的「大管家」。它负责从麦克风采集声音,到编码发送,再到接收端解码播放的全流程。
我个人觉得,VoiceEngine 最牛的地方不是编解码,而是音频处理链:
- AEC(回声消除):扬声器声音被麦克风重新采集,不消除的话就是刺耳啸叫。WebRTC 的 AEC 算法基于 NLMS 自适应滤波,效果相当好。
- NS(降噪):抑制背景噪音,比如风扇声、键盘声。WebRTC 用的是频谱减法,复杂度低但效果够用。
- AGC(自动增益控制):说话声音忽大忽小时,自动调整音量到合适范围。
- VAD(语音活动检测):判断当前是不是有人在说话,用于节省带宽和计算资源。
避坑指南:我曾经在项目中遇到回声问题,排查了两天才发现是 AEC 的 delay_estimator 参数没调好。WebRTC 默认的 AEC 对 50ms 以内的回声效果很好,但如果设备延迟超过 100ms,就需要手动设置 set_stream_delay_ms()。否则,你会听到自己的回声——那感觉,嗯,很酸爽。
3.3.2 VideoEngine
VideoEngine 负责视频的采集、编码、传输和渲染。它的核心组件包括:
- 视频采集器:从摄像头获取原始帧,支持 YUV、NV12 等格式。
- 编码器:VP8/VP9/H264 可选。VP8 是 WebRTC 的亲儿子,兼容性最好;H264 硬件编码在移动端更省电。
- Jitter Buffer(抖动缓冲):网络延迟不稳定时,Jitter Buffer 会缓存几帧数据,等网络稳定后再播放。这是音画同步的关键。
- 图像增强:亮度调整、对比度增强、降噪等。
你想想看,视频通话最怕什么?卡顿、花屏、音画不同步。VideoEngine 的 Jitter Buffer 就是专门解决这些问题的。它内部维护一个 帧队列,根据网络抖动动态调整缓存深度。
关键参数:Jitter Buffer 的延迟通常设置在 50ms~200ms 之间。网络差时自动增大,网络好时自动减小。我建议你在生产环境中开启 RTCRtpReceiver.getStats() 监控 jitterBufferDelay 指标,一旦超过 300ms,用户就会明显感觉到延迟。
3.3.3 Session Management
Session Management 是 WebRTC 的「外交官」。它不直接处理音视频数据,而是负责建立和维护连接。
它的核心职责有三块:
- SDP 协商:双方交换媒体能力(编解码、分辨率、带宽等),达成一致后才能开始通信。
- ICE/STUN/TURN:解决 NAT 穿透问题。STUN 用于获取公网地址,TURN 作为中继兜底。
- DTLS 加密:所有音视频数据都通过 DTLS 加密传输,防止被窃听。
| 组件 | 作用 | 典型场景 |
|---|---|---|
| SDP | 描述媒体能力 | offer/answer 交换 |
| ICE | 候选地址收集与连通性检查 | P2P 打洞 |
| STUN | 获取公网 IP 和端口 | NAT 穿透 |
| TURN | 中继转发 | 对称 NAT 或防火墙限制 |
| DTLS | 加密传输 | 所有媒体流 |
我的建议:Session Management 的调试是最头疼的。我建议你在开发阶段打开 chrome://webrtc-internals,里面能看到完整的 ICE 状态机变化、SDP 内容、以及候选地址列表。我曾经靠这个工具定位到一个 TURN 服务器配置错误的问题——STUN 请求能通,但 TURN 的 relay 类型候选一直失败,最后发现是端口没开。
3.4 三个模块如何协同工作
光讲模块不够,咱们看看它们怎么配合。假设 Alice 和 Bob 要视频通话:
- Session Management 先上场:Alice 创建
RTCPeerConnection,生成 SDP offer,通过信令服务器发给 Bob。Bob 回复 SDP answer。同时 ICE 开始收集候选地址。 - VoiceEngine 和 VideoEngine 启动:Alice 的麦克风和摄像头开始采集数据,经过编码后打包成 RTP 包。
- 传输层 发送:RTP 包通过 SRTP 加密,经 ICE 选定的路径发送给 Bob。
- Bob 端接收:VideoEngine 的 Jitter Buffer 缓存并排序,然后解码渲染。VoiceEngine 做回声消除和降噪后播放。
整个过程是流水线作业,任何一个模块出问题,都会导致通话质量下降。我记得有一次线上事故,用户反馈视频卡顿但音频正常,最后定位到是 VideoEngine 的编码器在弱网下没有及时降分辨率——Session Management 的带宽估计模块没把网络状况反馈给编码器。
总结一下:WebRTC 的架构设计非常精妙。Web 层让你快速上手,Native 层给你深度控制。VoiceEngine 管声音,VideoEngine 管画面,Session Management 管连接。三个模块各司其职,又紧密配合。理解了这些,你就能在遇到问题时快速定位——是编码问题、网络问题、还是协商问题。