webrtc 的拥塞控制接口,主要由NetworkControllerInterface基类控制,当前webrtc主要由两套拥塞控制算法,GCC(Google Congestion Control,谷歌拥塞控制)和PCC(Performance-oriented Congestion,基于性能的拥塞控制)。
cpp
//GCC
class GoogCcNetworkController : public NetworkControllerInterface {
public:
GoogCcNetworkController(NetworkControllerConfig config,
GoogCcConfig goog_cc_config);
~GoogCcNetworkController() override;
//PCC
class PccNetworkController : public NetworkControllerInterface {
public:
enum class Mode {
kStartup,
// Slow start phase of PCC doubles sending rate each monitor interval.
kSlowStart,
// After getting the first decrease in utility function PCC exits slow start
// and enters the online learning phase.
kOnlineLearning,
// If we got that sending with the lower rate resulted in higher packet
// loss, then the measurements are unreliable and we need to double check
// them.
kDoubleCheck
};
一,GCC介绍
1.1 整体介绍
目录:modules\congestion_controller\goog_cc
GoogCcNetworkController 是 WebRTC 中实现 Google Congestion Control (GCC) 算法的核心类, specifically 针对**发送端带宽估计(Send-Side Bandwidth Estimation, SS-BWE)**进行了优化。它是 NetworkControllerInterface 的主要实现之一,负责协调多个子模块,根据网络反馈(丢包、延迟)动态调整视频/音频的发送码率,以在保证流畅度的同时最大化画质。
GoogCcNetworkController 是 WebRTC 默认且最成熟的拥塞控制器。它通过延迟梯度检测快速响应拥塞,通过丢包率处理严重拥塞,通过探针机制快速探索带宽上限,并通过ALR 检测避免在无数据发送时误降码率。这种多信号融合的策略使其在各种复杂的网络环境下都能提供稳定的实时通信体验。
1.2 核心架构:多估算器融合
GCC 并不依赖单一指标,而是融合了多种信号来做出决策。GoogCcNetworkController 持有并协调以下关键组件:
1.2.1 delay_based_bwe (DelayBasedBwe):
• 基于延迟的带宽估计。它分析 RTP 包的到达时间间隔(Inter-arrival time),使用卡尔曼滤波等算法检测网络队列是否正在堆积(Overuse)。如果延迟增加趋势明显,说明网络拥塞,需要降低码率。这是 GCC 的核心,用于快速响应拥塞。
1.2.2 bandwidth_estimation (SendSideBandwidthEstimation):
• 发送端带宽估算器。它结合来自 DelayBasedBwe 的延迟信号和来自 TransportLossReport 的丢包信号。
• 它维护最终的目标码率(Target Bitrate),执行 AIMD(加性增、乘性减)逻辑:
• 收到 Overuse 信号 -> 大幅降低码率。
• 网络空闲 -> 线性增加码率。
• 高丢包 -> 根据丢包率比例降低码率。
1.2.3 acknowledged_bitrate_estimator:
• 估算实际成功到达接收端的比特率。这作为带宽估计的下限参考,确保不会将码率设得比实际网络吞吐量还低太多。
1.2.4 probe_controller (ProbeController):
• 探针控制器。当网络空闲或码率受限时,它会触发"探针簇"(Probe Clusters)------即短时间内突发的高码率数据包。通过观察这些探针是否能完整通过,可以快速探测网络的真实可用带宽上限,从而让码率迅速爬升,而不是缓慢线性增加。
1.2.5 alr_detector (AlrDetector):
• 应用限制速率检测器(Application-Limited Rate Detector)。检测发送端是否因为没数据可发(如摄像头静止、屏幕共享无变化)而导致发送速率低于网络容量。如果是 ALR 状态,拥控算法会暂停降低码率,避免误判。
二,PCC介绍
2.1 整体介绍
目录:modules\congestion_controller\pcc
PccNetworkController 是 WebRTC 中实现 PCC (Performance-oriented Congestion Control) Vivace 算法的核心类。与传统的基于丢包(如 TCP Reno)或基于延迟梯度(如 GCC/BBR)的拥塞控制不同,PCC 是一种**基于在线学习(Online Learning)的拥控算法。它不试图建立精确的网络模型,而是通过实时"试探"不同的发送速率,并根据一个自定义的效用函数(Utility Function)**来评估网络性能,从而动态调整发送速率以最大化该效用值。
PccNetworkController 实现了 WebRTC 中一种先进的、基于机器学习和在线优化理论的拥塞控制算法。它不依赖固定的阈值,而是通过不断的"微扰"和"反馈"来感知网络环境的变化。
• 优点: 在复杂网络环境(如高丢包、高抖动)下往往比传统算法表现更好,因为它直接优化最终用户关心的指标(吞吐量、延迟、丢包的加权组合)。
• 缺点: 实现复杂,收敛速度受 MI 长度影响,且在极短时间的剧烈波动下可能不如基于梯度的延迟算法(如 BBR)反应迅速。
它是 WebRTC NetworkControllerInterface 的一个具体实现,可以替换默认的 GCC (Google Congestion Control) 控制器,为开发者提供了另一种高性能的传输选择。
2.2 核心工作原理:监控区间 (Monitor Interval, MI)
2.2.1 MI介绍
PCC将时间划分为连续的监控区间(MI)。在每个 MI 内,控制器会尝试两个略微不同的发送速率:
-
:比当前估计速率稍高。
-
:比当前估计速率稍低。
在 MI 结束时,PCC 收集这两个速率下的网络统计数据(吞吐量、延迟、丢包率),代入效用函数计算得分。如果高速率的效用更高,则增加基准速率 ;否则降低 。这本质上是一个**梯度上升(Gradient Ascent)**过程,用于寻找效用函数的最大值。
2.2.3 状态机 (Mode Enum)
类内部维护一个状态机,决定当前的行为策略:
• kStartup: 初始状态。
• kSlowStart: 慢启动阶段。为了快速探测可用带宽,每个 MI 结束后,发送速率直接翻倍。直到效用函数首次出现下降(说明可能触及瓶颈),才退出慢启动。
• kOnlineLearning: 在线学习阶段(正常模式)。使用梯度上升算法微调速率,步长由 sampling_step_ () 控制。
• kDoubleCheck: 双重检查阶段。如果测量结果出现异常(例如降低速率后丢包反而更高,这违背常理,可能是噪声或测量误差),进入此状态重新验证测量数据的可靠性。
三、比较
|------|-----------------------------------------------------------|---------------------------------------------------------|
| 特性 | GoogCcNetworkController (GCC) | PccNetworkController (PCC) |
| 理论基础 | 经典控制理论 + 启发式规则。结合基于延迟梯度(Delay-based)和基于丢包(Loss-based)的信号。 | 在线凸优化 (Online Convex Optimization)。将拥塞控制视为一个效用函数最大化问题。 |
| 决策依据 | 显式网络状态推断。试图判断网络是"拥塞"、"空闲"还是"过用",并据此调整码率。 | 黑盒试探与反馈。不建立精确网络模型,而是通过微调发送速率,观察性能指标(吞吐量、延迟、丢包)的变化来指导方向。 |
| 主要目标 | 在低延迟和高吞吐量之间取得平衡,快速响应拥塞以避免队列堆积。 | 最大化自定义的效用函数 (Utility Function),该函数加权了吞吐量、延迟和丢包率。 |
| 核心类 | DelayBasedBwe, SendSideBandwidthEstimation | PccBitrateController, PccMonitorInterval |
| 辅助模块 | AlrDetector (应用限制检测), ProbeController (带宽探针) | RttTracker, UtilityFunction (隐含在控制器中) |
| 反馈依赖 | 高度依赖 TWCC (Transport-wide Congestion Control) 提供的精确到达时间戳。 | 同样依赖 TWCC,但更关注统计聚合后的效用值。 |
| 收敛速度 | 快(通过探针机制)。探针可以让码率在几秒内从低值跳变到真实带宽附近。 | 中等。依赖于梯度上升的步长 和 MI 的长度。需要多个 MI 才能收敛到最优值。 |
| | | |
3.1 工作机制对比
3.1.1. 带宽估算方式
• GCC:
• 双轨制:同时运行 DelayBasedBwe(监测单向延迟变化趋势)和 SendSideBandwidthEstimation(监测丢包率)。
• 状态机:根据延迟梯度判断网络状态(Normal/Overusing/Underusing)。
• Overusing(延迟增加):大幅降低码率(Multiplicative Decrease)。
• Normal:线性增加码率(Additive Increase)。
• High Loss:根据丢包比例降低码率。
• 探针 (Probing):使用 ProbeController 发送突发数据包簇,以快速探测可用带宽上限,打破线性增加的缓慢过程。
• PCC:
• 监控区间 (Monitor Intervals, MI):将时间划分为连续的区间。
• 微扰试探:在每个 MI 内,交替使用 和 两个速率发送数据。
• 效用计算:MI 结束后,计算两个速率下的效用值 。
• 梯度上升:如果高速率的效用更高,则增加基准速率 ;否则降低 。这是一种直接的梯度下降/上升优化过程。
3.1.2. 对丢包和延迟的处理
• GCC:
• 对延迟梯度非常敏感。一旦检测到排队延迟增加,立即反应。
• 对丢包的反应取决于配置。在高丢包网络下,GCC 可能会过度降低码率,因为它难以区分是随机丢包还是拥塞丢包(尽管有改进算法)。
• PCC:
• 通过效用函数统一处理。如果高丢包导致的效用惩罚小于高吞吐量带来的收益,PCC 可能会选择保持较高码率。
• 更能适应高丢包、高抖动的非传统网络环境(如卫星链路、蜂窝网络),因为它不假设丢包一定意味着拥塞。
3.2 优缺点分析
3.2.1 GoogCcNetworkController (GCC)
- 优点:
• 成熟稳定:WebRTC 默认算法,经过多年大规模部署验证。
• 低延迟优先:对队列堆积非常敏感,能很好地保护交互式应用的延迟体验。
• 快速启动:探针机制使其能快速利用空闲带宽。
- 缺点:
• 高丢包环境下表现不佳:在传统互联网(低丢包)表现完美,但在丢包率 >5-10% 的网络中,码率可能波动剧烈或过低。
• 参数复杂:有许多阈值和增益参数需要精细调优。
3.1.2 PccNetworkController (PCC)
- 优点:
• 鲁棒性强:在复杂网络(高丢包、高抖动、异构网络)中往往能获得更高的吞吐量和更稳定的质量。
• 模型无关:不需要假设特定的网络行为模型(如 AIMD 友好性),直接优化最终用户体验指标。
• 公平性:理论上在与 TCP 流共存时具有更好的公平性(取决于效用函数设计)。
- 缺点:
• 收敛较慢:在没有探针的情况下,依靠梯度上升爬升带宽的速度可能比 GCC 慢。
• 计算开销:每个 MI 都需要计算效用值和梯度,虽然开销不大,但逻辑比 GCC 的状态机复杂。
• 参数敏感:效用函数的权重()和步长 对性能影响巨大,需要根据应用场景调整。
3.3 应用场景
3.3.1 选择 GCC (GoogCcNetworkController):
• 标准的互联网视频会议、直播、即时通讯。
• 网络环境相对良好(丢包率 < 2-3%)。
• 对延迟极其敏感的应用(如在线游戏、远程桌面)。
• 需要与现有 WebRTC 生态系统最大兼容性的场景。
3.3.2 选择 PCC (PccNetworkController):
• 弱网环境:移动网络(4G/5G 切换)、卫星通信、高丢包 Wi-Fi。
• 大文件传输或高码率流媒体:对吞吐量要求高于极致低延迟的场景。
• 研究与新协议实验:希望探索基于机器学习和优化理论的新一代拥控算法。
• 网络路径复杂,传统基于丢包或延迟的启发式规则失效的场景。
四 总结
总之,GCC 是"经验主义"的代表,通过精心设计的规则和探针来应对网络变化,是目前 WebRTC 的工业标准。 PCC 是"理性主义"的代表,通过数学优化方法直接寻找性能最优解,是未来方向,特别适用于挑战性网络环境。
在 WebRTC 代码库中,你可以通过 GoogCcConfig 或构建选项来选择启用哪种控制器。默认情况下,绝大多数生产环境仍使用 GCC。
另外webrtc已经移除了BBR拥塞控制,在 2020 年前后通过 Issue 9883 彻底从代码库删除了。