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 94645dcc4a..d8a0ce9d64 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -720,7 +720,8 @@ PacerConfig GoogCcNetworkController::GetPacingRates(Timestamp at_time) const { // Pacing rate is based on target rate before congestion window pushback, // because we don't want to build queues in the pacer when pushback occurs. DataRate pacing_rate = DataRate::Zero(); - if (pace_at_max_of_bwe_and_lower_link_capacity_ && estimate_) { + if (pace_at_max_of_bwe_and_lower_link_capacity_ && estimate_ && + !bandwidth_estimation_->PaceAtLossBasedEstimate()) { pacing_rate = std::max({min_total_allocated_bitrate_, estimate_->link_capacity_lower, last_loss_based_target_rate_}) * diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc index 95f821352a..7deeb7ad64 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -499,6 +499,8 @@ absl::optional LossBasedBweV2::CreateConfig( FieldTrialParameter padding_duration("PaddingDuration", TimeDelta::Zero()); FieldTrialParameter bound_best_candidate("BoundBestCandidate", false); + FieldTrialParameter pace_at_loss_based_estimate( + "PaceAtLossBasedEstimate", false); if (key_value_config) { ParseFieldTrial({&enabled, &bandwidth_rampup_upper_bound_factor, @@ -538,7 +540,8 @@ absl::optional LossBasedBweV2::CreateConfig( &hold_duration_factor, &use_byte_loss_rate, &padding_duration, - &bound_best_candidate}, + &bound_best_candidate, + &pace_at_loss_based_estimate}, key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2")); } @@ -604,6 +607,7 @@ absl::optional LossBasedBweV2::CreateConfig( config->use_byte_loss_rate = use_byte_loss_rate.Get(); config->padding_duration = padding_duration.Get(); config->bound_best_candidate = bound_best_candidate.Get(); + config->pace_at_loss_based_estimate = pace_at_loss_based_estimate.Get(); return config; } @@ -1199,4 +1203,9 @@ bool LossBasedBweV2::CanKeepIncreasingState(DataRate estimate) const { last_padding_info_.padding_rate < estimate; } +bool LossBasedBweV2::PaceAtLossBasedEstimate() const { + return config_->pace_at_loss_based_estimate && + loss_based_result_.state != LossBasedState::kDelayBasedEstimate; +} + } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h index 9afbb11f1f..34c96c66d9 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -74,6 +74,7 @@ class LossBasedBweV2 { rtc::ArrayView packet_results, DataRate delay_based_estimate, bool in_alr); + bool PaceAtLossBasedEstimate() const; // For unit testing only. void SetBandwidthEstimate(DataRate bandwidth_estimate); @@ -124,6 +125,7 @@ class LossBasedBweV2 { bool use_byte_loss_rate = false; TimeDelta padding_duration = TimeDelta::Zero(); bool bound_best_candidate = false; + bool pace_at_loss_based_estimate = false; }; struct Derivatives { diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc index 9b7ad03148..bb867f4fb0 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc @@ -1776,5 +1776,41 @@ TEST_F(LossBasedBweV2Test, UseByteLossRate) { DataRate::KilobitsPerSec(150)); } +TEST_F(LossBasedBweV2Test, PaceAtLossBasedEstimate) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "PaceAtLossBasedEstimate:true,PaddingDuration:1000ms")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(1000)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(1000), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDelayBasedEstimate); + EXPECT_FALSE(loss_based_bandwidth_estimator.PaceAtLossBasedEstimate()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(1000), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + EXPECT_TRUE(loss_based_bandwidth_estimator.PaceAtLossBasedEstimate()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * 2), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(1000), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreaseUsingPadding); + EXPECT_TRUE(loss_based_bandwidth_estimator.PaceAtLossBasedEstimate()); +} + } // namespace } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc index 211d86c95d..7b305f12f1 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -700,8 +700,12 @@ bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV2Enabled() const { bool SendSideBandwidthEstimation::LossBasedBandwidthEstimatorV2ReadyForUse() const { - return LossBasedBandwidthEstimatorV2Enabled() && - loss_based_bandwidth_estimator_v2_->IsReady(); + return loss_based_bandwidth_estimator_v2_->IsReady(); +} + +bool SendSideBandwidthEstimation::PaceAtLossBasedEstimate() const { + return LossBasedBandwidthEstimatorV2ReadyForUse() && + loss_based_bandwidth_estimator_v2_->PaceAtLossBasedEstimate(); } } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h index dd4d25a236..1d919af7b6 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h @@ -129,6 +129,7 @@ class SendSideBandwidthEstimation { BandwidthUsage delay_detector_state, absl::optional probe_bitrate, bool in_alr); + bool PaceAtLossBasedEstimate() const; private: friend class GoogCcStatePrinter;