send_side_bandwidth_estimation.cc revision 53805324c0fa904d796cc0b333868c591f2c5f2c
1/* 2 * Copyright (c) 2012 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 "webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h" 12 13#include <cmath> 14 15#include "webrtc/base/checks.h" 16#include "webrtc/base/logging.h" 17#include "webrtc/system_wrappers/include/field_trial.h" 18#include "webrtc/system_wrappers/include/metrics.h" 19#include "webrtc/call/rtc_event_log.h" 20 21namespace webrtc { 22namespace { 23const int64_t kBweIncreaseIntervalMs = 1000; 24const int64_t kBweDecreaseIntervalMs = 300; 25const int64_t kStartPhaseMs = 2000; 26const int64_t kBweConverganceTimeMs = 20000; 27const int kLimitNumPackets = 20; 28const int kDefaultMinBitrateBps = 10000; 29const int kDefaultMaxBitrateBps = 1000000000; 30const int64_t kLowBitrateLogPeriodMs = 10000; 31 32struct UmaRampUpMetric { 33 const char* metric_name; 34 int bitrate_kbps; 35}; 36 37const UmaRampUpMetric kUmaRampupMetrics[] = { 38 {"WebRTC.BWE.RampUpTimeTo500kbpsInMs", 500}, 39 {"WebRTC.BWE.RampUpTimeTo1000kbpsInMs", 1000}, 40 {"WebRTC.BWE.RampUpTimeTo2000kbpsInMs", 2000}}; 41const size_t kNumUmaRampupMetrics = 42 sizeof(kUmaRampupMetrics) / sizeof(kUmaRampupMetrics[0]); 43 44} 45 46SendSideBandwidthEstimation::SendSideBandwidthEstimation() 47 : lost_packets_since_last_loss_update_Q8_(0), 48 expected_packets_since_last_loss_update_(0), 49 bitrate_(0), 50 min_bitrate_configured_(kDefaultMinBitrateBps), 51 max_bitrate_configured_(kDefaultMaxBitrateBps), 52 last_low_bitrate_log_ms_(-1), 53 has_decreased_since_last_fraction_loss_(false), 54 time_last_receiver_block_ms_(-1), 55 last_fraction_loss_(0), 56 last_round_trip_time_ms_(0), 57 bwe_incoming_(0), 58 time_last_decrease_ms_(0), 59 first_report_time_ms_(-1), 60 initially_lost_packets_(0), 61 bitrate_at_2_seconds_kbps_(0), 62 uma_update_state_(kNoUpdate), 63 rampup_uma_stats_updated_(kNumUmaRampupMetrics, false), 64 event_log_(nullptr) {} 65 66SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {} 67 68void SendSideBandwidthEstimation::SetSendBitrate(int bitrate) { 69 RTC_DCHECK_GT(bitrate, 0); 70 bitrate_ = bitrate; 71 72 // Clear last sent bitrate history so the new value can be used directly 73 // and not capped. 74 min_bitrate_history_.clear(); 75} 76 77void SendSideBandwidthEstimation::SetMinMaxBitrate(int min_bitrate, 78 int max_bitrate) { 79 RTC_DCHECK_GE(min_bitrate, 0); 80 min_bitrate_configured_ = std::max(min_bitrate, kDefaultMinBitrateBps); 81 if (max_bitrate > 0) { 82 max_bitrate_configured_ = 83 std::max<uint32_t>(min_bitrate_configured_, max_bitrate); 84 } else { 85 max_bitrate_configured_ = kDefaultMaxBitrateBps; 86 } 87} 88 89int SendSideBandwidthEstimation::GetMinBitrate() const { 90 return min_bitrate_configured_; 91} 92 93void SendSideBandwidthEstimation::CurrentEstimate(int* bitrate, 94 uint8_t* loss, 95 int64_t* rtt) const { 96 *bitrate = bitrate_; 97 *loss = last_fraction_loss_; 98 *rtt = last_round_trip_time_ms_; 99} 100 101void SendSideBandwidthEstimation::UpdateReceiverEstimate( 102 int64_t now_ms, uint32_t bandwidth) { 103 bwe_incoming_ = bandwidth; 104 bitrate_ = CapBitrateToThresholds(now_ms, bitrate_); 105} 106 107void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, 108 int64_t rtt, 109 int number_of_packets, 110 int64_t now_ms) { 111 if (first_report_time_ms_ == -1) 112 first_report_time_ms_ = now_ms; 113 114 // Update RTT. 115 last_round_trip_time_ms_ = rtt; 116 117 // Check sequence number diff and weight loss report 118 if (number_of_packets > 0) { 119 // Calculate number of lost packets. 120 const int num_lost_packets_Q8 = fraction_loss * number_of_packets; 121 // Accumulate reports. 122 lost_packets_since_last_loss_update_Q8_ += num_lost_packets_Q8; 123 expected_packets_since_last_loss_update_ += number_of_packets; 124 125 // Don't generate a loss rate until it can be based on enough packets. 126 if (expected_packets_since_last_loss_update_ < kLimitNumPackets) 127 return; 128 129 has_decreased_since_last_fraction_loss_ = false; 130 last_fraction_loss_ = lost_packets_since_last_loss_update_Q8_ / 131 expected_packets_since_last_loss_update_; 132 133 // Reset accumulators. 134 lost_packets_since_last_loss_update_Q8_ = 0; 135 expected_packets_since_last_loss_update_ = 0; 136 } 137 time_last_receiver_block_ms_ = now_ms; 138 UpdateEstimate(now_ms); 139 UpdateUmaStats(now_ms, rtt, (fraction_loss * number_of_packets) >> 8); 140} 141 142void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms, 143 int64_t rtt, 144 int lost_packets) { 145 int bitrate_kbps = static_cast<int>((bitrate_ + 500) / 1000); 146 for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) { 147 if (!rampup_uma_stats_updated_[i] && 148 bitrate_kbps >= kUmaRampupMetrics[i].bitrate_kbps) { 149 RTC_HISTOGRAM_COUNTS_SPARSE_100000(kUmaRampupMetrics[i].metric_name, 150 now_ms - first_report_time_ms_); 151 rampup_uma_stats_updated_[i] = true; 152 } 153 } 154 if (IsInStartPhase(now_ms)) { 155 initially_lost_packets_ += lost_packets; 156 } else if (uma_update_state_ == kNoUpdate) { 157 uma_update_state_ = kFirstDone; 158 bitrate_at_2_seconds_kbps_ = bitrate_kbps; 159 RTC_HISTOGRAM_COUNTS_SPARSE("WebRTC.BWE.InitiallyLostPackets", 160 initially_lost_packets_, 0, 100, 50); 161 RTC_HISTOGRAM_COUNTS_SPARSE("WebRTC.BWE.InitialRtt", static_cast<int>(rtt), 162 0, 2000, 50); 163 RTC_HISTOGRAM_COUNTS_SPARSE("WebRTC.BWE.InitialBandwidthEstimate", 164 bitrate_at_2_seconds_kbps_, 0, 2000, 50); 165 } else if (uma_update_state_ == kFirstDone && 166 now_ms - first_report_time_ms_ >= kBweConverganceTimeMs) { 167 uma_update_state_ = kDone; 168 int bitrate_diff_kbps = 169 std::max(bitrate_at_2_seconds_kbps_ - bitrate_kbps, 0); 170 RTC_HISTOGRAM_COUNTS_SPARSE("WebRTC.BWE.InitialVsConvergedDiff", 171 bitrate_diff_kbps, 0, 2000, 50); 172 } 173} 174 175void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) { 176 // We trust the REMB during the first 2 seconds if we haven't had any 177 // packet loss reported, to allow startup bitrate probing. 178 if (last_fraction_loss_ == 0 && IsInStartPhase(now_ms) && 179 bwe_incoming_ > bitrate_) { 180 bitrate_ = CapBitrateToThresholds(now_ms, bwe_incoming_); 181 min_bitrate_history_.clear(); 182 min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_)); 183 return; 184 } 185 UpdateMinHistory(now_ms); 186 // Only start updating bitrate when receiving receiver blocks. 187 // TODO(pbos): Handle the case when no receiver report is received for a very 188 // long time. 189 if (time_last_receiver_block_ms_ != -1) { 190 if (last_fraction_loss_ <= 5) { 191 // Loss < 2%: Increase rate by 8% of the min bitrate in the last 192 // kBweIncreaseIntervalMs. 193 // Note that by remembering the bitrate over the last second one can 194 // rampup up one second faster than if only allowed to start ramping 195 // at 8% per second rate now. E.g.: 196 // If sending a constant 100kbps it can rampup immediatly to 108kbps 197 // whenever a receiver report is received with lower packet loss. 198 // If instead one would do: bitrate_ *= 1.08^(delta time), it would 199 // take over one second since the lower packet loss to achieve 108kbps. 200 bitrate_ = static_cast<uint32_t>( 201 min_bitrate_history_.front().second * 1.08 + 0.5); 202 203 // Add 1 kbps extra, just to make sure that we do not get stuck 204 // (gives a little extra increase at low rates, negligible at higher 205 // rates). 206 bitrate_ += 1000; 207 208 if (event_log_) { 209 event_log_->LogBwePacketLossEvent( 210 bitrate_, last_fraction_loss_, 211 expected_packets_since_last_loss_update_); 212 } 213 } else if (last_fraction_loss_ <= 26) { 214 // Loss between 2% - 10%: Do nothing. 215 } else { 216 // Loss > 10%: Limit the rate decreases to once a kBweDecreaseIntervalMs + 217 // rtt. 218 if (!has_decreased_since_last_fraction_loss_ && 219 (now_ms - time_last_decrease_ms_) >= 220 (kBweDecreaseIntervalMs + last_round_trip_time_ms_)) { 221 time_last_decrease_ms_ = now_ms; 222 223 // Reduce rate: 224 // newRate = rate * (1 - 0.5*lossRate); 225 // where packetLoss = 256*lossRate; 226 bitrate_ = static_cast<uint32_t>( 227 (bitrate_ * static_cast<double>(512 - last_fraction_loss_)) / 228 512.0); 229 has_decreased_since_last_fraction_loss_ = true; 230 } 231 if (event_log_) { 232 event_log_->LogBwePacketLossEvent( 233 bitrate_, last_fraction_loss_, 234 expected_packets_since_last_loss_update_); 235 } 236 } 237 } 238 bitrate_ = CapBitrateToThresholds(now_ms, bitrate_); 239} 240 241bool SendSideBandwidthEstimation::IsInStartPhase(int64_t now_ms) const { 242 return first_report_time_ms_ == -1 || 243 now_ms - first_report_time_ms_ < kStartPhaseMs; 244} 245 246void SendSideBandwidthEstimation::UpdateMinHistory(int64_t now_ms) { 247 // Remove old data points from history. 248 // Since history precision is in ms, add one so it is able to increase 249 // bitrate if it is off by as little as 0.5ms. 250 while (!min_bitrate_history_.empty() && 251 now_ms - min_bitrate_history_.front().first + 1 > 252 kBweIncreaseIntervalMs) { 253 min_bitrate_history_.pop_front(); 254 } 255 256 // Typical minimum sliding-window algorithm: Pop values higher than current 257 // bitrate before pushing it. 258 while (!min_bitrate_history_.empty() && 259 bitrate_ <= min_bitrate_history_.back().second) { 260 min_bitrate_history_.pop_back(); 261 } 262 263 min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_)); 264} 265 266uint32_t SendSideBandwidthEstimation::CapBitrateToThresholds( 267 int64_t now_ms, uint32_t bitrate) { 268 if (bwe_incoming_ > 0 && bitrate > bwe_incoming_) { 269 bitrate = bwe_incoming_; 270 } 271 if (bitrate > max_bitrate_configured_) { 272 bitrate = max_bitrate_configured_; 273 } 274 if (bitrate < min_bitrate_configured_) { 275 if (last_low_bitrate_log_ms_ == -1 || 276 now_ms - last_low_bitrate_log_ms_ > kLowBitrateLogPeriodMs) { 277 LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate / 1000 278 << " kbps is below configured min bitrate " 279 << min_bitrate_configured_ / 1000 << " kbps."; 280 last_low_bitrate_log_ms_ = now_ms; 281 } 282 bitrate = min_bitrate_configured_; 283 } 284 return bitrate; 285} 286 287void SendSideBandwidthEstimation::SetEventLog(RtcEventLog* event_log) { 288 event_log_ = event_log; 289} 290 291} // namespace webrtc 292