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