From f783b938fa1cf9daafb9641652f677a33c506b2d Mon Sep 17 00:00:00 2001 From: Diep Bui Date: Tue, 10 May 2022 15:00:36 +0000 Subject: [PATCH] Delay increasing estimate to the delay based estimate after loss happens. The change bounds the estimate increment by MaxIncreaseFactor in DelayedIncreaseWindow after seeing loss. MaxIncreaseFactor is set to 1000 to disable the change by default. Improve trendline integration: always allow to decrease the estimate, and only allow to increase the estimate if overusing and underusing are not in the state window. Other improvement: bound candidates by delay based estimate, instance upper bound, and bandwidth limit in the current window. Clean: remove the flag BackoffWhenOverusing since it has negative impacts when experimenting. Bug: webrtc:12707 Change-Id: Ia4c1e58d692071967e8807a8b9d64b8ae4caf837 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261240 Reviewed-by: Per Kjellander Commit-Queue: Diep Bui Cr-Commit-Position: refs/heads/main@{#36847} --- .../congestion_controller/goog_cc/BUILD.gn | 1 + .../goog_cc/loss_based_bwe_v2.cc | 137 ++- .../goog_cc/loss_based_bwe_v2.h | 16 +- .../goog_cc/loss_based_bwe_v2_test.cc | 781 +++++++++++------- 4 files changed, 569 insertions(+), 366 deletions(-) diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 468daad75d..851122ec5c 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -162,6 +162,7 @@ rtc_library("loss_based_bwe_v2") { "../../../api/units:timestamp", "../../../rtc_base:logging", "../../../rtc_base/experiments:field_trial_parser", + "../../remote_bitrate_estimator", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", 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 d13e23d1b4..0d19e567e8 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -28,6 +28,7 @@ #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "rtc_base/experiments/field_trial_list.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" @@ -219,6 +220,34 @@ void LossBasedBweV2::UpdateBandwidthEstimate( current_estimate_.loss_limited_bandwidth) { last_time_estimate_reduced_ = last_send_time_most_recent_observation_; } + + // Bound the estimate increasement if: + // 1. The estimate is limited due to loss, and + // 2. The estimate has been increased for less than `delayed_increase_window` + // ago, and + // 3. The best candidate is greater than bandwidth_limit_in_current_window. + if (limited_due_to_loss_candidate_ && + recovering_after_loss_timestamp_.IsFinite() && + recovering_after_loss_timestamp_ + config_->delayed_increase_window > + last_send_time_most_recent_observation_ && + best_candidate.loss_limited_bandwidth > + bandwidth_limit_in_current_window_) { + best_candidate.loss_limited_bandwidth = bandwidth_limit_in_current_window_; + } + limited_due_to_loss_candidate_ = + delay_based_estimate.IsFinite() && + best_candidate.loss_limited_bandwidth < delay_based_estimate; + + if (limited_due_to_loss_candidate_ && + (recovering_after_loss_timestamp_.IsInfinite() || + recovering_after_loss_timestamp_ + config_->delayed_increase_window < + last_send_time_most_recent_observation_)) { + bandwidth_limit_in_current_window_ = std::max( + congestion_controller::GetMinBitrate(), + best_candidate.loss_limited_bandwidth * config_->max_increase_factor); + recovering_after_loss_timestamp_ = last_send_time_most_recent_observation_; + } + current_estimate_ = best_candidate; } @@ -273,8 +302,11 @@ absl::optional LossBasedBweV2::CreateConfig( FieldTrialParameter delay_based_limit_factor("DelayBasedLimitFactor", 1.0); FieldTrialParameter trendline_window_size("TrendlineWindowSize", 20); - FieldTrialParameter backoff_when_overusing("BackoffWhenOverusing", - false); + FieldTrialParameter max_increase_factor("MaxIncreaseFactor", 1000.0); + FieldTrialParameter delayed_increase_window( + "DelayedIncreaseWindow", TimeDelta::Millis(300)); + FieldTrialParameter use_acked_bitrate_only_when_overusing( + "UseAckedBitrateOnlyWhenOverusing", false); if (key_value_config) { ParseFieldTrial({&enabled, @@ -303,7 +335,9 @@ absl::optional LossBasedBweV2::CreateConfig( &trendline_integration_enabled, &delay_based_limit_factor, &trendline_window_size, - &backoff_when_overusing}, + &max_increase_factor, + &delayed_increase_window, + &use_acked_bitrate_only_when_overusing}, key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2")); } @@ -349,7 +383,10 @@ absl::optional LossBasedBweV2::CreateConfig( config->trendline_integration_enabled = trendline_integration_enabled.Get(); config->delay_based_limit_factor = delay_based_limit_factor.Get(); config->trendline_window_size = trendline_window_size.Get(); - config->backoff_when_overusing = backoff_when_overusing.Get(); + config->max_increase_factor = max_increase_factor.Get(); + config->delayed_increase_window = delayed_increase_window.Get(); + config->use_acked_bitrate_only_when_overusing = + use_acked_bitrate_only_when_overusing.Get(); return config; } @@ -510,6 +547,16 @@ bool LossBasedBweV2::IsConfigValid() const { << config_->trendline_window_size; valid = false; } + if (config_->max_increase_factor <= 0.0) { + RTC_LOG(LS_WARNING) << "The maximum increase factor must be positive: " + << config_->max_increase_factor; + valid = false; + } + if (config_->delayed_increase_window <= TimeDelta::Zero()) { + RTC_LOG(LS_WARNING) << "The delayed increase window must be positive: " + << config_->delayed_increase_window.ms(); + valid = false; + } return valid; } @@ -535,12 +582,32 @@ double LossBasedBweV2::GetAverageReportedLossRatio() const { return static_cast(num_lost_packets) / num_packets; } -DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const { - if (!acknowledged_bitrate_.has_value()) - return DataRate::PlusInfinity(); +DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound( + DataRate delay_based_estimate) const { + DataRate candidate_bandwidth_upper_bound = DataRate::PlusInfinity(); + if (limited_due_to_loss_candidate_) { + candidate_bandwidth_upper_bound = bandwidth_limit_in_current_window_; + } - DataRate candidate_bandwidth_upper_bound = - config_->bandwidth_rampup_upper_bound_factor * (*acknowledged_bitrate_); + if (config_->trendline_integration_enabled) { + candidate_bandwidth_upper_bound = + std::min(GetInstantUpperBound(), candidate_bandwidth_upper_bound); + if (IsValid(delay_based_estimate)) { + candidate_bandwidth_upper_bound = + std::min(delay_based_estimate, candidate_bandwidth_upper_bound); + } + } + + if (!acknowledged_bitrate_.has_value()) + return candidate_bandwidth_upper_bound; + + candidate_bandwidth_upper_bound = + IsValid(candidate_bandwidth_upper_bound) + ? std::min(candidate_bandwidth_upper_bound, + config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_)) + : config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_); if (config_->rampup_acceleration_max_factor > 0.0) { const TimeDelta time_since_bandwidth_reduced = std::min( @@ -561,16 +628,8 @@ std::vector LossBasedBweV2::GetCandidates( DataRate delay_based_estimate) const { std::vector bandwidths; bool can_increase_bitrate = TrendlineEsimateAllowBitrateIncrease(); - bool can_decrease_bitrate = TrendlineEsimateAllowBitrateDecrease(); for (double candidate_factor : config_->candidate_factors) { - if (!can_increase_bitrate && candidate_factor >= 1.0) { - // When the network is overusing, the estimate is forced to decrease - // even if there is no loss yet. - if (candidate_factor > 1 || config_->backoff_when_overusing) { - continue; - } - } - if (!can_decrease_bitrate && candidate_factor < 1.0) { + if (!can_increase_bitrate && candidate_factor > 1.0) { continue; } bandwidths.push_back(candidate_factor * @@ -593,15 +652,20 @@ std::vector LossBasedBweV2::GetCandidates( } const DataRate candidate_bandwidth_upper_bound = - GetCandidateBandwidthUpperBound(); + GetCandidateBandwidthUpperBound(delay_based_estimate); std::vector candidates; candidates.resize(bandwidths.size()); for (size_t i = 0; i < bandwidths.size(); ++i) { ChannelParameters candidate = current_estimate_; - candidate.loss_limited_bandwidth = std::min( - bandwidths[i], std::max(current_estimate_.loss_limited_bandwidth, - candidate_bandwidth_upper_bound)); + if (config_->trendline_integration_enabled) { + candidate.loss_limited_bandwidth = + std::min(bandwidths[i], candidate_bandwidth_upper_bound); + } else { + candidate.loss_limited_bandwidth = std::min( + bandwidths[i], std::max(current_estimate_.loss_limited_bandwidth, + candidate_bandwidth_upper_bound)); + } candidate.inherent_loss = GetFeasibleInherentLoss(candidate); candidates[i] = candidate; } @@ -760,32 +824,14 @@ void LossBasedBweV2::NewtonsMethodUpdate( } } -bool LossBasedBweV2::TrendlineEsimateAllowBitrateDecrease() const { - if (!config_->trendline_integration_enabled) { - return true; - } - - for (const auto& detector_state : delay_detector_states_) { - if (detector_state == BandwidthUsage::kBwOverusing) { - return true; - } - } - - for (const auto& detector_state : delay_detector_states_) { - if (detector_state == BandwidthUsage::kBwUnderusing) { - return false; - } - } - return true; -} - bool LossBasedBweV2::TrendlineEsimateAllowBitrateIncrease() const { if (!config_->trendline_integration_enabled) { return true; } for (const auto& detector_state : delay_detector_states_) { - if (detector_state == BandwidthUsage::kBwOverusing) { + if (detector_state == BandwidthUsage::kBwOverusing || + detector_state == BandwidthUsage::kBwUnderusing) { return false; } } @@ -797,6 +843,10 @@ bool LossBasedBweV2::TrendlineEsimateAllowEmergencyBackoff() const { return true; } + if (!config_->use_acked_bitrate_only_when_overusing) { + return true; + } + for (const auto& detector_state : delay_detector_states_) { if (detector_state == BandwidthUsage::kBwOverusing) { return true; @@ -836,11 +886,10 @@ bool LossBasedBweV2::PushBackObservation( const Timestamp last_send_time = packet_results_summary.last_send_time; const TimeDelta observation_duration = last_send_time - last_send_time_most_recent_observation_; - // Too small to be meaningful. if (observation_duration <= TimeDelta::Zero() || (observation_duration < config_->observation_duration_lower_bound && - (delay_detector_state == BandwidthUsage::kBwNormal || + (delay_detector_state != BandwidthUsage::kBwOverusing || !config_->trendline_integration_enabled))) { return false; } 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 0c496c86bb..9db711250b 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -87,7 +87,9 @@ class LossBasedBweV2 { bool trendline_integration_enabled = false; double delay_based_limit_factor = 1.0; int trendline_window_size = 0; - bool backoff_when_overusing = false; + double max_increase_factor = 0.0; + TimeDelta delayed_increase_window = TimeDelta::Zero(); + bool use_acked_bitrate_only_when_overusing = false; }; struct Derivatives { @@ -119,7 +121,7 @@ class LossBasedBweV2 { double GetAverageReportedLossRatio() const; std::vector GetCandidates( DataRate delay_based_estimate) const; - DataRate GetCandidateBandwidthUpperBound() const; + DataRate GetCandidateBandwidthUpperBound(DataRate delay_based_estimate) const; Derivatives GetDerivatives(const ChannelParameters& channel_parameters) const; double GetFeasibleInherentLoss( const ChannelParameters& channel_parameters) const; @@ -132,12 +134,9 @@ class LossBasedBweV2 { void CalculateTemporalWeights(); void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const; - // Returns true if either - // 1. At least one of states in the window is kBwOverusing, or - // 2. There are no kBwUnderusing states in the window. - bool TrendlineEsimateAllowBitrateDecrease() const; - // Returns false if there exists an overusing state in the window. + // Returns false if there exists a kBwOverusing or kBwUnderusing in the + // window. bool TrendlineEsimateAllowBitrateIncrease() const; // Returns true if there exists an overusing state in the window. @@ -163,6 +162,9 @@ class LossBasedBweV2 { std::vector instant_upper_bound_temporal_weights_; std::vector temporal_weights_; std::deque delay_detector_states_; + Timestamp recovering_after_loss_timestamp_ = Timestamp::MinusInfinity(); + DataRate bandwidth_limit_in_current_window_ = DataRate::PlusInfinity(); + bool limited_due_to_loss_candidate_ = false; }; } // namespace webrtc 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 dbe745745e..8e002b4bd6 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 @@ -11,6 +11,7 @@ #include "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h" #include +#include #include "api/network_state_predictor.h" #include "api/transport/network_types.h" @@ -29,71 +30,132 @@ namespace { using ::webrtc::test::ExplicitKeyValueConfig; constexpr TimeDelta kObservationDurationLowerBound = TimeDelta::Millis(200); +constexpr TimeDelta kDelayedIncreaseWindow = TimeDelta::Millis(300); +constexpr double kMaxIncreaseFactor = 1.5; -std::string Config(bool enabled, bool valid) { - char buffer[1024]; - rtc::SimpleStringBuilder config_string(buffer); +class LossBasedBweV2Test : public ::testing::TestWithParam { + protected: + std::string Config(bool enabled, + bool valid, + bool trendline_integration_enabled) { + char buffer[1024]; + rtc::SimpleStringBuilder config_string(buffer); - config_string << "WebRTC-Bwe-LossBasedBweV2/"; + config_string << "WebRTC-Bwe-LossBasedBweV2/"; - if (enabled) { - config_string << "Enabled:true"; - } else { - config_string << "Enabled:false"; + if (enabled) { + config_string << "Enabled:true"; + } else { + config_string << "Enabled:false"; + } + + if (valid) { + config_string << ",BwRampupUpperBoundFactor:1.2"; + } else { + config_string << ",BwRampupUpperBoundFactor:0.0"; + } + + if (trendline_integration_enabled) { + config_string << ",TrendlineIntegrationEnabled:true"; + } else { + config_string << ",TrendlineIntegrationEnabled:false"; + } + + config_string + << ",CandidateFactors:1.1|1.0|0.95,HigherBwBiasFactor:0.01," + "DelayBasedCandidate:true," + "InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:" + "14kbps," + "InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01," + "NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15," + "SendingRateSmoothingFactor:0.01," + "InstantUpperBoundTemporalWeightFactor:0.97," + "InstantUpperBoundBwBalance:90kbps," + "InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98"; + + config_string.AppendFormat( + ",ObservationDurationLowerBound:%dms", + static_cast(kObservationDurationLowerBound.ms())); + config_string.AppendFormat(",MaxIncreaseFactor:%f", kMaxIncreaseFactor); + config_string.AppendFormat(",DelayedIncreaseWindow:%dms", + static_cast(kDelayedIncreaseWindow.ms())); + + config_string << "/"; + + return config_string.str(); } - if (valid) { - config_string << ",BwRampupUpperBoundFactor:1.2"; - } else { - config_string << ",BwRampupUpperBoundFactor:0.0"; + std::vector CreatePacketResultsWithReceivedPackets( + Timestamp first_packet_timestamp) { + std::vector enough_feedback(2); + enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.send_time = first_packet_timestamp; + enough_feedback[1].sent_packet.send_time = + first_packet_timestamp + kObservationDurationLowerBound; + enough_feedback[0].receive_time = + first_packet_timestamp + kObservationDurationLowerBound; + enough_feedback[1].receive_time = + first_packet_timestamp + 2 * kObservationDurationLowerBound; + return enough_feedback; } - config_string - << ",CandidateFactors:1.1|1.0|0.95,HigherBwBiasFactor:0.01," - "DelayBasedCandidate:true," - "InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:14kbps," - "InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01," - "NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15," - "SendingRateSmoothingFactor:0.01," - "InstantUpperBoundTemporalWeightFactor:0.97," - "InstantUpperBoundBwBalance:90kbps," - "InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98," - "BackoffWhenOverusing:true"; + std::vector CreatePacketResultsWith50pLossRate( + Timestamp first_packet_timestamp) { + std::vector enough_feedback(2); + enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.send_time = first_packet_timestamp; + enough_feedback[1].sent_packet.send_time = + first_packet_timestamp + kObservationDurationLowerBound; + enough_feedback[0].receive_time = + first_packet_timestamp + kObservationDurationLowerBound; + enough_feedback[1].receive_time = Timestamp::PlusInfinity(); + return enough_feedback; + } - config_string.AppendFormat( - ",ObservationDurationLowerBound:%dms", - static_cast(kObservationDurationLowerBound.ms())); + std::vector CreatePacketResultsWith100pLossRate( + Timestamp first_packet_timestamp) { + std::vector enough_feedback(2); + enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.send_time = first_packet_timestamp; + enough_feedback[1].sent_packet.send_time = + first_packet_timestamp + kObservationDurationLowerBound; + enough_feedback[0].receive_time = Timestamp::PlusInfinity(); + enough_feedback[1].receive_time = Timestamp::PlusInfinity(); + return enough_feedback; + } +}; - config_string << "/"; - - return config_string.str(); -} - -TEST(LossBasedBweV2Test, EnabledWhenGivenValidConfigurationValues) { +TEST_P(LossBasedBweV2Test, EnabledWhenGivenValidConfigurationValues) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_TRUE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST(LossBasedBweV2Test, DisabledWhenGivenDisabledConfiguration) { +TEST_P(LossBasedBweV2Test, DisabledWhenGivenDisabledConfiguration) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/false, /*valid=*/true)); + Config(/*enabled=*/false, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST(LossBasedBweV2Test, DisabledWhenGivenNonValidConfigurationValues) { +TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonValidConfigurationValues) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/false)); + Config(/*enabled=*/true, /*valid=*/false, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) { +TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) { ExplicitKeyValueConfig key_value_config_negative_candidate_factor( "WebRTC-Bwe-LossBasedBweV2/Enabled:true,CandidateFactors:-1.3|1.1/"); LossBasedBweV2 loss_based_bandwidth_estimator_1( @@ -107,8 +169,8 @@ TEST(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) { EXPECT_FALSE(loss_based_bandwidth_estimator_2.IsEnabled()); } -TEST(LossBasedBweV2Test, - DisabledWhenGivenConfigurationThatDoesNotAllowGeneratingCandidates) { +TEST_P(LossBasedBweV2Test, + DisabledWhenGivenConfigurationThatDoesNotAllowGeneratingCandidates) { ExplicitKeyValueConfig key_value_config( "WebRTC-Bwe-LossBasedBweV2/" "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false," @@ -117,20 +179,15 @@ TEST(LossBasedBweV2Test, EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) { - PacketResult enough_feedback[2]; - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; +TEST_P(LossBasedBweV2Test, + BandwidthEstimateGivenInitializationAndThenFeedback) { + std::vector enough_feedback = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -145,20 +202,13 @@ TEST(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) { .IsFinite()); } -TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { - PacketResult enough_feedback[2]; - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - +TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { + std::vector enough_feedback = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( @@ -171,7 +221,7 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { .IsPlusInfinity()); } -TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { +TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { // Create packet results where the observation duration is less than the lower // bound. PacketResult not_enough_feedback[2]; @@ -186,7 +236,8 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { Timestamp::Zero() + kObservationDurationLowerBound; ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -208,32 +259,19 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { .IsPlusInfinity()); } -TEST(LossBasedBweV2Test, - SetValueIsTheEstimateUntilAdditionalFeedbackHasBeenReceived) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; +TEST_P(LossBasedBweV2Test, + SetValueIsTheEstimateUntilAdditionalFeedbackHasBeenReceived) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -260,32 +298,19 @@ TEST(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); } -TEST(LossBasedBweV2Test, - SetAcknowledgedBitrateOnlyAffectsTheBweWhenAdditionalFeedbackIsGiven) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; +TEST_P(LossBasedBweV2Test, + SetAcknowledgedBitrateOnlyAffectsTheBweWhenAdditionalFeedbackIsGiven) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator_1(&key_value_config); LossBasedBweV2 loss_based_bandwidth_estimator_2(&key_value_config); @@ -320,24 +345,15 @@ TEST(LossBasedBweV2Test, /*delay_based_limit=*/DataRate::PlusInfinity())); } -TEST(LossBasedBweV2Test, - BandwidthEstimateIsCappedToBeTcpFairGivenTooHighLossRate) { - PacketResult enough_feedback_no_received_packets[2]; - enough_feedback_no_received_packets[0].sent_packet.size = - DataSize::Bytes(15'000); - enough_feedback_no_received_packets[1].sent_packet.size = - DataSize::Bytes(15'000); - enough_feedback_no_received_packets[0].sent_packet.send_time = - Timestamp::Zero(); - enough_feedback_no_received_packets[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_no_received_packets[0].receive_time = - Timestamp::PlusInfinity(); - enough_feedback_no_received_packets[1].receive_time = - Timestamp::PlusInfinity(); +TEST_P(LossBasedBweV2Test, + BandwidthEstimateIsCappedToBeTcpFairGivenTooHighLossRate) { + std::vector enough_feedback_no_received_packets = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -351,75 +367,22 @@ TEST(LossBasedBweV2Test, DataRate::KilobitsPerSec(100)); } -// When network is overusing and flag `BackoffWhenOverusing` is true, -// the bandwidth estimate is forced to decrease even if there is no loss yet. -TEST(LossBasedBweV2Test, BandwidthEstimateDecreasesWhenOverusing) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = Timestamp::PlusInfinity(); - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = Timestamp::PlusInfinity(); - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; +TEST_P(LossBasedBweV2Test, BandwidthEstimateNotIncreaseWhenNetworkUnderusing) { + if (!GetParam()) { + GTEST_SKIP() << "This test should run only if " + "trendline_integration_enabled is enabled"; + } + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate( - DataRate::KilobitsPerSec(300)); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing); - EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), - DataRate::KilobitsPerSec(600)); - - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), - DataRate::KilobitsPerSec(600)); -} - -TEST(LossBasedBweV2Test, BandwidthEstimateIncreasesWhenUnderusing) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; - - ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -427,53 +390,38 @@ TEST(LossBasedBweV2Test, BandwidthEstimateIncreasesWhenUnderusing) { loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwUnderusing); - EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( + EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( /*delay_based_limit=*/DataRate::PlusInfinity()), DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( + EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( /*delay_based_limit=*/DataRate::PlusInfinity()), DataRate::KilobitsPerSec(600)); } -// When network is underusing, estimate can increase but never be higher than +// When network is normal, estimate can increase but never be higher than // the delay based estimate. -TEST(LossBasedBweV2Test, - BandwidthEstimateCappedByDelayBasedEstimateWhenUnderusing) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; +TEST_P(LossBasedBweV2Test, + BandwidthEstimateCappedByDelayBasedEstimateWhenNetworkNormal) { // Create two packet results, network is in normal state, 100% packets are // received, and no delay increase. - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; - + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), - BandwidthUsage::kBwUnderusing); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); // If the delay based estimate is infinity, then loss based estimate increases // and not bounded by delay based estimate. EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( @@ -490,30 +438,20 @@ TEST(LossBasedBweV2Test, // When loss based bwe receives a strong signal of overusing and an increase in // loss rate, it should acked bitrate for emegency backoff. -TEST(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; +TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { // Create two packet results, first packet has 50% loss rate, second packet // has 100% loss rate. - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = Timestamp::PlusInfinity(); - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = Timestamp::PlusInfinity(); - enough_feedback_2[1].receive_time = Timestamp::PlusInfinity(); + std::vector enough_feedback_1 = + CreatePacketResultsWith50pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -535,85 +473,298 @@ TEST(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { acked_bitrate); } -// When network is in normal state, and if the acked bitrate is small, then the -// loss based estimate is higher than the acked bitrate. -TEST(LossBasedBweV2Test, NotUseAckedBitrateInNormalState) { - PacketResult enough_feedback_1[2]; - PacketResult enough_feedback_2[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_2[0].sent_packet.send_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[1].sent_packet.send_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - enough_feedback_2[0].receive_time = - Timestamp::Zero() + 3 * kObservationDurationLowerBound; - enough_feedback_2[1].receive_time = - Timestamp::Zero() + 4 * kObservationDurationLowerBound; - +// When receiving the same packet feedback, loss based bwe ignores the feedback +// and returns the current estimate. +TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); - DataRate acked_bitrate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(300)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), - acked_bitrate); - - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), - acked_bitrate); -} - -TEST(LossBasedBweV2Test, NoUpdateIfObservationDurationUnchanged) { - PacketResult enough_feedback_1[2]; - enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); - enough_feedback_1[1].sent_packet.send_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[0].receive_time = - Timestamp::Zero() + kObservationDurationLowerBound; - enough_feedback_1[1].receive_time = - Timestamp::Zero() + 2 * kObservationDurationLowerBound; - - ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true)); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - DataRate acked_bitrate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - DataRate current_estimate = - loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()); + DataRate estimate_1 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); // Use the same feedback and check if the estimate is unchanged. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - DataRate new_estimate = loss_based_bandwidth_estimator.GetBandwidthEstimate( + DataRate estimate_2 = loss_based_bandwidth_estimator.GetBandwidthEstimate( /*delay_based_limit=*/DataRate::PlusInfinity()); - EXPECT_EQ(current_estimate, new_estimate); + EXPECT_EQ(estimate_2, estimate_1); } +// When receiving feedback of packets that were sent within an observation +// duration, and network is in the normal state, loss based bwe returns the +// current estimate. +TEST_P(LossBasedBweV2Test, + NoBweChangeIfObservationDurationIsSmallAndNetworkNormal) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound - TimeDelta::Millis(1)); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate estimate_1 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate estimate_2 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + EXPECT_EQ(estimate_2, estimate_1); +} + +// When receiving feedback of packets that were sent within an observation +// duration, and network is in the underusing state, loss based bwe returns the +// current estimate. +TEST_P(LossBasedBweV2Test, + NoBweIncreaseIfObservationDurationIsSmallAndNetworkUnderusing) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound - TimeDelta::Millis(1)); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate estimate_1 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, DataRate::PlusInfinity(), + BandwidthUsage::kBwUnderusing); + DataRate estimate_2 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + EXPECT_LE(estimate_2, estimate_1); +} + +// When receiving feedback of packets that were sent within an observation +// duration, network is overusing, and trendline integration is enabled, loss +// based bwe updates its estimate. +TEST_P(LossBasedBweV2Test, + UpdateEstimateIfObservationDurationIsSmallAndNetworkOverusing) { + if (!GetParam()) { + GTEST_SKIP() << "This test should run only if " + "trendline_integration_enabled is enabled"; + } + std::vector enough_feedback_1 = + CreatePacketResultsWith50pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound - TimeDelta::Millis(1)); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(300)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate estimate_1 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, DataRate::PlusInfinity(), + BandwidthUsage::kBwOverusing); + DataRate estimate_2 = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + EXPECT_LT(estimate_2, estimate_1); +} + +TEST_P(LossBasedBweV2Test, + IncreaseToDelayBasedEstimateIfNoLossOrDelayIncrease) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + 2 * kObservationDurationLowerBound); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + delay_based_estimate); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + delay_based_estimate); +} + +// After loss based bwe backs off, the next estimate is capped by +// MaxIncreaseFactor * current estimate. +TEST_P(LossBasedBweV2Test, + IncreaseByMaxIncreaseFactorAfterLossBasedBweBacksOff) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(300)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + DataRate estimate_1 = + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate); + // Increase the acknowledged bitrate to make sure that the estimate is not + // capped too low. + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(5000)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal); + + // The estimate is capped by current_estimate * kMaxIncreaseFactor because it + // recently backed off. + DataRate estimate_2 = + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate); + EXPECT_EQ(estimate_2, estimate_1 * kMaxIncreaseFactor); + EXPECT_LE(estimate_2, delay_based_estimate); +} + +// After loss based bwe backs off, the estimate is bounded during the delayed +// window. +TEST_P(LossBasedBweV2Test, + EstimateBitrateIsBoundedDuringDelayedWindowAfterLossBasedBweBacksOff) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWith50pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kDelayedIncreaseWindow - TimeDelta::Millis(2)); + std::vector enough_feedback_3 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kDelayedIncreaseWindow - TimeDelta::Millis(1)); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(300)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + // Increase the acknowledged bitrate to make sure that the estimate is not + // capped too low. + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(5000)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal); + + // The estimate is capped by current_estimate * kMaxIncreaseFactor because + // it recently backed off. + DataRate estimate_2 = + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal); + // The latest estimate is the same as the previous estimate since the sent + // packets were sent within the DelayedIncreaseWindow. + EXPECT_EQ( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + estimate_2); +} + +// The estimate is not bounded after the delayed increase window. +TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { + std::vector enough_feedback_1 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kDelayedIncreaseWindow - TimeDelta::Millis(1)); + std::vector enough_feedback_3 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kDelayedIncreaseWindow + TimeDelta::Millis(1)); + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true, + /*trendline_integration_enabled=*/GetParam())); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(300)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + // Increase the acknowledged bitrate to make sure that the estimate is not + // capped too low. + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(5000)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal); + + // The estimate is capped by current_estimate * kMaxIncreaseFactor because it + // recently backed off. + DataRate estimate_2 = + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal); + // The estimate can continue increasing after the DelayedIncreaseWindow. + EXPECT_GE( + loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + estimate_2); +} + +INSTANTIATE_TEST_SUITE_P(LossBasedBweV2Tests, + LossBasedBweV2Test, + ::testing::Bool()); + } // namespace } // namespace webrtc