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 9005956dff..a0b32181af 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -221,6 +222,16 @@ void LossBasedBweV2::UpdateBandwidthEstimate( last_time_estimate_reduced_ = last_send_time_most_recent_observation_; } + // Do not increase the estimate if the average loss is greater than current + // inherent loss. + if (GetAverageReportedLossRatio() > best_candidate.inherent_loss && + config_->not_increase_if_inherent_loss_less_than_average_loss && + current_estimate_.loss_limited_bandwidth < + best_candidate.loss_limited_bandwidth) { + best_candidate.loss_limited_bandwidth = + current_estimate_.loss_limited_bandwidth; + } + // Bound the estimate increase if: // 1. The estimate is limited due to loss, and // 2. The estimate has been increased for less than `delayed_increase_window` @@ -270,6 +281,10 @@ absl::optional LossBasedBweV2::CreateConfig( "HigherLogBwBiasFactor", 0.001); FieldTrialParameter inherent_loss_lower_bound( "InherentLossLowerBound", 1.0e-3); + FieldTrialParameter loss_threshold_of_high_bandwidth_preference( + "LossThresholdOfHighBandwidthPreference", 0.99); + FieldTrialParameter bandwidth_preference_smoothing_factor( + "BandwidthPreferenceSmoothingFactor", 0.002); FieldTrialParameter inherent_loss_upper_bound_bandwidth_balance( "InherentLossUpperBoundBwBalance", DataRate::KilobitsPerSec(15.0)); FieldTrialParameter inherent_loss_upper_bound_offset( @@ -306,6 +321,9 @@ absl::optional LossBasedBweV2::CreateConfig( "DelayedIncreaseWindow", TimeDelta::Millis(300)); FieldTrialParameter use_acked_bitrate_only_when_overusing( "UseAckedBitrateOnlyWhenOverusing", false); + FieldTrialParameter + not_increase_if_inherent_loss_less_than_average_loss( + "NotIncreaseIfInherentLossLessThanAverageLoss", false); if (key_value_config) { ParseFieldTrial({&enabled, @@ -316,6 +334,8 @@ absl::optional LossBasedBweV2::CreateConfig( &higher_bandwidth_bias_factor, &higher_log_bandwidth_bias_factor, &inherent_loss_lower_bound, + &loss_threshold_of_high_bandwidth_preference, + &bandwidth_preference_smoothing_factor, &inherent_loss_upper_bound_bandwidth_balance, &inherent_loss_upper_bound_offset, &initial_inherent_loss_estimate, @@ -335,7 +355,8 @@ absl::optional LossBasedBweV2::CreateConfig( &trendline_observations_window_size, &max_increase_factor, &delayed_increase_window, - &use_acked_bitrate_only_when_overusing}, + &use_acked_bitrate_only_when_overusing, + ¬_increase_if_inherent_loss_less_than_average_loss}, key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2")); } @@ -354,6 +375,10 @@ absl::optional LossBasedBweV2::CreateConfig( config->higher_log_bandwidth_bias_factor = higher_log_bandwidth_bias_factor.Get(); config->inherent_loss_lower_bound = inherent_loss_lower_bound.Get(); + config->loss_threshold_of_high_bandwidth_preference = + loss_threshold_of_high_bandwidth_preference.Get(); + config->bandwidth_preference_smoothing_factor = + bandwidth_preference_smoothing_factor.Get(); config->inherent_loss_upper_bound_bandwidth_balance = inherent_loss_upper_bound_bandwidth_balance.Get(); config->inherent_loss_upper_bound_offset = @@ -385,6 +410,8 @@ absl::optional LossBasedBweV2::CreateConfig( config->delayed_increase_window = delayed_increase_window.Get(); config->use_acked_bitrate_only_when_overusing = use_acked_bitrate_only_when_overusing.Get(); + config->not_increase_if_inherent_loss_less_than_average_loss = + not_increase_if_inherent_loss_less_than_average_loss.Get(); return config; } @@ -447,6 +474,20 @@ bool LossBasedBweV2::IsConfigValid() const { << config_->inherent_loss_lower_bound; valid = false; } + if (config_->loss_threshold_of_high_bandwidth_preference < 0.0 || + config_->loss_threshold_of_high_bandwidth_preference >= 1.0) { + RTC_LOG(LS_WARNING) + << "The loss threshold of high bandwidth preference must be in [0, 1): " + << config_->loss_threshold_of_high_bandwidth_preference; + valid = false; + } + if (config_->bandwidth_preference_smoothing_factor <= 0.0 || + config_->bandwidth_preference_smoothing_factor > 1.0) { + RTC_LOG(LS_WARNING) + << "The bandwidth preference smoothing factor must be in (0, 1]: " + << config_->bandwidth_preference_smoothing_factor; + valid = false; + } if (config_->inherent_loss_upper_bound_bandwidth_balance <= DataRate::Zero()) { RTC_LOG(LS_WARNING) @@ -720,10 +761,23 @@ double LossBasedBweV2::GetInherentLossUpperBound(DataRate bandwidth) const { return std::min(inherent_loss_upper_bound, 1.0); } +double LossBasedBweV2::AdjustBiasFactor(double loss_rate, + double bias_factor) const { + return bias_factor * + (config_->loss_threshold_of_high_bandwidth_preference - loss_rate) / + (config_->bandwidth_preference_smoothing_factor + + std::abs(config_->loss_threshold_of_high_bandwidth_preference - + loss_rate)); +} + double LossBasedBweV2::GetHighBandwidthBias(DataRate bandwidth) const { if (IsValid(bandwidth)) { - return config_->higher_bandwidth_bias_factor * bandwidth.kbps() + - config_->higher_log_bandwidth_bias_factor * + const double average_reported_loss_ratio = GetAverageReportedLossRatio(); + return AdjustBiasFactor(average_reported_loss_ratio, + config_->higher_bandwidth_bias_factor) * + bandwidth.kbps() + + AdjustBiasFactor(average_reported_loss_ratio, + config_->higher_log_bandwidth_bias_factor) * std::log(1.0 + bandwidth.kbps()); } return 0.0; 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 aee9ebd809..fdfb440c72 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -68,6 +68,8 @@ class LossBasedBweV2 { double higher_bandwidth_bias_factor = 0.0; double higher_log_bandwidth_bias_factor = 0.0; double inherent_loss_lower_bound = 0.0; + double loss_threshold_of_high_bandwidth_preference = 0.0; + double bandwidth_preference_smoothing_factor = 0.0; DataRate inherent_loss_upper_bound_bandwidth_balance = DataRate::MinusInfinity(); double inherent_loss_upper_bound_offset = 0.0; @@ -89,6 +91,7 @@ class LossBasedBweV2 { double max_increase_factor = 0.0; TimeDelta delayed_increase_window = TimeDelta::Zero(); bool use_acked_bitrate_only_when_overusing = false; + bool not_increase_if_inherent_loss_less_than_average_loss = false; }; struct Derivatives { @@ -125,6 +128,7 @@ class LossBasedBweV2 { double GetFeasibleInherentLoss( const ChannelParameters& channel_parameters) const; double GetInherentLossUpperBound(DataRate bandwidth) const; + double AdjustBiasFactor(double loss_rate, double bias_factor) const; double GetHighBandwidthBias(DataRate bandwidth) const; double GetObjective(const ChannelParameters& channel_parameters) const; DataRate GetSendingRate(DataRate instantaneous_sending_rate) const; 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 8e09533966..9dc6144217 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 @@ -100,6 +100,23 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { return enough_feedback; } + std::vector CreatePacketResultsWith10pLossRate( + Timestamp first_packet_timestamp) { + std::vector enough_feedback(10); + enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); + for (unsigned i = 0; i < enough_feedback.size(); ++i) { + enough_feedback[i].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[i].sent_packet.send_time = + first_packet_timestamp + + static_cast(i) * kObservationDurationLowerBound; + enough_feedback[i].receive_time = + first_packet_timestamp + + static_cast(i + 1) * kObservationDurationLowerBound; + } + enough_feedback[9].receive_time = Timestamp::PlusInfinity(); + return enough_feedback; + } + std::vector CreatePacketResultsWith50pLossRate( Timestamp first_packet_timestamp) { std::vector enough_feedback(2); @@ -785,6 +802,117 @@ TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { estimate_2); } +TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { + ExplicitKeyValueConfig key_value_config( + "WebRTC-Bwe-LossBasedBweV2/" + "Enabled:true,CandidateFactors:1.2,AckedRateCandidate:false," + "ObservationWindowSize:2," + "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," + "ObservationDurationLowerBound:200ms," + "NotIncreaseIfInherentLossLessThanAverageLoss:true/"); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + + std::vector enough_feedback_10p_loss_1 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_1, delay_based_estimate, + BandwidthUsage::kBwNormal); + + std::vector enough_feedback_10p_loss_2 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_2, delay_based_estimate, + BandwidthUsage::kBwNormal); + + // Do not increase the bitrate because inherent loss is less than average loss + EXPECT_EQ( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + DataRate::KilobitsPerSec(600)); +} + +TEST_P(LossBasedBweV2Test, + SelectHighBandwidthCandidateIfLossRateIsLessThanThreshold) { + ExplicitKeyValueConfig key_value_config( + "WebRTC-Bwe-LossBasedBweV2/" + "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false," + "ObservationWindowSize:2," + "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," + "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," + "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." + "20/"); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + + std::vector enough_feedback_10p_loss_1 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_1, delay_based_estimate, + BandwidthUsage::kBwNormal); + + std::vector enough_feedback_10p_loss_2 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_2, delay_based_estimate, + BandwidthUsage::kBwNormal); + + // Because LossThresholdOfHighBandwidthPreference is 20%, the average loss is + // 10%, bandwidth estimate should increase. + EXPECT_GT( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + DataRate::KilobitsPerSec(600)); +} + +TEST_P(LossBasedBweV2Test, + SelectLowBandwidthCandidateIfLossRateIsIsHigherThanThreshold) { + ExplicitKeyValueConfig key_value_config( + "WebRTC-Bwe-LossBasedBweV2/" + "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false," + "ObservationWindowSize:2," + "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," + "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," + "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." + "05/"); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + + std::vector enough_feedback_10p_loss_1 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_1, delay_based_estimate, + BandwidthUsage::kBwNormal); + + std::vector enough_feedback_10p_loss_2 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_2, delay_based_estimate, + BandwidthUsage::kBwNormal); + + // Because LossThresholdOfHighBandwidthPreference is 5%, the average loss is + // 10%, bandwidth estimate should decrease. + EXPECT_LT( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + DataRate::KilobitsPerSec(600)); +} + INSTANTIATE_TEST_SUITE_P(LossBasedBweV2Tests, LossBasedBweV2Test, ::testing::Bool());