send_side_bandwidth_estimation.cc revision edeea91803eac26f6a229e88a7045797d2af61b7
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/system_wrappers/interface/field_trial.h"
16#include "webrtc/system_wrappers/interface/logging.h"
17#include "webrtc/system_wrappers/interface/metrics.h"
18
19namespace webrtc {
20namespace {
21enum { kBweIncreaseIntervalMs = 1000 };
22enum { kBweDecreaseIntervalMs = 300 };
23enum { kLimitNumPackets = 20 };
24enum { kAvgPacketSizeBytes = 1000 };
25enum { kStartPhaseMs = 2000 };
26enum { kBweConverganceTimeMs = 20000 };
27
28// Calculate the rate that TCP-Friendly Rate Control (TFRC) would apply.
29// The formula in RFC 3448, Section 3.1, is used.
30uint32_t CalcTfrcBps(uint16_t rtt, uint8_t loss) {
31  if (rtt == 0 || loss == 0) {
32    // Input variables out of range.
33    return 0;
34  }
35  double R = static_cast<double>(rtt) / 1000;  // RTT in seconds.
36  int b = 1;  // Number of packets acknowledged by a single TCP acknowledgement:
37              // recommended = 1.
38  double t_RTO = 4.0 * R;  // TCP retransmission timeout value in seconds
39                           // recommended = 4*R.
40  double p = static_cast<double>(loss) / 255;  // Packet loss rate in [0, 1).
41  double s = static_cast<double>(kAvgPacketSizeBytes);
42
43  // Calculate send rate in bytes/second.
44  double X =
45      s / (R * std::sqrt(2 * b * p / 3) +
46           (t_RTO * (3 * std::sqrt(3 * b * p / 8) * p * (1 + 32 * p * p))));
47
48  // Convert to bits/second.
49  return (static_cast<uint32_t>(X * 8));
50}
51}
52
53SendSideBandwidthEstimation::SendSideBandwidthEstimation()
54    : accumulate_lost_packets_Q8_(0),
55      accumulate_expected_packets_(0),
56      bitrate_(0),
57      min_bitrate_configured_(0),
58      max_bitrate_configured_(0),
59      time_last_receiver_block_ms_(0),
60      last_fraction_loss_(0),
61      last_round_trip_time_ms_(0),
62      bwe_incoming_(0),
63      time_last_decrease_ms_(0),
64      first_report_time_ms_(-1),
65      initially_lost_packets_(0),
66      bitrate_at_2_seconds_kbps_(0),
67      uma_update_state_(kNoUpdate) {
68}
69
70SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {}
71
72void SendSideBandwidthEstimation::SetSendBitrate(uint32_t bitrate) {
73  bitrate_ = bitrate;
74
75  // Clear last sent bitrate history so the new value can be used directly
76  // and not capped.
77  min_bitrate_history_.clear();
78}
79
80void SendSideBandwidthEstimation::SetMinMaxBitrate(uint32_t min_bitrate,
81                                                   uint32_t max_bitrate) {
82  min_bitrate_configured_ = min_bitrate;
83  max_bitrate_configured_ = max_bitrate;
84}
85
86void SendSideBandwidthEstimation::SetMinBitrate(uint32_t min_bitrate) {
87  min_bitrate_configured_ = min_bitrate;
88}
89
90void SendSideBandwidthEstimation::CurrentEstimate(uint32_t* bitrate,
91                                                  uint8_t* loss,
92                                                  uint32_t* rtt) const {
93  *bitrate = bitrate_;
94  *loss = last_fraction_loss_;
95  *rtt = last_round_trip_time_ms_;
96}
97
98void SendSideBandwidthEstimation::UpdateReceiverEstimate(uint32_t bandwidth) {
99  bwe_incoming_ = bandwidth;
100  bitrate_ = CapBitrateToThresholds(bitrate_);
101}
102
103void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
104                                                      uint32_t rtt,
105                                                      int number_of_packets,
106                                                      int64_t now_ms) {
107  if (first_report_time_ms_ == -1)
108    first_report_time_ms_ = now_ms;
109
110  // Update RTT.
111  last_round_trip_time_ms_ = rtt;
112
113  // Check sequence number diff and weight loss report
114  if (number_of_packets > 0) {
115    // Calculate number of lost packets.
116    const int num_lost_packets_Q8 = fraction_loss * number_of_packets;
117    // Accumulate reports.
118    accumulate_lost_packets_Q8_ += num_lost_packets_Q8;
119    accumulate_expected_packets_ += number_of_packets;
120
121    // Report loss if the total report is based on sufficiently many packets.
122    if (accumulate_expected_packets_ >= kLimitNumPackets) {
123      last_fraction_loss_ =
124          accumulate_lost_packets_Q8_ / accumulate_expected_packets_;
125
126      // Reset accumulators.
127      accumulate_lost_packets_Q8_ = 0;
128      accumulate_expected_packets_ = 0;
129    } else {
130      // Early return without updating estimate.
131      return;
132    }
133  }
134  time_last_receiver_block_ms_ = now_ms;
135  UpdateEstimate(now_ms);
136  UpdateUmaStats(now_ms, rtt, (fraction_loss * number_of_packets) >> 8);
137}
138
139void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms,
140                                                 int rtt,
141                                                 int lost_packets) {
142  if (IsInStartPhase(now_ms)) {
143    initially_lost_packets_ += lost_packets;
144  } else if (uma_update_state_ == kNoUpdate) {
145    uma_update_state_ = kFirstDone;
146    bitrate_at_2_seconds_kbps_ = (bitrate_ + 500) / 1000;
147    RTC_HISTOGRAM_COUNTS(
148        "WebRTC.BWE.InitiallyLostPackets", initially_lost_packets_, 0, 100, 50);
149    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", rtt, 0, 2000, 50);
150    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate",
151                         bitrate_at_2_seconds_kbps_,
152                         0,
153                         2000,
154                         50);
155  } else if (uma_update_state_ == kFirstDone &&
156             now_ms - first_report_time_ms_ >= kBweConverganceTimeMs) {
157    uma_update_state_ = kDone;
158    int bitrate_diff_kbps = std::max(
159        bitrate_at_2_seconds_kbps_ - static_cast<int>((bitrate_ + 500) / 1000),
160        0);
161    RTC_HISTOGRAM_COUNTS(
162        "WebRTC.BWE.InitialVsConvergedDiff", bitrate_diff_kbps, 0, 2000, 50);
163  }
164}
165
166void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
167  // We trust the REMB during the first 2 seconds if we haven't had any
168  // packet loss reported, to allow startup bitrate probing.
169  if (ProbingExperimentIsEnabled()) {
170    if (last_fraction_loss_ == 0 && IsInStartPhase(now_ms) &&
171        bwe_incoming_ > bitrate_) {
172      bitrate_ = CapBitrateToThresholds(bwe_incoming_);
173      min_bitrate_history_.clear();
174      min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_));
175      return;
176    }
177  }
178  UpdateMinHistory(now_ms);
179  // Only start updating bitrate when receiving receiver blocks.
180  if (time_last_receiver_block_ms_ != 0) {
181    if (last_fraction_loss_ <= 5) {
182      // Loss < 2%: Increase rate by 8% of the min bitrate in the last
183      // kBweIncreaseIntervalMs.
184      // Note that by remembering the bitrate over the last second one can
185      // rampup up one second faster than if only allowed to start ramping
186      // at 8% per second rate now. E.g.:
187      //   If sending a constant 100kbps it can rampup immediatly to 108kbps
188      //   whenever a receiver report is received with lower packet loss.
189      //   If instead one would do: bitrate_ *= 1.08^(delta time), it would
190      //   take over one second since the lower packet loss to achieve 108kbps.
191      bitrate_ = static_cast<uint32_t>(
192          min_bitrate_history_.front().second * 1.08 + 0.5);
193
194      // Add 1 kbps extra, just to make sure that we do not get stuck
195      // (gives a little extra increase at low rates, negligible at higher
196      // rates).
197      bitrate_ += 1000;
198
199    } else if (last_fraction_loss_ <= 26) {
200      // Loss between 2% - 10%: Do nothing.
201
202    } else {
203      // Loss > 10%: Limit the rate decreases to once a kBweDecreaseIntervalMs +
204      // rtt.
205      if ((now_ms - time_last_decrease_ms_) >=
206          static_cast<uint32_t>(kBweDecreaseIntervalMs +
207                                last_round_trip_time_ms_)) {
208        time_last_decrease_ms_ = now_ms;
209
210        // Reduce rate:
211        //   newRate = rate * (1 - 0.5*lossRate);
212        //   where packetLoss = 256*lossRate;
213        bitrate_ = static_cast<uint32_t>(
214            (bitrate_ * static_cast<double>(512 - last_fraction_loss_)) /
215            512.0);
216
217        // Calculate what rate TFRC would apply in this situation and to not
218        // reduce further than it.
219        bitrate_ = std::max(
220            bitrate_,
221            CalcTfrcBps(last_round_trip_time_ms_, last_fraction_loss_));
222      }
223    }
224  }
225  bitrate_ = CapBitrateToThresholds(bitrate_);
226}
227
228bool SendSideBandwidthEstimation::IsInStartPhase(int64_t now_ms) const {
229  return first_report_time_ms_ == -1 ||
230         now_ms - first_report_time_ms_ < kStartPhaseMs;
231}
232
233void SendSideBandwidthEstimation::UpdateMinHistory(int64_t now_ms) {
234  // Remove old data points from history.
235  // Since history precision is in ms, add one so it is able to increase
236  // bitrate if it is off by as little as 0.5ms.
237  while (!min_bitrate_history_.empty() &&
238         now_ms - min_bitrate_history_.front().first + 1 >
239             kBweIncreaseIntervalMs) {
240    min_bitrate_history_.pop_front();
241  }
242
243  // Typical minimum sliding-window algorithm: Pop values higher than current
244  // bitrate before pushing it.
245  while (!min_bitrate_history_.empty() &&
246         bitrate_ <= min_bitrate_history_.back().second) {
247    min_bitrate_history_.pop_back();
248  }
249
250  min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_));
251}
252
253uint32_t SendSideBandwidthEstimation::CapBitrateToThresholds(uint32_t bitrate) {
254  if (bwe_incoming_ > 0 && bitrate > bwe_incoming_) {
255    bitrate = bwe_incoming_;
256  }
257  if (bitrate > max_bitrate_configured_) {
258    bitrate = max_bitrate_configured_;
259  }
260  if (bitrate < min_bitrate_configured_) {
261    LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate / 1000
262                    << " kbps is below configured min bitrate "
263                    << min_bitrate_configured_ / 1000 << " kbps.";
264    bitrate = min_bitrate_configured_;
265  }
266  return bitrate;
267}
268
269bool SendSideBandwidthEstimation::ProbingExperimentIsEnabled() const {
270  return webrtc::field_trial::FindFullName("WebRTC-BitrateProbing") ==
271         "Enabled";
272}
273}  // namespace webrtc
274