From 8850aecb454fdf3cf12ea18940d3c7035a9621e9 Mon Sep 17 00:00:00 2001 From: Diep Bui Date: Mon, 7 Nov 2022 13:18:51 +0000 Subject: [PATCH] Probing integration in loss based bwe 2. Previously, cleanup in GetCandidateBandwidthUpperBound in loss_based_bwe_v2.cc causes unbounded bandwidth estimate. It leads to many warning logs being printed out at loss_based_bwe_v2.cc:95. However, the cleanup is still necessary because the param bandwidth_rampup_upper_bound_factor is not used in current launches. To fix the infinite estimate, we set max_bitrate in loss based bwe, which is derived from goog_cc, and not allow the estimate to go above that value. *** Original change description *** * Revert "Probing integration in loss based bwe 2." (diepbp@webrtc.org) * https://webrtc-review.googlesource.com/c/src/+/277400 *** Bug: webrtc:12707 Change-Id: If0cd16daba4a4941043a1610edca2a13c9564328 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/281280 Commit-Queue: Diep Bui Reviewed-by: Per Kjellander Cr-Commit-Position: refs/heads/main@{#38574} --- .../goog_cc/goog_cc_network_control.cc | 4 +- .../goog_cc/loss_based_bwe_v2.cc | 157 ++++-- .../goog_cc/loss_based_bwe_v2.h | 29 +- .../goog_cc/loss_based_bwe_v2_test.cc | 479 +++++++++++++----- .../goog_cc/send_side_bandwidth_estimation.cc | 23 +- .../goog_cc/send_side_bandwidth_estimation.h | 5 +- 6 files changed, 501 insertions(+), 196 deletions(-) diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index fcb77faacd..9cc9da27c1 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -549,8 +549,8 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time, result.target_bitrate); } - bandwidth_estimation_->UpdateLossBasedEstimator(report, - result.delay_detector_state); + bandwidth_estimation_->UpdateLossBasedEstimator( + report, result.delay_detector_state, probe_bitrate); if (result.updated) { // Update the estimate in the ProbeController, in case we want to probe. MaybeTriggerOnNetworkChanged(&update, report.feedback_time); 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 e671bd2599..1a694b7317 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -42,6 +42,10 @@ bool IsValid(DataRate datarate) { return datarate.IsFinite(); } +bool IsValid(absl::optional datarate) { + return datarate.has_value() && IsValid(datarate.value()); +} + bool IsValid(Timestamp timestamp) { return timestamp.IsFinite(); } @@ -134,8 +138,10 @@ bool LossBasedBweV2::IsReady() const { num_observations_ > 0; } -DataRate LossBasedBweV2::GetBandwidthEstimate( +LossBasedBweV2::Result LossBasedBweV2::GetLossBasedResult( DataRate delay_based_limit) const { + Result result; + result.state = current_state_; if (!IsReady()) { if (!IsEnabled()) { RTC_LOG(LS_WARNING) @@ -150,17 +156,21 @@ DataRate LossBasedBweV2::GetBandwidthEstimate( "statistics before it can be used."; } } - return IsValid(delay_based_limit) ? delay_based_limit - : DataRate::PlusInfinity(); + result.bandwidth_estimate = IsValid(delay_based_limit) + ? delay_based_limit + : DataRate::PlusInfinity(); + return result; } - if (delay_based_limit.IsFinite()) { - return std::min({current_estimate_.loss_limited_bandwidth, - GetInstantUpperBound(), delay_based_limit}); + if (IsValid(delay_based_limit)) { + result.bandwidth_estimate = + std::min({current_estimate_.loss_limited_bandwidth, + GetInstantUpperBound(), delay_based_limit}); } else { - return std::min(current_estimate_.loss_limited_bandwidth, - GetInstantUpperBound()); + result.bandwidth_estimate = std::min( + current_estimate_.loss_limited_bandwidth, GetInstantUpperBound()); } + return result; } void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) { @@ -181,24 +191,42 @@ void LossBasedBweV2::SetBandwidthEstimate(DataRate bandwidth_estimate) { } } -void LossBasedBweV2::SetMinBitrate(DataRate min_bitrate) { +void LossBasedBweV2::SetMinMaxBitrate(DataRate min_bitrate, + DataRate max_bitrate) { if (IsValid(min_bitrate)) { min_bitrate_ = min_bitrate; } else { RTC_LOG(LS_WARNING) << "The min bitrate must be finite: " << ToString(min_bitrate); } + + if (IsValid(max_bitrate)) { + max_bitrate_ = max_bitrate; + } else { + RTC_LOG(LS_WARNING) << "The max bitrate must be finite: " + << ToString(max_bitrate); + } +} + +void LossBasedBweV2::SetProbeBitrate(absl::optional probe_bitrate) { + if (probe_bitrate.has_value() && IsValid(probe_bitrate.value())) { + if (!IsValid(probe_bitrate_) || probe_bitrate_ > probe_bitrate.value()) { + probe_bitrate_ = probe_bitrate.value(); + } + } } void LossBasedBweV2::UpdateBandwidthEstimate( rtc::ArrayView packet_results, DataRate delay_based_estimate, - BandwidthUsage delay_detector_state) { + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate) { if (!IsEnabled()) { RTC_LOG(LS_WARNING) << "The estimator must be enabled before it can be used."; return; } + SetProbeBitrate(probe_bitrate); if (packet_results.empty()) { RTC_LOG(LS_VERBOSE) << "The estimate cannot be updated without any loss statistics."; @@ -241,34 +269,75 @@ void LossBasedBweV2::UpdateBandwidthEstimate( current_estimate_.loss_limited_bandwidth; } - // Bound the estimate increase if: - // 1. The estimate is limited due to loss, and - // 2. The estimate has been increased for less than `delayed_increase_window` - // 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 (IsBandwidthLimitedDueToLoss()) { + // Bound the estimate increase if: + // 1. The estimate has been increased for less than + // `delayed_increase_window` ago, and + // 2. The best candidate is greater than bandwidth_limit_in_current_window. + if (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_; + } - if (limited_due_to_loss_candidate_ && + bool increasing_when_loss_limited = + IsEstimateIncreasingWhenLossLimited(best_candidate); + // Bound the best candidate by the acked bitrate unless there is a recent + // probe result. + if (increasing_when_loss_limited && !IsValid(probe_bitrate_) && + IsValid(acknowledged_bitrate_)) { + best_candidate.loss_limited_bandwidth = + IsValid(best_candidate.loss_limited_bandwidth) + ? std::min(best_candidate.loss_limited_bandwidth, + config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_)) + : config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_); + } + + // Use probe bitrate as the estimate as probe bitrate is trusted to be + // correct. After being used, the probe bitrate is reset. + if (config_->probe_integration_enabled && IsValid(probe_bitrate_)) { + best_candidate.loss_limited_bandwidth = + std::min(probe_bitrate_, best_candidate.loss_limited_bandwidth); + probe_bitrate_ = DataRate::MinusInfinity(); + } + } + + if (IsEstimateIncreasingWhenLossLimited(best_candidate)) { + current_state_ = LossBasedState::kIncreasing; + } else if (IsValid(delay_based_estimate) && + best_candidate.loss_limited_bandwidth < delay_based_estimate) { + current_state_ = LossBasedState::kDecreasing; + } else if (IsValid(delay_based_estimate) && + best_candidate.loss_limited_bandwidth == delay_based_estimate) { + current_state_ = LossBasedState::kDelayBasedEstimate; + } + current_estimate_ = best_candidate; + + if (IsBandwidthLimitedDueToLoss() && (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( - kCongestionControllerMinBitrate, - best_candidate.loss_limited_bandwidth * config_->max_increase_factor); + bandwidth_limit_in_current_window_ = + std::max(kCongestionControllerMinBitrate, + current_estimate_.loss_limited_bandwidth * + config_->max_increase_factor); recovering_after_loss_timestamp_ = last_send_time_most_recent_observation_; } +} - current_estimate_ = best_candidate; +bool LossBasedBweV2::IsEstimateIncreasingWhenLossLimited( + const ChannelParameters& best_candidate) { + return (current_estimate_.loss_limited_bandwidth < + best_candidate.loss_limited_bandwidth || + (current_estimate_.loss_limited_bandwidth == + best_candidate.loss_limited_bandwidth && + current_state_ == LossBasedState::kIncreasing)) && + IsBandwidthLimitedDueToLoss(); } // Returns a `LossBasedBweV2::Config` iff the `key_value_config` specifies a @@ -339,6 +408,8 @@ absl::optional LossBasedBweV2::CreateConfig( "BandwidthCapAtHighLossRate", DataRate::KilobitsPerSec(500.0)); FieldTrialParameter slope_of_bwe_high_loss_func( "SlopeOfBweHighLossFunc", 1000); + FieldTrialParameter probe_integration_enabled("ProbeIntegrationEnabled", + false); if (key_value_config) { ParseFieldTrial({&enabled, &bandwidth_rampup_upper_bound_factor, @@ -371,6 +442,7 @@ absl::optional LossBasedBweV2::CreateConfig( &delayed_increase_window, &use_acked_bitrate_only_when_overusing, ¬_increase_if_inherent_loss_less_than_average_loss, + &probe_integration_enabled, &high_loss_rate_threshold, &bandwidth_cap_at_high_loss_rate, &slope_of_bwe_high_loss_func}, @@ -433,6 +505,8 @@ absl::optional LossBasedBweV2::CreateConfig( config->bandwidth_cap_at_high_loss_rate = bandwidth_cap_at_high_loss_rate.Get(); config->slope_of_bwe_high_loss_func = slope_of_bwe_high_loss_func.Get(); + config->probe_integration_enabled = probe_integration_enabled.Get(); + return config; } @@ -644,8 +718,9 @@ double LossBasedBweV2::GetAverageReportedLossRatio() const { DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound( DataRate delay_based_estimate) const { - DataRate candidate_bandwidth_upper_bound = DataRate::PlusInfinity(); - if (limited_due_to_loss_candidate_) { + DataRate candidate_bandwidth_upper_bound = max_bitrate_; + if (IsBandwidthLimitedDueToLoss() && + IsValid(bandwidth_limit_in_current_window_)) { candidate_bandwidth_upper_bound = bandwidth_limit_in_current_window_; } @@ -661,14 +736,6 @@ DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound( 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( config_->rampup_acceleration_maxout_time, @@ -860,11 +927,11 @@ DataRate LossBasedBweV2::GetSendingRate( } DataRate LossBasedBweV2::GetInstantUpperBound() const { - return cached_instant_upper_bound_.value_or(DataRate::PlusInfinity()); + return cached_instant_upper_bound_.value_or(max_bitrate_); } void LossBasedBweV2::CalculateInstantUpperBound() { - DataRate instant_limit = DataRate::PlusInfinity(); + DataRate instant_limit = max_bitrate_; const double average_reported_loss_ratio = GetAverageReportedLossRatio(); if (average_reported_loss_ratio > config_->instant_upper_bound_loss_offset) { instant_limit = config_->instant_upper_bound_bandwidth_balance / @@ -995,4 +1062,8 @@ bool LossBasedBweV2::PushBackObservation( return true; } +bool LossBasedBweV2::IsBandwidthLimitedDueToLoss() const { + return current_state_ != LossBasedState::kDelayBasedEstimate; +} + } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h index 88cae01418..cad6294c15 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -27,8 +27,21 @@ namespace webrtc { +// State of the loss based estimate, which can be either increasing/decreasing +// when network is loss limited, or equal to the delay based estimate. +enum class LossBasedState { + kIncreasing = 0, + kDecreasing = 1, + kDelayBasedEstimate = 2 +}; + class LossBasedBweV2 { public: + struct Result { + ~Result() = default; + DataRate bandwidth_estimate = DataRate::Zero(); + LossBasedState state = LossBasedState::kDelayBasedEstimate; + }; // Creates a disabled `LossBasedBweV2` if the // `key_value_config` is not valid. explicit LossBasedBweV2(const FieldTrialsView* key_value_config); @@ -44,15 +57,16 @@ class LossBasedBweV2 { bool IsReady() const; // Returns `DataRate::PlusInfinity` if no BWE can be calculated. - DataRate GetBandwidthEstimate(DataRate delay_based_limit) const; + Result GetLossBasedResult(DataRate delay_based_limit) const; void SetAcknowledgedBitrate(DataRate acknowledged_bitrate); void SetBandwidthEstimate(DataRate bandwidth_estimate); - void SetMinBitrate(DataRate min_bitrate); + void SetMinMaxBitrate(DataRate min_bitrate, DataRate max_bitrate); void UpdateBandwidthEstimate( rtc::ArrayView packet_results, DataRate delay_based_estimate, - BandwidthUsage delay_detector_state); + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate); private: struct ChannelParameters { @@ -95,6 +109,7 @@ class LossBasedBweV2 { double high_loss_rate_threshold = 1.0; DataRate bandwidth_cap_at_high_loss_rate = DataRate::MinusInfinity(); double slope_of_bwe_high_loss_func = 1000.0; + bool probe_integration_enabled = false; }; struct Derivatives { @@ -155,6 +170,10 @@ class LossBasedBweV2 { const std::vector& packet_feedbacks, Timestamp at_time); void UpdateDelayDetector(BandwidthUsage delay_detector_state); + bool IsEstimateIncreasingWhenLossLimited( + const ChannelParameters& best_candidate); + bool IsBandwidthLimitedDueToLoss() const; + void SetProbeBitrate(absl::optional probe_bitrate); absl::optional acknowledged_bitrate_; absl::optional config_; @@ -170,8 +189,10 @@ class LossBasedBweV2 { 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; DataRate min_bitrate_ = DataRate::KilobitsPerSec(1); + DataRate max_bitrate_ = DataRate::PlusInfinity(); + LossBasedState current_state_ = LossBasedState::kDelayBasedEstimate; + DataRate probe_bitrate_ = DataRate::PlusInfinity(); }; } // 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 0e039fd49a..688161ade4 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 @@ -202,8 +202,10 @@ TEST_P(LossBasedBweV2Test, ReturnsDelayBasedEstimateWhenDisabled) { /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::KilobitsPerSec(100)), + EXPECT_EQ(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::KilobitsPerSec(100)) + .bandwidth_estimate, DataRate::KilobitsPerSec(100)); } @@ -214,8 +216,10 @@ TEST_P(LossBasedBweV2Test, /*trendline_integration_enabled=*/GetParam())); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::KilobitsPerSec(100)), + EXPECT_EQ(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::KilobitsPerSec(100)) + .bandwidth_estimate, DataRate::KilobitsPerSec(100)); } @@ -233,13 +237,14 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE( loss_based_bandwidth_estimator - .GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity()) - .IsFinite()); + .GetLossBasedResult(/*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate.IsFinite()); } TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { @@ -252,13 +257,14 @@ TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE( loss_based_bandwidth_estimator - .GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity()) - .IsPlusInfinity()); + .GetLossBasedResult(/*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate.IsPlusInfinity()); } TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { @@ -286,17 +292,18 @@ TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE( loss_based_bandwidth_estimator - .GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity()) - .IsPlusInfinity()); + .GetLossBasedResult(/*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate.IsPlusInfinity()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - not_enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + not_enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE( loss_based_bandwidth_estimator - .GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity()) - .IsPlusInfinity()); + .GetLossBasedResult(/*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate.IsPlusInfinity()); } TEST_P(LossBasedBweV2Test, @@ -317,24 +324,32 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); - EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_NE(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); - EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_EQ(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); - EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_NE(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); } @@ -359,30 +374,42 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator_2.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); - EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_EQ(loss_based_bandwidth_estimator_1 + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(660)); loss_based_bandwidth_estimator_1.SetAcknowledgedBitrate( - DataRate::KilobitsPerSec(600)); + DataRate::KilobitsPerSec(900)); - EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_EQ(loss_based_bandwidth_estimator_1 + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(660)); loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); - EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), - loss_based_bandwidth_estimator_2.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity())); + EXPECT_NE(loss_based_bandwidth_estimator_1 + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, + loss_based_bandwidth_estimator_2 + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate); } TEST_P(LossBasedBweV2Test, @@ -400,10 +427,12 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_no_received_packets, DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); - EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_EQ(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(100)); } @@ -429,14 +458,19 @@ TEST_P(LossBasedBweV2Test, BandwidthEstimateNotIncreaseWhenNetworkUnderusing) { DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, DataRate::PlusInfinity(), - BandwidthUsage::kBwUnderusing); - EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt); + EXPECT_LE(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, 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()), + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + EXPECT_LE(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); } @@ -461,18 +495,24 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_GT(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // If the delay based estimate is not infinity, then loss based estimate is // bounded by delay based estimate. - EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::KilobitsPerSec(500)), + EXPECT_EQ(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::KilobitsPerSec(500)) + .bandwidth_estimate, DataRate::KilobitsPerSec(500)); } @@ -500,16 +540,18 @@ TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); // Update estimate when network is overusing, and 50% loss rate. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwOverusing, + /*probe_estimate=*/absl::nullopt); // Update estimate again when network is continuously overusing, and 100% // loss rate. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwOverusing, + /*probe_estimate=*/absl::nullopt); // The estimate bitrate now is backed off based on acked bitrate. - EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()), + EXPECT_LE(loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate, acked_bitrate); } @@ -529,15 +571,21 @@ TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { 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()); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_1 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; // Use the same feedback and check if the estimate is unchanged. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); - DataRate estimate_2 = loss_based_bandwidth_estimator.GetBandwidthEstimate( - /*delay_based_limit=*/DataRate::PlusInfinity()); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_2 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; EXPECT_EQ(estimate_2, estimate_1); } @@ -560,14 +608,20 @@ TEST_P(LossBasedBweV2Test, 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()); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_1 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; 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()); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_2 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; EXPECT_EQ(estimate_2, estimate_1); } @@ -590,15 +644,20 @@ TEST_P(LossBasedBweV2Test, 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()); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_1 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; 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()); + BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt); + DataRate estimate_2 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; EXPECT_LE(estimate_2, estimate_1); } @@ -628,15 +687,20 @@ TEST_P(LossBasedBweV2Test, 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()); + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_1 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; 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()); + enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwOverusing, + /*probe_estimate=*/absl::nullopt); + DataRate estimate_2 = loss_based_bandwidth_estimator + .GetLossBasedResult( + /*delay_based_limit=*/DataRate::PlusInfinity()) + .bandwidth_estimate; EXPECT_LT(estimate_2, estimate_1); } @@ -658,28 +722,75 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, delay_based_estimate); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, delay_based_estimate); } -// After loss based bwe backs off, the next estimate is capped by -// MaxIncreaseFactor * current estimate. TEST_P(LossBasedBweV2Test, IncreaseByMaxIncreaseFactorAfterLossBasedBweBacksOff) { + ExplicitKeyValueConfig key_value_config( + "WebRTC-Bwe-LossBasedBweV2/" + "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," + "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," + "InstantUpperBoundBwBalance:10000kbps," + "DelayBasedCandidate:true,MaxIncreaseFactor:1.5,BwRampupUpperBoundFactor:" + "2.0/"); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + DataRate acked_rate = DataRate::KilobitsPerSec(300); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); + + // Create some loss to create the loss limited scenario. std::vector enough_feedback_1 = - CreatePacketResultsWithReceivedPackets( + CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + LossBasedBweV2::Result result_at_loss = + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate); + + // Network recovers after loss. std::vector enough_feedback_2 = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + + LossBasedBweV2::Result result_after_recovery = + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate); + EXPECT_EQ(result_after_recovery.bandwidth_estimate, + result_at_loss.bandwidth_estimate * 1.5); +} + +// After loss based bwe backs off, the next estimate is capped by +// a factor of acked bitrate. +TEST_P(LossBasedBweV2Test, + IncreaseByFactorOfAckedBitrateAfterLossBasedBweBacksOff) { + std::vector enough_feedback_1 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + std::vector enough_feedback_2 = + CreatePacketResultsWith10pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( Config(/*enabled=*/true, /*valid=*/true, /*trendline_integration_enabled=*/GetParam())); @@ -691,22 +802,22 @@ TEST_P(LossBasedBweV2Test, 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); + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); - // The estimate is capped by current_estimate * kMaxIncreaseFactor because it - // recently backed off. + // Change the acked bitrate to make sure that the estimate is bounded by a + // factor of acked bitrate. + DataRate acked_bitrate = DataRate::KilobitsPerSec(50); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + + // The estimate is capped by acked_bitrate * BwRampupUpperBoundFactor. 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); + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate; + EXPECT_EQ(estimate_2, acked_bitrate * 1.2); } // After loss based bwe backs off, the estimate is bounded during the delayed @@ -735,25 +846,30 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(300)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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); + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate; loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, estimate_2); } @@ -781,24 +897,29 @@ TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(300)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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); + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // 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.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate; loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal); + enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); // The estimate can continue increasing after the DelayedIncreaseWindow. EXPECT_GE( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, estimate_2); } @@ -821,7 +942,7 @@ TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_10p_loss_2 = CreatePacketResultsWith10pLossRate( @@ -829,11 +950,12 @@ TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // Do not increase the bitrate because inherent loss is less than average loss EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); } @@ -858,7 +980,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_10p_loss_2 = CreatePacketResultsWith10pLossRate( @@ -866,12 +988,13 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // Because LossThresholdOfHighBandwidthPreference is 20%, the average loss is // 10%, bandwidth estimate should increase. EXPECT_GT( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); } @@ -896,7 +1019,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_10p_loss_2 = CreatePacketResultsWith10pLossRate( @@ -904,15 +1027,54 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // Because LossThresholdOfHighBandwidthPreference is 5%, the average loss is // 10%, bandwidth estimate should decrease. EXPECT_LT( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(600)); } +TEST_P(LossBasedBweV2Test, UseProbeResultWhenRecoveringFromLoss) { + ExplicitKeyValueConfig key_value_config( + "WebRTC-Bwe-LossBasedBweV2/" + "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," + "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," + "InstantUpperBoundBwBalance:10000kbps," + "DelayBasedCandidate:true,MaxIncreaseFactor:1000," + "BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true/"); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); + DataRate acked_rate = DataRate::KilobitsPerSec(300); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); + + // Create some loss to create the loss limited scenario. + std::vector enough_feedback_1 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, + /*probe_estimate=*/absl::nullopt); + + // Network recovers after loss. + DataRate probe_estimate = DataRate::KilobitsPerSec(300); + std::vector enough_feedback_2 = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, + probe_estimate); + + LossBasedBweV2::Result result_after_recovery = + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate); + EXPECT_EQ(result_after_recovery.bandwidth_estimate, probe_estimate); +} + TEST_P(LossBasedBweV2Test, StricterBoundUsingHighLossRateThresholdAt10pLossRate) { ExplicitKeyValueConfig key_value_config( @@ -924,7 +1086,9 @@ TEST_P(LossBasedBweV2Test, "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." "05,HighLossRateThreshold:0.09/"); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetMinBitrate(DataRate::KilobitsPerSec(10)); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); @@ -934,7 +1098,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_10p_loss_2 = CreatePacketResultsWith10pLossRate( @@ -942,12 +1106,13 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // At 10% loss rate and high loss rate threshold to be 10%, cap the estimate // to be 500 * 1000-0.1 = 400kbps. EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(400)); } @@ -962,7 +1127,9 @@ TEST_P(LossBasedBweV2Test, "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." "05,HighLossRateThreshold:0.3/"); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetMinBitrate(DataRate::KilobitsPerSec(10)); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); @@ -972,7 +1139,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_50p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_50p_loss_2 = CreatePacketResultsWith50pLossRate( @@ -980,12 +1147,13 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_50p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // At 50% loss rate and high loss rate threshold to be 30%, cap the estimate // to be the min bitrate. EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(10)); } @@ -1000,7 +1168,9 @@ TEST_P(LossBasedBweV2Test, "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." "05,HighLossRateThreshold:0.3/"); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetMinBitrate(DataRate::KilobitsPerSec(10)); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); @@ -1010,7 +1180,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_100p_loss_2 = CreatePacketResultsWith100pLossRate( @@ -1018,12 +1188,13 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // At 100% loss rate and high loss rate threshold to be 30%, cap the estimate // to be the min bitrate. EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(10)); } @@ -1037,7 +1208,9 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." "05,HighLossRateThreshold:0.3/"); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - loss_based_bandwidth_estimator.SetMinBitrate(DataRate::KilobitsPerSec(10)); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); @@ -1047,12 +1220,13 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // Make sure that the estimate is set to min bitrate because of 100% loss // rate. EXPECT_EQ( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(10)); // Create some feedbacks with 0 loss rate to simulate network recovering. @@ -1062,7 +1236,7 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_0p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); std::vector enough_feedback_0p_loss_2 = CreatePacketResultsWithReceivedPackets( @@ -1070,14 +1244,39 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { kObservationDurationLowerBound * 2); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_0p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal); + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); // The estimate increases as network recovers. EXPECT_GT( - loss_based_bandwidth_estimator.GetBandwidthEstimate(delay_based_estimate), + loss_based_bandwidth_estimator.GetLossBasedResult(delay_based_estimate) + .bandwidth_estimate, DataRate::KilobitsPerSec(10)); } +TEST_P(LossBasedBweV2Test, EstimateIsNotHigherThanMaxBitrate) { + 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.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000)); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(1000)); + std::vector enough_feedback = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(), + BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt); + + EXPECT_LE( + loss_based_bandwidth_estimator + .GetLossBasedResult(/*delay_based_estimate=*/DataRate::PlusInfinity()) + .bandwidth_estimate, + DataRate::KilobitsPerSec(1000)); +} + INSTANTIATE_TEST_SUITE_P(LossBasedBweV2Tests, LossBasedBweV2Test, ::testing::Bool()); diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc index 12a7d4191e..a59fa974bf 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -229,6 +229,7 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation( bitrate_threshold_(kDefaultBitrateThreshold), loss_based_bandwidth_estimator_v1_(key_value_config), loss_based_bandwidth_estimator_v2_(key_value_config), + loss_based_state_(LossBasedState::kDelayBasedEstimate), disable_receiver_limit_caps_only_("Disabled") { RTC_DCHECK(event_log); if (BweLossExperimentIsEnabled()) { @@ -245,7 +246,8 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation( ParseFieldTrial({&disable_receiver_limit_caps_only_}, key_value_config->Lookup("WebRTC-Bwe-ReceiverLimitCapsOnly")); if (LossBasedBandwidthEstimatorV2Enabled()) { - loss_based_bandwidth_estimator_v2_.SetMinBitrate(min_bitrate_configured_); + loss_based_bandwidth_estimator_v2_.SetMinMaxBitrate( + min_bitrate_configured_, max_bitrate_configured_); } } @@ -307,6 +309,8 @@ void SendSideBandwidthEstimation::SetMinMaxBitrate(DataRate min_bitrate, } else { max_bitrate_configured_ = kDefaultMaxBitrate; } + loss_based_bandwidth_estimator_v2_.SetMinMaxBitrate(min_bitrate_configured_, + max_bitrate_configured_); } int SendSideBandwidthEstimation::GetMinBitrate() const { @@ -320,6 +324,10 @@ DataRate SendSideBandwidthEstimation::target_rate() const { return std::max(min_bitrate_configured_, target); } +LossBasedState SendSideBandwidthEstimation::loss_based_state() const { + return loss_based_state_; +} + DataRate SendSideBandwidthEstimation::delay_based_limit() const { return delay_based_limit_; } @@ -364,14 +372,16 @@ void SendSideBandwidthEstimation::SetAcknowledgedRate( void SendSideBandwidthEstimation::UpdateLossBasedEstimator( const TransportPacketsFeedback& report, - BandwidthUsage delay_detector_state) { + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate) { if (LossBasedBandwidthEstimatorV1Enabled()) { loss_based_bandwidth_estimator_v1_.UpdateLossStatistics( report.packet_feedbacks, report.feedback_time); } if (LossBasedBandwidthEstimatorV2Enabled()) { loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate( - report.packet_feedbacks, delay_based_limit_, delay_detector_state); + report.packet_feedbacks, delay_based_limit_, delay_detector_state, + probe_bitrate); UpdateEstimate(report.feedback_time); } } @@ -519,10 +529,11 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { } if (LossBasedBandwidthEstimatorV2ReadyForUse()) { - DataRate new_bitrate = - loss_based_bandwidth_estimator_v2_.GetBandwidthEstimate( + LossBasedBweV2::Result result = + loss_based_bandwidth_estimator_v2_.GetLossBasedResult( delay_based_limit_); - UpdateTargetBitrate(new_bitrate, at_time); + loss_based_state_ = result.state; + UpdateTargetBitrate(result.bandwidth_estimate, at_time); return; } diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h index 4b60689302..fc8b750552 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h @@ -85,6 +85,7 @@ class SendSideBandwidthEstimation { void OnRouteChange(); DataRate target_rate() const; + LossBasedState loss_based_state() const; DataRate delay_based_limit() const; uint8_t fraction_loss() const { return last_fraction_loss_; } TimeDelta round_trip_time() const { return last_round_trip_time_; } @@ -119,7 +120,8 @@ class SendSideBandwidthEstimation { void SetAcknowledgedRate(absl::optional acknowledged_rate, Timestamp at_time); void UpdateLossBasedEstimator(const TransportPacketsFeedback& report, - BandwidthUsage delay_detector_state); + BandwidthUsage delay_detector_state, + absl::optional probe_bitrate); private: friend class GoogCcStatePrinter; @@ -201,6 +203,7 @@ class SendSideBandwidthEstimation { DataRate bitrate_threshold_; LossBasedBandwidthEstimation loss_based_bandwidth_estimator_v1_; LossBasedBweV2 loss_based_bandwidth_estimator_v2_; + LossBasedState loss_based_state_; FieldTrialFlag disable_receiver_limit_caps_only_; }; } // namespace webrtc