blob: 1fc08c57826c057587e0bd865d858db87a5eb54b [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/bitrate_controller/send_side_bandwidth_estimation.h"
#include <math.h> // sqrt()
#include "system_wrappers/interface/trace.h"
namespace webrtc {
SendSideBandwidthEstimation::SendSideBandwidthEstimation()
: critsect_(CriticalSectionWrapper::CreateCriticalSection()),
accumulate_lost_packets_Q8_(0),
accumulate_expected_packets_(0),
bitrate_(0),
min_bitrate_configured_(0),
max_bitrate_configured_(0),
last_fraction_loss_(0),
last_round_trip_time_(0),
bwe_incoming_(0),
time_last_increase_(0),
time_last_decrease_(0) {
}
SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {
delete critsect_;
}
void SendSideBandwidthEstimation::SetSendBitrate(const uint32_t bitrate) {
CriticalSectionScoped cs(critsect_);
bitrate_ = bitrate;
}
void SendSideBandwidthEstimation::SetMinMaxBitrate(const uint32_t min_bitrate,
const uint32_t max_bitrate) {
CriticalSectionScoped cs(critsect_);
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;
}
}
bool SendSideBandwidthEstimation::UpdateBandwidthEstimate(
const uint32_t bandwidth,
uint32_t* new_bitrate,
uint8_t* fraction_lost,
uint16_t* rtt) {
*new_bitrate = 0;
CriticalSectionScoped cs(critsect_);
bwe_incoming_ = bandwidth;
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;
}
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;
}
// Update RTT.
last_round_trip_time_ = 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;
// 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_;
// 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;
}
}
// 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;
}
bool SendSideBandwidthEstimation::AvailableBandwidth(
uint32_t* bandwidth) const {
CriticalSectionScoped cs(critsect_);
if (bitrate_ == 0) {
return false;
}
*bandwidth = bitrate_;
return true;
}
/*
* 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;
}
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))));
return (static_cast<uint32_t>(X * 8)); // bits/second
}
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_;
}
if (new_bitrate > max_bitrate_configured_) {
new_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_;
}
*bitrate = new_bitrate;
return true;
}
} // namespace webrtc