当前位置: 首页 > news >正文

webrtc弱网-LossBasedBweV2类源码分析与算法原理

1. 核心功能

LossBasedBweV2是WebRTC Google Congestion Control (GoogCC) 算法套件中的第二代基于丢包的带宽估计器。它的核心功能是:

  • 带宽估计: 根据网络数据包的丢失情况,估算当前网络路径可用的带宽上限。其核心假设是:当发送速率超过网络容量时,将出现拥塞,表现为数据包丢失。通过分析丢包模式,它可以反向推断出这个容量瓶颈。

  • 状态输出: 不仅输出一个带宽估计值(DataRate),还输出一个状态(LossBasedState)。这个状态用于指导上层控制器(如GoogCCNetworkController)的行为,例如:

    • kIncreasing/kIncreaseUsingPadding: 建议可以尝试增加发送速率,后者暗示可以使用填充数据来探测。

    • kDecreasing: 估计值正在因丢包而下降,应减少发送速率。

    • kDelayBasedEstimate: 当前未处于丢包受限状态,应优先使用基于延迟的估计结果。

  • 多源信息融合: 它并非孤立工作,而是融合了多种信息源:

    • 丢包信息: 主要输入,来自RTCP Receiver Reports或传输反馈。

    • 延迟基于估计值: 来自DelayBasedBwe的另一个估计值,用作上限或候选值。

    • 确认速率: 当前网络的吞吐量测量值,用作参考和下限。

    • 配置参数: 通过字段试验(Field Trials)提供大量可调参数,用于控制算法行为。

2. 核心算法原理

LossBasedBweV2的核心算法基于最大似然估计(Maximum Likelihood Estimation, MLE),其基本原理可以概括为:

  1. 建立丢包模型: 算法假设一个信道模型,其中包丢失概率由两部分组成:

    • 固有丢失(inherent_loss: 代表与拥塞无关的随机丢包(如无线链路错误)。

    • 拥塞丢失: 当发送速率(sending_rate)超过信道的“丢包受限带宽”(loss_limited_bandwidth)时,按一定比例((sending_rate - loss_limited_bandwidth) / sending_rate)产生额外丢包。
      总的丢包概率函数为:
      loss_probability = inherent_loss + (1 - inherent_loss) * max(0, (sending_rate - loss_limited_bandwidth) / sending_rate)

  2. 定义似然函数: 给定一组观测到的包接收/丢失情况,计算在这组信道参数(inherent_lossloss_limited_bandwidth)下,观察到这组结果的似然度(Likelihood)。似然度是模型参数的函数。

  3. 最大化似然函数: 算法的目标是找到一组参数(inherent_lossloss_limited_bandwidth),使得观察到的数据的似然度最大。这组参数就是最可能产生当前观测数据的信道状态,其中的loss_limited_bandwidth就是最终的带宽估计值。

  4. 牛顿法优化: 为了高效地找到使似然函数最大化的参数,算法对inherent_loss参数使用了牛顿法(Newton's Method)进行迭代优化。GetDerivatives()函数计算似然函数的一阶和二阶导数,NewtonsMethodUpdate()根据导数更新inherent_loss的值。

  5. 高带宽偏好: 为了防止算法在存在随机丢包(高inherent_loss)时过于保守,似然函数中引入了一个高带宽偏置项(high_bandwidth_bias。该项会随着候选带宽的增加而增加,从而让算法更倾向于选择高带宽的估计,即使它需要假设一个更高的固有丢包率来解释观测到的丢包。GetHighBandwidthBias()AdjustBiasFactor()负责计算这个偏置。

3. 关键数据结构

  • LossBasedBweV2::Config

    • 作用: 包含所有可配置的实验参数,通过字段试验字符串(如WebRTC-Bwe-LossBasedBweV2)解析而来。这些参数控制着算法的几乎所有方面,包括观察窗口大小、候选因子、牛顿法迭代次数、各种阈值和开关等。其有效性由IsConfigValid()函数验证。

    • 重要性: 使得算法行为高度可调,便于A/B测试和算法迭代。

  • LossBasedBweV2::ChannelParameters

    • 作用: 表示信道模型的一个候选参数集。

      • loss_limited_bandwidth: 待评估的带宽估计值。

      • inherent_loss: 对应的固有丢包率估计。

    • 重要性: MLE优化过程的核心操作对象。

  • LossBasedBweV2::Observation

    • 作用: 存储一个时间窗口内的丢包观测结果。由多次UpdateBandwidthEstimate调用中积累的PacketResult汇总而成,直到持续时间满足observation_duration_lower_bound

      • num_packetsnum_lost_packetsnum_received_packets

      • sizelost_size (字节数,use_byte_loss_rate为true时使用)

      • sending_rate: 该观测窗口内的平均发送速率(经过平滑处理)。

      • id: 观测的唯一ID,用于时间加权。

    • 重要性: 是似然计算的基础数据单元。

  • LossBasedBweV2::Result

    • 作用: 算法的输出结果。

      • bandwidth_estimate: 最终计算出的基于丢包的带宽估计值。

      • state: 估计器的状态(Increasing/Decreasing/DelayBasedEstimate),用于指导拥塞控制行为。

  • HoldInfo 和 PaddingInfo

    • 作用: 用于实现状态保持(Hold)填充(Padding)逻辑。

      • HoldInfo: 在估计减少后,暂时限制估计值的增长幅度和持续时间,避免过快回升再次引发丢包。

      • PaddingInfo: 当状态为kIncreaseUsingPadding时,记录用于判断是否持续进行填充探测的速率和时间戳。

    • 重要性: 这些是增强算法稳定性和主动探测能力的机制。

4. 核心方法详解

  • UpdateBandwidthEstimate

    • 入口方法。接收新的包反馈信息(packet_results)、当前的延迟估计值(delay_based_estimate)和是否在应用限制区域(in_alr)的标志。

    • 流程:

      1. 更新观测值: 调用PushBackObservation将新的包结果汇总到当前部分观测中,如果持续时间足够,则创建一个新的Observation并加入环形缓冲区。

      2. 生成候选: 调用GetCandidates生成一组待评估的ChannelParameters候选。候选来自:

        • 当前估计乘以配置的candidate_factors(如1.02, 1.0, 0.95)。

        • 确认速率(acknowledged_bitrate_)。

        • 延迟估计值(delay_based_estimate_)。

        • 即时上限(GetInstantUpperBound(),在ALR状态下)。

      3. 评估候选: 对每个候选,使用牛顿法优化其inherent_lossNewtonsMethodUpdate),然后计算其似然函数值加上高带宽偏置后的目标函数值GetObjective)。

      4. 选择最佳候选: 选择目标函数值最大的候选作为best_candidate

      5. 应用约束和规则

        • 平均丢失检查: 如果平均上报丢包率大于最佳候选的固有丢包率,可能禁止增加(not_increase_if_inherent_loss_less_than_average_loss)。

        • 延迟增加窗口: 在刚减少带宽后的一段时间(delayed_increase_window)内,限制增长上限(bandwidth_limit_in_current_window)。

        • 确认速率约束: 在丢包受限状态下,如果估计要增加,则其上限受acknowledged_bitrate_乘以一个因子约束。

      6. 最终边界处理: 将最佳候选的带宽与即时下限(GetInstantLowerBound,主要来自确认速率)、即时上限(GetInstantUpperBound,基于平均丢包率计算)和延迟估计值进行比对,得到最终的bounded_bandwidth_estimate

      7. 状态机更新: 根据最终估计值的变化、与延迟估计的关系以及Hold/Padding的状态,决定新的LossBasedState

      8. 更新内部状态: 设置current_best_estimate_loss_based_result_last_hold_info_last_padding_info_等。

  • GetCandidates

    • 根据配置和当前状态,生成一系列带宽候选值,然后为每个带宽值创建一个ChannelParameters结构体,并为其设置一个可行的初始inherent_lossGetFeasibleInherentLoss)。

  • GetDerivatives 和 NewtonsMethodUpdate

    • MLE优化的核心。GetDerivatives计算当前参数下似然函数对inherent_loss的一阶和二阶导数。NewtonsMethodUpdate根据牛顿迭代公式 inherent_loss -= step_size * (first_derivative / second_derivative) 更新参数,并将结果钳位到可行范围内 [inherent_loss_lower_bound, GetInherentLossUpperBound]

  • GetObjective

    • 计算候选参数的目标函数值,即对数似然值 + 高带宽偏置。算法目标是最大化该函数。

  • GetInstantUpperBound 和 CalculateInstantUpperBound

    • 基于近期平均丢包率计算一个带宽上限。其模型为:instant_upper_bound = bandwidth_balance / (average_loss - loss_offset)。如果平均丢包率很低,这个上限会很高(max_bitrate_),丢包率越高,这个上限越低。

  • GetInstantLowerBound 和 CalculateInstantLowerBound

    • 计算带宽下限,通常取max(min_bitrate_, acknowledged_bitrate_ * factor)。确保估计值不会低于当前网络的实际吞吐量太多。

5. 设计亮点

  1. 基于模型的MLE方法: 相比于简单的丢包阈值法(如SendSideBandwidthEstimation中使用的),V2版本采用了更严谨的概率模型和优化方法,理论上能更准确地反映网络状态。

  2. 灵活可配置性: 通过大量的字段试验参数暴露了算法的核心旋钮,使得算法可以快速迭代和调优,无需修改代码。

  3. 多候选评估: 不是只做一次优化,而是生成多个候选点并评估,避免陷入局部最优,并能融合其他估计源(如延迟估计、确认速率)。

  4. 状态机与控制逻辑: 输出的State为上层控制器提供了丰富的语义信息,使得拥塞控制策略可以更精细,例如区分“可用填充数据探测”的增加和普通增加。

  5. 时间加权: 对观测窗口内的历史数据使用指数衰减加权(temporal_weights_),更重视近期的网络状况。

  6. Hold机制: 在带宽下降后引入一个“冷静期”,防止估计过快反弹,提高稳定性。

  7. 区分包丢失率和字节丢失率: 通过use_byte_loss_rate开关,可以选择是基于包计数还是基于字节计数来计算丢包率,以适应不同的场景。

6. 典型工作流程

  1. 初始化: 创建LossBasedBweV2对象,通过字段试验解析并验证配置(CreateConfigIsConfigValid)。初始化观察窗口、权重向量等。初始状态为未就绪。

  2. 设置初始值: 通常由上层控制器调用SetBandwidthEstimate或通过UpdateBandwidthEstimate传入的第一个delay_based_estimate来设置初始带宽估计。

  3. 持续更新

    • 上层控制器定期(如每次收到传输反馈时)调用UpdateBandwidthEstimate

    • 该方法汇总包反馈,形成观测点。

    • 生成多个候选带宽值。

    • 对每个候选,优化其固有丢包率,并计算目标函数。

    • 选择最佳候选。

    • 应用各种约束和规则(Hold、ACK速率约束等)得到最终估计。

    • 根据最终估计值的变化和与其他估计值的关系,更新状态机。

    • 返回Result(带宽+状态)。

  4. 控制决策: 上层控制器(如GoogCCNetworkController)根据返回的Result中的statebandwidth_estimate,结合其他模块(如延迟基于BWE、探测器)的输出,最终决定目标码率、是否发起探测等控制命令。

7. LossBasedBweV2 核心算法流程图

7.1.总体流程图

7.2.处理包结果并创建观测

7.3.生成候选带宽值

7.4.评估候选并选择最佳

7.5.应用后处理规则

7.6.确定最终估计与状态

7.7.牛顿法优化过程

8.核心算法精解

void LossBasedBweV2::UpdateBandwidthEstimate(rtc::ArrayView<const PacketResult> packet_results,DataRate delay_based_estimate,bool in_alr) {// 存储延迟基于的带宽估计值,用于后续比较和约束delay_based_estimate_ = delay_based_estimate;// 检查估计器是否已启用if (!IsEnabled()) {RTC_LOG(LS_WARNING) << "The estimator must be enabled before it can be used.";return;}// 检查是否有包结果数据if (packet_results.empty()) {RTC_LOG(LS_VERBOSE) << "The estimate cannot be updated without any loss statistics.";return;}// 处理包结果并创建观测数据if (!PushBackObservation(packet_results)) {return;}// 如果当前最佳估计尚未初始化,使用延迟基于的估计进行初始化if (!IsValid(current_best_estimate_.loss_limited_bandwidth)) {if (!IsValid(delay_based_estimate)) {RTC_LOG(LS_WARNING) << "The delay based estimate must be finite: " << ToString(delay_based_estimate);return;}current_best_estimate_.loss_limited_bandwidth = delay_based_estimate;loss_based_result_ = {.bandwidth_estimate = delay_based_estimate,.state = LossBasedState::kDelayBasedEstimate};}// 初始化最佳候选为当前最佳估计ChannelParameters best_candidate = current_best_estimate_;double objective_max = std::numeric_limits<double>::lowest();// 生成并评估所有候选带宽值for (ChannelParameters candidate : GetCandidates(in_alr)) {// 使用牛顿法优化候选的固有丢包率参数NewtonsMethodUpdate(candidate);// 计算候选的目标函数值const double candidate_objective = GetObjective(candidate);// 选择目标函数值最大的候选if (candidate_objective > objective_max) {objective_max = candidate_objective;best_candidate = candidate;}}// 如果估计值减少了,记录减少时间if (best_candidate.loss_limited_bandwidth <current_best_estimate_.loss_limited_bandwidth) {last_time_estimate_reduced_ = last_send_time_most_recent_observation_;}// 如果平均丢包率大于当前固有丢包率,且配置允许,禁止增加估计值if (GetAverageReportedLossRatio() > best_candidate.inherent_loss &&config_->not_increase_if_inherent_loss_less_than_average_loss &&current_best_estimate_.loss_limited_bandwidth <best_candidate.loss_limited_bandwidth) {best_candidate.loss_limited_bandwidth =current_best_estimate_.loss_limited_bandwidth;}// 如果处于丢包受限状态,应用额外的约束if (IsInLossLimitedState()) {// 在延迟增加窗口内限制估计值的增长if (recovering_after_loss_timestamp_.IsFinite() &&recovering_after_loss_timestamp_ + config_->delayed_increase_window >last_send_time_most_recent_observation_ &&best_candidate.loss_limited_bandwidth >bandwidth_limit_in_current_window_) {best_candidate.loss_limited_bandwidth =bandwidth_limit_in_current_window_;}// 检查估计是否在丢包受限状态下增加bool increasing_when_loss_limited = IsEstimateIncreasingWhenLossLimited(/*old_estimate=*/current_best_estimate_.loss_limited_bandwidth,/*new_estimate=*/best_candidate.loss_limited_bandwidth);// 如果估计在增加且确认速率有效,使用确认速率约束估计值if (increasing_when_loss_limited && IsValid(acknowledged_bitrate_)) {double rampup_factor = config_->bandwidth_rampup_upper_bound_factor;// 如果在保持状态下,使用不同的增长因子if (IsValid(last_hold_info_.rate) &&acknowledged_bitrate_ <config_->bandwidth_rampup_hold_threshold * last_hold_info_.rate) {rampup_factor = config_->bandwidth_rampup_upper_bound_factor_in_hold;}// 应用确认速率约束best_candidate.loss_limited_bandwidth =std::max(current_best_estimate_.loss_limited_bandwidth,std::min(best_candidate.loss_limited_bandwidth,rampup_factor * (*acknowledged_bitrate_)));// 如果状态为减少但估计值未变,稍微增加以确保状态切换if (loss_based_result_.state == LossBasedState::kDecreasing &&best_candidate.loss_limited_bandwidth ==current_best_estimate_.loss_limited_bandwidth) {best_candidate.loss_limited_bandwidth =current_best_estimate_.loss_limited_bandwidth +DataRate::BitsPerSec(1);}}}// 应用最终边界约束DataRate bounded_bandwidth_estimate = DataRate::PlusInfinity();if (IsValid(delay_based_estimate_)) {bounded_bandwidth_estimate =std::max(GetInstantLowerBound(),std::min({best_candidate.loss_limited_bandwidth,GetInstantUpperBound(), delay_based_estimate_}));} else {bounded_bandwidth_estimate = std::max(GetInstantLowerBound(), std::min(best_candidate.loss_limited_bandwidth,GetInstantUpperBound()));}// 如果配置要求约束最佳候选,并且约束后的估计小于最佳候选,重置估计if (config_->bound_best_candidate &&bounded_bandwidth_estimate < best_candidate.loss_limited_bandwidth) {RTC_LOG(LS_INFO) << "Resetting loss based BWE to " << bounded_bandwidth_estimate.kbps()<< "due to loss. Avg loss rate: " << GetAverageReportedLossRatio();current_best_estimate_.loss_limited_bandwidth = bounded_bandwidth_estimate;current_best_estimate_.inherent_loss = 0;} else {current_best_estimate_ = best_candidate;// 确保估计不低于确认速率的下限if (config_->lower_bound_by_acked_rate_factor > 0.0) {current_best_estimate_.loss_limited_bandwidth =std::max(current_best_estimate_.loss_limited_bandwidth,GetInstantLowerBound());}}// 处理保持状态下的估计约束if (loss_based_result_.state == LossBasedState::kDecreasing &&last_hold_info_.timestamp > last_send_time_most_recent_observation_ &&bounded_bandwidth_estimate < delay_based_estimate_) {// 确保确认速率是保持速率的下限if (config_->lower_bound_by_acked_rate_factor > 0.0) {last_hold_info_.rate =std::max(GetInstantLowerBound(), last_hold_info_.rate);}// 带宽估计不允许超过保持速率loss_based_result_.bandwidth_estimate =std::min(last_hold_info_.rate, bounded_bandwidth_estimate);return;}// 确定最终状态if (IsEstimateIncreasingWhenLossLimited(/*old_estimate=*/loss_based_result_.bandwidth_estimate,/*new_estimate=*/bounded_bandwidth_estimate) &&CanKeepIncreasingState(bounded_bandwidth_estimate) &&bounded_bandwidth_estimate < delay_based_estimate_ &&bounded_bandwidth_estimate < max_bitrate_) {// 设置增加状态,可能使用填充数据进行探测if (config_->padding_duration > TimeDelta::Zero() &&bounded_bandwidth_estimate > last_padding_info_.padding_rate) {last_padding_info_.padding_rate = bounded_bandwidth_estimate;last_padding_info_.padding_timestamp =last_send_time_most_recent_observation_;}loss_based_result_.state = config_->padding_duration > TimeDelta::Zero()? LossBasedState::kIncreaseUsingPadding: LossBasedState::kIncreasing;} else if (bounded_bandwidth_estimate < delay_based_estimate_ &&bounded_bandwidth_estimate < max_bitrate_) {// 设置减少状态if (loss_based_result_.state != LossBasedState::kDecreasing &&config_->hold_duration_factor > 0) {RTC_LOG(LS_INFO) << this << " " << "Switch to HOLD. Bounded BWE: "<< bounded_bandwidth_estimate.kbps()<< ", duration: " << last_hold_info_.duration.ms();last_hold_info_ = {.timestamp = last_send_time_most_recent_observation_ +last_hold_info_.duration,.duration =std::min(kMaxHoldDuration, last_hold_info_.duration *config_->hold_duration_factor),.rate = bounded_bandwidth_estimate};}last_padding_info_ = PaddingInfo();loss_based_result_.state = LossBasedState::kDecreasing;} else {// 重置保持和填充信息,使用延迟基于的估计last_hold_info_ = {.timestamp = Timestamp::MinusInfinity(),.duration = kInitHoldDuration,.rate = DataRate::PlusInfinity()};last_padding_info_ = PaddingInfo();loss_based_result_.state = LossBasedState::kDelayBasedEstimate;}// 设置最终带宽估计值loss_based_result_.bandwidth_estimate = bounded_bandwidth_estimate;// 更新延迟增加窗口和带宽限制if (IsInLossLimitedState() &&(recovering_after_loss_timestamp_.IsInfinite() ||recovering_after_loss_timestamp_ + config_->delayed_increase_window <last_send_time_most_recent_observation_)) {bandwidth_limit_in_current_window_ =std::max(kCongestionControllerMinBitrate,current_best_estimate_.loss_limited_bandwidth *config_->max_increase_factor);recovering_after_loss_timestamp_ = last_send_time_most_recent_observation_;}
}

LossBasedBweV2是WebRCC中一个设计复杂、高度可配置的第二代基于丢包的带宽估计器。它采用最大似然估计原理,结合了信道模型、优化算法、多源信息融合和状态机逻辑,旨在更准确、更稳定地从丢包事件中推断网络带宽,并为拥塞控制决策提供丰富的依据。


文章转载自:

http://9L512OxH.pfkpy.cn
http://1SZBKCxR.pfkpy.cn
http://Hham6ei3.pfkpy.cn
http://aZAl4s76.pfkpy.cn
http://WU1AkZLW.pfkpy.cn
http://MY6rUP4Z.pfkpy.cn
http://Oc6I0JKA.pfkpy.cn
http://zTUpeTGH.pfkpy.cn
http://qVpqhpjC.pfkpy.cn
http://pUdcrJm4.pfkpy.cn
http://CIr3XHWJ.pfkpy.cn
http://R2a1ZJBh.pfkpy.cn
http://FKoPxQJh.pfkpy.cn
http://FwH1n743.pfkpy.cn
http://8RdpueHA.pfkpy.cn
http://pXmLDbgI.pfkpy.cn
http://IIaakZLl.pfkpy.cn
http://Ug8aC9gh.pfkpy.cn
http://Il7RKZEP.pfkpy.cn
http://SlSihTPI.pfkpy.cn
http://K4mb0KV5.pfkpy.cn
http://Q7ruMXqz.pfkpy.cn
http://wXvZJnlH.pfkpy.cn
http://qr8Ced7x.pfkpy.cn
http://cNOExxzm.pfkpy.cn
http://ImkB1NgS.pfkpy.cn
http://KeX1AlO2.pfkpy.cn
http://C823dLuO.pfkpy.cn
http://8Sowd2Gh.pfkpy.cn
http://cyTjsss8.pfkpy.cn
http://www.dtcms.com/a/372152.html

相关文章:

  • leetcode hot100 二叉搜索树
  • 杂学项目1、S32K144与上位机通信
  • GitHub自动化利器:Probot框架实战指南
  • 一款没有任何限制的免费远程手机控制手机的软件简介
  • 企云网多应用授权系统源码 正版查询系统源码
  • Windows netstat 命令使用说明
  • 软件工程:DO-178中的适航要求核心要素
  • Caffeine Count-Min Sketch TinyLFU实现:FrequencySketch
  • 【系统分析师】第7章-基础知识:软件工程(核心总结)
  • 【拍摄学习记录】00-总结记录
  • 探索 CSS 过渡:打造流畅网页交互体验
  • 大语言模型(LLM)的基本概念
  • unsloth FastLanguageModel类主要函数详解,具体作用和参数
  • HTTPS协议——对于HTTP的协议的加密
  • Qwen2.5-VL翻译
  • 碳纤维和短切碳纤维(中)
  • unsloth 笔记: training的时候进行evaluation
  • 【linux kernel 常用数据结构和设计模式】【数据结构 1】【如何表达数据之间的一对一、一对多、多对多关系】
  • 【软件架构设计(19)】软件架构评估二:软件架构分析方法分类、质量属性场景、软件评估方法发展历程
  • 在OpenHarmony上适配图形显示【1】——确认drm是否正常
  • 四大金刚之计算机组成原理
  • 第 15 篇:PCA与降维——如何在信息爆炸的时代,抓住“主要矛盾”?
  • 《沈南鹏传 - 做最擅长的事》(中篇)读书笔记
  • 还在重启应用改 Topic?Spring Boot 动态 Kafka 消费的“终极形态”
  • 纸飞机飞行漂流瓶小游戏抖音快手微信小程序看广告流量主开源
  • 《沈南鹏传 - 做最擅长的事》(下篇)读书笔记
  • 网易UU远程,免费电脑远程控制软件
  • Prometheus 存储学习
  • 八.迪杰斯特拉(Dijkstra)算法
  • 大模型术语