From da0222b3fcdcd2b9f9e79effc9995afa62f23693 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Fri, 21 Dec 2018 14:14:43 +0100 Subject: [PATCH] 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 Reviewed-by: Christoffer Rodbro Cr-Commit-Position: refs/heads/master@{#26088} --- .../congestion_controller/goog_cc/BUILD.gn | 27 +++ .../goog_cc/delay_based_rate_controller.cc | 216 ++++++++++++++++++ .../goog_cc/delay_based_rate_controller.h | 97 ++++++++ .../goog_cc/goog_cc_network_control.cc | 115 +++++++--- .../goog_cc/goog_cc_network_control.h | 3 + .../goog_cc/link_capacity_estimator.cc | 18 +- .../goog_cc/link_capacity_estimator.h | 2 + .../goog_cc/packet_grouping.cc | 111 +++++++++ .../goog_cc/packet_grouping.h | 58 +++++ 9 files changed, 610 insertions(+), 37 deletions(-) create mode 100644 modules/congestion_controller/goog_cc/delay_based_rate_controller.cc create mode 100644 modules/congestion_controller/goog_cc/delay_based_rate_controller.h create mode 100644 modules/congestion_controller/goog_cc/packet_grouping.cc create mode 100644 modules/congestion_controller/goog_cc/packet_grouping.h diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 237769b5a6..039ea9a050 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -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", diff --git a/modules/congestion_controller/goog_cc/delay_based_rate_controller.cc b/modules/congestion_controller/goog_cc/delay_based_rate_controller.cc new file mode 100644 index 0000000000..7b768b8288 --- /dev/null +++ b/modules/congestion_controller/goog_cc/delay_based_rate_controller.cc @@ -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 +#include + +#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 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(), + delta.send.ms(), 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 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( + target_rate_.bps(), overuse_detector_->State())); + logged_state_ = overuse_detector_->State(); + logged_target_ = target_rate_; + } +} + +} // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/delay_based_rate_controller.h b/modules/congestion_controller/goog_cc/delay_based_rate_controller.h new file mode 100644 index 0000000000..2580c21905 --- /dev/null +++ b/modules/congestion_controller/goog_cc/delay_based_rate_controller.h @@ -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 + +#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 no_ack_backoff_fraction; + FieldTrialParameter no_ack_backoff_interval; + FieldTrialParameter ack_backoff_fraction; + FieldTrialParameter probe_backoff_fraction; + FieldTrialParameter initial_increase_rate; + FieldTrialParameter increase_rate; + FieldTrialParameter first_period_increase_rate; + FieldTrialParameter stop_increase_after; + FieldTrialParameter min_increase_interval; + FieldTrialParameter linear_increase_threshold; + FieldTrialParameter 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 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 probe_bitrate, + Timestamp at_time); + void MaybeLog(); + const DelayBasedRateControllerConfig conf_; + RtcEventLog* event_log_; + + PacketDelayGrouper packet_grouper_; + std::unique_ptr overuse_detector_; + LinkCapacityEstimator link_capacity_; + + DataRate min_rate_ = DataRate::Zero(); + DataRate max_rate_ = DataRate::Infinity(); + + absl::optional 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 logged_state_; + DataRate logged_target_ = DataRate::PlusInfinity(); +}; +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_RATE_CONTROLLER_H_ diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index 8240acc4f5..b69d83837a 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -145,7 +145,15 @@ GoogCcNetworkController::GoogCcNetworkController(RtcEventLog* event_log, absl::make_unique(event_log_)), alr_detector_(absl::make_unique()), 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()), 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 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 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. diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index c635ab483b..370ce829c6 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -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 bandwidth_estimation_; std::unique_ptr alr_detector_; std::unique_ptr probe_bitrate_estimator_; + const bool use_new_delay_based_controller_; std::unique_ptr delay_based_bwe_; + std::unique_ptr delay_based_controller_; std::unique_ptr acknowledged_bitrate_estimator_; absl::optional initial_config_; diff --git a/modules/congestion_controller/goog_cc/link_capacity_estimator.cc b/modules/congestion_controller/goog_cc/link_capacity_estimator.cc index 8f59c9a91e..e37d8d87b3 100644 --- a/modules/congestion_controller/goog_cc/link_capacity_estimator.cc +++ b/modules/congestion_controller/goog_cc/link_capacity_estimator.cc @@ -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 diff --git a/modules/congestion_controller/goog_cc/link_capacity_estimator.h b/modules/congestion_controller/goog_cc/link_capacity_estimator.h index cf7e799836..aa23491d9d 100644 --- a/modules/congestion_controller/goog_cc/link_capacity_estimator.h +++ b/modules/congestion_controller/goog_cc/link_capacity_estimator.h @@ -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 estimate_kbps_; diff --git a/modules/congestion_controller/goog_cc/packet_grouping.cc b/modules/congestion_controller/goog_cc/packet_grouping.cc new file mode 100644 index 0000000000..0ed6f79e22 --- /dev/null +++ b/modules/congestion_controller/goog_cc/packet_grouping.cc @@ -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 + +#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 PacketDelayGrouper::PopDeltas() { + std::vector 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 diff --git a/modules/congestion_controller/goog_cc/packet_grouping.h b/modules/congestion_controller/goog_cc/packet_grouping.h new file mode 100644 index 0000000000..b34ae84f5c --- /dev/null +++ b/modules/congestion_controller/goog_cc/packet_grouping.h @@ -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 +#include + +#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 PopDeltas(); + void Reset() { packet_groups_.clear(); } + + private: + std::deque packet_groups_; + int num_consecutive_reordered_packets_ = 0; +}; + +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_PACKET_GROUPING_H_