webrtc弱网-LinkCapacityEstimator类源码分析与算法原理
一、核心功能
LinkCapacityEstimator
是 WebRTC 中用于估计网络链路容量的类,主要用于带宽估计和拥塞控制。它通过接收网络状态反馈(如过载检测和探测速率)来动态更新链路容量估计值,并提供上下界估计,用于判断当前网络状态是否稳定或拥塞。
二、核心算法原理
该类使用指数加权移动平均(EWMA) 算法对链路容量样本进行平滑处理,并估计其方差(标准差)。具体包括:
平滑更新:使用不同权重(α)对新样本和旧估计值进行加权平均。
方差估计:计算估计值与实际样本的误差,并归一化后更新方差估计。
上下界计算:基于估计值 ± 3倍标准差计算链路容量的上下界。
三、关键数据结构
absl::optional<double> estimate_kbps_; // 当前链路容量估计值(kbps) double deviation_kbps_ = 0.4; // 归一化的方差估计(无单位)
四、核心方法详解
1. Update(DataRate capacity_sample, double alpha)
void Update(DataRate capacity_sample, double alpha) {double sample_kbps = capacity_sample.kbps();if (!estimate_kbps_.has_value()) {estimate_kbps_ = sample_kbps;} else {estimate_kbps_ = (1 - alpha) * estimate_kbps_.value() + alpha * sample_kbps;}// 计算归一化误差并更新方差估计const double norm = std::max(estimate_kbps_.value(), 1.0);double error_kbps = estimate_kbps_.value() - sample_kbps;deviation_kbps_ =(1 - alpha) * deviation_kbps_ + alpha * error_kbps * error_kbps / norm;// 钳制方差在合理范围内deviation_kbps_ = rtc::SafeClamp(deviation_kbps_, 0.4f, 2.5f); }
功能:使用 EWMA 更新链路容量估计和方差。
参数:
capacity_sample
:新的容量样本(如探测速率或确认速率)。alpha
:平滑系数,控制新样本的权重。
2. UpperBound() / LowerBound()
DataRate UpperBound() const {if (estimate_kbps_.has_value())return DataRate::KilobitsPerSec(estimate_kbps_.value() +3 * deviation_estimate_kbps());return DataRate::Infinity(); }
功能:返回容量估计的上下界(±3σ),用于判断网络是否稳定。
3. OnOveruseDetected(DataRate acknowledged_rate)
void OnOveruseDetected(DataRate acknowledged_rate) {Update(acknowledged_rate, 0.05); }
功能:在网络过载时使用较小α(0.05)缓慢更新估计,避免剧烈波动。
4. OnProbeRate(DataRate probe_rate)
void OnProbeRate(DataRate probe_rate) {Update(probe_rate, 0.5); }
功能:在主动探测时使用较大α(0.5)快速更新估计,响应探测结果。
五、设计亮点
自适应平滑系数:针对不同场景使用不同的α值,平衡响应速度与稳定性。
归一化方差估计:将方差归一化到估计值附近,避免数值不稳定。
方差钳制:将方差限制在 [0.4, 2.5] 范围内,防止极端值影响估计。
上下界计算:基于标准差提供置信区间,增强拥塞控制的鲁棒性。
六、典型工作流程
初始化:
Reset()
清空历史估计。接收样本:
收到探测数据包 →
OnProbeRate(probe_rate)
检测到网络过载 →
OnOveruseDetected(ack_rate)
更新估计:调用
Update()
方法平滑更新估计值和方差。查询状态:
estimate()
获取当前估计容量。UpperBound()/LowerBound()
获取置信区间。
重置:在连接变更或长时间无数据时调用
Reset()
。
七、注释精要
link_capacity_estimator.h
class LinkCapacityEstimator {public:LinkCapacityEstimator();DataRate UpperBound() const; // 容量上界(估计值 + 3σ)DataRate LowerBound() const; // 容量下界(估计值 - 3σ)void Reset(); // 重置估计器void OnOveruseDetected(DataRate acknowledged_rate); // 过用事件处理void OnProbeRate(DataRate probe_rate); // 探测速率处理bool has_estimate() const; // 是否有有效估计DataRate estimate() const; // 返回当前容量估计private:friend class GoogCcStatePrinter;void Update(DataRate capacity_sample, double alpha); // 核心更新方法double deviation_estimate_kbps() const; // 计算标准差(kbps)absl::optional<double> estimate_kbps_; // 当前容量估计(kbps)double deviation_kbps_ = 0.4; // 归一化的方差估计 };
link_capacity_estimator.cc
LinkCapacityEstimator::LinkCapacityEstimator() {}DataRate LinkCapacityEstimator::UpperBound() const {if (estimate_kbps_.has_value())return DataRate::KilobitsPerSec(estimate_kbps_.value() +3 * deviation_estimate_kbps());return DataRate::Infinity(); // 无估计时返回无穷大 }DataRate LinkCapacityEstimator::LowerBound() const {if (estimate_kbps_.has_value())return DataRate::KilobitsPerSec(std::max(0.0, estimate_kbps_.value() - 3 * deviation_estimate_kbps()));return DataRate::Zero(); // 无估计时返回0 }void LinkCapacityEstimator::Reset() {estimate_kbps_.reset(); // 重置估计值 }void LinkCapacityEstimator::OnOveruseDetected(DataRate acknowledged_rate) {Update(acknowledged_rate, 0.05); // 过用时使用小α缓慢更新 }void LinkCapacityEstimator::OnProbeRate(DataRate probe_rate) {Update(probe_rate, 0.5); // 探测时使用大α快速更新 }void LinkCapacityEstimator::Update(DataRate capacity_sample, double alpha) {double sample_kbps = capacity_sample.kbps();if (!estimate_kbps_.has_value()) {estimate_kbps_ = sample_kbps; // 初始化估计} else {// EWMA 更新估计值estimate_kbps_ = (1 - alpha) * estimate_kbps_.value() + alpha * sample_kbps;}// 归一化误差并更新方差估计const double norm = std::max(estimate_kbps_.value(), 1.0);double error_kbps = estimate_kbps_.value() - sample_kbps;deviation_kbps_ =(1 - alpha) * deviation_kbps_ + alpha * error_kbps * error_kbps / norm;// 钳制方差在合理范围内deviation_kbps_ = rtc::SafeClamp(deviation_kbps_, 0.4f, 2.5f); }bool LinkCapacityEstimator::has_estimate() const {return estimate_kbps_.has_value(); }DataRate LinkCapacityEstimator::estimate() const {return DataRate::KilobitsPerSec(*estimate_kbps_); }double LinkCapacityEstimator::deviation_estimate_kbps() const {// 计算实际标准差:sqrt(归一化方差 * 估计值)return sqrt(deviation_kbps_ * estimate_kbps_.value()); } LinkCapacityEstimator 是 WebRTC 谷歌拥塞控制(GoogleCC)算法中的核心组件,用于动态估计网络链路的可用带宽。它通过处理过用(Overuse)信号和探测(Probe)速率样本,采用指数加权移动平均(EWMA)算法来平滑更新带宽估计值及其方差。该估计器通过提供容量上界和下界(估计值±3倍标准差),为拥塞控制决策(如增加、保持或减少发送码率)提供关键依据,从而确保视频流在不同网络条件下都能平滑、稳定且高效地传输。