• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h"
12 
13 #include <algorithm>
14 #include <cstdio>
15 #include <limits>
16 #include <memory>
17 #include <string>
18 
19 #include "absl/strings/match.h"
20 #include "api/rtc_event_log/rtc_event.h"
21 #include "api/rtc_event_log/rtc_event_log.h"
22 #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
23 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/logging.h"
26 #include "system_wrappers/include/field_trial.h"
27 #include "system_wrappers/include/metrics.h"
28 
29 namespace webrtc {
30 namespace {
31 constexpr TimeDelta kBweIncreaseInterval = TimeDelta::Millis(1000);
32 constexpr TimeDelta kBweDecreaseInterval = TimeDelta::Millis(300);
33 constexpr TimeDelta kStartPhase = TimeDelta::Millis(2000);
34 constexpr TimeDelta kBweConverganceTime = TimeDelta::Millis(20000);
35 constexpr int kLimitNumPackets = 20;
36 constexpr DataRate kDefaultMaxBitrate = DataRate::BitsPerSec(1000000000);
37 constexpr TimeDelta kLowBitrateLogPeriod = TimeDelta::Millis(10000);
38 constexpr TimeDelta kRtcEventLogPeriod = TimeDelta::Millis(5000);
39 // Expecting that RTCP feedback is sent uniformly within [0.5, 1.5]s intervals.
40 constexpr TimeDelta kMaxRtcpFeedbackInterval = TimeDelta::Millis(5000);
41 
42 constexpr float kDefaultLowLossThreshold = 0.02f;
43 constexpr float kDefaultHighLossThreshold = 0.1f;
44 constexpr DataRate kDefaultBitrateThreshold = DataRate::Zero();
45 
46 struct UmaRampUpMetric {
47   const char* metric_name;
48   int bitrate_kbps;
49 };
50 
51 const UmaRampUpMetric kUmaRampupMetrics[] = {
52     {"WebRTC.BWE.RampUpTimeTo500kbpsInMs", 500},
53     {"WebRTC.BWE.RampUpTimeTo1000kbpsInMs", 1000},
54     {"WebRTC.BWE.RampUpTimeTo2000kbpsInMs", 2000}};
55 const size_t kNumUmaRampupMetrics =
56     sizeof(kUmaRampupMetrics) / sizeof(kUmaRampupMetrics[0]);
57 
58 const char kBweLosExperiment[] = "WebRTC-BweLossExperiment";
59 
BweLossExperimentIsEnabled()60 bool BweLossExperimentIsEnabled() {
61   std::string experiment_string =
62       webrtc::field_trial::FindFullName(kBweLosExperiment);
63   // The experiment is enabled iff the field trial string begins with "Enabled".
64   return absl::StartsWith(experiment_string, "Enabled");
65 }
66 
ReadBweLossExperimentParameters(float * low_loss_threshold,float * high_loss_threshold,uint32_t * bitrate_threshold_kbps)67 bool ReadBweLossExperimentParameters(float* low_loss_threshold,
68                                      float* high_loss_threshold,
69                                      uint32_t* bitrate_threshold_kbps) {
70   RTC_DCHECK(low_loss_threshold);
71   RTC_DCHECK(high_loss_threshold);
72   RTC_DCHECK(bitrate_threshold_kbps);
73   std::string experiment_string =
74       webrtc::field_trial::FindFullName(kBweLosExperiment);
75   int parsed_values =
76       sscanf(experiment_string.c_str(), "Enabled-%f,%f,%u", low_loss_threshold,
77              high_loss_threshold, bitrate_threshold_kbps);
78   if (parsed_values == 3) {
79     RTC_CHECK_GT(*low_loss_threshold, 0.0f)
80         << "Loss threshold must be greater than 0.";
81     RTC_CHECK_LE(*low_loss_threshold, 1.0f)
82         << "Loss threshold must be less than or equal to 1.";
83     RTC_CHECK_GT(*high_loss_threshold, 0.0f)
84         << "Loss threshold must be greater than 0.";
85     RTC_CHECK_LE(*high_loss_threshold, 1.0f)
86         << "Loss threshold must be less than or equal to 1.";
87     RTC_CHECK_LE(*low_loss_threshold, *high_loss_threshold)
88         << "The low loss threshold must be less than or equal to the high loss "
89            "threshold.";
90     RTC_CHECK_GE(*bitrate_threshold_kbps, 0)
91         << "Bitrate threshold can't be negative.";
92     RTC_CHECK_LT(*bitrate_threshold_kbps,
93                  std::numeric_limits<int>::max() / 1000)
94         << "Bitrate must be smaller enough to avoid overflows.";
95     return true;
96   }
97   RTC_LOG(LS_WARNING) << "Failed to parse parameters for BweLossExperiment "
98                          "experiment from field trial string. Using default.";
99   *low_loss_threshold = kDefaultLowLossThreshold;
100   *high_loss_threshold = kDefaultHighLossThreshold;
101   *bitrate_threshold_kbps = kDefaultBitrateThreshold.kbps();
102   return false;
103 }
104 }  // namespace
105 
LinkCapacityTracker()106 LinkCapacityTracker::LinkCapacityTracker()
107     : tracking_rate("rate", TimeDelta::Seconds(10)) {
108   ParseFieldTrial({&tracking_rate},
109                   field_trial::FindFullName("WebRTC-Bwe-LinkCapacity"));
110 }
111 
~LinkCapacityTracker()112 LinkCapacityTracker::~LinkCapacityTracker() {}
113 
UpdateDelayBasedEstimate(Timestamp at_time,DataRate delay_based_bitrate)114 void LinkCapacityTracker::UpdateDelayBasedEstimate(
115     Timestamp at_time,
116     DataRate delay_based_bitrate) {
117   if (delay_based_bitrate < last_delay_based_estimate_) {
118     capacity_estimate_bps_ =
119         std::min(capacity_estimate_bps_, delay_based_bitrate.bps<double>());
120     last_link_capacity_update_ = at_time;
121   }
122   last_delay_based_estimate_ = delay_based_bitrate;
123 }
124 
OnStartingRate(DataRate start_rate)125 void LinkCapacityTracker::OnStartingRate(DataRate start_rate) {
126   if (last_link_capacity_update_.IsInfinite())
127     capacity_estimate_bps_ = start_rate.bps<double>();
128 }
129 
OnRateUpdate(absl::optional<DataRate> acknowledged,DataRate target,Timestamp at_time)130 void LinkCapacityTracker::OnRateUpdate(absl::optional<DataRate> acknowledged,
131                                        DataRate target,
132                                        Timestamp at_time) {
133   if (!acknowledged)
134     return;
135   DataRate acknowledged_target = std::min(*acknowledged, target);
136   if (acknowledged_target.bps() > capacity_estimate_bps_) {
137     TimeDelta delta = at_time - last_link_capacity_update_;
138     double alpha = delta.IsFinite() ? exp(-(delta / tracking_rate.Get())) : 0;
139     capacity_estimate_bps_ = alpha * capacity_estimate_bps_ +
140                              (1 - alpha) * acknowledged_target.bps<double>();
141   }
142   last_link_capacity_update_ = at_time;
143 }
144 
OnRttBackoff(DataRate backoff_rate,Timestamp at_time)145 void LinkCapacityTracker::OnRttBackoff(DataRate backoff_rate,
146                                        Timestamp at_time) {
147   capacity_estimate_bps_ =
148       std::min(capacity_estimate_bps_, backoff_rate.bps<double>());
149   last_link_capacity_update_ = at_time;
150 }
151 
estimate() const152 DataRate LinkCapacityTracker::estimate() const {
153   return DataRate::BitsPerSec(capacity_estimate_bps_);
154 }
155 
RttBasedBackoff()156 RttBasedBackoff::RttBasedBackoff()
157     : rtt_limit_("limit", TimeDelta::Seconds(3)),
158       drop_fraction_("fraction", 0.8),
159       drop_interval_("interval", TimeDelta::Seconds(1)),
160       bandwidth_floor_("floor", DataRate::KilobitsPerSec(5)),
161       // By initializing this to plus infinity, we make sure that we never
162       // trigger rtt backoff unless packet feedback is enabled.
163       last_propagation_rtt_update_(Timestamp::PlusInfinity()),
164       last_propagation_rtt_(TimeDelta::Zero()),
165       last_packet_sent_(Timestamp::MinusInfinity()) {
166   ParseFieldTrial(
167       {&rtt_limit_, &drop_fraction_, &drop_interval_, &bandwidth_floor_},
168       field_trial::FindFullName("WebRTC-Bwe-MaxRttLimit"));
169 }
170 
UpdatePropagationRtt(Timestamp at_time,TimeDelta propagation_rtt)171 void RttBasedBackoff::UpdatePropagationRtt(Timestamp at_time,
172                                            TimeDelta propagation_rtt) {
173   last_propagation_rtt_update_ = at_time;
174   last_propagation_rtt_ = propagation_rtt;
175 }
176 
CorrectedRtt(Timestamp at_time) const177 TimeDelta RttBasedBackoff::CorrectedRtt(Timestamp at_time) const {
178   TimeDelta time_since_rtt = at_time - last_propagation_rtt_update_;
179   TimeDelta timeout_correction = time_since_rtt;
180   // Avoid timeout when no packets are being sent.
181   TimeDelta time_since_packet_sent = at_time - last_packet_sent_;
182   timeout_correction =
183       std::max(time_since_rtt - time_since_packet_sent, TimeDelta::Zero());
184   return timeout_correction + last_propagation_rtt_;
185 }
186 
187 RttBasedBackoff::~RttBasedBackoff() = default;
188 
SendSideBandwidthEstimation(RtcEventLog * event_log)189 SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log)
190     : lost_packets_since_last_loss_update_(0),
191       expected_packets_since_last_loss_update_(0),
192       current_target_(DataRate::Zero()),
193       last_logged_target_(DataRate::Zero()),
194       min_bitrate_configured_(
195           DataRate::BitsPerSec(congestion_controller::GetMinBitrateBps())),
196       max_bitrate_configured_(kDefaultMaxBitrate),
197       last_low_bitrate_log_(Timestamp::MinusInfinity()),
198       has_decreased_since_last_fraction_loss_(false),
199       last_loss_feedback_(Timestamp::MinusInfinity()),
200       last_loss_packet_report_(Timestamp::MinusInfinity()),
201       last_fraction_loss_(0),
202       last_logged_fraction_loss_(0),
203       last_round_trip_time_(TimeDelta::Zero()),
204       receiver_limit_(DataRate::PlusInfinity()),
205       delay_based_limit_(DataRate::PlusInfinity()),
206       time_last_decrease_(Timestamp::MinusInfinity()),
207       first_report_time_(Timestamp::MinusInfinity()),
208       initially_lost_packets_(0),
209       bitrate_at_2_seconds_(DataRate::Zero()),
210       uma_update_state_(kNoUpdate),
211       uma_rtt_state_(kNoUpdate),
212       rampup_uma_stats_updated_(kNumUmaRampupMetrics, false),
213       event_log_(event_log),
214       last_rtc_event_log_(Timestamp::MinusInfinity()),
215       low_loss_threshold_(kDefaultLowLossThreshold),
216       high_loss_threshold_(kDefaultHighLossThreshold),
217       bitrate_threshold_(kDefaultBitrateThreshold) {
218   RTC_DCHECK(event_log);
219   if (BweLossExperimentIsEnabled()) {
220     uint32_t bitrate_threshold_kbps;
221     if (ReadBweLossExperimentParameters(&low_loss_threshold_,
222                                         &high_loss_threshold_,
223                                         &bitrate_threshold_kbps)) {
224       RTC_LOG(LS_INFO) << "Enabled BweLossExperiment with parameters "
225                        << low_loss_threshold_ << ", " << high_loss_threshold_
226                        << ", " << bitrate_threshold_kbps;
227       bitrate_threshold_ = DataRate::KilobitsPerSec(bitrate_threshold_kbps);
228     }
229   }
230 }
231 
~SendSideBandwidthEstimation()232 SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {}
233 
OnRouteChange()234 void SendSideBandwidthEstimation::OnRouteChange() {
235   lost_packets_since_last_loss_update_ = 0;
236   expected_packets_since_last_loss_update_ = 0;
237   current_target_ = DataRate::Zero();
238   min_bitrate_configured_ =
239       DataRate::BitsPerSec(congestion_controller::GetMinBitrateBps());
240   max_bitrate_configured_ = kDefaultMaxBitrate;
241   last_low_bitrate_log_ = Timestamp::MinusInfinity();
242   has_decreased_since_last_fraction_loss_ = false;
243   last_loss_feedback_ = Timestamp::MinusInfinity();
244   last_loss_packet_report_ = Timestamp::MinusInfinity();
245   last_fraction_loss_ = 0;
246   last_logged_fraction_loss_ = 0;
247   last_round_trip_time_ = TimeDelta::Zero();
248   receiver_limit_ = DataRate::PlusInfinity();
249   delay_based_limit_ = DataRate::PlusInfinity();
250   time_last_decrease_ = Timestamp::MinusInfinity();
251   first_report_time_ = Timestamp::MinusInfinity();
252   initially_lost_packets_ = 0;
253   bitrate_at_2_seconds_ = DataRate::Zero();
254   uma_update_state_ = kNoUpdate;
255   uma_rtt_state_ = kNoUpdate;
256   last_rtc_event_log_ = Timestamp::MinusInfinity();
257 }
258 
SetBitrates(absl::optional<DataRate> send_bitrate,DataRate min_bitrate,DataRate max_bitrate,Timestamp at_time)259 void SendSideBandwidthEstimation::SetBitrates(
260     absl::optional<DataRate> send_bitrate,
261     DataRate min_bitrate,
262     DataRate max_bitrate,
263     Timestamp at_time) {
264   SetMinMaxBitrate(min_bitrate, max_bitrate);
265   if (send_bitrate) {
266     link_capacity_.OnStartingRate(*send_bitrate);
267     SetSendBitrate(*send_bitrate, at_time);
268   }
269 }
270 
SetSendBitrate(DataRate bitrate,Timestamp at_time)271 void SendSideBandwidthEstimation::SetSendBitrate(DataRate bitrate,
272                                                  Timestamp at_time) {
273   RTC_DCHECK_GT(bitrate, DataRate::Zero());
274   // Reset to avoid being capped by the estimate.
275   delay_based_limit_ = DataRate::PlusInfinity();
276   if (loss_based_bandwidth_estimation_.Enabled()) {
277     loss_based_bandwidth_estimation_.MaybeReset(bitrate);
278   }
279   UpdateTargetBitrate(bitrate, at_time);
280   // Clear last sent bitrate history so the new value can be used directly
281   // and not capped.
282   min_bitrate_history_.clear();
283 }
284 
SetMinMaxBitrate(DataRate min_bitrate,DataRate max_bitrate)285 void SendSideBandwidthEstimation::SetMinMaxBitrate(DataRate min_bitrate,
286                                                    DataRate max_bitrate) {
287   min_bitrate_configured_ =
288       std::max(min_bitrate, congestion_controller::GetMinBitrate());
289   if (max_bitrate > DataRate::Zero() && max_bitrate.IsFinite()) {
290     max_bitrate_configured_ = std::max(min_bitrate_configured_, max_bitrate);
291   } else {
292     max_bitrate_configured_ = kDefaultMaxBitrate;
293   }
294 }
295 
GetMinBitrate() const296 int SendSideBandwidthEstimation::GetMinBitrate() const {
297   return min_bitrate_configured_.bps<int>();
298 }
299 
target_rate() const300 DataRate SendSideBandwidthEstimation::target_rate() const {
301   return std::max(min_bitrate_configured_, current_target_);
302 }
303 
GetEstimatedLinkCapacity() const304 DataRate SendSideBandwidthEstimation::GetEstimatedLinkCapacity() const {
305   return link_capacity_.estimate();
306 }
307 
UpdateReceiverEstimate(Timestamp at_time,DataRate bandwidth)308 void SendSideBandwidthEstimation::UpdateReceiverEstimate(Timestamp at_time,
309                                                          DataRate bandwidth) {
310   // TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no
311   // limitation.
312   receiver_limit_ = bandwidth.IsZero() ? DataRate::PlusInfinity() : bandwidth;
313   ApplyTargetLimits(at_time);
314 }
315 
UpdateDelayBasedEstimate(Timestamp at_time,DataRate bitrate)316 void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(Timestamp at_time,
317                                                            DataRate bitrate) {
318   link_capacity_.UpdateDelayBasedEstimate(at_time, bitrate);
319   // TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no
320   // limitation.
321   delay_based_limit_ = bitrate.IsZero() ? DataRate::PlusInfinity() : bitrate;
322   ApplyTargetLimits(at_time);
323 }
324 
SetAcknowledgedRate(absl::optional<DataRate> acknowledged_rate,Timestamp at_time)325 void SendSideBandwidthEstimation::SetAcknowledgedRate(
326     absl::optional<DataRate> acknowledged_rate,
327     Timestamp at_time) {
328   acknowledged_rate_ = acknowledged_rate;
329   if (acknowledged_rate && loss_based_bandwidth_estimation_.Enabled()) {
330     loss_based_bandwidth_estimation_.UpdateAcknowledgedBitrate(
331         *acknowledged_rate, at_time);
332   }
333 }
334 
IncomingPacketFeedbackVector(const TransportPacketsFeedback & report)335 void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
336     const TransportPacketsFeedback& report) {
337   if (loss_based_bandwidth_estimation_.Enabled()) {
338     loss_based_bandwidth_estimation_.UpdateLossStatistics(
339         report.packet_feedbacks, report.feedback_time);
340   }
341 }
342 
UpdatePacketsLost(int packets_lost,int number_of_packets,Timestamp at_time)343 void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost,
344                                                     int number_of_packets,
345                                                     Timestamp at_time) {
346   last_loss_feedback_ = at_time;
347   if (first_report_time_.IsInfinite())
348     first_report_time_ = at_time;
349 
350   // Check sequence number diff and weight loss report
351   if (number_of_packets > 0) {
352     // Accumulate reports.
353     lost_packets_since_last_loss_update_ += packets_lost;
354     expected_packets_since_last_loss_update_ += number_of_packets;
355 
356     // Don't generate a loss rate until it can be based on enough packets.
357     if (expected_packets_since_last_loss_update_ < kLimitNumPackets)
358       return;
359 
360     has_decreased_since_last_fraction_loss_ = false;
361     int64_t lost_q8 = lost_packets_since_last_loss_update_ << 8;
362     int64_t expected = expected_packets_since_last_loss_update_;
363     last_fraction_loss_ = std::min<int>(lost_q8 / expected, 255);
364 
365     // Reset accumulators.
366 
367     lost_packets_since_last_loss_update_ = 0;
368     expected_packets_since_last_loss_update_ = 0;
369     last_loss_packet_report_ = at_time;
370     UpdateEstimate(at_time);
371   }
372   UpdateUmaStatsPacketsLost(at_time, packets_lost);
373 }
374 
UpdateUmaStatsPacketsLost(Timestamp at_time,int packets_lost)375 void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(Timestamp at_time,
376                                                             int packets_lost) {
377   DataRate bitrate_kbps =
378       DataRate::KilobitsPerSec((current_target_.bps() + 500) / 1000);
379   for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) {
380     if (!rampup_uma_stats_updated_[i] &&
381         bitrate_kbps.kbps() >= kUmaRampupMetrics[i].bitrate_kbps) {
382       RTC_HISTOGRAMS_COUNTS_100000(i, kUmaRampupMetrics[i].metric_name,
383                                    (at_time - first_report_time_).ms());
384       rampup_uma_stats_updated_[i] = true;
385     }
386   }
387   if (IsInStartPhase(at_time)) {
388     initially_lost_packets_ += packets_lost;
389   } else if (uma_update_state_ == kNoUpdate) {
390     uma_update_state_ = kFirstDone;
391     bitrate_at_2_seconds_ = bitrate_kbps;
392     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitiallyLostPackets",
393                          initially_lost_packets_, 0, 100, 50);
394     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate",
395                          bitrate_at_2_seconds_.kbps(), 0, 2000, 50);
396   } else if (uma_update_state_ == kFirstDone &&
397              at_time - first_report_time_ >= kBweConverganceTime) {
398     uma_update_state_ = kDone;
399     int bitrate_diff_kbps = std::max(
400         bitrate_at_2_seconds_.kbps<int>() - bitrate_kbps.kbps<int>(), 0);
401     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialVsConvergedDiff", bitrate_diff_kbps,
402                          0, 2000, 50);
403   }
404 }
405 
UpdateRtt(TimeDelta rtt,Timestamp at_time)406 void SendSideBandwidthEstimation::UpdateRtt(TimeDelta rtt, Timestamp at_time) {
407   // Update RTT if we were able to compute an RTT based on this RTCP.
408   // FlexFEC doesn't send RTCP SR, which means we won't be able to compute RTT.
409   if (rtt > TimeDelta::Zero())
410     last_round_trip_time_ = rtt;
411 
412   if (!IsInStartPhase(at_time) && uma_rtt_state_ == kNoUpdate) {
413     uma_rtt_state_ = kDone;
414     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", rtt.ms<int>(), 0, 2000, 50);
415   }
416 }
417 
UpdateEstimate(Timestamp at_time)418 void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) {
419   if (rtt_backoff_.CorrectedRtt(at_time) > rtt_backoff_.rtt_limit_) {
420     if (at_time - time_last_decrease_ >= rtt_backoff_.drop_interval_ &&
421         current_target_ > rtt_backoff_.bandwidth_floor_) {
422       time_last_decrease_ = at_time;
423       DataRate new_bitrate =
424           std::max(current_target_ * rtt_backoff_.drop_fraction_,
425                    rtt_backoff_.bandwidth_floor_.Get());
426       link_capacity_.OnRttBackoff(new_bitrate, at_time);
427       UpdateTargetBitrate(new_bitrate, at_time);
428       return;
429     }
430     // TODO(srte): This is likely redundant in most cases.
431     ApplyTargetLimits(at_time);
432     return;
433   }
434 
435   // We trust the REMB and/or delay-based estimate during the first 2 seconds if
436   // we haven't had any packet loss reported, to allow startup bitrate probing.
437   if (last_fraction_loss_ == 0 && IsInStartPhase(at_time)) {
438     DataRate new_bitrate = current_target_;
439     // TODO(srte): We should not allow the new_bitrate to be larger than the
440     // receiver limit here.
441     if (receiver_limit_.IsFinite())
442       new_bitrate = std::max(receiver_limit_, new_bitrate);
443     if (delay_based_limit_.IsFinite())
444       new_bitrate = std::max(delay_based_limit_, new_bitrate);
445     if (loss_based_bandwidth_estimation_.Enabled()) {
446       loss_based_bandwidth_estimation_.SetInitialBitrate(new_bitrate);
447     }
448 
449     if (new_bitrate != current_target_) {
450       min_bitrate_history_.clear();
451       if (loss_based_bandwidth_estimation_.Enabled()) {
452         min_bitrate_history_.push_back(std::make_pair(at_time, new_bitrate));
453       } else {
454         min_bitrate_history_.push_back(
455             std::make_pair(at_time, current_target_));
456       }
457       UpdateTargetBitrate(new_bitrate, at_time);
458       return;
459     }
460   }
461   UpdateMinHistory(at_time);
462   if (last_loss_packet_report_.IsInfinite()) {
463     // No feedback received.
464     // TODO(srte): This is likely redundant in most cases.
465     ApplyTargetLimits(at_time);
466     return;
467   }
468 
469   if (loss_based_bandwidth_estimation_.Enabled()) {
470     loss_based_bandwidth_estimation_.Update(
471         at_time, min_bitrate_history_.front().second, last_round_trip_time_);
472     DataRate new_bitrate = MaybeRampupOrBackoff(current_target_, at_time);
473     UpdateTargetBitrate(new_bitrate, at_time);
474     return;
475   }
476 
477   TimeDelta time_since_loss_packet_report = at_time - last_loss_packet_report_;
478   if (time_since_loss_packet_report < 1.2 * kMaxRtcpFeedbackInterval) {
479     // We only care about loss above a given bitrate threshold.
480     float loss = last_fraction_loss_ / 256.0f;
481     // We only make decisions based on loss when the bitrate is above a
482     // threshold. This is a crude way of handling loss which is uncorrelated
483     // to congestion.
484     if (current_target_ < bitrate_threshold_ || loss <= low_loss_threshold_) {
485       // Loss < 2%: Increase rate by 8% of the min bitrate in the last
486       // kBweIncreaseInterval.
487       // Note that by remembering the bitrate over the last second one can
488       // rampup up one second faster than if only allowed to start ramping
489       // at 8% per second rate now. E.g.:
490       //   If sending a constant 100kbps it can rampup immediately to 108kbps
491       //   whenever a receiver report is received with lower packet loss.
492       //   If instead one would do: current_bitrate_ *= 1.08^(delta time),
493       //   it would take over one second since the lower packet loss to achieve
494       //   108kbps.
495       DataRate new_bitrate = DataRate::BitsPerSec(
496           min_bitrate_history_.front().second.bps() * 1.08 + 0.5);
497 
498       // Add 1 kbps extra, just to make sure that we do not get stuck
499       // (gives a little extra increase at low rates, negligible at higher
500       // rates).
501       new_bitrate += DataRate::BitsPerSec(1000);
502       UpdateTargetBitrate(new_bitrate, at_time);
503       return;
504     } else if (current_target_ > bitrate_threshold_) {
505       if (loss <= high_loss_threshold_) {
506         // Loss between 2% - 10%: Do nothing.
507       } else {
508         // Loss > 10%: Limit the rate decreases to once a kBweDecreaseInterval
509         // + rtt.
510         if (!has_decreased_since_last_fraction_loss_ &&
511             (at_time - time_last_decrease_) >=
512                 (kBweDecreaseInterval + last_round_trip_time_)) {
513           time_last_decrease_ = at_time;
514 
515           // Reduce rate:
516           //   newRate = rate * (1 - 0.5*lossRate);
517           //   where packetLoss = 256*lossRate;
518           DataRate new_bitrate = DataRate::BitsPerSec(
519               (current_target_.bps() *
520                static_cast<double>(512 - last_fraction_loss_)) /
521               512.0);
522           has_decreased_since_last_fraction_loss_ = true;
523           UpdateTargetBitrate(new_bitrate, at_time);
524           return;
525         }
526       }
527     }
528   }
529   // TODO(srte): This is likely redundant in most cases.
530   ApplyTargetLimits(at_time);
531 }
532 
UpdatePropagationRtt(Timestamp at_time,TimeDelta propagation_rtt)533 void SendSideBandwidthEstimation::UpdatePropagationRtt(
534     Timestamp at_time,
535     TimeDelta propagation_rtt) {
536   rtt_backoff_.UpdatePropagationRtt(at_time, propagation_rtt);
537 }
538 
OnSentPacket(const SentPacket & sent_packet)539 void SendSideBandwidthEstimation::OnSentPacket(const SentPacket& sent_packet) {
540   // Only feedback-triggering packets will be reported here.
541   rtt_backoff_.last_packet_sent_ = sent_packet.send_time;
542 }
543 
IsInStartPhase(Timestamp at_time) const544 bool SendSideBandwidthEstimation::IsInStartPhase(Timestamp at_time) const {
545   return first_report_time_.IsInfinite() ||
546          at_time - first_report_time_ < kStartPhase;
547 }
548 
UpdateMinHistory(Timestamp at_time)549 void SendSideBandwidthEstimation::UpdateMinHistory(Timestamp at_time) {
550   // Remove old data points from history.
551   // Since history precision is in ms, add one so it is able to increase
552   // bitrate if it is off by as little as 0.5ms.
553   while (!min_bitrate_history_.empty() &&
554          at_time - min_bitrate_history_.front().first + TimeDelta::Millis(1) >
555              kBweIncreaseInterval) {
556     min_bitrate_history_.pop_front();
557   }
558 
559   // Typical minimum sliding-window algorithm: Pop values higher than current
560   // bitrate before pushing it.
561   while (!min_bitrate_history_.empty() &&
562          current_target_ <= min_bitrate_history_.back().second) {
563     min_bitrate_history_.pop_back();
564   }
565 
566   min_bitrate_history_.push_back(std::make_pair(at_time, current_target_));
567 }
568 
MaybeRampupOrBackoff(DataRate new_bitrate,Timestamp at_time)569 DataRate SendSideBandwidthEstimation::MaybeRampupOrBackoff(DataRate new_bitrate,
570                                                            Timestamp at_time) {
571   // TODO(crodbro): reuse this code in UpdateEstimate instead of current
572   // inlining of very similar functionality.
573   const TimeDelta time_since_loss_packet_report =
574       at_time - last_loss_packet_report_;
575   if (time_since_loss_packet_report < 1.2 * kMaxRtcpFeedbackInterval) {
576     new_bitrate = min_bitrate_history_.front().second * 1.08;
577     new_bitrate += DataRate::BitsPerSec(1000);
578   }
579   return new_bitrate;
580 }
581 
GetUpperLimit() const582 DataRate SendSideBandwidthEstimation::GetUpperLimit() const {
583   DataRate upper_limit = std::min(delay_based_limit_, receiver_limit_);
584   upper_limit = std::min(upper_limit, max_bitrate_configured_);
585   if (loss_based_bandwidth_estimation_.Enabled() &&
586       loss_based_bandwidth_estimation_.GetEstimate() > DataRate::Zero()) {
587     upper_limit =
588         std::min(upper_limit, loss_based_bandwidth_estimation_.GetEstimate());
589   }
590   return upper_limit;
591 }
592 
MaybeLogLowBitrateWarning(DataRate bitrate,Timestamp at_time)593 void SendSideBandwidthEstimation::MaybeLogLowBitrateWarning(DataRate bitrate,
594                                                             Timestamp at_time) {
595   if (at_time - last_low_bitrate_log_ > kLowBitrateLogPeriod) {
596     RTC_LOG(LS_WARNING) << "Estimated available bandwidth " << ToString(bitrate)
597                         << " is below configured min bitrate "
598                         << ToString(min_bitrate_configured_) << ".";
599     last_low_bitrate_log_ = at_time;
600   }
601 }
602 
MaybeLogLossBasedEvent(Timestamp at_time)603 void SendSideBandwidthEstimation::MaybeLogLossBasedEvent(Timestamp at_time) {
604   if (current_target_ != last_logged_target_ ||
605       last_fraction_loss_ != last_logged_fraction_loss_ ||
606       at_time - last_rtc_event_log_ > kRtcEventLogPeriod) {
607     event_log_->Log(std::make_unique<RtcEventBweUpdateLossBased>(
608         current_target_.bps(), last_fraction_loss_,
609         expected_packets_since_last_loss_update_));
610     last_logged_fraction_loss_ = last_fraction_loss_;
611     last_logged_target_ = current_target_;
612     last_rtc_event_log_ = at_time;
613   }
614 }
615 
UpdateTargetBitrate(DataRate new_bitrate,Timestamp at_time)616 void SendSideBandwidthEstimation::UpdateTargetBitrate(DataRate new_bitrate,
617                                                       Timestamp at_time) {
618   new_bitrate = std::min(new_bitrate, GetUpperLimit());
619   if (new_bitrate < min_bitrate_configured_) {
620     MaybeLogLowBitrateWarning(new_bitrate, at_time);
621     new_bitrate = min_bitrate_configured_;
622   }
623   current_target_ = new_bitrate;
624   MaybeLogLossBasedEvent(at_time);
625   link_capacity_.OnRateUpdate(acknowledged_rate_, current_target_, at_time);
626 }
627 
ApplyTargetLimits(Timestamp at_time)628 void SendSideBandwidthEstimation::ApplyTargetLimits(Timestamp at_time) {
629   UpdateTargetBitrate(current_target_, at_time);
630 }
631 }  // namespace webrtc
632