pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2014 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 11 | #include "modules/remote_bitrate_estimator/aimd_rate_control.h" |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 12 | |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 13 | #include <inttypes.h> |
| 14 | |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 15 | #include <algorithm> |
| 16 | #include <cassert> |
| 17 | #include <cmath> |
Piotr Tworek | 5e4833c | 2017-12-12 11:09:31 | [diff] [blame] | 18 | #include <cstdio> |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 19 | #include <string> |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 20 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 21 | #include "modules/remote_bitrate_estimator/include/bwe_defines.h" |
| 22 | #include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 23 | #include "modules/remote_bitrate_estimator/overuse_detector.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 24 | #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 25 | #include "rtc_base/checks.h" |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 26 | #include "rtc_base/logging.h" |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 27 | #include "rtc_base/numerics/safe_minmax.h" |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 28 | #include "system_wrappers/include/field_trial.h" |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 29 | |
| 30 | namespace webrtc { |
| 31 | |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 32 | static const int64_t kDefaultRttMs = 200; |
| 33 | static const int64_t kMaxFeedbackIntervalMs = 1000; |
| 34 | static const float kDefaultBackoffFactor = 0.85f; |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 35 | static const int64_t kDefaultInitialBackOffIntervalMs = 200; |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 36 | |
| 37 | const char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor"; |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 38 | const char kBweInitialBackOffIntervalExperiment[] = |
| 39 | "WebRTC-BweInitialBackOffInterval"; |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 40 | |
Bjorn Terelius | 95de63b | 2018-05-16 18:18:21 | [diff] [blame] | 41 | float ReadBackoffFactor() { |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 42 | std::string experiment_string = |
| 43 | webrtc::field_trial::FindFullName(kBweBackOffFactorExperiment); |
| 44 | float backoff_factor; |
| 45 | int parsed_values = |
| 46 | sscanf(experiment_string.c_str(), "Enabled-%f", &backoff_factor); |
| 47 | if (parsed_values == 1) { |
Stefan Holmer | 92cacec | 2017-10-10 07:07:25 | [diff] [blame] | 48 | if (backoff_factor >= 1.0f) { |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 49 | RTC_LOG(WARNING) << "Back-off factor must be less than 1."; |
Stefan Holmer | 92cacec | 2017-10-10 07:07:25 | [diff] [blame] | 50 | } else if (backoff_factor <= 0.0f) { |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 51 | RTC_LOG(WARNING) << "Back-off factor must be greater than 0."; |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 52 | } else { |
| 53 | return backoff_factor; |
| 54 | } |
| 55 | } |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 56 | RTC_LOG(LS_WARNING) << "Failed to parse parameters for AimdRateControl " |
| 57 | "experiment from field trial string. Using default."; |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 58 | return kDefaultBackoffFactor; |
| 59 | } |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 60 | |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 61 | int64_t ReadInitialBackoffIntervalMs() { |
| 62 | std::string experiment_string = |
| 63 | webrtc::field_trial::FindFullName(kBweInitialBackOffIntervalExperiment); |
| 64 | int64_t backoff_interval; |
| 65 | int parsed_values = |
| 66 | sscanf(experiment_string.c_str(), "Enabled-%" SCNd64, &backoff_interval); |
| 67 | if (parsed_values == 1) { |
| 68 | if (10 <= backoff_interval && backoff_interval <= 200) { |
| 69 | return backoff_interval; |
| 70 | } |
| 71 | RTC_LOG(WARNING) |
| 72 | << "Initial back-off interval must be between 10 and 200 ms."; |
| 73 | } |
| 74 | RTC_LOG(LS_WARNING) << "Failed to parse parameters for " |
| 75 | << kBweInitialBackOffIntervalExperiment |
| 76 | << " experiment. Using default."; |
| 77 | return kDefaultInitialBackOffIntervalMs; |
| 78 | } |
| 79 | |
stefan | 4fbd145 | 2015-09-28 10:57:14 | [diff] [blame] | 80 | AimdRateControl::AimdRateControl() |
michaelt | f082c2aa | 2016-11-07 12:17:14 | [diff] [blame] | 81 | : min_configured_bitrate_bps_(congestion_controller::GetMinBitrateBps()), |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 82 | max_configured_bitrate_bps_(30000000), |
| 83 | current_bitrate_bps_(max_configured_bitrate_bps_), |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 84 | latest_estimated_throughput_bps_(current_bitrate_bps_), |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 85 | avg_max_bitrate_kbps_(-1.0f), |
| 86 | var_max_bitrate_kbps_(0.4f), |
| 87 | rate_control_state_(kRcHold), |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 88 | rate_control_region_(kRcMaxUnknown), |
| 89 | time_last_bitrate_change_(-1), |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 90 | time_last_bitrate_decrease_(-1), |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 91 | time_first_throughput_estimate_(-1), |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 92 | bitrate_is_initialized_(false), |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 93 | beta_(webrtc::field_trial::IsEnabled(kBweBackOffFactorExperiment) |
Bjorn Terelius | 95de63b | 2018-05-16 18:18:21 | [diff] [blame] | 94 | ? ReadBackoffFactor() |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 95 | : kDefaultBackoffFactor), |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 96 | rtt_(kDefaultRttMs), |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 97 | in_experiment_(!AdaptiveThresholdExperimentIsDisabled()), |
| 98 | smoothing_experiment_( |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 99 | webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")), |
| 100 | in_initial_backoff_interval_experiment_( |
| 101 | webrtc::field_trial::IsEnabled(kBweInitialBackOffIntervalExperiment)), |
| 102 | initial_backoff_interval_ms_(kDefaultInitialBackOffIntervalMs) { |
| 103 | if (in_initial_backoff_interval_experiment_) { |
| 104 | initial_backoff_interval_ms_ = ReadInitialBackoffIntervalMs(); |
| 105 | RTC_LOG(LS_INFO) << "Using aimd rate control with initial back-off interval" |
| 106 | << " " << initial_backoff_interval_ms_ << " ms."; |
| 107 | } |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 108 | RTC_LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_; |
Stefan Holmer | ea00e48 | 2017-10-06 06:43:34 | [diff] [blame] | 109 | } |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 110 | |
stefan | 5a2c506 | 2017-01-27 14:43:18 | [diff] [blame] | 111 | AimdRateControl::~AimdRateControl() {} |
| 112 | |
| 113 | void AimdRateControl::SetStartBitrate(int start_bitrate_bps) { |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 114 | current_bitrate_bps_ = start_bitrate_bps; |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 115 | latest_estimated_throughput_bps_ = current_bitrate_bps_; |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 116 | bitrate_is_initialized_ = true; |
stefan | 5a2c506 | 2017-01-27 14:43:18 | [diff] [blame] | 117 | } |
| 118 | |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 119 | void AimdRateControl::SetMinBitrate(int min_bitrate_bps) { |
| 120 | min_configured_bitrate_bps_ = min_bitrate_bps; |
| 121 | current_bitrate_bps_ = std::max<int>(min_bitrate_bps, current_bitrate_bps_); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | bool AimdRateControl::ValidEstimate() const { |
| 125 | return bitrate_is_initialized_; |
| 126 | } |
| 127 | |
pkasting@chromium.org | 0b1534c | 2014-12-15 22:09:40 | [diff] [blame] | 128 | int64_t AimdRateControl::GetFeedbackInterval() const { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 129 | // Estimate how often we can send RTCP if we allocate up to 5% of bandwidth |
| 130 | // to feedback. |
pkasting@chromium.org | 0b1534c | 2014-12-15 22:09:40 | [diff] [blame] | 131 | static const int kRtcpSize = 80; |
kwiberg | 0703856 | 2017-06-12 18:40:47 | [diff] [blame] | 132 | const int64_t interval = static_cast<int64_t>( |
pkasting@chromium.org | 0b1534c | 2014-12-15 22:09:40 | [diff] [blame] | 133 | kRtcpSize * 8.0 * 1000.0 / (0.05 * current_bitrate_bps_) + 0.5); |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 134 | const int64_t kMinFeedbackIntervalMs = 200; |
kwiberg | 0703856 | 2017-06-12 18:40:47 | [diff] [blame] | 135 | return rtc::SafeClamp(interval, kMinFeedbackIntervalMs, |
| 136 | kMaxFeedbackIntervalMs); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 137 | } |
| 138 | |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 139 | bool AimdRateControl::TimeToReduceFurther( |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 140 | int64_t now_ms, |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 141 | uint32_t estimated_throughput_bps) const { |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 | [diff] [blame] | 142 | const int64_t bitrate_reduction_interval = |
| 143 | std::max<int64_t>(std::min<int64_t>(rtt_, 200), 10); |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 144 | if (now_ms - time_last_bitrate_change_ >= bitrate_reduction_interval) { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 145 | return true; |
| 146 | } |
| 147 | if (ValidEstimate()) { |
howtofly | df28e47 | 2016-12-02 11:27:08 | [diff] [blame] | 148 | // TODO(terelius/holmer): Investigate consequences of increasing |
| 149 | // the threshold to 0.95 * LatestEstimate(). |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 150 | const uint32_t threshold = static_cast<uint32_t>(0.5 * LatestEstimate()); |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 151 | return estimated_throughput_bps < threshold; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 152 | } |
| 153 | return false; |
| 154 | } |
| 155 | |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 156 | bool AimdRateControl::InitialTimeToReduceFurther(int64_t now_ms) const { |
| 157 | if (!in_initial_backoff_interval_experiment_) { |
| 158 | return ValidEstimate() && |
| 159 | TimeToReduceFurther(now_ms, LatestEstimate() / 2 - 1); |
| 160 | } |
| 161 | // TODO(terelius): We could use the RTT (clamped to suitable limits) instead |
| 162 | // of a fixed bitrate_reduction_interval. |
| 163 | if (time_last_bitrate_decrease_ == -1 || |
| 164 | now_ms - time_last_bitrate_decrease_ >= initial_backoff_interval_ms_) { |
| 165 | return true; |
| 166 | } |
| 167 | return false; |
| 168 | } |
| 169 | |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 170 | uint32_t AimdRateControl::LatestEstimate() const { |
| 171 | return current_bitrate_bps_; |
| 172 | } |
| 173 | |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 | [diff] [blame] | 174 | void AimdRateControl::SetRtt(int64_t rtt) { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 175 | rtt_ = rtt; |
| 176 | } |
| 177 | |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 178 | uint32_t AimdRateControl::Update(const RateControlInput* input, |
| 179 | int64_t now_ms) { |
Erik Språng | 51e6030 | 2016-06-10 20:13:21 | [diff] [blame] | 180 | RTC_CHECK(input); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 181 | |
| 182 | // Set the initial bit rate value to what we're receiving the first half |
| 183 | // second. |
Anastasia Koloskova | 6d19180 | 2018-06-11 09:44:29 | [diff] [blame] | 184 | // TODO(bugs.webrtc.org/9379): The comment above doesn't match to the code. |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 185 | if (!bitrate_is_initialized_) { |
Stefan Holmer | 11324b9 | 2015-07-09 15:27:48 | [diff] [blame] | 186 | const int64_t kInitializationTimeMs = 5000; |
henrikg | 91d6ede | 2015-09-17 07:24:34 | [diff] [blame] | 187 | RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTimeMs); |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 188 | if (time_first_throughput_estimate_ < 0) { |
| 189 | if (input->estimated_throughput_bps) |
| 190 | time_first_throughput_estimate_ = now_ms; |
| 191 | } else if (now_ms - time_first_throughput_estimate_ > |
| 192 | kInitializationTimeMs && |
| 193 | input->estimated_throughput_bps) { |
| 194 | current_bitrate_bps_ = *input->estimated_throughput_bps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 195 | bitrate_is_initialized_ = true; |
| 196 | } |
| 197 | } |
| 198 | |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 199 | current_bitrate_bps_ = ChangeBitrate(current_bitrate_bps_, *input, now_ms); |
| 200 | return current_bitrate_bps_; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 204 | bitrate_is_initialized_ = true; |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 205 | uint32_t prev_bitrate_bps = current_bitrate_bps_; |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 206 | current_bitrate_bps_ = ClampBitrate(bitrate_bps, bitrate_bps); |
| 207 | time_last_bitrate_change_ = now_ms; |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 208 | if (current_bitrate_bps_ < prev_bitrate_bps) { |
| 209 | time_last_bitrate_decrease_ = now_ms; |
| 210 | } |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 211 | } |
| 212 | |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 213 | int AimdRateControl::GetNearMaxIncreaseRateBps() const { |
| 214 | RTC_DCHECK_GT(current_bitrate_bps_, 0); |
| 215 | double bits_per_frame = static_cast<double>(current_bitrate_bps_) / 30.0; |
| 216 | double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0)); |
| 217 | double avg_packet_size_bits = bits_per_frame / packets_per_frame; |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 218 | |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 219 | // Approximate the over-use estimator delay to 100 ms. |
| 220 | const int64_t response_time = in_experiment_ ? (rtt_ + 100) * 2 : rtt_ + 100; |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 221 | constexpr double kMinIncreaseRateBps = 4000; |
| 222 | return static_cast<int>(std::max( |
| 223 | kMinIncreaseRateBps, (avg_packet_size_bits * 1000) / response_time)); |
| 224 | } |
| 225 | |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 226 | int AimdRateControl::GetExpectedBandwidthPeriodMs() const { |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 227 | const int kMinPeriodMs = smoothing_experiment_ ? 500 : 2000; |
alexnarest | b335e31 | 2017-09-19 19:00:32 | [diff] [blame] | 228 | constexpr int kDefaultPeriodMs = 3000; |
minyue | 93e4522 | 2017-05-18 21:32:41 | [diff] [blame] | 229 | constexpr int kMaxPeriodMs = 50000; |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 230 | |
| 231 | int increase_rate = GetNearMaxIncreaseRateBps(); |
| 232 | if (!last_decrease_) |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 233 | return smoothing_experiment_ ? kMinPeriodMs : kDefaultPeriodMs; |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 234 | |
Per Kjellander | dd3eae5 | 2018-05-18 07:12:15 | [diff] [blame] | 235 | return std::min(kMaxPeriodMs, |
| 236 | std::max<int>(1000 * static_cast<int64_t>(*last_decrease_) / |
| 237 | increase_rate, |
| 238 | kMinPeriodMs)); |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 239 | } |
| 240 | |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 241 | uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps, |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 242 | const RateControlInput& input, |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 243 | int64_t now_ms) { |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 244 | uint32_t estimated_throughput_bps = |
| 245 | input.estimated_throughput_bps.value_or(latest_estimated_throughput_bps_); |
| 246 | if (input.estimated_throughput_bps) |
| 247 | latest_estimated_throughput_bps_ = *input.estimated_throughput_bps; |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 248 | |
Stefan Holmer | 11324b9 | 2015-07-09 15:27:48 | [diff] [blame] | 249 | // An over-use should always trigger us to reduce the bitrate, even though |
| 250 | // we have not yet established our first estimate. By acting on the over-use, |
| 251 | // we will end up with a valid estimate. |
michaelt | 9765370 | 2017-04-11 07:49:44 | [diff] [blame] | 252 | if (!bitrate_is_initialized_ && |
| 253 | input.bw_state != BandwidthUsage::kBwOverusing) |
Stefan Holmer | 11324b9 | 2015-07-09 15:27:48 | [diff] [blame] | 254 | return current_bitrate_bps_; |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 255 | |
| 256 | ChangeState(input, now_ms); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 257 | // Calculated here because it's used in multiple places. |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 258 | const float estimated_throughput_kbps = estimated_throughput_bps / 1000.0f; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 259 | // Calculate the max bit rate std dev given the normalized |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 260 | // variance and the current throughput bitrate. |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 261 | const float std_max_bit_rate = |
| 262 | sqrt(var_max_bitrate_kbps_ * avg_max_bitrate_kbps_); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 263 | switch (rate_control_state_) { |
stefan | c62642c | 2015-07-07 11:20:34 | [diff] [blame] | 264 | case kRcHold: |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 265 | break; |
stefan | c62642c | 2015-07-07 11:20:34 | [diff] [blame] | 266 | |
| 267 | case kRcIncrease: |
| 268 | if (avg_max_bitrate_kbps_ >= 0 && |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 269 | estimated_throughput_kbps > |
stefan | c62642c | 2015-07-07 11:20:34 | [diff] [blame] | 270 | avg_max_bitrate_kbps_ + 3 * std_max_bit_rate) { |
| 271 | ChangeRegion(kRcMaxUnknown); |
| 272 | avg_max_bitrate_kbps_ = -1.0; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 273 | } |
| 274 | if (rate_control_region_ == kRcNearMax) { |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 275 | uint32_t additive_increase_bps = |
| 276 | AdditiveRateIncrease(now_ms, time_last_bitrate_change_); |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 277 | new_bitrate_bps += additive_increase_bps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 278 | } else { |
| 279 | uint32_t multiplicative_increase_bps = MultiplicativeRateIncrease( |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 280 | now_ms, time_last_bitrate_change_, new_bitrate_bps); |
| 281 | new_bitrate_bps += multiplicative_increase_bps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 282 | } |
| 283 | |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 284 | time_last_bitrate_change_ = now_ms; |
| 285 | break; |
stefan | c62642c | 2015-07-07 11:20:34 | [diff] [blame] | 286 | |
| 287 | case kRcDecrease: |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 288 | // Set bit rate to something slightly lower than max |
| 289 | // to get rid of any self-induced delay. |
| 290 | new_bitrate_bps = |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 291 | static_cast<uint32_t>(beta_ * estimated_throughput_bps + 0.5); |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 292 | if (new_bitrate_bps > current_bitrate_bps_) { |
| 293 | // Avoid increasing the rate when over-using. |
| 294 | if (rate_control_region_ != kRcMaxUnknown) { |
| 295 | new_bitrate_bps = static_cast<uint32_t>( |
| 296 | beta_ * avg_max_bitrate_kbps_ * 1000 + 0.5f); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 297 | } |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 298 | new_bitrate_bps = std::min(new_bitrate_bps, current_bitrate_bps_); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 299 | } |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 300 | ChangeRegion(kRcNearMax); |
| 301 | |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 302 | if (bitrate_is_initialized_ && |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 303 | estimated_throughput_bps < current_bitrate_bps_) { |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 304 | constexpr float kDegradationFactor = 0.9f; |
| 305 | if (smoothing_experiment_ && |
| 306 | new_bitrate_bps < |
| 307 | kDegradationFactor * beta_ * current_bitrate_bps_) { |
| 308 | // If bitrate decreases more than a normal back off after overuse, it |
| 309 | // indicates a real network degradation. We do not let such a decrease |
| 310 | // to determine the bandwidth estimation period. |
Danil Chapovalov | 0040b66 | 2018-06-18 08:48:16 | [diff] [blame] | 311 | last_decrease_ = absl::nullopt; |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 312 | } else { |
Oskar Sundbom | 18f26d1 | 2017-11-16 09:52:14 | [diff] [blame] | 313 | last_decrease_ = current_bitrate_bps_ - new_bitrate_bps; |
Ivo Creusen | 46ca287 | 2017-10-09 10:28:39 | [diff] [blame] | 314 | } |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 315 | } |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 316 | if (estimated_throughput_kbps < |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 317 | avg_max_bitrate_kbps_ - 3 * std_max_bit_rate) { |
| 318 | avg_max_bitrate_kbps_ = -1.0f; |
| 319 | } |
| 320 | |
terelius | 6737045 | 2017-04-19 16:15:04 | [diff] [blame] | 321 | bitrate_is_initialized_ = true; |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 322 | UpdateMaxThroughputEstimate(estimated_throughput_kbps); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 323 | // Stay on hold until the pipes are cleared. |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 324 | rate_control_state_ = kRcHold; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 325 | time_last_bitrate_change_ = now_ms; |
Bjorn Terelius | 0c7ec80 | 2018-07-18 12:59:56 | [diff] [blame] | 326 | time_last_bitrate_decrease_ = now_ms; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 327 | break; |
stefan | c62642c | 2015-07-07 11:20:34 | [diff] [blame] | 328 | |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 329 | default: |
| 330 | assert(false); |
| 331 | } |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 332 | return ClampBitrate(new_bitrate_bps, estimated_throughput_bps); |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 333 | } |
| 334 | |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 335 | uint32_t AimdRateControl::ClampBitrate( |
| 336 | uint32_t new_bitrate_bps, |
| 337 | uint32_t estimated_throughput_bps) const { |
stefan | db752f9 | 2016-12-05 16:23:40 | [diff] [blame] | 338 | // Don't change the bit rate if the send side is too far off. |
| 339 | // We allow a bit more lag at very low rates to not too easily get stuck if |
| 340 | // the encoder produces uneven outputs. |
| 341 | const uint32_t max_bitrate_bps = |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 342 | static_cast<uint32_t>(1.5f * estimated_throughput_bps) + 10000; |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 343 | if (new_bitrate_bps > current_bitrate_bps_ && |
| 344 | new_bitrate_bps > max_bitrate_bps) { |
| 345 | new_bitrate_bps = std::max(current_bitrate_bps_, max_bitrate_bps); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 346 | } |
stefan | e3a5567 | 2017-02-13 17:08:22 | [diff] [blame] | 347 | new_bitrate_bps = std::max(new_bitrate_bps, min_configured_bitrate_bps_); |
| 348 | return new_bitrate_bps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 349 | } |
| 350 | |
| 351 | uint32_t AimdRateControl::MultiplicativeRateIncrease( |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 352 | int64_t now_ms, |
| 353 | int64_t last_ms, |
| 354 | uint32_t current_bitrate_bps) const { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 355 | double alpha = 1.08; |
| 356 | if (last_ms > -1) { |
kwiberg | 7885d3f | 2017-04-25 19:35:07 | [diff] [blame] | 357 | auto time_since_last_update_ms = |
| 358 | rtc::SafeMin<int64_t>(now_ms - last_ms, 1000); |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 359 | alpha = pow(alpha, time_since_last_update_ms / 1000.0); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 360 | } |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 361 | uint32_t multiplicative_increase_bps = |
| 362 | std::max(current_bitrate_bps * (alpha - 1.0), 1000.0); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 363 | return multiplicative_increase_bps; |
| 364 | } |
| 365 | |
michaelt | 4a4b3cf | 2016-11-17 09:18:43 | [diff] [blame] | 366 | uint32_t AimdRateControl::AdditiveRateIncrease(int64_t now_ms, |
| 367 | int64_t last_ms) const { |
| 368 | return static_cast<uint32_t>((now_ms - last_ms) * |
| 369 | GetNearMaxIncreaseRateBps() / 1000); |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 370 | } |
| 371 | |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 372 | void AimdRateControl::UpdateMaxThroughputEstimate( |
| 373 | float estimated_throughput_kbps) { |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 374 | const float alpha = 0.05f; |
| 375 | if (avg_max_bitrate_kbps_ == -1.0f) { |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 376 | avg_max_bitrate_kbps_ = estimated_throughput_kbps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 377 | } else { |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 378 | avg_max_bitrate_kbps_ = |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 379 | (1 - alpha) * avg_max_bitrate_kbps_ + alpha * estimated_throughput_kbps; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 380 | } |
| 381 | // Estimate the max bit rate variance and normalize the variance |
| 382 | // with the average max bit rate. |
| 383 | const float norm = std::max(avg_max_bitrate_kbps_, 1.0f); |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 384 | var_max_bitrate_kbps_ = |
| 385 | (1 - alpha) * var_max_bitrate_kbps_ + |
Bjorn Terelius | 43d0b98 | 2018-06-28 14:38:05 | [diff] [blame] | 386 | alpha * (avg_max_bitrate_kbps_ - estimated_throughput_kbps) * |
| 387 | (avg_max_bitrate_kbps_ - estimated_throughput_kbps) / norm; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 388 | // 0.4 ~= 14 kbit/s at 500 kbit/s |
| 389 | if (var_max_bitrate_kbps_ < 0.4f) { |
| 390 | var_max_bitrate_kbps_ = 0.4f; |
| 391 | } |
| 392 | // 2.5f ~= 35 kbit/s at 500 kbit/s |
| 393 | if (var_max_bitrate_kbps_ > 2.5f) { |
| 394 | var_max_bitrate_kbps_ = 2.5f; |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | void AimdRateControl::ChangeState(const RateControlInput& input, |
| 399 | int64_t now_ms) { |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 400 | switch (input.bw_state) { |
michaelt | 9765370 | 2017-04-11 07:49:44 | [diff] [blame] | 401 | case BandwidthUsage::kBwNormal: |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 402 | if (rate_control_state_ == kRcHold) { |
| 403 | time_last_bitrate_change_ = now_ms; |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 404 | rate_control_state_ = kRcIncrease; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 405 | } |
| 406 | break; |
michaelt | 9765370 | 2017-04-11 07:49:44 | [diff] [blame] | 407 | case BandwidthUsage::kBwOverusing: |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 408 | if (rate_control_state_ != kRcDecrease) { |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 409 | rate_control_state_ = kRcDecrease; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 410 | } |
| 411 | break; |
michaelt | 9765370 | 2017-04-11 07:49:44 | [diff] [blame] | 412 | case BandwidthUsage::kBwUnderusing: |
terelius | d1b0e0e | 2017-04-03 09:27:08 | [diff] [blame] | 413 | rate_control_state_ = kRcHold; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 414 | break; |
| 415 | default: |
| 416 | assert(false); |
| 417 | } |
| 418 | } |
| 419 | |
| 420 | void AimdRateControl::ChangeRegion(RateControlRegion region) { |
| 421 | rate_control_region_ = region; |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 422 | } |
| 423 | |
pbos@webrtc.org | 9f79fe6 | 2014-12-04 15:34:06 | [diff] [blame] | 424 | } // namespace webrtc |