写点什么

webrtc BitrateEstimator

用户头像
糖米唐爹
关注
发布于: 3 小时前
webrtc BitrateEstimator

备注: 以上代码基于 89 版本!!!

一,引言

‘即时带宽预估器',我暂且这样称呼它,它也是 gcc 的一部分,该值被用于 Delay-based controller。假设现在要开发‘检测用户带宽’这样一个功能,我们脑海中第一方案是什么? 通过发送一个大文件,记录该文件的大小和所需用的时间,用 bw = filesize/interval 就可以计算出当前的可用带宽,其实这也是 webrtc BitrateEstimator 实现的原理。webrtc 实现了两个 BitrateEstimator ProbeBitrateEstimator 和 AcknowledgedBitrateEstimator,下面简单介绍。


二,接收即时带宽评估

无论是 ProbeBitrateEstimator, 还是 AcknowledgedBitrateEstimator,都是根据 rtcp 的 transport-cc-feedback 来计算接收端的即时速率,处理流程如下:



三,ProbeBitrateEstimator


1)简介

probe 是 gcc 探测带宽的辅助类,它提供了两个功能

  • 在通道建立初始阶段,增加额外的 pandding 包,使 gcc 迅速探测到最大带宽,类似 tcp 的慢启动阶段。

  • 当网络恢复,配合 ALR 迅速测得最大带宽。

2)probe 触发条件

  • 网络状态发生切换。见函数:ProbeController::OnNetworkAvailability

  • 当启动 ALR 检测且 ALR 受限也会启动见 :https://xie.infoq.cn/article/2091ae4f237a7f89ca7ecfedd

  • 探测完成,所设置的最大带宽发生变化,也会触发,见函数:ProbeController::SetBitrates

3)即时带宽计算

  1. 当 paced 定时发送 rtp 数据,首先判断是否正在进行 probing ,取出最新的 ProbeCluster 信息,会连同该 rtp 数据包的长度,序列号等信息存储到 TransportFeedbackAdapter history 中。

  2. 当数据送到网卡,记录该时间戳,并更新到 TransportFeedbackAdapter history。

  3. 收到 TransportPacketsFeedback 包,TransportFeedbackAdapter 根据每个 feedback 带有序列号,从 TransportFeedbackAdapter history 取出已发送数据包的相关信息并配合 TransportPacketsFeedback 所带的信息构造 PacketResult 对象,在 ProbeBitrateEstimator 评估即时带宽,见函数:

absl::optional<DataRate> ProbeBitrateEstimator::HandleProbeAndEstimateBitrate(    const PacketResult& packet_feedback) {  int cluster_id = packet_feedback.sent_packet.pacing_info.probe_cluster_id;  EraseOldClusters(packet_feedback.receive_time);  AggregatedCluster* cluster = &clusters_[cluster_id];  cluster->size_total += packet_feedback.sent_packet.size;  cluster->num_probes += 1;
TimeDelta send_interval = cluster->last_send - cluster->first_send; TimeDelta receive_interval = cluster->last_receive - cluster->first_receive; //1, 即时发送速率 = 已发送数据量/所用的时间间隔 DataSize send_size = cluster->size_total - cluster->size_last_send; DataRate send_rate = send_size / send_interval; //2,即时接收速率 = 被ack 的数据量/所用的时间间隔 DataSize receive_size = cluster->size_total - cluster->size_first_receive; DataRate receive_rate = receive_size / receive_interval; // 3,即时发送速率与接收速率最小值,即为probe 的 DataRate res = std::min(send_rate, receive_rate); estimated_data_rate_ = res; return estimated_data_rate_;}
复制代码


四,AcknowledgedBitrateEstimator


1)简介

BitrateEstimator 是 AcknowledgedBitrateEstimator 算法实现类,它是用来计算即时接收带宽,BitrateEstimator 维护一个滑动时间窗口,这个窗口大小在初始阶段是 500ms ,后续为 150ms。用净荷的 ack 的吞吐量除以这个窗口,就得到了即时接收带宽。


2)BitrateEstimator 函数

  1. UpdateWindow 统计 rate_window_ms 即时带宽。

float BitrateEstimator::UpdateWindow(int64_t now_ms,                                     int bytes,                                     int rate_window_ms,                                     bool* is_small_sample) {  // 收到的transport-cc-feedback包乱序,会影响评估,重置窗口和接收的数据量总量。  if (now_ms < prev_time_ms_) {    prev_time_ms_ = -1;    sum_ = 0;    current_window_ms_ = 0;  }  if (prev_time_ms_ >= 0) {    // 计算当前时间窗口大小    current_window_ms_ += now_ms - prev_time_ms_;    // 时间窗口过期,清零处理,    if (now_ms - prev_time_ms_ > rate_window_ms) {      sum_ = 0;      current_window_ms_ %= rate_window_ms;    }  }  prev_time_ms_ = now_ms;  float bitrate_sample = -1.0f;  if (current_window_ms_ >= rate_window_ms) {    *is_small_sample = sum_ < small_sample_threshold_->bytes();    // 即时带宽计算    bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms);    current_window_ms_ -= rate_window_ms;    sum_ = 0;  }  sum_ += bytes;  return bitrate_sample;}
复制代码
  1. Update 函数用到了贝叶斯估计,目的是为了减少由于网络抖动导致的评估值的误差,函数注解很明了,不再赘述。

void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) {  int rate_window_ms = noninitial_window_ms_.Get();// 150ms  // We use a larger window at the beginning to get a more stable sample that  // we can use to initialize the estimate.  if (bitrate_estimate_kbps_ < 0.f)    rate_window_ms = initial_window_ms_.Get(); //500ms  bool is_small_sample = false;  float bitrate_sample_kbps = UpdateWindow(at_time.ms(), amount.bytes(),                                           rate_window_ms, &is_small_sample);  if (bitrate_sample_kbps < 0.0f)    return;  if (bitrate_estimate_kbps_ < 0.0f) {    // This is the very first sample we get. Use it to initialize the estimate.    bitrate_estimate_kbps_ = bitrate_sample_kbps;    return;  }  // Optionally use higher uncertainty for very small samples to avoid dropping  // estimate and for samples obtained in ALR.  float scale = uncertainty_scale_;  if (is_small_sample && bitrate_sample_kbps < bitrate_estimate_kbps_) {    scale = small_sample_uncertainty_scale_;  } else if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) {    // Optionally use higher uncertainty for samples obtained during ALR.    scale = uncertainty_scale_in_alr_;  }
// Define the sample uncertainty as a function of how far away it is from the // current estimate. With low values of uncertainty_symmetry_cap_ we add more // uncertainty to increases than to decreases. For higher values we approach // symmetry. float sample_uncertainty = scale * std::abs(bitrate_estimate_kbps_ - bitrate_sample_kbps) / (bitrate_estimate_kbps_ + std::min(bitrate_sample_kbps, uncertainty_symmetry_cap_.Get().kbps<float>()));
float sample_var = sample_uncertainty * sample_uncertainty; // Update a bayesian estimate of the rate, weighting it lower if the sample // uncertainty is large. // The bitrate estimate uncertainty is increased with each update to model // that the bitrate changes over time. float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f; bitrate_estimate_kbps_ = (sample_var * bitrate_estimate_kbps_ + pred_bitrate_estimate_var * bitrate_sample_kbps) / (sample_var + pred_bitrate_estimate_var); bitrate_estimate_kbps_ = std::max(bitrate_estimate_kbps_, estimate_floor_.Get().kbps<float>()); bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var / (sample_var + pred_bitrate_estimate_var);}
复制代码


用户头像

糖米唐爹

关注

还未添加个人签名 2020.08.12 加入

还未添加个人简介

评论

发布
暂无评论
webrtc BitrateEstimator