From 5edefa87f74612ca07a5e2f148b373440cc57297 Mon Sep 17 00:00:00 2001 From: Diep Bui Date: Fri, 22 Jul 2022 19:21:28 +0000 Subject: [PATCH] Update loss based bwe 2 to handle low bandwidth networks and no delay signal. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add loss threshold for high bandwidth preference. If the average loss ratio is less than the threshold, then the model prefers higher bandwidth candidates. Otherwise, it prefers lower bandwidth candidates. Before, it always prefers higher bandwidth candidate. The default value is 0.99, means it always prefers high bandwidth candidates. 2. Only increase the estimate if the inherent loss (random loss) is equal to/greater than the average loss. If the inherent loss is less than the average loss, then it is oversending, thus should not increase the estimate. Bug: webrtc:12707 Change-Id: I37eb536679ca29e017a4a47703b417efd4d103ca Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/269101 Commit-Queue: Diep Bui Reviewed-by: Jakob Ivarsson‎ Reviewed-by: Philip Eliasson Cr-Commit-Position: refs/heads/main@{#37608} --- .../goog_cc/loss_based_bwe_v2.cc | 60 +++++++- .../goog_cc/loss_based_bwe_v2.h | 4 + .../goog_cc/loss_based_bwe_v2_test.cc | 128 ++++++++++++++++++ 3 files changed, 189 insertions(+), 3 deletions(-) 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());