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);
}