2014-12-04 15:34:06 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2014 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/remote_bitrate_estimator/aimd_rate_control.h"
|
2014-12-04 15:34:06 +00:00
|
|
|
|
2018-07-18 14:59:56 +02:00
|
|
|
#include <inttypes.h>
|
2014-12-04 15:34:06 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cmath>
|
2017-12-12 12:09:31 +01:00
|
|
|
#include <cstdio>
|
2017-10-06 08:43:34 +02:00
|
|
|
#include <string>
|
2014-12-04 15:34:06 +00:00
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
|
2017-10-06 08:43:34 +02:00
|
|
|
#include "modules/remote_bitrate_estimator/overuse_detector.h"
|
2018-07-18 14:59:56 +02:00
|
|
|
#include "rtc_base/checks.h"
|
2017-10-06 08:43:34 +02:00
|
|
|
#include "rtc_base/logging.h"
|
2018-07-18 14:59:56 +02:00
|
|
|
#include "rtc_base/numerics/safe_minmax.h"
|
2017-10-06 08:43:34 +02:00
|
|
|
#include "system_wrappers/include/field_trial.h"
|
2014-12-04 15:34:06 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
constexpr TimeDelta kDefaultRtt = TimeDelta::Millis<200>();
|
2018-11-22 14:20:06 +01:00
|
|
|
constexpr double kDefaultBackoffFactor = 0.85;
|
2018-11-19 18:02:20 +01:00
|
|
|
constexpr TimeDelta kDefaultInitialBackOffInterval = TimeDelta::Millis<200>();
|
2017-10-06 08:43:34 +02:00
|
|
|
|
|
|
|
|
const char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor";
|
2018-07-18 14:59:56 +02:00
|
|
|
const char kBweInitialBackOffIntervalExperiment[] =
|
|
|
|
|
"WebRTC-BweInitialBackOffInterval";
|
2017-10-06 08:43:34 +02:00
|
|
|
|
2018-11-22 14:20:06 +01:00
|
|
|
double ReadBackoffFactor() {
|
2017-10-06 08:43:34 +02:00
|
|
|
std::string experiment_string =
|
|
|
|
|
webrtc::field_trial::FindFullName(kBweBackOffFactorExperiment);
|
2018-11-22 14:20:06 +01:00
|
|
|
double backoff_factor;
|
2017-10-06 08:43:34 +02:00
|
|
|
int parsed_values =
|
2018-11-22 14:20:06 +01:00
|
|
|
sscanf(experiment_string.c_str(), "Enabled-%lf", &backoff_factor);
|
2017-10-06 08:43:34 +02:00
|
|
|
if (parsed_values == 1) {
|
2018-11-22 14:20:06 +01:00
|
|
|
if (backoff_factor >= 1.0) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(WARNING) << "Back-off factor must be less than 1.";
|
2018-11-22 14:20:06 +01:00
|
|
|
} else if (backoff_factor <= 0.0) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(WARNING) << "Back-off factor must be greater than 0.";
|
2017-10-06 08:43:34 +02:00
|
|
|
} else {
|
|
|
|
|
return backoff_factor;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_WARNING) << "Failed to parse parameters for AimdRateControl "
|
|
|
|
|
"experiment from field trial string. Using default.";
|
2017-10-06 08:43:34 +02:00
|
|
|
return kDefaultBackoffFactor;
|
|
|
|
|
}
|
2014-12-04 15:34:06 +00:00
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
TimeDelta ReadInitialBackoffInterval() {
|
2018-07-18 14:59:56 +02:00
|
|
|
std::string experiment_string =
|
|
|
|
|
webrtc::field_trial::FindFullName(kBweInitialBackOffIntervalExperiment);
|
|
|
|
|
int64_t backoff_interval;
|
|
|
|
|
int parsed_values =
|
|
|
|
|
sscanf(experiment_string.c_str(), "Enabled-%" SCNd64, &backoff_interval);
|
|
|
|
|
if (parsed_values == 1) {
|
|
|
|
|
if (10 <= backoff_interval && backoff_interval <= 200) {
|
2018-11-19 18:02:20 +01:00
|
|
|
return TimeDelta::ms(backoff_interval);
|
2018-07-18 14:59:56 +02:00
|
|
|
}
|
|
|
|
|
RTC_LOG(WARNING)
|
|
|
|
|
<< "Initial back-off interval must be between 10 and 200 ms.";
|
|
|
|
|
}
|
|
|
|
|
RTC_LOG(LS_WARNING) << "Failed to parse parameters for "
|
|
|
|
|
<< kBweInitialBackOffIntervalExperiment
|
|
|
|
|
<< " experiment. Using default.";
|
2018-11-19 18:02:20 +01:00
|
|
|
return kDefaultInitialBackOffInterval;
|
2018-07-18 14:59:56 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-28 03:57:14 -07:00
|
|
|
AimdRateControl::AimdRateControl()
|
2018-11-19 18:02:20 +01:00
|
|
|
: min_configured_bitrate_(congestion_controller::GetMinBitrate()),
|
|
|
|
|
max_configured_bitrate_(DataRate::kbps(30000)),
|
|
|
|
|
current_bitrate_(max_configured_bitrate_),
|
|
|
|
|
latest_estimated_throughput_(current_bitrate_),
|
2018-11-22 14:20:06 +01:00
|
|
|
link_capacity_estimate_kbps_(),
|
|
|
|
|
var_link_capacity_estimate_kbps_(0.4),
|
2014-12-04 15:34:06 +00:00
|
|
|
rate_control_state_(kRcHold),
|
2018-11-19 18:02:20 +01:00
|
|
|
time_last_bitrate_change_(Timestamp::MinusInfinity()),
|
|
|
|
|
time_last_bitrate_decrease_(Timestamp::MinusInfinity()),
|
|
|
|
|
time_first_throughput_estimate_(Timestamp::MinusInfinity()),
|
2014-12-04 15:34:06 +00:00
|
|
|
bitrate_is_initialized_(false),
|
2017-10-06 08:43:34 +02:00
|
|
|
beta_(webrtc::field_trial::IsEnabled(kBweBackOffFactorExperiment)
|
2018-05-16 20:18:21 +02:00
|
|
|
? ReadBackoffFactor()
|
2017-10-06 08:43:34 +02:00
|
|
|
: kDefaultBackoffFactor),
|
2018-11-19 18:02:20 +01:00
|
|
|
rtt_(kDefaultRtt),
|
2017-10-09 12:28:39 +02:00
|
|
|
in_experiment_(!AdaptiveThresholdExperimentIsDisabled()),
|
|
|
|
|
smoothing_experiment_(
|
2018-07-18 14:59:56 +02:00
|
|
|
webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")),
|
|
|
|
|
in_initial_backoff_interval_experiment_(
|
|
|
|
|
webrtc::field_trial::IsEnabled(kBweInitialBackOffIntervalExperiment)),
|
2018-11-19 18:02:20 +01:00
|
|
|
initial_backoff_interval_(kDefaultInitialBackOffInterval) {
|
2018-07-18 14:59:56 +02:00
|
|
|
if (in_initial_backoff_interval_experiment_) {
|
2018-11-19 18:02:20 +01:00
|
|
|
initial_backoff_interval_ = ReadInitialBackoffInterval();
|
2018-07-18 14:59:56 +02:00
|
|
|
RTC_LOG(LS_INFO) << "Using aimd rate control with initial back-off interval"
|
2018-11-19 18:02:20 +01:00
|
|
|
<< " " << ToString(initial_backoff_interval_) << ".";
|
2018-07-18 14:59:56 +02:00
|
|
|
}
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_;
|
2017-10-06 08:43:34 +02:00
|
|
|
}
|
2014-12-04 15:34:06 +00:00
|
|
|
|
2017-01-27 06:43:18 -08:00
|
|
|
AimdRateControl::~AimdRateControl() {}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
void AimdRateControl::SetStartBitrate(DataRate start_bitrate) {
|
|
|
|
|
current_bitrate_ = start_bitrate;
|
|
|
|
|
latest_estimated_throughput_ = current_bitrate_;
|
2018-05-18 07:12:15 +00:00
|
|
|
bitrate_is_initialized_ = true;
|
2017-01-27 06:43:18 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
void AimdRateControl::SetMinBitrate(DataRate min_bitrate) {
|
|
|
|
|
min_configured_bitrate_ = min_bitrate;
|
|
|
|
|
current_bitrate_ = std::max(min_bitrate, current_bitrate_);
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AimdRateControl::ValidEstimate() const {
|
|
|
|
|
return bitrate_is_initialized_;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
TimeDelta AimdRateControl::GetFeedbackInterval() const {
|
2014-12-04 15:34:06 +00:00
|
|
|
// Estimate how often we can send RTCP if we allocate up to 5% of bandwidth
|
|
|
|
|
// to feedback.
|
2018-11-19 18:02:20 +01:00
|
|
|
const DataSize kRtcpSize = DataSize::bytes(80);
|
|
|
|
|
const DataRate rtcp_bitrate = current_bitrate_ * 0.05;
|
|
|
|
|
const TimeDelta interval = kRtcpSize / rtcp_bitrate;
|
|
|
|
|
const TimeDelta kMinFeedbackInterval = TimeDelta::ms(200);
|
|
|
|
|
const TimeDelta kMaxFeedbackInterval = TimeDelta::ms(1000);
|
|
|
|
|
return interval.Clamped(kMinFeedbackInterval, kMaxFeedbackInterval);
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
bool AimdRateControl::TimeToReduceFurther(Timestamp at_time,
|
|
|
|
|
DataRate estimated_throughput) const {
|
|
|
|
|
const TimeDelta bitrate_reduction_interval =
|
|
|
|
|
rtt_.Clamped(TimeDelta::ms(10), TimeDelta::ms(200));
|
|
|
|
|
if (at_time - time_last_bitrate_change_ >= bitrate_reduction_interval) {
|
2014-12-04 15:34:06 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (ValidEstimate()) {
|
2016-12-02 03:27:08 -08:00
|
|
|
// TODO(terelius/holmer): Investigate consequences of increasing
|
|
|
|
|
// the threshold to 0.95 * LatestEstimate().
|
2018-11-19 18:02:20 +01:00
|
|
|
const DataRate threshold = 0.5 * LatestEstimate();
|
|
|
|
|
return estimated_throughput < threshold;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
bool AimdRateControl::InitialTimeToReduceFurther(Timestamp at_time) const {
|
2018-07-18 14:59:56 +02:00
|
|
|
if (!in_initial_backoff_interval_experiment_) {
|
|
|
|
|
return ValidEstimate() &&
|
2018-11-19 18:02:20 +01:00
|
|
|
TimeToReduceFurther(at_time,
|
|
|
|
|
LatestEstimate() / 2 - DataRate::bps(1));
|
2018-07-18 14:59:56 +02:00
|
|
|
}
|
|
|
|
|
// TODO(terelius): We could use the RTT (clamped to suitable limits) instead
|
|
|
|
|
// of a fixed bitrate_reduction_interval.
|
2018-11-19 18:02:20 +01:00
|
|
|
if (time_last_bitrate_decrease_.IsInfinite() ||
|
|
|
|
|
at_time - time_last_bitrate_decrease_ >= initial_backoff_interval_) {
|
2018-07-18 14:59:56 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::LatestEstimate() const {
|
|
|
|
|
return current_bitrate_;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
void AimdRateControl::SetRtt(TimeDelta rtt) {
|
2014-12-04 15:34:06 +00:00
|
|
|
rtt_ = rtt;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::Update(const RateControlInput* input,
|
|
|
|
|
Timestamp at_time) {
|
2016-06-10 22:13:21 +02:00
|
|
|
RTC_CHECK(input);
|
2014-12-04 15:34:06 +00:00
|
|
|
|
|
|
|
|
// Set the initial bit rate value to what we're receiving the first half
|
|
|
|
|
// second.
|
2018-06-11 11:44:29 +02:00
|
|
|
// TODO(bugs.webrtc.org/9379): The comment above doesn't match to the code.
|
2014-12-04 15:34:06 +00:00
|
|
|
if (!bitrate_is_initialized_) {
|
2018-11-19 18:02:20 +01:00
|
|
|
const TimeDelta kInitializationTime = TimeDelta::seconds(5);
|
|
|
|
|
RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTime.ms());
|
|
|
|
|
if (time_first_throughput_estimate_.IsInfinite()) {
|
|
|
|
|
if (input->estimated_throughput)
|
|
|
|
|
time_first_throughput_estimate_ = at_time;
|
|
|
|
|
} else if (at_time - time_first_throughput_estimate_ >
|
|
|
|
|
kInitializationTime &&
|
|
|
|
|
input->estimated_throughput) {
|
|
|
|
|
current_bitrate_ = *input->estimated_throughput;
|
2014-12-04 15:34:06 +00:00
|
|
|
bitrate_is_initialized_ = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
current_bitrate_ = ChangeBitrate(current_bitrate_, *input, at_time);
|
|
|
|
|
return current_bitrate_;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
void AimdRateControl::SetEstimate(DataRate bitrate, Timestamp at_time) {
|
2014-12-04 15:34:06 +00:00
|
|
|
bitrate_is_initialized_ = true;
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate prev_bitrate = current_bitrate_;
|
|
|
|
|
current_bitrate_ = ClampBitrate(bitrate, bitrate);
|
|
|
|
|
time_last_bitrate_change_ = at_time;
|
|
|
|
|
if (current_bitrate_ < prev_bitrate) {
|
|
|
|
|
time_last_bitrate_decrease_ = at_time;
|
2018-07-18 14:59:56 +02:00
|
|
|
}
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {
|
|
|
|
|
RTC_DCHECK(!current_bitrate_.IsZero());
|
|
|
|
|
const TimeDelta kFrameInterval = TimeDelta::seconds(1) / 30;
|
|
|
|
|
DataSize frame_size = current_bitrate_ * kFrameInterval;
|
|
|
|
|
const DataSize kPacketSize = DataSize::bytes(1200);
|
|
|
|
|
double packets_per_frame = std::ceil(frame_size / kPacketSize);
|
|
|
|
|
DataSize avg_packet_size = frame_size / packets_per_frame;
|
2017-04-19 09:15:04 -07:00
|
|
|
|
2016-11-17 01:18:43 -08:00
|
|
|
// Approximate the over-use estimator delay to 100 ms.
|
2018-11-19 18:02:20 +01:00
|
|
|
TimeDelta response_time = rtt_ + TimeDelta::ms(100);
|
|
|
|
|
if (in_experiment_)
|
|
|
|
|
response_time = response_time * 2;
|
|
|
|
|
double increase_rate_bps_per_second =
|
|
|
|
|
(avg_packet_size / response_time).bps<double>();
|
|
|
|
|
double kMinIncreaseRateBpsPerSecond = 4000;
|
|
|
|
|
return std::max(kMinIncreaseRateBpsPerSecond, increase_rate_bps_per_second);
|
2016-11-17 01:18:43 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
TimeDelta AimdRateControl::GetExpectedBandwidthPeriod() const {
|
|
|
|
|
const TimeDelta kMinPeriod =
|
|
|
|
|
smoothing_experiment_ ? TimeDelta::ms(500) : TimeDelta::seconds(2);
|
|
|
|
|
const TimeDelta kDefaultPeriod = TimeDelta::seconds(3);
|
|
|
|
|
const TimeDelta kMaxPeriod = TimeDelta::seconds(50);
|
2017-04-19 09:15:04 -07:00
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
double increase_rate_bps_per_second = GetNearMaxIncreaseRateBpsPerSecond();
|
2017-04-19 09:15:04 -07:00
|
|
|
if (!last_decrease_)
|
2018-11-19 18:02:20 +01:00
|
|
|
return smoothing_experiment_ ? kMinPeriod : kDefaultPeriod;
|
|
|
|
|
double time_to_recover_decrease_seconds =
|
|
|
|
|
last_decrease_->bps() / increase_rate_bps_per_second;
|
|
|
|
|
TimeDelta period = TimeDelta::seconds(time_to_recover_decrease_seconds);
|
|
|
|
|
return period.Clamped(kMinPeriod, kMaxPeriod);
|
2016-11-17 01:18:43 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate,
|
2017-04-03 02:27:08 -07:00
|
|
|
const RateControlInput& input,
|
2018-11-19 18:02:20 +01:00
|
|
|
Timestamp at_time) {
|
|
|
|
|
DataRate estimated_throughput =
|
|
|
|
|
input.estimated_throughput.value_or(latest_estimated_throughput_);
|
|
|
|
|
if (input.estimated_throughput)
|
|
|
|
|
latest_estimated_throughput_ = *input.estimated_throughput;
|
2017-04-03 02:27:08 -07:00
|
|
|
|
2015-07-09 17:27:48 +02:00
|
|
|
// An over-use should always trigger us to reduce the bitrate, even though
|
|
|
|
|
// we have not yet established our first estimate. By acting on the over-use,
|
|
|
|
|
// we will end up with a valid estimate.
|
2017-04-11 00:49:44 -07:00
|
|
|
if (!bitrate_is_initialized_ &&
|
|
|
|
|
input.bw_state != BandwidthUsage::kBwOverusing)
|
2018-11-19 18:02:20 +01:00
|
|
|
return current_bitrate_;
|
2017-04-03 02:27:08 -07:00
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
ChangeState(input, at_time);
|
2014-12-04 15:34:06 +00:00
|
|
|
// Calculated here because it's used in multiple places.
|
2018-11-22 14:20:06 +01:00
|
|
|
const double estimated_throughput_kbps = estimated_throughput.kbps<double>();
|
|
|
|
|
|
2014-12-04 15:34:06 +00:00
|
|
|
// Calculate the max bit rate std dev given the normalized
|
2018-11-22 14:20:06 +01:00
|
|
|
// variance and the current throughput bitrate. The standard deviation will
|
|
|
|
|
// only be used if link_capacity_estimate_kbps_ has a value.
|
|
|
|
|
const double std_link_capacity_kbps =
|
|
|
|
|
sqrt(var_link_capacity_estimate_kbps_ *
|
|
|
|
|
link_capacity_estimate_kbps_.value_or(0));
|
2014-12-04 15:34:06 +00:00
|
|
|
switch (rate_control_state_) {
|
2015-07-07 04:20:34 -07:00
|
|
|
case kRcHold:
|
2014-12-04 15:34:06 +00:00
|
|
|
break;
|
2015-07-07 04:20:34 -07:00
|
|
|
|
|
|
|
|
case kRcIncrease:
|
2018-11-22 14:20:06 +01:00
|
|
|
if (link_capacity_estimate_kbps_.has_value() &&
|
|
|
|
|
estimated_throughput_kbps > link_capacity_estimate_kbps_.value() +
|
|
|
|
|
3 * std_link_capacity_kbps) {
|
|
|
|
|
// The link capacity appears to have changed. Forget the previous
|
|
|
|
|
// estimate and use multiplicative increase to quickly discover new
|
|
|
|
|
// capacity.
|
|
|
|
|
link_capacity_estimate_kbps_.reset();
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-22 14:20:06 +01:00
|
|
|
if (link_capacity_estimate_kbps_.has_value()) {
|
|
|
|
|
// The link_capacity_estimate_kbps_ is reset if the measured throughput
|
|
|
|
|
// is too far from the estimate. We can therefore assume that our target
|
|
|
|
|
// rate is reasonably close to link capacity and use additive increase.
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate additive_increase =
|
|
|
|
|
AdditiveRateIncrease(at_time, time_last_bitrate_change_);
|
|
|
|
|
new_bitrate += additive_increase;
|
2014-12-04 15:34:06 +00:00
|
|
|
} else {
|
2018-11-22 14:20:06 +01:00
|
|
|
// If we don't have an estimate of the link capacity, use faster ramp up
|
|
|
|
|
// to discover the capacity.
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate multiplicative_increase = MultiplicativeRateIncrease(
|
|
|
|
|
at_time, time_last_bitrate_change_, new_bitrate);
|
|
|
|
|
new_bitrate += multiplicative_increase;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
time_last_bitrate_change_ = at_time;
|
2014-12-04 15:34:06 +00:00
|
|
|
break;
|
2015-07-07 04:20:34 -07:00
|
|
|
|
|
|
|
|
case kRcDecrease:
|
2018-11-22 14:20:06 +01:00
|
|
|
// Set bit rate to something slightly lower than the measured throughput
|
2017-02-13 09:08:22 -08:00
|
|
|
// to get rid of any self-induced delay.
|
2018-11-19 18:02:20 +01:00
|
|
|
new_bitrate = estimated_throughput * beta_;
|
|
|
|
|
if (new_bitrate > current_bitrate_) {
|
2017-02-13 09:08:22 -08:00
|
|
|
// Avoid increasing the rate when over-using.
|
2018-11-22 14:20:06 +01:00
|
|
|
if (link_capacity_estimate_kbps_.has_value()) {
|
|
|
|
|
new_bitrate =
|
|
|
|
|
DataRate::kbps(beta_ * link_capacity_estimate_kbps_.value());
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-19 18:02:20 +01:00
|
|
|
new_bitrate = std::min(new_bitrate, current_bitrate_);
|
2017-02-13 09:08:22 -08:00
|
|
|
}
|
2014-12-04 15:34:06 +00:00
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) {
|
2018-11-22 14:20:06 +01:00
|
|
|
constexpr double kDegradationFactor = 0.9;
|
2017-10-09 12:28:39 +02:00
|
|
|
if (smoothing_experiment_ &&
|
2018-11-19 18:02:20 +01:00
|
|
|
new_bitrate < kDegradationFactor * beta_ * current_bitrate_) {
|
2017-10-09 12:28:39 +02:00
|
|
|
// If bitrate decreases more than a normal back off after overuse, it
|
|
|
|
|
// indicates a real network degradation. We do not let such a decrease
|
|
|
|
|
// to determine the bandwidth estimation period.
|
2018-06-18 10:48:16 +02:00
|
|
|
last_decrease_ = absl::nullopt;
|
2017-10-09 12:28:39 +02:00
|
|
|
} else {
|
2018-11-19 18:02:20 +01:00
|
|
|
last_decrease_ = current_bitrate_ - new_bitrate;
|
2017-10-09 12:28:39 +02:00
|
|
|
}
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-22 14:20:06 +01:00
|
|
|
if (link_capacity_estimate_kbps_.has_value() &&
|
|
|
|
|
estimated_throughput_kbps < link_capacity_estimate_kbps_.value() -
|
|
|
|
|
3 * std_link_capacity_kbps) {
|
|
|
|
|
// The current throughput is far from the estimated link capacity. Clear
|
|
|
|
|
// the estimate to allow an fast update in UpdateLinkCapacityEstimate.
|
|
|
|
|
link_capacity_estimate_kbps_.reset();
|
2017-02-13 09:08:22 -08:00
|
|
|
}
|
|
|
|
|
|
2017-04-19 09:15:04 -07:00
|
|
|
bitrate_is_initialized_ = true;
|
2018-11-22 14:20:06 +01:00
|
|
|
UpdateLinkCapacityEstimate(estimated_throughput_kbps);
|
2014-12-04 15:34:06 +00:00
|
|
|
// Stay on hold until the pipes are cleared.
|
2017-04-03 02:27:08 -07:00
|
|
|
rate_control_state_ = kRcHold;
|
2018-11-19 18:02:20 +01:00
|
|
|
time_last_bitrate_change_ = at_time;
|
|
|
|
|
time_last_bitrate_decrease_ = at_time;
|
2014-12-04 15:34:06 +00:00
|
|
|
break;
|
2015-07-07 04:20:34 -07:00
|
|
|
|
2014-12-04 15:34:06 +00:00
|
|
|
default:
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
2018-11-19 18:02:20 +01:00
|
|
|
return ClampBitrate(new_bitrate, estimated_throughput);
|
2017-02-13 09:08:22 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate,
|
|
|
|
|
DataRate estimated_throughput) const {
|
2016-12-05 08:23:40 -08:00
|
|
|
// Don't change the bit rate if the send side is too far off.
|
|
|
|
|
// We allow a bit more lag at very low rates to not too easily get stuck if
|
|
|
|
|
// the encoder produces uneven outputs.
|
2018-11-19 18:02:20 +01:00
|
|
|
const DataRate max_bitrate = 1.5 * estimated_throughput + DataRate::kbps(10);
|
|
|
|
|
if (new_bitrate > current_bitrate_ && new_bitrate > max_bitrate) {
|
|
|
|
|
new_bitrate = std::max(current_bitrate_, max_bitrate);
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-19 18:02:20 +01:00
|
|
|
new_bitrate = std::max(new_bitrate, min_configured_bitrate_);
|
|
|
|
|
return new_bitrate;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::MultiplicativeRateIncrease(
|
|
|
|
|
Timestamp at_time,
|
|
|
|
|
Timestamp last_time,
|
|
|
|
|
DataRate current_bitrate) const {
|
2014-12-04 15:34:06 +00:00
|
|
|
double alpha = 1.08;
|
2018-11-19 18:02:20 +01:00
|
|
|
if (last_time.IsFinite()) {
|
|
|
|
|
auto time_since_last_update = at_time - last_time;
|
|
|
|
|
alpha = pow(alpha, std::min(time_since_last_update.seconds<double>(), 1.0));
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate multiplicative_increase =
|
|
|
|
|
std::max(current_bitrate * (alpha - 1.0), DataRate::bps(1000));
|
|
|
|
|
return multiplicative_increase;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-19 18:02:20 +01:00
|
|
|
DataRate AimdRateControl::AdditiveRateIncrease(Timestamp at_time,
|
|
|
|
|
Timestamp last_time) const {
|
|
|
|
|
double time_period_seconds = (at_time - last_time).seconds<double>();
|
|
|
|
|
double data_rate_increase_bps =
|
|
|
|
|
GetNearMaxIncreaseRateBpsPerSecond() * time_period_seconds;
|
|
|
|
|
return DataRate::bps(data_rate_increase_bps);
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 14:20:06 +01:00
|
|
|
void AimdRateControl::UpdateLinkCapacityEstimate(
|
|
|
|
|
double estimated_throughput_kbps) {
|
|
|
|
|
const double alpha = 0.05;
|
|
|
|
|
if (!link_capacity_estimate_kbps_.has_value()) {
|
|
|
|
|
link_capacity_estimate_kbps_ = estimated_throughput_kbps;
|
2014-12-04 15:34:06 +00:00
|
|
|
} else {
|
2018-11-22 14:20:06 +01:00
|
|
|
link_capacity_estimate_kbps_ =
|
|
|
|
|
(1 - alpha) * link_capacity_estimate_kbps_.value() +
|
|
|
|
|
alpha * estimated_throughput_kbps;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-22 14:20:06 +01:00
|
|
|
// Estimate the variance of the link capacity estimate and normalize the
|
|
|
|
|
// variance with the link capacity estimate.
|
|
|
|
|
const double norm = std::max(link_capacity_estimate_kbps_.value(), 1.0);
|
|
|
|
|
var_link_capacity_estimate_kbps_ =
|
|
|
|
|
(1 - alpha) * var_link_capacity_estimate_kbps_ +
|
|
|
|
|
alpha *
|
|
|
|
|
(link_capacity_estimate_kbps_.value() - estimated_throughput_kbps) *
|
|
|
|
|
(link_capacity_estimate_kbps_.value() - estimated_throughput_kbps) /
|
|
|
|
|
norm;
|
2014-12-04 15:34:06 +00:00
|
|
|
// 0.4 ~= 14 kbit/s at 500 kbit/s
|
2018-11-22 14:20:06 +01:00
|
|
|
if (var_link_capacity_estimate_kbps_ < 0.4) {
|
|
|
|
|
var_link_capacity_estimate_kbps_ = 0.4;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
2018-11-22 14:20:06 +01:00
|
|
|
// 2.5 ~= 35 kbit/s at 500 kbit/s
|
|
|
|
|
if (var_link_capacity_estimate_kbps_ > 2.5) {
|
|
|
|
|
var_link_capacity_estimate_kbps_ = 2.5;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AimdRateControl::ChangeState(const RateControlInput& input,
|
2018-11-19 18:02:20 +01:00
|
|
|
Timestamp at_time) {
|
2017-04-03 02:27:08 -07:00
|
|
|
switch (input.bw_state) {
|
2017-04-11 00:49:44 -07:00
|
|
|
case BandwidthUsage::kBwNormal:
|
2014-12-04 15:34:06 +00:00
|
|
|
if (rate_control_state_ == kRcHold) {
|
2018-11-19 18:02:20 +01:00
|
|
|
time_last_bitrate_change_ = at_time;
|
2017-04-03 02:27:08 -07:00
|
|
|
rate_control_state_ = kRcIncrease;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
break;
|
2017-04-11 00:49:44 -07:00
|
|
|
case BandwidthUsage::kBwOverusing:
|
2014-12-04 15:34:06 +00:00
|
|
|
if (rate_control_state_ != kRcDecrease) {
|
2017-04-03 02:27:08 -07:00
|
|
|
rate_control_state_ = kRcDecrease;
|
2014-12-04 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
break;
|
2017-04-11 00:49:44 -07:00
|
|
|
case BandwidthUsage::kBwUnderusing:
|
2017-04-03 02:27:08 -07:00
|
|
|
rate_control_state_ = kRcHold;
|
2014-12-04 15:34:06 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webrtc
|