webrtc中GCC拥塞控制模块之码率控制器AimdRateControl

   aimd的全称是Additive Increase Multiplicative Decrease,意思是:加性增加,乘性减少。AimdRateControl是一种码率控制实现,当未检测到over-use时,基于加性的码率增加,当检测到over-use时,基于乘性的比特率减少。当认为可用带宽有变化或未知时,我们将切换到“慢启动模式”,成倍增加。
   AimdRateControl码率控制模块有三种状态:kRcHold,kRcIncrease和kRcDecrease 。“kRcIncrease”是未检测到拥塞的状态;“kRcDecrease”是检测到拥塞的状态,“kRcHold”是等待累积队列耗尽后进入“增加”状态的状态,状态迁移过程取决于基于延迟的码率控制输出的网络状态,网络状态有三种:kRcHold,kBwOverusing和kBwUnderusing,码率控制的状态机如下:

在这里插入图片描述

状态Hold
   保持原码率,且状态继续保持Hold
状态kRcIncrease
   如果测量的吞吐量与估计值相差太远,则重置link_capacity估计值。因此,我们可以假设我们的目标速率与链接容量相当接近,并使用加性增加;如果我们没有对link_capacity的估计,可以使用更快的乘型增加。
码率加性算法因子:
加性因子计算为当前码率下平均码率ave_bitrate,
               ave_bitrate=avg_packet_size/(rtt+100)
其中avg_packet_size表示包平均字节大小,是在1/30秒时间间隔内在当前码率下,按单包最大1200字节计算的平均单包字节大小;rtt加100ms表示接近over-use的延时是时间,按最糟糕的情况计算ave_bitrate,然后与4000取最大。
ave_bitrate代码实现如下:

double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {
  const TimeDelta kFrameInterval = TimeDelta::seconds(1) / 30;//1/30秒的时间间隔
  DataSize frame_size = current_bitrate_ * kFrameInterval;//间隔内当前码率下的字节数
  const DataSize kPacketSize = DataSize::bytes(1200);//按最大1200字节包计算
  double packets_per_frame = std::ceil(frame_size / kPacketSize);//间隔内平均包个数,为浮点型
  DataSize avg_packet_size = frame_size / packets_per_frame;//每个包平均字节个数
  
  TimeDelta response_time = rtt_ + TimeDelta::ms(100);//rtt+100按最坏情况计算响应时间
  if (in_experiment_)
    response_time = response_time * 2;
  double increase_rate_bps_per_second =//计算平均码率
      (avg_packet_size / response_time).bps<double>();
  double kMinIncreaseRateBpsPerSecond = 4000;
  return std::max(kMinIncreaseRateBpsPerSecond, increase_rate_bps_per_second);//与4000取两者最大
}

码率乘性算法因子:
               alpha=alphamin(timeDelta,1)
其中alpha初始值为1.08,timeDelta为本次码率控制器更新码率时间与上一次更新码率时间的差,则乘性后的码率为max(curbitrate*alpha,curbitrate+1000)。代码如下:

DataRate AimdRateControl::MultiplicativeRateIncrease(
    Timestamp at_time,
    Timestamp last_time,
    DataRate current_bitrate) const {
  double alpha = 1.08;//默认乘性因子1.08
  if (last_time.IsFinite()) {
    auto time_since_last_update = at_time - last_time;//相邻两次码率控制器更新码率时间差
    alpha = pow(alpha, std::min(time_since_last_update.seconds<double>(), 1.0));//计算乘性因子
  }
  DataRate multiplicative_increase =
      std::max(current_bitrate * (alpha - 1.0), DataRate::bps(1000));
        return multiplicative_increase;
}

状态kRcDecrease
   如果网络处于over-use状态,需要减少码率,从ack计算的码率降低原来的85%,如果码率还是比码率控制器估计的码率大,则码率降低为链路容量link_capacity估计值的85%。

case kRcDecrease:
      // TODO(srte): Remove when |estimate_bounded_backoff_| has been validated.
      if (network_estimate_ && capacity_deviation_ratio_threshold_ &&
          !estimate_bounded_backoff_) {
        estimated_throughput = std::max(estimated_throughput,
                                        network_estimate_->link_capacity_lower);
      }
      if (estimated_throughput > low_throughput_threshold_) {//low_throughput_threshold_=0
        // 将比特率设置为略低于测量吞吐量的值,以消除任何自引起的延迟。
        new_bitrate = estimated_throughput * beta_;
        if (new_bitrate > current_bitrate_) {
          // 当过度使用时,避免增加速率。
          if (link_capacity_.has_estimate()) {
            new_bitrate = beta_ * link_capacity_.estimate();
          }
        }
        if (estimate_bounded_backoff_ && network_estimate_) {
          new_bitrate = std::max(
              new_bitrate, network_estimate_->link_capacity_lower * beta_);
        }
      } else {
        new_bitrate = estimated_throughput;
        if (link_capacity_.has_estimate()) {
          new_bitrate = std::max(new_bitrate, link_capacity_.estimate());
        }
        new_bitrate = std::min(new_bitrate, low_throughput_threshold_.Get());
      }
      new_bitrate = std::min(new_bitrate, current_bitrate_);

      if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) {
        constexpr double kDegradationFactor = 0.9;
        if (smoothing_experiment_ &&
            new_bitrate < kDegradationFactor * beta_ * current_bitrate_) {
          // If bitrate decreases more than a normal back off after overuse, it
          // indicates a real network degradation. We do not let such a decrease
          // to determine the bandwidth estimation period.
          last_decrease_ = absl::nullopt;
        } else {
          last_decrease_ = current_bitrate_ - new_bitrate;
        }
      }
      if (estimated_throughput < link_capacity_.LowerBound()) {
        // The current throughput is far from the estimated link capacity. Clear
        // the estimate to allow an immediate update in OnOveruseDetected.
        link_capacity_.Reset();
      }

更新link_capacity估计值
根据ack测量的吞吐量更新链路容量估计值,初始时将测量的码率赋予链路容量,
      estimate_kbps_ = (1 - alpha) * estimate_kbps_.value() + alpha * sample_kbps;
其中estimate_kbps_为链路容量,alpha为计算因子alpha=0.05,sample_kbps为计算的码率(探测码率,或ack码率)

void LinkCapacityEstimator::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;// 估计链路容量估计的方差,并将方差与链路容量估计进行归一化。
  // 0.4 ~= 14 kbit/s at 500 kbit/s
  // 2.5f ~= 35 kbit/s at 500 kbit/s
  deviation_kbps_ = rtc::SafeClamp(deviation_kbps_, 0.4f, 2.5f);
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱钻研技术的小羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值