WebRTC 源码阅读笔记之AcknowledgedBitrateEstimator
Table of Contents
AcknowledgedBitrateEstimatorInterface
确认的比特率估算器接口
class AcknowledgedBitrateEstimatorInterface {
public:
static std::unique_ptr<AcknowledgedBitrateEstimatorInterface> Create(
const WebRtcKeyValueConfig* key_value_config);
virtual ~AcknowledgedBitrateEstimatorInterface();
virtual void IncomingPacketFeedbackVector(
const std::vector<PacketResult>& packet_feedback_vector) = 0;
virtual absl::optional<DataRate> bitrate() const = 0;
virtual absl::optional<DataRate> PeekRate() const = 0;
virtual void SetAlr(bool in_alr) = 0;
virtual void SetAlrEndedTime(Timestamp alr_ended_time) = 0;
};
AcknowledgedBitrateEstimator
确认的比特率估算器
class AcknowledgedBitrateEstimator
: public AcknowledgedBitrateEstimatorInterface {
public:
AcknowledgedBitrateEstimator(
const WebRtcKeyValueConfig* key_value_config,
std::unique_ptr<BitrateEstimator> bitrate_estimator);
explicit AcknowledgedBitrateEstimator(
const WebRtcKeyValueConfig* key_value_config);
~AcknowledgedBitrateEstimator() override;
void IncomingPacketFeedbackVector(
const std::vector<PacketResult>& packet_feedback_vector) override;
absl::optional<DataRate> bitrate() const override;
absl::optional<DataRate> PeekRate() const override;
void SetAlr(bool in_alr) override;
void SetAlrEndedTime(Timestamp alr_ended_time) override;
private:
absl::optional<Timestamp> alr_ended_time_;
bool in_alr_;
std::unique_ptr<BitrateEstimator> bitrate_estimator_;
};
AcknowledgedBitrateEstimator::IncomingPacketFeedbackVector
void AcknowledgedBitrateEstimator::IncomingPacketFeedbackVector(
const std::vector<PacketResult>& packet_feedback_vector) {
RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
packet_feedback_vector.end(),
PacketResult::ReceiveTimeOrder()));
//遍历数据包反馈列表
for (const auto& packet : packet_feedback_vector) {
//当 ALR 停止, 发送的包的时间比 ALR 的停止时间还晚,则期望一个快速的速率改变
if (alr_ended_time_ && packet.sent_packet.send_time > *alr_ended_time_) {
bitrate_estimator_->ExpectFastRateChange();
alr_ended_time_.reset();
}
//确认的估计量等于发送的包大小, 再加上先前未确认的包
DataSize acknowledged_estimate = packet.sent_packet.size;
acknowledged_estimate += packet.sent_packet.prior_unacked_data;
//以包的接收时间,确认估计量,是否在 ALR 三个参数来修正带宽估算器
bitrate_estimator_->Update(packet.receive_time, acknowledged_estimate,
in_alr_);
}
}
BitrateEstimator
计算给定的确认的吞吐量的贝叶斯估计值,其中包含到达时间和有效负载大小。与当前估计值相差甚远或基于少量数据包的样本权重较小,因为它们被认为更有可能是由与拥塞无关的延迟峰值引起的。
// Computes a bayesian estimate of the throughput given acks containing
// the arrival time and payload size. Samples which are far from the current
// estimate or are based on few packets are given a smaller weight, as they
// are considered to be more likely to have been caused by, e.g., delay spikes
// unrelated to congestion.
class BitrateEstimator {
public:
explicit BitrateEstimator(const WebRtcKeyValueConfig* key_value_config);
virtual ~BitrateEstimator();
virtual void Update(Timestamp at_time, DataSize amount, bool in_alr);
virtual absl::optional<DataRate> bitrate() const;
absl::optional<DataRate> PeekRate() const;
virtual void ExpectFastRateChange();
private:
float UpdateWindow(int64_t now_ms,
int bytes,
int rate_window_ms,
bool* is_small_sample);
int sum_;
FieldTrialConstrained<int> initial_window_ms_;
FieldTrialConstrained<int> noninitial_window_ms_;
FieldTrialParameter<double> uncertainty_scale_;
FieldTrialParameter<double> uncertainty_scale_in_alr_;
FieldTrialParameter<double> small_sample_uncertainty_scale_;
FieldTrialParameter<DataSize> small_sample_threshold_;
FieldTrialParameter<DataRate> uncertainty_symmetry_cap_;
FieldTrialParameter<DataRate> estimate_floor_;
int64_t current_window_ms_;
int64_t prev_time_ms_;
float bitrate_estimate_kbps_;
float bitrate_estimate_var_;
};
BitrateEstimator::Update
这里用到了贝叶斯估计, 带宽估算准确的概率是随着实际的传输比特率的变化而调整的
现象 B 出现的情况下事件 A 发生的概率, 等于事件 A 发生时现象 B 出现的概率,乘以事件 A 发生的概率, 再除以现象 B 出现的概率
void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) {
int rate_window_ms = noninitial_window_ms_.Get();
// 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();
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);
BWE_TEST_LOGGING_PLOT(1, "acknowledged_bitrate", at_time.ms(),
bitrate_estimate_kbps_ * 1000);
}
UpdateWindow
修改当前时间所在的滑动窗口的传输字节数
float BitrateEstimator::UpdateWindow(int64_t now_ms,
int bytes,
int rate_window_ms,
bool* is_small_sample) {
RTC_DCHECK(is_small_sample != nullptr);
// Reset if time moves backwards.
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_;
// Reset if nothing has been received for more than a full window.
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;
}
absl::optional<DataRate> BitrateEstimator::bitrate() const {
if (bitrate_estimate_kbps_ < 0.f)
return absl::nullopt;
return DataRate::KilobitsPerSec(bitrate_estimate_kbps_);
}
absl::optional<DataRate> BitrateEstimator::PeekRate() const {
if (current_window_ms_ > 0)
return DataSize::Bytes(sum_) / TimeDelta::Millis(current_window_ms_);
return absl::nullopt;
}
Comments |0|
Category: Uncategorized