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_