三、WebRTC架构解析:整体架构、Native层与Web层、核心模块

WebRTC的架构,说白了就是一套「浏览器也能做实时音视频」的底层方案。我刚开始接触时也觉得它很神秘,后来拆开一看,其实就三层:Web API层、Native C++层、以及最底层的硬件抽象层

嗯,咱们今天重点聊中间那层——Native层。因为所有核心能力都藏在这里。

3.1 WebRTC整体架构:一张图看懂

先给你看一张我手绘的架构图。别小看它,我当年啃源码时就是靠这张图理清脉络的。

Web API 层 getUserMedia · RTCPeerConnection · RTCDataChannel Native C++ 核心层 音频引擎 Audio Capture NetEQ (抖动消除) AEC / ANC / AGC Opus / G.711 编解码 视频引擎 Video Capture VP8 / VP9 / H.264 Jitter Buffer SVC / Simulcast 传输模块 ICE / STUN / TURN DTLS / SRTP SCTP (数据通道) 带宽估计 (GCC) 硬件抽象层 摄像头 · 麦克风 · 扬声器 · 网卡

你看,从上到下非常清晰。Web API 层暴露给 JavaScript,Native 层做脏活累活,硬件抽象层屏蔽设备差异。我个人习惯把中间那层称为「WebRTC的心脏」,因为所有编解码、网络传输、回声消除都在这里完成。

3.2 Native层与Web层:谁在干活?

很多初学者会问:WebRTC到底是在浏览器里跑,还是在操作系统里跑?

答案是:两边都有

Web层(JavaScript)只负责两件事:

  • 调用 API(比如 getUserMedia 打开摄像头)
  • 处理信令(把 SDP、ICE Candidate 发给对方)

而真正的音视频采集、编码、加密、传输,全部在 Native 层完成。Chrome 用的是自己内置的 WebRTC Native 库,Safari 用的是系统库,但底层逻辑一模一样。

核心区别:

  • Web 层:胶水代码,负责调度
  • Native 层:引擎代码,负责干活

我在项目中遇到过一个问题:用 RTCPeerConnection 创建连接后,发现视频一直黑屏。查了半天,原来是 Native 层的视频采集模块没拿到摄像头权限。Web 层报的错很模糊,但 Native 层的日志里清清楚楚写着 Camera access denied。所以我的建议是——调试时一定要打开 Native 层的日志,Chrome 里输入 chrome://webrtc-internals 就能看到。

3.3 音频引擎:不止是「能出声」

音频引擎是 WebRTC 里最成熟、也最复杂的模块。它包含四个核心组件:

组件 作用 我的经验
NetEQ 网络抖动消除 + 丢包补偿 曾经遇到网络抖动 200ms,NetEQ 硬是让声音没断
AEC 回声消除 扬声器声音被麦克风重新采集,AEC 负责干掉它
ANC 噪声抑制 风扇声、键盘声,ANC 能压掉大部分
AGC 自动增益控制 说话声音忽大忽小?AGC 帮你拉平

嗯,这里要注意:NetEQ 是 WebRTC 音频的杀手锏。它不只是简单的抖动缓冲,而是用了自适应算法——网络差时自动拉长音频包,网络好时自动缩短。我做过测试,在 30% 丢包率下,Opus 编码 + NetEQ 依然能听清对话内容。

避坑指南:

我曾经在集成 WebRTC 到 Android 应用时,发现回声消除失效。排查了两天,最后发现是手机底层的 AEC 和 WebRTC 的 AEC 冲突了。解决方案很简单:关掉硬件 AEC,只用 WebRTC 的软件 AEC。

3.4 视频引擎:编码、解码、自适应

视频引擎的核心任务就三个:采集、编码、传输自适应

先说编码。WebRTC 支持三种视频编码器:

  • VP8:默认编码器,兼容性最好
  • VP9:压缩率更高,但解码更耗性能
  • H.264:硬件编码支持好,iOS 上必用

你想想看,如果两个人视频通话,一个用 Chrome(支持 VP8/VP9),一个用 Safari(只支持 H.264),怎么协商?WebRTC 的答案是 SDP 协商——双方列出自己支持的编码器,然后选一个共同支持的。这就是为什么 createOffercreateAnswer 里会有一长串编码器列表。

视频引擎里还有一个很重要的东西叫 Simulcast( simulcast 编码)。它允许发送方同时编码出多个分辨率的视频流,接收方根据网络状况选择最合适的那一路。我在做多人会议时,Simulcast 简直是救命稻草——手机端收 360p,PC 端收 720p,互不影响。

注意:

Simulcast 会增加发送端的 CPU 和带宽消耗。如果设备性能有限,建议用 SVC(可伸缩视频编码)替代,它只编码一次,但解码时可以截取不同质量层。

3.5 传输模块:ICE、DTLS、SRTP 三板斧

传输模块是 WebRTC 的「通信管道」。它要解决三个问题:

  1. 怎么找到对方?——ICE + STUN + TURN
  2. 怎么保证安全?——DTLS 握手 + SRTP 加密
  3. 怎么传数据?——SCTP 用于数据通道,UDP 用于音视频

ICE 的全称是 Interactive Connectivity Establishment,说白了就是「想尽一切办法建立连接」。它会先尝试直连(STUN),如果失败就通过中继(TURN)。我遇到过最极端的情况:两个用户都在对称 NAT 后面,直连和 STUN 都失败,最后靠 TURN 服务器中转才连上。延迟虽然高了 50ms,但至少能通话。

DTLS 和 SRTP 是安全层。DTLS 负责交换密钥,SRTP 负责加密音视频数据。嗯,这里有个细节:DTLS 握手是在 ICE 连接建立之后才开始的。所以如果你看到连接卡在「DTLS 握手失败」,大概率是网络问题导致 UDP 包被丢了。

传输模块的关键指标:

  • RTT(往返时延):低于 200ms 体验良好
  • 丢包率:低于 5% 不影响通话
  • 抖动:低于 30ms 不需要 NetEQ 介入

3.6 一个小结

WebRTC 的架构其实不复杂。你只要记住:

  • Web 层是遥控器,Native 层是发动机
  • 音频引擎负责让你听清,视频引擎负责让你看清
  • 传输模块负责让数据跑通

我个人觉得,理解架构最好的方式就是动手抓包。打开 chrome://webrtc-internals,看一次 ICE 连接过程,看一次 DTLS 握手,比读十篇文章都管用。

好,这一章就到这里。下一章咱们聊信令——那个 WebRTC 标准里没规定、但实际项目里绕不开的东西。


公众号:蓝海资料掘金营,微信 deep3321