webrtc/modules/congestion_controller/goog_cc/delay_based_rate_controller.cc
Sebastian Jansson da0222b3fc Adds new timer based rate controller trial to GoogCC
The new controller behaves mostly like before, but increases the target
rate on timer update rather than when feedback is received. This makes
the behavior easier to predict. It also uses a duration parameter to
track the increase, removing the meed for the minimum rate increase
constants that exists in the previous solution.

Bug: webrtc:9718
Change-Id: Iae31a9ba2d6474a8236f8eb72f86ff434f1d1fc6
Reviewed-on: https://webrtc-review.googlesource.com/c/114681
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26088}
2018-12-21 14:14:08 +00:00

217 lines
8.2 KiB
C++

/*
* Copyright 2018 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/congestion_controller/goog_cc/delay_based_rate_controller.h"
#include <algorithm>
#include <cmath>
#include "absl/memory/memory.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
// Parameters for linear least squares fit of regression line to noisy data.
constexpr size_t kDefaultTrendlineWindowSize = 20;
constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
constexpr double kDefaultTrendlineThresholdGain = 4.0;
} // namespace
DelayBasedRateControllerConfig::DelayBasedRateControllerConfig()
: enabled("Enabled"),
no_ack_backoff_fraction("no_ack_frac", 0.8),
no_ack_backoff_interval("no_ack_int", TimeDelta::ms(1000)),
ack_backoff_fraction("ack_dec", 0.90),
probe_backoff_fraction("probe_dec", 0.85),
initial_increase_rate("probe_inc", 0.03),
increase_rate("inc", 0.01),
first_period_increase_rate("min_step", DataRate::kbps(5)),
stop_increase_after("stop", TimeDelta::ms(500)),
min_increase_interval("int", TimeDelta::ms(100)),
linear_increase_threshold("cut", DataRate::kbps(300)),
reference_duration_offset("dur_offs", TimeDelta::ms(100)) {
ParseFieldTrial(
{&enabled, &no_ack_backoff_fraction, &no_ack_backoff_interval,
&ack_backoff_fraction, &probe_backoff_fraction, &initial_increase_rate,
&increase_rate, &stop_increase_after, &min_increase_interval,
&first_period_increase_rate, &linear_increase_threshold,
&reference_duration_offset},
field_trial::FindFullName("WebRTC-Bwe-DelayBasedRateController"));
}
DelayBasedRateControllerConfig::~DelayBasedRateControllerConfig() = default;
DelayBasedRateController::DelayBasedRateController(
RtcEventLog* event_log,
TargetRateConstraints constraints)
: event_log_(event_log),
overuse_detector_(new TrendlineEstimator(kDefaultTrendlineWindowSize,
kDefaultTrendlineSmoothingCoeff,
kDefaultTrendlineThresholdGain)),
target_rate_(constraints.starting_rate.value()) {
UpdateConstraints(constraints);
MaybeLog();
}
DelayBasedRateController::~DelayBasedRateController() = default;
void DelayBasedRateController::OnRouteChange() {
packet_grouper_.Reset();
link_capacity_.Reset();
overuse_detector_.reset(new TrendlineEstimator(
kDefaultTrendlineWindowSize, kDefaultTrendlineSmoothingCoeff,
kDefaultTrendlineThresholdGain));
logged_state_.reset();
}
void DelayBasedRateController::UpdateConstraints(TargetRateConstraints msg) {
if (msg.min_data_rate)
min_rate_ = *msg.min_data_rate;
if (msg.max_data_rate)
max_rate_ = *msg.max_data_rate;
if (msg.starting_rate)
target_rate_ = *msg.starting_rate;
target_rate_.Clamp(min_rate_, max_rate_);
}
void DelayBasedRateController::SetAcknowledgedRate(DataRate acknowledged_rate) {
acknowledged_rate_ = acknowledged_rate;
if (acknowledged_rate > link_capacity_.UpperBound())
link_capacity_.Reset();
}
void DelayBasedRateController::OnTransportPacketsFeedback(
TransportPacketsFeedback msg,
absl::optional<DataRate> probe_bitrate) {
auto packets = msg.ReceivedWithSendInfo();
last_rtt_ = msg.feedback_time - packets.back().sent_packet.send_time;
first_unacked_send_ = msg.first_unacked_send_time;
for (auto& packet : packets) {
packet_grouper_.AddPacketInfo(packet, msg.feedback_time);
}
for (auto& delta : packet_grouper_.PopDeltas()) {
overuse_detector_->Update(delta.receive.ms<double>(),
delta.send.ms<double>(), delta.receive_time.ms());
}
BandwidthUsage usage = overuse_detector_->State();
Timestamp at_time = msg.feedback_time;
last_feedback_update_ = at_time;
if (probe_bitrate) {
if (!acknowledged_rate_)
acknowledged_rate_ = *probe_bitrate;
target_rate_ = *probe_bitrate * conf_.probe_backoff_fraction;
increase_reference_ = target_rate_;
link_capacity_.OnProbeRate(*probe_bitrate);
}
if (usage == BandwidthUsage::kBwNormal) {
if (!increasing_state_) {
increasing_state_ = true;
// Offset the next increase time by one RTT to avoid increasing too soon
// after overuse.
last_increase_update_ = at_time + last_rtt_;
accumulated_duration_ = 0;
increase_reference_ = target_rate_;
}
} else if (usage == BandwidthUsage::kBwOverusing && !probe_bitrate) {
increasing_state_ = false;
if (!acknowledged_rate_ &&
at_time - last_no_ack_backoff_ >= conf_.no_ack_backoff_interval) {
// Until we recieve out first acknowledged rate, we back of from the
// target rate, but pace the backoffs to avoid dropping the rate too fast.
last_no_ack_backoff_ = at_time;
target_rate_ = target_rate_ * conf_.no_ack_backoff_fraction;
} else if (acknowledged_rate_) {
if (acknowledged_rate_ < link_capacity_.LowerBound())
link_capacity_.Reset();
link_capacity_.OnOveruseDetected(*acknowledged_rate_);
target_rate_ = acknowledged_rate_.value() * conf_.ack_backoff_fraction;
}
target_rate_.Clamp(min_rate_, max_rate_);
}
MaybeLog();
}
void DelayBasedRateController::OnFeedbackUpdate(
BandwidthUsage usage,
absl::optional<DataRate> probe_bitrate,
Timestamp at_time) {}
void DelayBasedRateController::OnTimeUpdate(Timestamp at_time) {
if (!increasing_state_ ||
at_time < last_increase_update_ + conf_.min_increase_interval)
return;
TimeDelta time_span = at_time - last_increase_update_;
last_increase_update_ = at_time;
if (at_time > last_feedback_update_ + conf_.stop_increase_after)
return;
TimeDelta rtt_lower_bound =
std::max(last_rtt_, at_time - first_unacked_send_);
TimeDelta reference_span = rtt_lower_bound + conf_.reference_duration_offset;
accumulated_duration_ += time_span / reference_span;
if (link_capacity_.has_estimate() &&
increase_reference_ > conf_.linear_increase_threshold) {
DataRate linear_increase_rate =
conf_.increase_rate.Get() * conf_.linear_increase_threshold.Get();
DataRate increase_amount = accumulated_duration_ * linear_increase_rate;
target_rate_ = increase_reference_ + increase_amount;
} else {
double increase_rate = link_capacity_.has_estimate()
? conf_.initial_increase_rate
: conf_.increase_rate;
double increase_factor = 1 + increase_rate;
double increase_amount = pow(increase_factor, accumulated_duration_);
target_rate_ = increase_reference_ * increase_amount;
}
target_rate_.Clamp(min_rate_, max_rate_);
MaybeLog();
}
void DelayBasedRateController::OnRemoteBitrateControl(RemoteBitrateReport msg) {
target_rate_ = msg.bandwidth;
increasing_state_ = false;
}
TimeDelta DelayBasedRateController::GetExpectedBandwidthPeriod() const {
double expected_overuse = 0.05;
double bandwidth_cycle_max_min_ratio =
1 / conf_.ack_backoff_fraction + expected_overuse;
TimeDelta reference_span = last_rtt_ + conf_.reference_duration_offset;
TimeDelta period = reference_span * log(bandwidth_cycle_max_min_ratio) /
log(1 + conf_.increase_rate);
return period.Clamped(TimeDelta::seconds(1), TimeDelta::seconds(20));
}
DataRate DelayBasedRateController::target_rate() const {
return target_rate_;
}
bool DelayBasedRateController::in_underuse() const {
return overuse_detector_->State() == BandwidthUsage::kBwUnderusing;
}
void DelayBasedRateController::MaybeLog() {
if (event_log_ && (logged_target_ != target_rate_ ||
logged_state_ != overuse_detector_->State())) {
event_log_->Log(absl::make_unique<RtcEventBweUpdateDelayBased>(
target_rate_.bps(), overuse_detector_->State()));
logged_state_ = overuse_detector_->State();
logged_target_ = target_rate_;
}
}
} // namespace webrtc