summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc')
-rw-r--r--chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc304
1 files changed, 146 insertions, 158 deletions
diff --git a/chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
index ce385db54c1..5da23f06624 100644
--- a/chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
+++ b/chromium/third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
@@ -10,216 +10,204 @@
#include "webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h"
-#include <math.h> // sqrt()
+#include <cmath>
-#include "webrtc/system_wrappers/interface/trace.h"
+#include "webrtc/system_wrappers/interface/logging.h"
namespace webrtc {
+namespace {
+enum { kBweIncreaseIntervalMs = 1000 };
+enum { kBweDecreaseIntervalMs = 300 };
+enum { kLimitNumPackets = 20 };
+enum { kAvgPacketSizeBytes = 1000 };
+
+// Calculate the rate that TCP-Friendly Rate Control (TFRC) would apply.
+// The formula in RFC 3448, Section 3.1, is used.
+uint32_t CalcTfrcBps(uint16_t rtt, uint8_t loss) {
+ if (rtt == 0 || loss == 0) {
+ // Input variables out of range.
+ return 0;
+ }
+ double R = static_cast<double>(rtt) / 1000; // RTT in seconds.
+ int b = 1; // Number of packets acknowledged by a single TCP acknowledgement:
+ // recommended = 1.
+ double t_RTO = 4.0 * R; // TCP retransmission timeout value in seconds
+ // recommended = 4*R.
+ double p = static_cast<double>(loss) / 255; // Packet loss rate in [0, 1).
+ double s = static_cast<double>(kAvgPacketSizeBytes);
+
+ // Calculate send rate in bytes/second.
+ double X =
+ s / (R * std::sqrt(2 * b * p / 3) +
+ (t_RTO * (3 * std::sqrt(3 * b * p / 8) * p * (1 + 32 * p * p))));
+
+ // Convert to bits/second.
+ return (static_cast<uint32_t>(X * 8));
+}
+}
SendSideBandwidthEstimation::SendSideBandwidthEstimation()
- : critsect_(CriticalSectionWrapper::CreateCriticalSection()),
- accumulate_lost_packets_Q8_(0),
+ : accumulate_lost_packets_Q8_(0),
accumulate_expected_packets_(0),
bitrate_(0),
min_bitrate_configured_(0),
max_bitrate_configured_(0),
+ time_last_receiver_block_ms_(0),
last_fraction_loss_(0),
- last_round_trip_time_(0),
+ last_round_trip_time_ms_(0),
bwe_incoming_(0),
- time_last_increase_(0),
- time_last_decrease_(0) {
-}
+ time_last_decrease_ms_(0) {}
-SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {
- delete critsect_;
-}
+SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {}
-void SendSideBandwidthEstimation::SetSendBitrate(const uint32_t bitrate) {
- CriticalSectionScoped cs(critsect_);
+void SendSideBandwidthEstimation::SetSendBitrate(uint32_t bitrate) {
bitrate_ = bitrate;
+
+ // Clear last sent bitrate history so the new value can be used directly
+ // and not capped.
+ min_bitrate_history_.clear();
}
-void SendSideBandwidthEstimation::SetMinMaxBitrate(const uint32_t min_bitrate,
- const uint32_t max_bitrate) {
- CriticalSectionScoped cs(critsect_);
+void SendSideBandwidthEstimation::SetMinMaxBitrate(uint32_t min_bitrate,
+ uint32_t max_bitrate) {
min_bitrate_configured_ = min_bitrate;
- if (max_bitrate == 0) {
- // no max configured use 1Gbit/s
- max_bitrate_configured_ = 1000000000;
- } else {
- max_bitrate_configured_ = max_bitrate;
- }
+ max_bitrate_configured_ = max_bitrate;
}
-bool SendSideBandwidthEstimation::UpdateBandwidthEstimate(
- const uint32_t bandwidth,
- uint32_t* new_bitrate,
- uint8_t* fraction_lost,
- uint16_t* rtt) {
- *new_bitrate = 0;
- CriticalSectionScoped cs(critsect_);
+void SendSideBandwidthEstimation::SetMinBitrate(uint32_t min_bitrate) {
+ min_bitrate_configured_ = min_bitrate;
+}
- bwe_incoming_ = bandwidth;
+void SendSideBandwidthEstimation::CurrentEstimate(uint32_t* bitrate,
+ uint8_t* loss,
+ uint32_t* rtt) const {
+ *bitrate = bitrate_;
+ *loss = last_fraction_loss_;
+ *rtt = last_round_trip_time_ms_;
+}
- if (bitrate_ == 0) {
- // SendSideBandwidthEstimation off
- return false;
- }
- if (bwe_incoming_ > 0 && bitrate_ > bwe_incoming_) {
- bitrate_ = bwe_incoming_;
- *new_bitrate = bitrate_;
- *fraction_lost = last_fraction_loss_;
- *rtt = last_round_trip_time_;
- return true;
- }
- return false;
+void SendSideBandwidthEstimation::UpdateReceiverEstimate(uint32_t bandwidth) {
+ bwe_incoming_ = bandwidth;
+ CapBitrateToThresholds();
}
-bool SendSideBandwidthEstimation::UpdatePacketLoss(
- const int number_of_packets,
- const uint32_t rtt,
- const uint32_t now_ms,
- uint8_t* loss,
- uint32_t* new_bitrate) {
- CriticalSectionScoped cs(critsect_);
-
- if (bitrate_ == 0) {
- // SendSideBandwidthEstimation off
- return false;
- }
+void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
+ uint32_t rtt,
+ int number_of_packets,
+ uint32_t now_ms) {
// Update RTT.
- last_round_trip_time_ = rtt;
+ last_round_trip_time_ms_ = rtt;
// Check sequence number diff and weight loss report
if (number_of_packets > 0) {
// Calculate number of lost packets.
- const int num_lost_packets_Q8 = *loss * number_of_packets;
+ const int num_lost_packets_Q8 = fraction_loss * number_of_packets;
// Accumulate reports.
accumulate_lost_packets_Q8_ += num_lost_packets_Q8;
accumulate_expected_packets_ += number_of_packets;
// Report loss if the total report is based on sufficiently many packets.
if (accumulate_expected_packets_ >= kLimitNumPackets) {
- *loss = accumulate_lost_packets_Q8_ / accumulate_expected_packets_;
+ last_fraction_loss_ =
+ accumulate_lost_packets_Q8_ / accumulate_expected_packets_;
- // Reset accumulators
+ // Reset accumulators.
accumulate_lost_packets_Q8_ = 0;
accumulate_expected_packets_ = 0;
} else {
- // Report zero loss until we have enough data to estimate
- // the loss rate.
- return false;
+ // Early return without updating estimate.
+ return;
}
}
- // Keep for next time.
- last_fraction_loss_ = *loss;
- uint32_t bitrate = 0;
- if (!ShapeSimple(*loss, rtt, now_ms, &bitrate)) {
- // No change.
- return false;
- }
- bitrate_ = bitrate;
- *new_bitrate = bitrate;
- return true;
+ time_last_receiver_block_ms_ = now_ms;
+ UpdateEstimate(now_ms);
}
-bool SendSideBandwidthEstimation::AvailableBandwidth(
- uint32_t* bandwidth) const {
- CriticalSectionScoped cs(critsect_);
- if (bitrate_ == 0) {
- return false;
+void SendSideBandwidthEstimation::UpdateEstimate(uint32_t now_ms) {
+ UpdateMinHistory(now_ms);
+
+ // Only start updating bitrate when receiving receiver blocks.
+ if (time_last_receiver_block_ms_ != 0) {
+ if (last_fraction_loss_ <= 5) {
+ // Loss < 2%: Increase rate by 8% of the min bitrate in the last
+ // kBweIncreaseIntervalMs.
+ // Note that by remembering the bitrate over the last second one can
+ // rampup up one second faster than if only allowed to start ramping
+ // at 8% per second rate now. E.g.:
+ // If sending a constant 100kbps it can rampup immediatly to 108kbps
+ // whenever a receiver report is received with lower packet loss.
+ // If instead one would do: bitrate_ *= 1.08^(delta time), it would
+ // take over one second since the lower packet loss to achieve 108kbps.
+ bitrate_ = static_cast<uint32_t>(
+ min_bitrate_history_.front().second * 1.08 + 0.5);
+
+ // Add 1 kbps extra, just to make sure that we do not get stuck
+ // (gives a little extra increase at low rates, negligible at higher
+ // rates).
+ bitrate_ += 1000;
+
+ } else if (last_fraction_loss_ <= 26) {
+ // Loss between 2% - 10%: Do nothing.
+
+ } else {
+ // Loss > 10%: Limit the rate decreases to once a kBweDecreaseIntervalMs +
+ // rtt.
+ if ((now_ms - time_last_decrease_ms_) >=
+ static_cast<uint32_t>(kBweDecreaseIntervalMs +
+ last_round_trip_time_ms_)) {
+ time_last_decrease_ms_ = now_ms;
+
+ // Reduce rate:
+ // newRate = rate * (1 - 0.5*lossRate);
+ // where packetLoss = 256*lossRate;
+ bitrate_ = static_cast<uint32_t>(
+ (bitrate_ * static_cast<double>(512 - last_fraction_loss_)) /
+ 512.0);
+
+ // Calculate what rate TFRC would apply in this situation and to not
+ // reduce further than it.
+ bitrate_ = std::max(
+ bitrate_,
+ CalcTfrcBps(last_round_trip_time_ms_, last_fraction_loss_));
+ }
+ }
}
- *bandwidth = bitrate_;
- return true;
+ CapBitrateToThresholds();
}
-/*
- * Calculate the rate that TCP-Friendly Rate Control (TFRC) would apply.
- * The formula in RFC 3448, Section 3.1, is used.
- */
-uint32_t SendSideBandwidthEstimation::CalcTFRCbps(uint16_t rtt, uint8_t loss) {
- if (rtt == 0 || loss == 0) {
- // input variables out of range
- return 0;
+void SendSideBandwidthEstimation::UpdateMinHistory(uint32_t now_ms) {
+ // Remove old data points from history.
+ // Since history precision is in ms, add one so it is able to increase
+ // bitrate if it is off by as little as 0.5ms.
+ while (!min_bitrate_history_.empty() &&
+ now_ms - min_bitrate_history_.front().first + 1 >
+ kBweIncreaseIntervalMs) {
+ min_bitrate_history_.pop_front();
}
- double R = static_cast<double>(rtt) / 1000; // RTT in seconds
- int b = 1; // number of packets acknowledged by a single TCP acknowledgement;
- // recommended = 1
- double t_RTO = 4.0 * R; // TCP retransmission timeout value in seconds
- // recommended = 4*R
- double p = static_cast<double>(loss) / 255; // packet loss rate in [0, 1)
- double s = static_cast<double>(kAvgPacketSizeBytes);
- // calculate send rate in bytes/second
- double X = s / (R * sqrt(2 * b * p / 3) +
- (t_RTO * (3 * sqrt(3 * b * p / 8) * p * (1 + 32 * p * p))));
+ // Typical minimum sliding-window algorithm: Pop values higher than current
+ // bitrate before pushing it.
+ while (!min_bitrate_history_.empty() &&
+ bitrate_ <= min_bitrate_history_.back().second) {
+ min_bitrate_history_.pop_back();
+ }
- return (static_cast<uint32_t>(X * 8)); // bits/second
+ min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_));
}
-bool SendSideBandwidthEstimation::ShapeSimple(const uint8_t loss,
- const uint32_t rtt,
- const uint32_t now_ms,
- uint32_t* bitrate) {
- uint32_t new_bitrate = 0;
- bool reducing = false;
-
- // Limit the rate increases to once a kBWEIncreaseIntervalMs.
- if (loss <= 5) {
- if ((now_ms - time_last_increase_) < kBWEIncreaseIntervalMs) {
- return false;
- }
- time_last_increase_ = now_ms;
- }
- // Limit the rate decreases to once a kBWEDecreaseIntervalMs + rtt.
- if (loss > 26) {
- if ((now_ms - time_last_decrease_) < kBWEDecreaseIntervalMs + rtt) {
- return false;
- }
- time_last_decrease_ = now_ms;
- }
-
- if (loss > 5 && loss <= 26) {
- // 2% - 10%
- new_bitrate = bitrate_;
- } else if (loss > 26) {
- // 26/256 ~= 10%
- // reduce rate: newRate = rate * (1 - 0.5*lossRate)
- // packetLoss = 256*lossRate
- new_bitrate = static_cast<uint32_t>((bitrate_ *
- static_cast<double>(512 - loss)) / 512.0);
- reducing = true;
- } else {
- // increase rate by 8%
- new_bitrate = static_cast<uint32_t>(bitrate_ * 1.08 + 0.5);
-
- // add 1 kbps extra, just to make sure that we do not get stuck
- // (gives a little extra increase at low rates, negligible at higher rates)
- new_bitrate += 1000;
- }
- if (reducing) {
- // Calculate what rate TFRC would apply in this situation
- // scale loss to Q0 (back to [0, 255])
- uint32_t tfrc_bitrate = CalcTFRCbps(rtt, loss);
- if (tfrc_bitrate > new_bitrate) {
- // do not reduce further if rate is below TFRC rate
- new_bitrate = tfrc_bitrate;
- }
- }
- if (bwe_incoming_ > 0 && new_bitrate > bwe_incoming_) {
- new_bitrate = bwe_incoming_;
+void SendSideBandwidthEstimation::CapBitrateToThresholds() {
+ if (bwe_incoming_ > 0 && bitrate_ > bwe_incoming_) {
+ bitrate_ = bwe_incoming_;
}
- if (new_bitrate > max_bitrate_configured_) {
- new_bitrate = max_bitrate_configured_;
+ if (bitrate_ > max_bitrate_configured_) {
+ bitrate_ = max_bitrate_configured_;
}
- if (new_bitrate < min_bitrate_configured_) {
- WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
- "The configured min bitrate (%u kbps) is greater than the "
- "estimated available bandwidth (%u kbps).\n",
- min_bitrate_configured_ / 1000, new_bitrate / 1000);
- new_bitrate = min_bitrate_configured_;
+ if (bitrate_ < min_bitrate_configured_) {
+ LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate_ / 1000
+ << " kbps is below configured min bitrate "
+ << min_bitrate_configured_ / 1000 << " kbps.";
+ bitrate_ = min_bitrate_configured_;
}
- *bitrate = new_bitrate;
- return true;
}
+
} // namespace webrtc