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