webrtc代码走读(十)-QOS-Sender Side BWE原理

1、背景介绍

为什么 Sender Side BWE 是 WebRTC 的核心

BWE(Bandwidth Estimation,带宽估计)是 WebRTC 视频引擎中决定通讯质量的关键模块。其核心作用是:在保证网络不拥塞的前提下,动态计算发送端可承载的最大视频码率,直接避免因码率超出网络承载能力导致的画面卡顿、花屏等问题。

1.1 BWE 算法的演进历程

BWE 算法的发展本质是"从被动响应到主动预测"的升级,具体分为三个阶段:

阶段 核心逻辑 优缺点 代表算法
早期版本 基于丢包的被动评估:逐步增加发送量,直到检测到丢包才降低码率 优点:实现简单;缺点:丢包已代表网络拥塞,属于"事后补救",延迟高 基础丢包反馈算法
中期版本 基于延迟的主动预测:通过接收端时延变化预判拥塞,提前调整码率 优点:比丢包更灵敏,可避免拥塞发生;缺点:依赖接收端计算,反馈链路长 KalmanFilter(接收端计算)
最新版本 发送端本地化计算:将延迟分析逻辑迁移到发送端,减少反馈开销 优点:响应速度更快,减少网络往返延迟;缺点:对发送端算力有轻微要求 Trendline(发送端计算)
1.2 GCC vs Sender Side BWE

WebRTC 历史上存在两种主流拥塞控制算法,开发中需明确区分,避免代码混淆:

对比维度 GCC(Google Congest Control) Sender Side BWE
码控计算模块位置 接收端 发送端
RTP 头部扩展字段 AbsSendTime(绝对发送时间) TransportSequenceNumber(传输序列号)
接收端关键对象 RemoteBitrateEstimatorAbsSendTime RemoteEstimatorProxy
网络延时滤波器 Kalman Filter Trendline Filter
接收端反馈 RTCP 报文 REMB(Receiver Estimated Maximum Bitrate) TransportCC(Transport Congestion Control)
适用 WebRTC 版本 M55 之前 M55 之后(当前主流版本)

2 Sender Side BWE 的三大核心逻辑

Sender Side BWE 通过"多维度评估+动态融合"确定最终码率,核心逻辑分为三部分:REMB 兼容逻辑、基于丢包的拥塞控制、基于延迟的拥塞控制 ,最终取三者最小值作为发送码率(min(base, remb, bwe))。

2.1 REMB Bitrate:向下兼容逻辑

REMB(Receiver Estimated Maximum Bitrate)是 GCC 算法中接收端反馈的"建议最大码率"。在 Sender Side BWE 中,REMB 仅作为向下兼容老版本的备用逻辑,不参与主流计算。

  • 作用:当接收端为 M55 之前的老版本时,发送端仍能通过 REMB 报文获取码率建议,避免版本不兼容导致的通讯失败。
  • 优先级:最低,仅当基于延迟和丢包的计算结果无效时才使用。
2.2 基于丢包的拥塞控制:通过丢包率直接调整码率

核心思想

丢包率直接反映网络拥塞程度:

  • 丢包率极低(<2%):网络空闲,可提升码率;
  • 丢包率高(>10%):网络拥塞,需降低码率;
  • 丢包率中等(2%~10%):网络处于临界状态,维持当前码率。

关键公式与阈值

WebRTC 中通过以下逻辑计算丢包调整后的码率:

plaintext 复制代码
if 丢包率 fL(tk) < 0.02(2%):
    码率 = 当前码率 × 1.08 + 1000bps(8%增长+保底1kbps,避免低码率时停滞)
elif 丢包率 fL(tk) > 0.1(10%):
    码率 = 当前码率 × (512 - 丢包率×256) / 512(约等于码率 × (1 - 0.5×丢包率))
else:
    码率保持不变
  • 阈值说明:low_loss_threshold_ = 0.02f(2%)、high_loss_threshold_ = 0.1f(10%),为 WebRTC 内置默认值,开发中可通过 BitrateController 接口修改。
2.3 基于延迟的拥塞控制:预测拥塞的核心逻辑

基于延迟的拥塞控制是 Sender Side BWE 的核心 ,通过分析"包组到达时间的延迟趋势"预判网络状态,分为四个关键步骤:包组延迟评估(InterArrival)→ 滤波器趋势判断(TrendlineEstimator)→ 过载检测(OveruseDetector)→ 码率调节(AimdRateControl)

2.3.1 步骤1:包组延迟评估(InterArrival)------ 为什么要按"组"计算延迟?

  • 问题本质:视频帧可能被拆分为多个 RTP 包(如 1 帧 1080P 视频可能拆分为 10 个 RTP 包),若单个包计算延迟,会因"同一帧内包的发送间隔极短"导致延迟计算失真。
  • 解决方案:按"帧"分组(即"包组"),计算两组包的延迟差,核心参数如下:
参数 定义 计算公式 示例
delta_timestamp 两组包的发送时间差 T2(第二组最后一个包的发送时间) - T1(第一组最后一个包的发送时间) 若两组包分属不同帧,发送间隔为 40ms(25fps 帧率),则 delta_timestamp = 40ms
delta_arrival 两组包的到达时间差 t2(第二组最后一个包的到达时间) - t1(第一组最后一个包的到达时间) 若网络延迟稳定,delta_arrival ≈ delta_timestamp;若网络拥塞,delta_arrival > delta_timestamp
delta_size 两组包的大小差 第二组包的总字节数 - 第一组包的总字节数 若第一组 10KB,第二组 12KB,则 delta_size = 2KB

步骤2:Trendline 滤波趋势判断------ 如何量化延迟趋势?

Trendline 滤波器的核心是:通过"累积延迟"和"平滑延迟"计算延迟增长斜率,斜率越大,说明网络拥塞越严重。

关键计算步骤(附公式与注释)

  1. 单个包组的延迟增长值
    delay_i = delta_arrival - delta_timestamp

    • 含义:若 delay_i > 0,说明当前组的到达延迟比上一组高,网络开始堆积数据;若 delay_i < 0,说明网络延迟降低。
  2. 累积延迟
    acc_delay_i = acc_delay_{i-1} + delay_i

    • 含义:叠加历史延迟增长值,反映延迟的长期趋势。
  3. 平滑延迟(避免瞬时波动影响)
    smo_delay_i = alpha × smo_delay_{i-1} + (1 - alpha) × acc_delay_i

    • 参数:alpha = 0.9(WebRTC 内置,平衡平滑度与响应速度);
    • 作用:过滤瞬时延迟抖动,避免因单个包的网络波动误判拥塞。
  4. 趋势斜率计算

    • 分子(numerator):sum( (trans_k - trans_avg) × (smo_delay_k - smo_delay_avg) )
      • trans_k:第 k 组包的传输持续时间(从组内第一个包到达至最后一个包到达的时间);
      • trans_avg:所有组 trans_k 的平均值;
      • smo_delay_avg:所有组 smo_delay_k 的平均值。
    • 分母(denominator):sum( (trans_k - trans_avg)^2 )
    • 最终趋势值:trendline_i = numerator / denominator
      • 含义:trendline_i > 0 表示延迟呈上升趋势(网络拥塞);trendline_i < 0 表示延迟呈下降趋势(网络空闲)。

步骤3:过载检测(OveruseDetector)------ 如何判断网络状态?

通过 Trendline 计算的 trendline_i,结合动态阈值 gamma_1,判断网络处于"过载(overuse)""正常(normal)"还是"未充分利用(underuse)",核心是一个有限状态机

状态机迁移逻辑(伪代码)

plaintext 复制代码
// 输入:当前包组的趋势值 trendline_i,周期内包组个数 N
m_i = trendline_i × N  // 周期内总趋势值,放大趋势差异

if m_i > gamma_1(动态阈值,由网络抖动自适应调整):
    // 延迟增长过快,网络过载
    current_state = overuse
    // 过载时,需记录过载持续时间,避免瞬时波动误判
    overuse_time += delta_T
    if overuse_time > overuse_threshold:
        // 过载持续超过阈值,触发码率下降
        trigger_rate_decrease()
elif m_i < -gamma_1:
    // 延迟下降,网络未充分利用
    current_state = underuse
    trigger_rate_increase()  // 触发码率上升
else:
    // 延迟稳定,网络正常
    current_state = normal
    maintain_current_rate()  // 维持当前码率

步骤4:AIMD 码率调节(AimdRateControl)------ 如何调整码率?

AIMD(Additive Increase Multiplicative Decrease,和式增加,积式减少)是 TCP 拥塞控制的经典思想,WebRTC 对其进行了适配,核心逻辑根据网络状态动态调整码率。

关键调节规则(附公式)
网络状态 调节策略 公式/说明 示例
未充分利用(underuse) 分阶段增长: 1. 会话初期(慢启动):倍数增长 2. 稳定期:线性增长 1. 慢启动:new_bitrate = current_bitrate × 1.08(8%倍数增长) 2. 稳定期:new_bitrate = current_bitrate + (RTT 周期内可传输码率) 若当前码率 1Mbps,慢启动后变为 1.08Mbps;稳定期若 RTT 为 100ms,可增加 1Mbps × 0.1 = 100kbps
过载(overuse) 乘法下降:基于过去 500ms 内的最大确认码率 new_bitrate = max_acked_bitrate_500ms × 0.85(降低 15%) 若过去 500ms 最大确认码率为 1Mbps,下降后为 850kbps
正常(normal) 维持当前码率 new_bitrate = current_bitrate -

3、WebRTC 源码实现解析

以下基于 WebRTC M100+ 版本源码,梳理 Sender Side BWE 的核心函数调用链。

  • src/modules/congestion_controller/send_side_congestion_controller.cc
  • src/modules/bitrate_controller/send_side_bandwidth_estimation.cc
  • src/modules/congestion_controller/delay_based_bwe/delay_based_bwe.cc
3.1 核心函数调用链总览

Sender Side BWE 的触发入口是"接收端 RTCP 反馈报文的处理",整体调用链如下:

plaintext 复制代码
// 1. 接收 RTCP 报文(TransportCC 或 RR)
BaseChannel::ProcessPacket → WebRtcVideoChannel::OnRtcpReceived → Call::DeliverRtcp → VideoSendStreamImpl::DeliverRtcp
// 2. 解析 RTCP 报文,触发拥塞控制回调
→ ModuleRtpRtcpImpl::IncomingRtcpPacket → RTCPReceiver::IncomingPacket → RTCPReceiver::TriggerCallbacksFromRtcpPacket
// 3. 分支1:基于延迟的拥塞控制(核心)
→ SendSideCongestionController::OnTransportFeedback → DelayBasedBwe::IncomingPacketFeedbackVector → BitrateControllerImpl::OnDelayBasedBweResult
// 3. 分支2:基于丢包的拥塞控制
→ BitrateControllerImpl::RtcpBandwidthObserverImpl::OnReceivedRtcpReceiverReport → BitrateControllerImpl::OnReceivedRtcpReceiverReport
// 4. 融合所有评估结果,确定最终码率
→ SendSideBandwidthEstimation::UpdateEstimate → SendSideBandwidthEstimation::CapBitrateToThresholds
// 5. 将码率更新到发送端各模块( pacing、FEC、编码器)
→ SendSideCongestionController::MaybeTriggerOnNetworkChanged
3.2 关键函数源码

基于延迟的拥塞控制:DelayBasedBwe::IncomingPacketFeedbackVector

cpp 复制代码
/**
 * @brief 接收端反馈的包组到达信息,更新延迟统计并计算 BWE 值
 * @param packet_feedbacks:接收端反馈的包组列表(包含每个包的发送时间、到达时间、序列号)
 * @param now_ms:当前时间(毫秒)
 * @return void
 * @note 该函数是基于延迟拥塞控制的入口,负责将反馈信息传递给 InterArrival 和 TrendlineEstimator
 */
void DelayBasedBwe::IncomingPacketFeedbackVector(
    const std::vector<PacketFeedback>& packet_feedbacks,
    int64_t now_ms) {
  // 遍历每个包的反馈信息,按包组分组(同一帧的包为一组)
  for (const auto& feedback : packet_feedbacks) {
    // 1. 检查包是否属于新的包组(通过序列号判断,同一帧的包序列号连续)
    if (!inter_arrival_->IsPacketInOrder(feedback.sequence_number)) {
      // 包乱序,跳过(乱序会导致延迟计算失真)
      continue;
    }

    // 2. 计算当前包组的延迟参数(delta_timestamp、delta_arrival、delta_size)
    std::optional<InterArrival::Result> result = inter_arrival_->ComputeDeltas(
        feedback.send_time_ms,  // 包的发送时间
        feedback.arrival_time_ms,  // 包的到达时间
        feedback.payload_size,  // 包的 payload 大小
        feedback.sequence_number,  // 包的序列号
        now_ms);

    // 3. 若成功计算出包组延迟参数,更新 Trendline 滤波器
    if (result) {
      // 调用 TrendlineEstimator 计算延迟趋势
      trendline_estimator_->Update(
          result->delta_send_time_ms,  // delta_timestamp
          result->delta_arrival_time_ms,  // delta_arrival
          result->delta_payload_size,  // delta_size
          now_ms);

      // 4. 调用 OveruseDetector 判断网络是否过载
      OveruseDetector::State overuse_state = overuse_detector_->Detect(
          trendline_estimator_->trendline_slope(),  // 延迟趋势斜率
          result->delta_arrival_time_ms,
          now_ms);

      // 5. 根据过载状态,通过 AIMD 调节码率
      aimd_rate_control_->Update(
          overuse_state,  // 网络过载状态
          trendline_estimator_->time_since_last_update_ms(),
          now_ms);
    }
  }

  // 6. 将计算出的 BWE 值(基于延迟)传递给 BitrateController
  int64_t target_bitrate_bps = aimd_rate_control_->GetTargetBitrate();
  OnDelayBasedBweResult(target_bitrate_bps, now_ms);
}

基于丢包的拥塞控制:SendSideBandwidthEstimation::UpdateEstimate

cpp 复制代码
/**
 * @brief 基于丢包率更新码率估计,是丢包拥塞控制的核心逻辑
 * @param now_ms:当前时间(毫秒)
 * @return void
 * @note 该函数结合丢包率、历史码率、反馈超时等因素,计算丢包调整后的码率
 */
void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
  uint32_t new_bitrate = current_bitrate_bps_;  // 初始化为当前码率

  // 1. 会话启动初期(前 2 秒)且无丢包:优先使用基于延迟的 BWE 值(快速启动)
  if (last_fraction_loss_ == 0 && IsInStartPhase(now_ms)) {
    // 取"基于延迟的 BWE"和"当前码率"的最大值(快速提升码率)
    new_bitrate = std::max(bwe_incoming_, new_bitrate);
    new_bitrate = std::max(delay_based_bitrate_bps_, new_bitrate);

    if (new_bitrate != current_bitrate_bps_) {
      min_bitrate_history_.clear();  // 清空历史最小码率(启动期无需参考历史)
      min_bitrate_history_.push_back(std::make_pair(now_ms, current_bitrate_bps_));
      CapBitrateToThresholds(now_ms, new_bitrate);  // 限制码率在 [min, max] 范围内
      return;
    }
  }

  // 2. 更新历史最小码率(用于后续码率增长计算)
  UpdateMinHistory(now_ms);

  // 3. 无任何反馈(如接收端离线):维持当前码率
  if (last_packet_report_ms_ == -1) {
    CapBitrateToThresholds(now_ms, current_bitrate_bps_);
    return;
  }

  // 4. 检查反馈是否超时(反馈间隔是否过长)
  int64_t time_since_packet_report_ms = now_ms - last_packet_report_ms_;
  int64_t time_since_feedback_ms = now_ms - last_feedback_ms_;

  // 5. 反馈未超时:基于丢包率调整码率
  if (time_since_packet_report_ms < 1.2 * kFeedbackIntervalMs) {
    // 转换丢包率(RTCP RR 报文中的丢包率是 0~255 的整数,需转为 0~1 的浮点数)
    float loss = last_fraction_loss_ / 256.0f;

    // 仅当码率高于阈值时,才基于丢包率调整(过滤非拥塞导致的丢包,如网络抖动)
    if (current_bitrate_bps_ < bitrate_threshold_bps_ || loss <= low_loss_threshold_) {
      // 情况1:丢包率 < 2% 或码率过低:码率增长 8% + 1kbps(避免低码率停滞)
      new_bitrate = static_cast<uint32_t>(
          min_bitrate_history_.front().second * 1.08 + 0.5);  // 8% 增长,四舍五入
      new_bitrate += 1000;  // 额外加 1kbps,低码率场景(如 10kbps)效果明显
    } else if (current_bitrate_bps_ > bitrate_threshold_bps_) {
      if (loss <= high_loss_threshold_) {
        // 情况2:丢包率 2%~10%:维持当前码率
        new_bitrate = current_bitrate_bps_;
      } else {
        // 情况3:丢包率 >10%:降低码率(每 kBweDecreaseIntervalMs + RTT 周期仅降一次)
        if (!has_decreased_since_last_fraction_loss_ &&
            (now_ms - time_last_decrease_ms_) >= (kBweDecreaseIntervalMs + last_round_trip_time_ms_)) {
          time_last_decrease_ms_ = now_ms;  // 记录上次降低时间,避免频繁降码率
          // 码率降低公式:newRate = 当前码率 × (512 - 丢包率×256) / 512 ≈ 当前码率 × (1 - 0.5×丢包率)
          new_bitrate = static_cast<uint32_t>(
              (current_bitrate_bps_ * static_cast<double>(512 - last_fraction_loss_)) / 512.0);
          has_decreased_since_last_fraction_loss_ = true;  // 标记已降低,避免重复操作
        }
      }
    }
  } 
  // 6. 反馈超时(接收端长时间未反馈):降低码率(应对网络断连风险)
  else if (time_since_feedback_ms > kFeedbackTimeoutIntervals * kFeedbackIntervalMs &&
           (last_timeout_ms_ == -1 || now_ms - last_timeout_ms_ > kTimeoutIntervalMs)) {
    if (in_timeout_experiment_) {
      LOG(LS_WARNING) << "Feedback timed out (" << time_since_feedback_ms 
                      << " ms), reducing bitrate.";
      new_bitrate *= 0.8;  // 超时后码率降低 20%
      // 重置丢包统计(避免超时后重复处理旧丢包)
      lost_packets_since_last_loss_update_Q8_ = 0;
      expected_packets_since_last_loss_update_ = 0;
      last_timeout_ms_ = now_ms;  // 记录上次超时时间
    }
  }

  // 7. 限制码率在 [min_bitrate_configured_, max_bitrate_configured_] 范围内
  CapBitrateToThresholds(now_ms, new_bitrate);
}

*融合所有评估结果:SendSideBandwidthEstimation::CapBitrateToThresholds

cpp 复制代码
/**
 * @brief 融合"基于延迟的 BWE""基于丢包的 BWE""REMB",并限制码率在配置范围内
 * @param now_ms:当前时间(毫秒)
 * @param bitrate_bps:待调整的码率(输入值)
 * @return void
 * @note 该函数是 Sender Side BWE 的"最终决策层",输出最终发送码率
 */
void SendSideBandwidthEstimation::CapBitrateToThresholds(int64_t now_ms,
                                                         uint32_t bitrate_bps) {
  // 1. 若 REMB 有效(兼容老版本),码率不能超过 REMB 值
  if (bwe_incoming_ > 0 && bitrate_bps > bwe_incoming_) {
    bitrate_bps = bwe_incoming_;
  }

  // 2. 若基于延迟的 BWE 有效,码率不能超过延迟 BWE 值(核心限制)
  if (delay_based_bitrate_bps_ > 0 && bitrate_bps > delay_based_bitrate_bps_) {
    bitrate_bps = delay_based_bitrate_bps_;
  }

  // 3. 码率不能超过配置的最大码率(开发者可通过 API 设置,如 setMaxBitrate)
  if (bitrate_bps > max_bitrate_configured_) {
    bitrate_bps = max_bitrate_configured_;
  }

  // 4. 码率不能低于配置的最小码率(避免画面质量过低)
  if (bitrate_bps < min_bitrate_configured_) {
    // 每隔 kLowBitrateLogPeriodMs 打印一次警告日志(避免日志刷屏)
    if (last_low_bitrate_log_ms_ == -1 ||
        now_ms - last_low_bitrate_log_ms_ > kLowBitrateLogPeriodMs) {
      LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate_bps / 1000
                      << " kbps is below configured min bitrate "
                      << min_bitrate_configured_ / 1000 << " kbps.";
      last_low_bitrate_log_ms_ = now_ms;
    }
    bitrate_bps = min_bitrate_configured_;
  }

  // 5. 若码率变化或丢包率变化,记录 RTC 事件日志(用于调试)
  if (bitrate_bps != current_bitrate_bps_ ||
      last_fraction_loss_ != last_logged_fraction_loss_ ||
      now_ms - last_rtc_event_log_ms_ > kRtcEventLogPeriodMs) {
    event_log_->LogLossBasedBweUpdate(bitrate_bps, last_fraction_loss_,
                                      expected_packets_since_last_loss_update_);
    last_logged_fraction_loss_ = last_fraction_loss_;
    last_rtc_event_log_ms_ = now_ms;
  }

  // 6. 更新当前码率(最终结果)
  current_bitrate_bps_ = bitrate_bps;
}

码率更新到发送端模块:SendSideCongestionController::MaybeTriggerOnNetworkChanged

cpp 复制代码
/**
 * @brief 将最终码率更新到发送端各核心模块( pacing、FEC、编码器)
 * @return void
 * @note 该函数是 Sender Side BWE 的"执行层",确保码率调整生效
 */
void SendSideCongestionController::MaybeTriggerOnNetworkChanged() {
  uint32_t bitrate_bps;       // 最终码率(bps)
  uint8_t fraction_loss;      // 丢包率(0~255)
  int64_t rtt;                // 网络往返延迟(ms)
  // 1. 从 BitrateController 获取最新的网络参数(码率、丢包率、RTT)
  bool estimate_changed = bitrate_controller_->GetNetworkParameters(
      &bitrate_bps, &fraction_loss, &rtt);

  // 2. 若码率变化,更新 Pacer(发送 pacing 模块,控制发送速率避免突发)
  if (estimate_changed) {
    pacer_->SetEstimatedBitrate(bitrate_bps);  // 调整 pacing 速率
    probe_controller_->SetEstimatedBitrate(bitrate_bps);  // 调整带宽探测速率
    retransmission_rate_limiter_->SetMaxRate(bitrate_bps);  // 调整重传速率上限
  }

  // 3. 处理网络断连或发送队列满的情况:码率设为 0(暂停发送)
  bitrate_bps = IsNetworkDown() || IsSendQueueFull() ? 0 : bitrate_bps;

  // 4. 若网络参数(码率、丢包率、RTT)变化,通知观察者(如编码器、FEC 模块)
  if (HasNetworkParametersToReportChanged(bitrate_bps, fraction_loss, rtt)) {
    int64_t probing_interval_ms;
    {
      rtc::CritScope cs(&bwe_lock_);  // 加锁,线程安全
      // 获取 BWE 周期(用于后续带宽探测)
      probing_interval_ms = delay_based_bwe_->GetExpectedBwePeriodMs();
    }

    {
      rtc::CritScope cs(&observer_lock_);  // 加锁,线程安全
      if (observer_) {
        // 通知观察者:网络参数变化,需调整编码码率、FEC 冗余度等
        observer_->OnNetworkChanged(bitrate_bps, fraction_loss, rtt,
                                    probing_interval_ms);
        // 示例:观察者可能是 VideoEncoder,此时会调用 SetRates(bitrate_bps) 调整编码码率
      }
    }
  }
}

4、开发应用实践:如何基于 Sender Side BWE 优化 WebRTC 应用

4.1 关键配置参数调整(提升通讯质量)

在实际开发中,可通过 WebRTC 的 API 调整以下参数,优化 Sender Side BWE 效果:

参数 作用 推荐配置 API 示例(C++)
最小码率(min_bitrate) 避免码率过低导致画面模糊 视频通话:300kbps(480P);直播:1Mbps(720P) webrtc::VideoSendStream::Config config; config.min_bitrate_bps = 300000;
最大码率(max_bitrate) 避免码率过高导致拥塞 基于网络环境:WiFi 设为 8Mbps(1080P);4G 设为 4Mbps config.max_bitrate_bps = 8000000;
BWE 启动期(start_phase_duration) 会话初期快速提升码率的时间 默认 2000ms(2秒),可根据需求调整为 3000ms send_side_bwe_.SetStartPhaseDurationMs(3000);
丢包率阈值(low_loss_threshold/high_loss_threshold) 调整丢包触发码率变化的敏感度 弱网环境可降低 high_loss_threshold 至 0.08(8%) send_side_bwe_.SetLossThresholds(0.02f, 0.08f);
4.2 常见问题与解决方案
问题现象 可能原因 解决方案
会话初期画面卡顿 BWE 启动期码率提升过慢 1. 延长启动期(SetStartPhaseDurationMs(3000));2. 增大启动期码率增长倍数(需修改 AIMD 源码)
弱网环境下码率频繁波动 延迟抖动导致 OveruseDetector 误判 1. 增大 Trendline 滤波器的 alpha 值(如 0.95);2. 提高过载检测的阈值 gamma_1
码率始终低于配置的最小码率 网络拥塞严重,BWE 计算结果过低 1. 检查是否配置了正确的最小码率;2. 优化视频编码参数(如降低分辨率、提高压缩率)
4.3 调试工具与日志分析

开发中可通过以下工具分析 Sender Side BWE 的运行状态:

  1. RTC 事件日志 :通过 event_log_->LogLossBasedBweUpdate 记录码率、丢包率变化,可使用 WebRTC 提供的 rtc_event_log_analyzer 工具可视化分析;
  2. Wireshark 抓包:过滤 TransportCC(RTCP 类型 205)或 REMB(RTCP 类型 206)报文,查看接收端反馈的延迟和丢包信息;
  3. WebRTC 内置 metrics :通过 webrtc::Metrics 模块获取 bwe_delay_based_bitratebwe_loss_based_bitrate 等指标,实时监控 BWE 计算结果。
相关推荐
音视频牛哥1 天前
RTMP/RTSP/WebRTC/SRT/HLS/DASH/GB28181/WebTransport/QUIC协议规范深度分析
人工智能·计算机视觉·音视频·webrtc·大牛直播sdk·dash·webtransport
周帝3 天前
一篇尘封已久的笔记-webRTC初探和学习建议
webrtc
撬动未来的支点4 天前
【音视频】WebRTC连接建立流程详解
webrtc
metaRTC5 天前
metaRTC7 mac/ios编程指南
macos·ios·webrtc
筏.k5 天前
WebRTC 集成 FFmpeg HEVC 硬件解码(hevc_cuvid)avcodec_open2错误码-558323010
ffmpeg·webrtc
qq_310658515 天前
webrtc代码走读(五)-QOS-FEC原理
网络·c++·webrtc
qq_310658516 天前
webrtc代码走读(七)-QOS-FEC-ulpfec rfc5109
网络·c++·webrtc
RTC老炮6 天前
webrtc弱网-PccBitrateController类源码分析与算法原理
网络·算法·webrtc
qq_310658517 天前
webrtc代码走读(八)-QOS-FEC-flexfec rfc8627
网络·c++·webrtc