bitrate_estimator.cc (6610B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/congestion_controller/goog_cc/bitrate_estimator.h" 12 13 #include <algorithm> 14 #include <cmath> 15 #include <cstdint> 16 #include <optional> 17 18 #include "api/field_trials_view.h" 19 #include "api/units/data_rate.h" 20 #include "api/units/data_size.h" 21 #include "api/units/time_delta.h" 22 #include "api/units/timestamp.h" 23 #include "rtc_base/checks.h" 24 #include "rtc_base/experiments/field_trial_parser.h" 25 26 namespace webrtc { 27 28 namespace { 29 constexpr int kInitialRateWindowMs = 500; 30 constexpr int kRateWindowMs = 150; 31 constexpr int kMinRateWindowMs = 150; 32 constexpr int kMaxRateWindowMs = 1000; 33 34 const char kBweThroughputWindowConfig[] = "WebRTC-BweThroughputWindowConfig"; 35 36 } // namespace 37 38 BitrateEstimator::BitrateEstimator(const FieldTrialsView* key_value_config) 39 : sum_(0), 40 initial_window_ms_("initial_window_ms", 41 kInitialRateWindowMs, 42 kMinRateWindowMs, 43 kMaxRateWindowMs), 44 noninitial_window_ms_("window_ms", 45 kRateWindowMs, 46 kMinRateWindowMs, 47 kMaxRateWindowMs), 48 uncertainty_scale_("scale", 10.0), 49 uncertainty_scale_in_alr_("scale_alr", uncertainty_scale_), 50 small_sample_uncertainty_scale_("scale_small", uncertainty_scale_), 51 small_sample_threshold_("small_thresh", DataSize::Zero()), 52 uncertainty_symmetry_cap_("symmetry_cap", DataRate::Zero()), 53 estimate_floor_("floor", DataRate::Zero()), 54 current_window_ms_(0), 55 prev_time_ms_(-1), 56 bitrate_estimate_kbps_(-1.0f), 57 bitrate_estimate_var_(50.0f) { 58 // E.g WebRTC-BweThroughputWindowConfig/initial_window_ms:350,window_ms:250/ 59 ParseFieldTrial( 60 {&initial_window_ms_, &noninitial_window_ms_, &uncertainty_scale_, 61 &uncertainty_scale_in_alr_, &small_sample_uncertainty_scale_, 62 &small_sample_threshold_, &uncertainty_symmetry_cap_, &estimate_floor_}, 63 key_value_config->Lookup(kBweThroughputWindowConfig)); 64 } 65 66 BitrateEstimator::~BitrateEstimator() = default; 67 68 void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) { 69 int rate_window_ms = noninitial_window_ms_.Get(); 70 // We use a larger window at the beginning to get a more stable sample that 71 // we can use to initialize the estimate. 72 if (bitrate_estimate_kbps_ < 0.f) 73 rate_window_ms = initial_window_ms_.Get(); 74 bool is_small_sample = false; 75 float bitrate_sample_kbps = UpdateWindow(at_time.ms(), amount.bytes(), 76 rate_window_ms, &is_small_sample); 77 if (bitrate_sample_kbps < 0.0f) 78 return; 79 if (bitrate_estimate_kbps_ < 0.0f) { 80 // This is the very first sample we get. Use it to initialize the estimate. 81 bitrate_estimate_kbps_ = bitrate_sample_kbps; 82 return; 83 } 84 // Optionally use higher uncertainty for very small samples to avoid dropping 85 // estimate and for samples obtained in ALR. 86 float scale = uncertainty_scale_; 87 if (is_small_sample && bitrate_sample_kbps < bitrate_estimate_kbps_) { 88 scale = small_sample_uncertainty_scale_; 89 } else if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) { 90 // Optionally use higher uncertainty for samples obtained during ALR. 91 scale = uncertainty_scale_in_alr_; 92 } 93 // Define the sample uncertainty as a function of how far away it is from the 94 // current estimate. With low values of uncertainty_symmetry_cap_ we add more 95 // uncertainty to increases than to decreases. For higher values we approach 96 // symmetry. 97 float sample_uncertainty = 98 scale * std::abs(bitrate_estimate_kbps_ - bitrate_sample_kbps) / 99 (bitrate_estimate_kbps_ + 100 std::min(bitrate_sample_kbps, 101 uncertainty_symmetry_cap_.Get().kbps<float>())); 102 103 float sample_var = sample_uncertainty * sample_uncertainty; 104 // Update a bayesian estimate of the rate, weighting it lower if the sample 105 // uncertainty is large. 106 // The bitrate estimate uncertainty is increased with each update to model 107 // that the bitrate changes over time. 108 float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f; 109 bitrate_estimate_kbps_ = (sample_var * bitrate_estimate_kbps_ + 110 pred_bitrate_estimate_var * bitrate_sample_kbps) / 111 (sample_var + pred_bitrate_estimate_var); 112 bitrate_estimate_kbps_ = 113 std::max(bitrate_estimate_kbps_, estimate_floor_.Get().kbps<float>()); 114 bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var / 115 (sample_var + pred_bitrate_estimate_var); 116 } 117 118 float BitrateEstimator::UpdateWindow(int64_t now_ms, 119 int bytes, 120 int rate_window_ms, 121 bool* is_small_sample) { 122 RTC_DCHECK(is_small_sample != nullptr); 123 // Reset if time moves backwards. 124 if (now_ms < prev_time_ms_) { 125 prev_time_ms_ = -1; 126 sum_ = 0; 127 current_window_ms_ = 0; 128 } 129 if (prev_time_ms_ >= 0) { 130 current_window_ms_ += now_ms - prev_time_ms_; 131 // Reset if nothing has been received for more than a full window. 132 if (now_ms - prev_time_ms_ > rate_window_ms) { 133 sum_ = 0; 134 current_window_ms_ %= rate_window_ms; 135 } 136 } 137 prev_time_ms_ = now_ms; 138 float bitrate_sample = -1.0f; 139 if (current_window_ms_ >= rate_window_ms) { 140 *is_small_sample = sum_ < small_sample_threshold_->bytes(); 141 bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms); 142 current_window_ms_ -= rate_window_ms; 143 sum_ = 0; 144 } 145 sum_ += bytes; 146 return bitrate_sample; 147 } 148 149 std::optional<DataRate> BitrateEstimator::bitrate() const { 150 if (bitrate_estimate_kbps_ < 0.f) 151 return std::nullopt; 152 return DataRate::KilobitsPerSec(bitrate_estimate_kbps_); 153 } 154 155 std::optional<DataRate> BitrateEstimator::PeekRate() const { 156 if (current_window_ms_ > 0) 157 return DataSize::Bytes(sum_) / TimeDelta::Millis(current_window_ms_); 158 return std::nullopt; 159 } 160 161 void BitrateEstimator::ExpectFastRateChange() { 162 // By setting the bitrate-estimate variance to a higher value we allow the 163 // bitrate to change fast for the next few samples. 164 bitrate_estimate_var_ += 200; 165 } 166 167 } // namespace webrtc