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}
This commit is contained in:
parent
49856f1891
commit
da0222b3fc
@ -26,6 +26,7 @@ rtc_static_library("goog_cc") {
|
||||
deps = [
|
||||
":alr_detector",
|
||||
":delay_based_bwe",
|
||||
":delay_based_rate_controller",
|
||||
":estimators",
|
||||
":probe_controller",
|
||||
":pushback_controller",
|
||||
@ -121,6 +122,7 @@ rtc_source_set("estimators") {
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base:rtc_numerics",
|
||||
"../../../rtc_base:safe_minmax",
|
||||
"../../../rtc_base/experiments:field_trial_parser",
|
||||
"../../../system_wrappers:field_trial",
|
||||
"../../remote_bitrate_estimator",
|
||||
"../../rtp_rtcp:rtp_rtcp_format",
|
||||
@ -129,6 +131,30 @@ rtc_source_set("estimators") {
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("delay_based_rate_controller") {
|
||||
configs += [ ":bwe_test_logging" ]
|
||||
sources = [
|
||||
"delay_based_rate_controller.cc",
|
||||
"delay_based_rate_controller.h",
|
||||
"packet_grouping.cc",
|
||||
"packet_grouping.h",
|
||||
]
|
||||
deps = [
|
||||
":estimators",
|
||||
":link_capacity_estimator",
|
||||
"../../../api/transport:network_control",
|
||||
"../../../logging:rtc_event_bwe",
|
||||
"../../../logging:rtc_event_log_api",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base/experiments:field_trial_parser",
|
||||
"../../../system_wrappers:field_trial",
|
||||
"../../../system_wrappers:metrics",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("delay_based_bwe") {
|
||||
configs += [ ":bwe_test_logging" ]
|
||||
sources = [
|
||||
@ -143,6 +169,7 @@ rtc_source_set("delay_based_bwe") {
|
||||
"../../../logging:rtc_event_log_api",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base/experiments:field_trial_parser",
|
||||
"../../../system_wrappers:field_trial",
|
||||
"../../../system_wrappers:metrics",
|
||||
"../../pacing",
|
||||
|
||||
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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
|
||||
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_RATE_CONTROLLER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_RATE_CONTROLLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "logging/rtc_event_log/rtc_event_log.h"
|
||||
#include "modules/congestion_controller/goog_cc/link_capacity_estimator.h"
|
||||
#include "modules/congestion_controller/goog_cc/packet_grouping.h"
|
||||
#include "modules/congestion_controller/goog_cc/trendline_estimator.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/experiments/field_trial_units.h"
|
||||
|
||||
namespace webrtc {
|
||||
struct DelayBasedRateControllerConfig {
|
||||
FieldTrialFlag enabled;
|
||||
FieldTrialParameter<double> no_ack_backoff_fraction;
|
||||
FieldTrialParameter<TimeDelta> no_ack_backoff_interval;
|
||||
FieldTrialParameter<double> ack_backoff_fraction;
|
||||
FieldTrialParameter<double> probe_backoff_fraction;
|
||||
FieldTrialParameter<double> initial_increase_rate;
|
||||
FieldTrialParameter<double> increase_rate;
|
||||
FieldTrialParameter<DataRate> first_period_increase_rate;
|
||||
FieldTrialParameter<TimeDelta> stop_increase_after;
|
||||
FieldTrialParameter<TimeDelta> min_increase_interval;
|
||||
FieldTrialParameter<DataRate> linear_increase_threshold;
|
||||
FieldTrialParameter<TimeDelta> reference_duration_offset;
|
||||
DelayBasedRateControllerConfig();
|
||||
~DelayBasedRateControllerConfig();
|
||||
};
|
||||
|
||||
// Rate controller for GoogCC, increases the target rate based on a
|
||||
// fixed increase interval and an RTT dependent increase rate.
|
||||
class DelayBasedRateController {
|
||||
public:
|
||||
DelayBasedRateController(RtcEventLog* event_log,
|
||||
TargetRateConstraints constraints);
|
||||
~DelayBasedRateController();
|
||||
void OnRouteChange();
|
||||
void UpdateConstraints(TargetRateConstraints constraints);
|
||||
void SetAcknowledgedRate(DataRate acknowledged_rate);
|
||||
void OnTransportPacketsFeedback(TransportPacketsFeedback msg,
|
||||
absl::optional<DataRate> probe_bitrate);
|
||||
void OnTimeUpdate(Timestamp at_time);
|
||||
void OnRemoteBitrateControl(RemoteBitrateReport msg);
|
||||
TimeDelta GetExpectedBandwidthPeriod() const;
|
||||
|
||||
bool Enabled() const { return conf_.enabled; }
|
||||
DataRate target_rate() const;
|
||||
bool in_underuse() const;
|
||||
|
||||
private:
|
||||
enum class ControllerSate { kHold, kExponentialIncrease, kLinearIncrease };
|
||||
friend class GoogCcStatePrinter;
|
||||
void OnFeedbackUpdate(BandwidthUsage usage,
|
||||
absl::optional<DataRate> probe_bitrate,
|
||||
Timestamp at_time);
|
||||
void MaybeLog();
|
||||
const DelayBasedRateControllerConfig conf_;
|
||||
RtcEventLog* event_log_;
|
||||
|
||||
PacketDelayGrouper packet_grouper_;
|
||||
std::unique_ptr<TrendlineEstimator> overuse_detector_;
|
||||
LinkCapacityEstimator link_capacity_;
|
||||
|
||||
DataRate min_rate_ = DataRate::Zero();
|
||||
DataRate max_rate_ = DataRate::Infinity();
|
||||
|
||||
absl::optional<DataRate> acknowledged_rate_;
|
||||
TimeDelta last_rtt_ = TimeDelta::seconds(1);
|
||||
Timestamp first_unacked_send_ = Timestamp::PlusInfinity();
|
||||
Timestamp last_feedback_update_ = Timestamp::MinusInfinity();
|
||||
|
||||
DataRate target_rate_;
|
||||
|
||||
Timestamp last_no_ack_backoff_ = Timestamp::MinusInfinity();
|
||||
bool increasing_state_ = false;
|
||||
double accumulated_duration_ = 0;
|
||||
Timestamp last_increase_update_ = Timestamp::PlusInfinity();
|
||||
DataRate increase_reference_ = DataRate::PlusInfinity();
|
||||
|
||||
absl::optional<BandwidthUsage> logged_state_;
|
||||
DataRate logged_target_ = DataRate::PlusInfinity();
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_RATE_CONTROLLER_H_
|
||||
@ -145,7 +145,15 @@ GoogCcNetworkController::GoogCcNetworkController(RtcEventLog* event_log,
|
||||
absl::make_unique<SendSideBandwidthEstimation>(event_log_)),
|
||||
alr_detector_(absl::make_unique<AlrDetector>()),
|
||||
probe_bitrate_estimator_(new ProbeBitrateEstimator(event_log)),
|
||||
delay_based_bwe_(new DelayBasedBwe(event_log_)),
|
||||
use_new_delay_based_controller_(
|
||||
field_trial::IsEnabled("WebRTC-Bwe-DelayBasedRateController")),
|
||||
delay_based_bwe_(use_new_delay_based_controller_
|
||||
? nullptr
|
||||
: new DelayBasedBwe(event_log_)),
|
||||
delay_based_controller_(
|
||||
use_new_delay_based_controller_
|
||||
? new DelayBasedRateController(event_log_, config.constraints)
|
||||
: nullptr),
|
||||
acknowledged_bitrate_estimator_(
|
||||
absl::make_unique<AcknowledgedBitrateEstimator>()),
|
||||
initial_config_(config),
|
||||
@ -164,8 +172,8 @@ GoogCcNetworkController::GoogCcNetworkController(RtcEventLog* event_log,
|
||||
ParseFieldTrial(
|
||||
{&safe_reset_on_route_change_, &safe_reset_acknowledged_rate_},
|
||||
field_trial::FindFullName("WebRTC-Bwe-SafeResetOnRouteChange"));
|
||||
|
||||
delay_based_bwe_->SetMinBitrate(congestion_controller::GetMinBitrate());
|
||||
if (delay_based_bwe_)
|
||||
delay_based_bwe_->SetMinBitrate(congestion_controller::GetMinBitrate());
|
||||
if (in_cwnd_experiment_ &&
|
||||
!ReadCwndExperimentParameter(&accepted_queue_ms_)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
|
||||
@ -215,11 +223,16 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange(
|
||||
|
||||
acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
|
||||
probe_bitrate_estimator_.reset(new ProbeBitrateEstimator(event_log_));
|
||||
delay_based_bwe_.reset(new DelayBasedBwe(event_log_));
|
||||
if (msg.constraints.starting_rate)
|
||||
delay_based_bwe_->SetStartBitrate(*msg.constraints.starting_rate);
|
||||
// TODO(srte): Use original values instead of converted.
|
||||
delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
|
||||
if (delay_based_bwe_) {
|
||||
delay_based_bwe_.reset(new DelayBasedBwe(event_log_));
|
||||
if (msg.constraints.starting_rate)
|
||||
delay_based_bwe_->SetStartBitrate(*msg.constraints.starting_rate);
|
||||
// TODO(srte): Use original values instead of converted.
|
||||
delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
|
||||
} else {
|
||||
delay_based_controller_->UpdateConstraints(msg.constraints);
|
||||
delay_based_controller_->OnRouteChange();
|
||||
}
|
||||
bandwidth_estimation_->OnRouteChange();
|
||||
bandwidth_estimation_->SetBitrates(
|
||||
msg.constraints.starting_rate, DataRate::bps(min_bitrate_bps),
|
||||
@ -257,7 +270,11 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval(
|
||||
}
|
||||
initial_config_.reset();
|
||||
}
|
||||
|
||||
if (delay_based_controller_) {
|
||||
delay_based_controller_->OnTimeUpdate(msg.at_time);
|
||||
bandwidth_estimation_->UpdateDelayBasedEstimate(
|
||||
msg.at_time, delay_based_controller_->target_rate());
|
||||
}
|
||||
bandwidth_estimation_->UpdateEstimate(msg.at_time);
|
||||
absl::optional<int64_t> start_time_ms =
|
||||
alr_detector_->GetApplicationLimitedRegionStartTime();
|
||||
@ -277,6 +294,8 @@ NetworkControlUpdate GoogCcNetworkController::OnRemoteBitrateReport(
|
||||
RTC_LOG(LS_ERROR) << "Received REMB for packet feedback only GoogCC";
|
||||
return NetworkControlUpdate();
|
||||
}
|
||||
if (delay_based_controller_)
|
||||
delay_based_controller_->OnRemoteBitrateControl(msg);
|
||||
bandwidth_estimation_->UpdateReceiverEstimate(msg.receive_time,
|
||||
msg.bandwidth);
|
||||
BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", msg.receive_time.ms(),
|
||||
@ -289,7 +308,8 @@ NetworkControlUpdate GoogCcNetworkController::OnRoundTripTimeUpdate(
|
||||
if (packet_feedback_only_)
|
||||
return NetworkControlUpdate();
|
||||
if (msg.smoothed) {
|
||||
delay_based_bwe_->OnRttUpdate(msg.round_trip_time);
|
||||
if (delay_based_bwe_)
|
||||
delay_based_bwe_->OnRttUpdate(msg.round_trip_time);
|
||||
} else {
|
||||
bandwidth_estimation_->UpdateRtt(msg.round_trip_time, msg.receive_time);
|
||||
}
|
||||
@ -377,9 +397,13 @@ GoogCcNetworkController::UpdateBitrateConstraints(
|
||||
starting_rate, DataRate::bps(min_bitrate_bps),
|
||||
constraints.max_data_rate.value_or(DataRate::Infinity()),
|
||||
constraints.at_time);
|
||||
if (starting_rate)
|
||||
delay_based_bwe_->SetStartBitrate(*starting_rate);
|
||||
delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
|
||||
if (delay_based_bwe_) {
|
||||
if (starting_rate)
|
||||
delay_based_bwe_->SetStartBitrate(*starting_rate);
|
||||
delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
|
||||
} else {
|
||||
delay_based_controller_->UpdateConstraints(constraints);
|
||||
}
|
||||
return probes;
|
||||
}
|
||||
|
||||
@ -437,7 +461,8 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
||||
int64_t sum_rtt_ms = std::accumulate(feedback_max_rtts_.begin(),
|
||||
feedback_max_rtts_.end(), 0);
|
||||
int64_t mean_rtt_ms = sum_rtt_ms / feedback_max_rtts_.size();
|
||||
delay_based_bwe_->OnRttUpdate(TimeDelta::ms(mean_rtt_ms));
|
||||
if (delay_based_bwe_)
|
||||
delay_based_bwe_->OnRttUpdate(TimeDelta::ms(mean_rtt_ms));
|
||||
}
|
||||
|
||||
TimeDelta feedback_min_rtt = TimeDelta::PlusInfinity();
|
||||
@ -488,6 +513,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
||||
probe_bitrate_estimator_->HandleProbeAndEstimateBitrate(feedback);
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<DataRate> probe_bitrate =
|
||||
probe_bitrate_estimator_->FetchAndResetLastEstimatedBitrate();
|
||||
if (fall_back_to_probe_rate_ && !acknowledged_bitrate)
|
||||
@ -495,30 +521,52 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
||||
bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate,
|
||||
report.feedback_time);
|
||||
bandwidth_estimation_->IncomingPacketFeedbackVector(report);
|
||||
DelayBasedBwe::Result result;
|
||||
result = delay_based_bwe_->IncomingPacketFeedbackVector(
|
||||
received_feedback_vector, acknowledged_bitrate, probe_bitrate,
|
||||
alr_start_time.has_value(), report.feedback_time);
|
||||
|
||||
NetworkControlUpdate update;
|
||||
if (result.updated) {
|
||||
if (result.probe) {
|
||||
bandwidth_estimation_->SetSendBitrate(result.target_bitrate,
|
||||
report.feedback_time);
|
||||
bool recovered_from_overuse = false;
|
||||
bool backoff_in_alr = false;
|
||||
// TODO(srte): Add support for ALR backoff trial in the new rate controller.
|
||||
if (delay_based_controller_) {
|
||||
if (acknowledged_bitrate)
|
||||
delay_based_controller_->SetAcknowledgedRate(*acknowledged_bitrate);
|
||||
bool prior_underuse = delay_based_controller_->in_underuse();
|
||||
delay_based_controller_->OnTransportPacketsFeedback(report, probe_bitrate);
|
||||
recovered_from_overuse =
|
||||
prior_underuse && !delay_based_controller_->in_underuse();
|
||||
if (probe_bitrate) {
|
||||
bandwidth_estimation_->SetSendBitrate(
|
||||
delay_based_controller_->target_rate(), report.feedback_time);
|
||||
}
|
||||
// Since SetSendBitrate now resets the delay-based estimate, we have to call
|
||||
// UpdateDelayBasedEstimate after SetSendBitrate.
|
||||
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time,
|
||||
result.target_bitrate);
|
||||
// Update the estimate in the ProbeController, in case we want to probe.
|
||||
bandwidth_estimation_->UpdateDelayBasedEstimate(
|
||||
report.feedback_time, delay_based_controller_->target_rate());
|
||||
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
|
||||
} else {
|
||||
DelayBasedBwe::Result result;
|
||||
result = delay_based_bwe_->IncomingPacketFeedbackVector(
|
||||
received_feedback_vector, acknowledged_bitrate, probe_bitrate,
|
||||
alr_start_time.has_value(), report.feedback_time);
|
||||
|
||||
if (result.updated) {
|
||||
if (result.probe) {
|
||||
bandwidth_estimation_->SetSendBitrate(result.target_bitrate,
|
||||
report.feedback_time);
|
||||
}
|
||||
// Since SetSendBitrate now resets the delay-based estimate, we have to
|
||||
// call UpdateDelayBasedEstimate after SetSendBitrate.
|
||||
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time,
|
||||
result.target_bitrate);
|
||||
// Update the estimate in the ProbeController, in case we want to probe.
|
||||
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
|
||||
}
|
||||
recovered_from_overuse = result.recovered_from_overuse;
|
||||
backoff_in_alr = result.backoff_in_alr;
|
||||
}
|
||||
if (result.recovered_from_overuse) {
|
||||
if (recovered_from_overuse) {
|
||||
probe_controller_->SetAlrStartTimeMs(alr_start_time);
|
||||
auto probes = probe_controller_->RequestProbe(report.feedback_time.ms());
|
||||
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
|
||||
probes.begin(), probes.end());
|
||||
} else if (result.backoff_in_alr) {
|
||||
} else if (backoff_in_alr) {
|
||||
// If we just backed off during ALR, request a new probe.
|
||||
auto probes = probe_controller_->RequestProbe(report.feedback_time.ms());
|
||||
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
|
||||
@ -565,7 +613,9 @@ NetworkControlUpdate GoogCcNetworkController::GetNetworkState(
|
||||
last_estimated_fraction_loss_ / 255.0;
|
||||
update.target_rate->network_estimate.round_trip_time = rtt;
|
||||
update.target_rate->network_estimate.bwe_period =
|
||||
delay_based_bwe_->GetExpectedBwePeriod();
|
||||
delay_based_bwe_ ? delay_based_bwe_->GetExpectedBwePeriod()
|
||||
: delay_based_controller_->GetExpectedBandwidthPeriod();
|
||||
|
||||
update.target_rate->at_time = at_time;
|
||||
update.target_rate->target_rate = bandwidth;
|
||||
update.pacer_config = GetPacingRates(at_time);
|
||||
@ -606,7 +656,10 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged(
|
||||
? bandwidth_estimation_->GetEstimatedLinkCapacity()
|
||||
: last_target_rate_;
|
||||
|
||||
TimeDelta bwe_period = delay_based_bwe_->GetExpectedBwePeriod();
|
||||
TimeDelta bwe_period =
|
||||
delay_based_bwe_
|
||||
? delay_based_bwe_->GetExpectedBwePeriod()
|
||||
: delay_based_controller_->GetExpectedBandwidthPeriod();
|
||||
|
||||
// Set the target rate to the full estimated bandwidth since the estimation
|
||||
// for legacy reasons includes target rate constraints.
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "modules/congestion_controller/goog_cc/alr_detector.h"
|
||||
#include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h"
|
||||
#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
|
||||
#include "modules/congestion_controller/goog_cc/delay_based_rate_controller.h"
|
||||
#include "modules/congestion_controller/goog_cc/probe_controller.h"
|
||||
#include "rtc_base/constructormagic.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
@ -81,7 +82,9 @@ class GoogCcNetworkController : public NetworkControllerInterface {
|
||||
std::unique_ptr<SendSideBandwidthEstimation> bandwidth_estimation_;
|
||||
std::unique_ptr<AlrDetector> alr_detector_;
|
||||
std::unique_ptr<ProbeBitrateEstimator> probe_bitrate_estimator_;
|
||||
const bool use_new_delay_based_controller_;
|
||||
std::unique_ptr<DelayBasedBwe> delay_based_bwe_;
|
||||
std::unique_ptr<DelayBasedRateController> delay_based_controller_;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
|
||||
|
||||
absl::optional<NetworkControllerConfig> initial_config_;
|
||||
|
||||
@ -35,18 +35,24 @@ void LinkCapacityEstimator::Reset() {
|
||||
}
|
||||
|
||||
void LinkCapacityEstimator::OnOveruseDetected(DataRate acknowledged_rate) {
|
||||
double ack_rate_kbps = acknowledged_rate.kbps();
|
||||
const float alpha = 0.05f;
|
||||
Update(acknowledged_rate, 0.05);
|
||||
}
|
||||
|
||||
void LinkCapacityEstimator::OnProbeRate(DataRate probe_rate) {
|
||||
Update(probe_rate, 0.5);
|
||||
}
|
||||
|
||||
void LinkCapacityEstimator::Update(DataRate capacity_sample, double alpha) {
|
||||
double sample_kbps = capacity_sample.kbps();
|
||||
if (!estimate_kbps_.has_value()) {
|
||||
estimate_kbps_ = ack_rate_kbps;
|
||||
estimate_kbps_ = sample_kbps;
|
||||
} else {
|
||||
estimate_kbps_ =
|
||||
(1 - alpha) * estimate_kbps_.value() + alpha * ack_rate_kbps;
|
||||
estimate_kbps_ = (1 - alpha) * estimate_kbps_.value() + alpha * sample_kbps;
|
||||
}
|
||||
// Estimate the variance of the link capacity estimate and normalize the
|
||||
// variance with the link capacity estimate.
|
||||
const double norm = std::max(estimate_kbps_.value(), 1.0);
|
||||
double error_kbps = estimate_kbps_.value() - ack_rate_kbps;
|
||||
double error_kbps = estimate_kbps_.value() - sample_kbps;
|
||||
deviation_kbps_ =
|
||||
(1 - alpha) * deviation_kbps_ + alpha * error_kbps * error_kbps / norm;
|
||||
// 0.4 ~= 14 kbit/s at 500 kbit/s
|
||||
|
||||
@ -21,11 +21,13 @@ class LinkCapacityEstimator {
|
||||
DataRate LowerBound() const;
|
||||
void Reset();
|
||||
void OnOveruseDetected(DataRate acknowledged_rate);
|
||||
void OnProbeRate(DataRate probe_rate);
|
||||
bool has_estimate() const;
|
||||
DataRate estimate() const;
|
||||
|
||||
private:
|
||||
friend class GoogCcStatePrinter;
|
||||
void Update(DataRate capacity_sample, double alpha);
|
||||
|
||||
double deviation_estimate_kbps() const;
|
||||
absl::optional<double> estimate_kbps_;
|
||||
|
||||
111
modules/congestion_controller/goog_cc/packet_grouping.cc
Normal file
111
modules/congestion_controller/goog_cc/packet_grouping.cc
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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/packet_grouping.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr TimeDelta kMaxSendTimeGroupDuration = TimeDelta::Millis<5>();
|
||||
constexpr TimeDelta kMaxReceiveTimeBurstDelta = TimeDelta::Millis<5>();
|
||||
constexpr TimeDelta kMaxReceiveTimeBurstDuration = TimeDelta::Millis<100>();
|
||||
constexpr TimeDelta kReceiveTimeOffsetThreshold = TimeDelta::Millis<3000>();
|
||||
constexpr int kReorderedResetThreshold = 3;
|
||||
} // namespace
|
||||
|
||||
PacketDelayGroup::PacketDelayGroup(PacketResult packet, Timestamp feedback_time)
|
||||
: first_send_time(packet.sent_packet.send_time),
|
||||
last_send_time(packet.sent_packet.send_time),
|
||||
first_receive_time(packet.receive_time),
|
||||
last_receive_time(packet.receive_time),
|
||||
last_feedback_time(feedback_time) {}
|
||||
|
||||
PacketDelayGroup::~PacketDelayGroup() = default;
|
||||
PacketDelayGroup::PacketDelayGroup(const PacketDelayGroup&) = default;
|
||||
|
||||
void PacketDelayGroup::AddPacketInfo(PacketResult packet,
|
||||
Timestamp feedback_time) {
|
||||
last_send_time = std::max(last_send_time, packet.sent_packet.send_time);
|
||||
first_receive_time = std::min(first_receive_time, packet.receive_time);
|
||||
last_receive_time = std::max(last_receive_time, packet.receive_time);
|
||||
last_feedback_time = std::max(last_feedback_time, feedback_time);
|
||||
}
|
||||
|
||||
bool PacketDelayGroup::BelongsToGroup(PacketResult packet) const {
|
||||
TimeDelta send_time_duration = packet.sent_packet.send_time - first_send_time;
|
||||
return send_time_duration <= kMaxSendTimeGroupDuration;
|
||||
}
|
||||
|
||||
bool PacketDelayGroup::BelongsToBurst(PacketResult packet) const {
|
||||
TimeDelta send_time_delta = packet.sent_packet.send_time - first_send_time;
|
||||
TimeDelta receive_time_delta = packet.receive_time - last_receive_time;
|
||||
TimeDelta receive_time_duration = packet.receive_time - first_receive_time;
|
||||
bool receiving_faster_than_sent = receive_time_delta < send_time_delta;
|
||||
return receiving_faster_than_sent &&
|
||||
receive_time_delta <= kMaxReceiveTimeBurstDelta &&
|
||||
receive_time_duration <= kMaxReceiveTimeBurstDuration;
|
||||
}
|
||||
|
||||
PacketDelayGrouper::PacketDelayGrouper() = default;
|
||||
|
||||
PacketDelayGrouper::~PacketDelayGrouper() = default;
|
||||
|
||||
void PacketDelayGrouper::AddPacketInfo(PacketResult packet,
|
||||
Timestamp feedback_time) {
|
||||
if (packet_groups_.empty()) {
|
||||
packet_groups_.emplace_back(packet, feedback_time);
|
||||
} else if (packet.sent_packet.send_time >=
|
||||
packet_groups_.back().first_send_time) {
|
||||
if (packet_groups_.back().BelongsToGroup(packet) ||
|
||||
packet_groups_.back().BelongsToBurst(packet)) {
|
||||
packet_groups_.back().AddPacketInfo(packet, feedback_time);
|
||||
} else {
|
||||
packet_groups_.emplace_back(packet, feedback_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PacketDelayDelta> PacketDelayGrouper::PopDeltas() {
|
||||
std::vector<PacketDelayDelta> deltas;
|
||||
while (packet_groups_.size() >= 3) {
|
||||
PacketDelayDelta delta;
|
||||
delta.receive_time = packet_groups_[1].last_receive_time;
|
||||
delta.send =
|
||||
packet_groups_[1].last_send_time - packet_groups_[0].last_send_time;
|
||||
delta.receive = packet_groups_[1].last_receive_time -
|
||||
packet_groups_[0].last_receive_time;
|
||||
delta.feedback = packet_groups_[1].last_feedback_time -
|
||||
packet_groups_[0].last_feedback_time;
|
||||
packet_groups_.pop_front();
|
||||
|
||||
if (delta.receive - delta.feedback >= kReceiveTimeOffsetThreshold) {
|
||||
RTC_LOG(LS_WARNING) << "The receive clock offset has changed (diff = "
|
||||
<< ToString(delta.receive - delta.feedback)
|
||||
<< "), resetting.";
|
||||
packet_groups_.pop_front();
|
||||
} else if (delta.receive < TimeDelta::Zero()) {
|
||||
++num_consecutive_reordered_packets_;
|
||||
if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) {
|
||||
RTC_LOG(LS_WARNING) << "Decreasing receive time in multiple "
|
||||
"consecutive packet groups, resetting";
|
||||
packet_groups_.pop_front();
|
||||
}
|
||||
} else {
|
||||
num_consecutive_reordered_packets_ = 0;
|
||||
deltas.push_back(delta);
|
||||
}
|
||||
}
|
||||
return deltas;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
58
modules/congestion_controller/goog_cc/packet_grouping.h
Normal file
58
modules/congestion_controller/goog_cc/packet_grouping.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_PACKET_GROUPING_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_PACKET_GROUPING_H_
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "api/transport/network_control.h"
|
||||
|
||||
namespace webrtc {
|
||||
struct PacketDelayGroup {
|
||||
explicit PacketDelayGroup(PacketResult packet, Timestamp feedback_time);
|
||||
|
||||
PacketDelayGroup(const PacketDelayGroup&);
|
||||
~PacketDelayGroup();
|
||||
void AddPacketInfo(PacketResult packet, Timestamp feedback_time);
|
||||
bool BelongsToGroup(PacketResult packet) const;
|
||||
bool BelongsToBurst(PacketResult packet) const;
|
||||
|
||||
Timestamp first_send_time;
|
||||
Timestamp last_send_time;
|
||||
|
||||
Timestamp first_receive_time;
|
||||
Timestamp last_receive_time;
|
||||
Timestamp last_feedback_time;
|
||||
};
|
||||
|
||||
struct PacketDelayDelta {
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
TimeDelta send = TimeDelta::Zero();
|
||||
TimeDelta receive = TimeDelta::Zero();
|
||||
TimeDelta feedback = TimeDelta::Zero();
|
||||
};
|
||||
|
||||
class PacketDelayGrouper {
|
||||
public:
|
||||
PacketDelayGrouper();
|
||||
~PacketDelayGrouper();
|
||||
void AddPacketInfo(PacketResult packet, Timestamp feedback_time);
|
||||
std::vector<PacketDelayDelta> PopDeltas();
|
||||
void Reset() { packet_groups_.clear(); }
|
||||
|
||||
private:
|
||||
std::deque<PacketDelayGroup> packet_groups_;
|
||||
int num_consecutive_reordered_packets_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_PACKET_GROUPING_H_
|
||||
Loading…
x
Reference in New Issue
Block a user