From d2811761e33bb4b9e965c1281939478c96c36787 Mon Sep 17 00:00:00 2001 From: Diep Bui Date: Tue, 15 Nov 2022 15:08:18 +0000 Subject: [PATCH] Probe when bandwidth is loss limited and the estimate is increasing. Add loss_limited_probe_scale as a scale factor which decides how much we should probe when bandwidth is loss limited. Bug: webrtc:12707 Change-Id: I194b2b40c9a7861d82b61585bcaf484ab228eedb Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/281360 Reviewed-by: Per Kjellander Commit-Queue: Diep Bui Cr-Commit-Position: refs/heads/main@{#38636} --- .../goog_cc/goog_cc_network_control.cc | 17 +- .../goog_cc/probe_controller.cc | 69 ++-- .../goog_cc/probe_controller.h | 18 +- .../goog_cc/probe_controller_unittest.cc | 321 +++++++++++++----- 4 files changed, 298 insertions(+), 127 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 033094f7fd..dcbc15db74 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -60,6 +60,19 @@ bool IsEnabled(const FieldTrialsView* config, absl::string_view key) { bool IsNotDisabled(const FieldTrialsView* config, absl::string_view key) { return !absl::StartsWith(config->Lookup(key), "Disabled"); } + +BandwidthLimitedCause GetBandwidthLimitedCause( + LossBasedState loss_based_state) { + switch (loss_based_state) { + case LossBasedState::kDecreasing: + return BandwidthLimitedCause::kLossLimitedBweDecreasing; + case LossBasedState::kIncreasing: + return BandwidthLimitedCause::kLossLimitedBweIncreasing; + default: + return BandwidthLimitedCause::kDelayBasedLimited; + } +} + } // namespace GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, @@ -669,9 +682,7 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( auto probes = probe_controller_->SetEstimatedBitrate( loss_based_target_rate, - /*bwe_limited_due_to_packet_loss=*/ - bandwidth_estimation_->loss_based_state() != - LossBasedState::kDelayBasedEstimate, + GetBandwidthLimitedCause(bandwidth_estimation_->loss_based_state()), at_time); update->probe_cluster_configs.insert(update->probe_cluster_configs.end(), probes.begin(), probes.end()); diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index aac957622f..00e1b59a55 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -106,22 +106,31 @@ ProbeControllerConfig::ProbeControllerConfig( min_probe_duration("min_probe_duration", TimeDelta::Millis(15)), limit_probe_target_rate_to_loss_bwe("limit_probe_target_rate_to_loss_bwe", false), + loss_limited_probe_scale("loss_limited_scale", 1.5), skip_if_estimate_larger_than_fraction_of_max( "skip_if_est_larger_than_fraction_of_max", 0.0) { - ParseFieldTrial( - {&first_exponential_probe_scale, &second_exponential_probe_scale, - &further_exponential_probe_scale, &further_probe_threshold, - &alr_probing_interval, &alr_probe_scale, - &probe_on_max_allocated_bitrate_change, &first_allocation_probe_scale, - &second_allocation_probe_scale, &allocation_allow_further_probing, - &min_probe_duration, &network_state_estimate_probing_interval, - &probe_if_estimate_lower_than_network_state_estimate_ratio, - &estimate_lower_than_network_state_estimate_probing_interval, - &network_state_probe_scale, &network_state_probe_duration, - &min_probe_packets_sent, &limit_probe_target_rate_to_loss_bwe, - &skip_if_estimate_larger_than_fraction_of_max}, - key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); + ParseFieldTrial({&first_exponential_probe_scale, + &second_exponential_probe_scale, + &further_exponential_probe_scale, + &further_probe_threshold, + &alr_probing_interval, + &alr_probe_scale, + &probe_on_max_allocated_bitrate_change, + &first_allocation_probe_scale, + &second_allocation_probe_scale, + &allocation_allow_further_probing, + &min_probe_duration, + &network_state_estimate_probing_interval, + &probe_if_estimate_lower_than_network_state_estimate_ratio, + &estimate_lower_than_network_state_estimate_probing_interval, + &network_state_probe_scale, + &network_state_probe_duration, + &min_probe_packets_sent, + &limit_probe_target_rate_to_loss_bwe, + &loss_limited_probe_scale, + &skip_if_estimate_larger_than_fraction_of_max}, + key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration ParseFieldTrial( @@ -129,8 +138,9 @@ ProbeControllerConfig::ProbeControllerConfig( key_value_config->Lookup("WebRTC-Bwe-InitialProbing")); ParseFieldTrial({&further_exponential_probe_scale, &further_probe_threshold}, key_value_config->Lookup("WebRTC-Bwe-ExponentialProbing")); - ParseFieldTrial({&alr_probing_interval, &alr_probe_scale}, - key_value_config->Lookup("WebRTC-Bwe-AlrProbing")); + ParseFieldTrial( + {&alr_probing_interval, &alr_probe_scale, &loss_limited_probe_scale}, + key_value_config->Lookup("WebRTC-Bwe-AlrProbing")); ParseFieldTrial( {&first_allocation_probe_scale, &second_allocation_probe_scale, &allocation_allow_further_probing, &allocation_probe_max}, @@ -277,13 +287,9 @@ std::vector ProbeController::InitiateExponentialProbing( std::vector ProbeController::SetEstimatedBitrate( DataRate bitrate, - bool bwe_limited_due_to_packet_loss, + BandwidthLimitedCause bandwidth_limited_cause, Timestamp at_time) { - if (bwe_limited_due_to_packet_loss != bwe_limited_due_to_packet_loss_ && - config_.limit_probe_target_rate_to_loss_bwe) { - state_ = State::kProbingComplete; - } - bwe_limited_due_to_packet_loss_ = bwe_limited_due_to_packet_loss; + bandwidth_limited_cause_ = bandwidth_limited_cause; if (bitrate < kBitrateDropThreshold * estimated_bitrate_) { time_of_last_large_drop_ = at_time; bitrate_before_last_large_drop_ = estimated_bitrate_; @@ -380,7 +386,7 @@ void ProbeController::SetNetworkStateEstimate( void ProbeController::Reset(Timestamp at_time) { network_available_ = true; - bwe_limited_due_to_packet_loss_ = false; + bandwidth_limited_cause_ = BandwidthLimitedCause::kDelayBasedLimited; state_ = State::kInit; min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); time_last_probing_initiated_ = Timestamp::Zero(); @@ -414,7 +420,7 @@ bool ProbeController::TimeForNetworkStateProbe(Timestamp at_time) const { } bool probe_due_to_low_estimate = - !bwe_limited_due_to_packet_loss_ && + bandwidth_limited_cause_ == BandwidthLimitedCause::kDelayBasedLimited && estimated_bitrate_ < config_.probe_if_estimate_lower_than_network_state_estimate_ratio * network_estimate_->link_capacity_upper; @@ -493,9 +499,20 @@ std::vector ProbeController::InitiateProbing( } DataRate estimate_capped_bitrate = DataRate::PlusInfinity(); - if (bwe_limited_due_to_packet_loss_ && - config_.limit_probe_target_rate_to_loss_bwe) { - estimate_capped_bitrate = std::min(estimated_bitrate_, max_probe_bitrate); + if (config_.limit_probe_target_rate_to_loss_bwe) { + switch (bandwidth_limited_cause_) { + case BandwidthLimitedCause::kLossLimitedBweDecreasing: + // If bandwidth estimate is decreasing because of packet loss, do not + // send probes. + return {}; + case BandwidthLimitedCause::kLossLimitedBweIncreasing: + estimate_capped_bitrate = + std::min(max_probe_bitrate, + estimated_bitrate_ * config_.loss_limited_probe_scale); + break; + case BandwidthLimitedCause::kDelayBasedLimited: + break; + } } if (config_.network_state_estimate_probing_interval->IsFinite() && network_estimate_ && network_estimate_->link_capacity_upper.IsFinite()) { diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index 6538b0eecd..9680d61a97 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -72,14 +72,23 @@ struct ProbeControllerConfig { FieldTrialParameter min_probe_packets_sent; // The minimum probing duration. FieldTrialParameter min_probe_duration; - // Max limit the target rate of a probe to current estimate if BWE is loss - // limited. + // Periodically probe when bandwidth estimate is loss limited. FieldTrialParameter limit_probe_target_rate_to_loss_bwe; + FieldTrialParameter loss_limited_probe_scale; // Dont send a probe if min(estimate, network state estimate) is larger than // this fraction of the set max bitrate. FieldTrialParameter skip_if_estimate_larger_than_fraction_of_max; }; +// Reason that bandwidth estimate is limited. Bandwidth estimate can be limited +// by either delay based bwe, or loss based bwe when it increases/decreases the +// estimate. +enum class BandwidthLimitedCause { + kLossLimitedBweIncreasing = 0, + kLossLimitedBweDecreasing = 1, + kDelayBasedLimited = 2 +}; + // This class controls initiation of probing to estimate initial channel // capacity. There is also support for probing during a session when max // bitrate is adjusted by an application. @@ -109,7 +118,7 @@ class ProbeController { ABSL_MUST_USE_RESULT std::vector SetEstimatedBitrate( DataRate bitrate, - bool bwe_limited_due_to_packet_loss, + BandwidthLimitedCause bandwidth_limited_cause, Timestamp at_time); void EnablePeriodicAlrProbing(bool enable); @@ -149,7 +158,8 @@ class ProbeController { bool TimeForNetworkStateProbe(Timestamp at_time) const; bool network_available_; - bool bwe_limited_due_to_packet_loss_; + BandwidthLimitedCause bandwidth_limited_cause_ = + BandwidthLimitedCause::kDelayBasedLimited; State state_; DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity(); diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index c060664cb7..5d971e98b1 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -102,7 +102,7 @@ TEST(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) { {.at_time = fixture.CurrentTime(), .network_available = false}); probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); probes = probe_controller->OnNetworkAvailability( {.at_time = fixture.CurrentTime(), .network_available = true}); EXPECT_GE(probes.size(), 2u); @@ -138,7 +138,7 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { // Long enough to time out exponential probing. fixture.AdvanceTime(kExponentialProbingTimeout); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetBitrates( @@ -156,18 +156,19 @@ TEST(ProbeControllerTest, ProbesOnMaxAllocatedBitrateIncreaseOnlyWhenInAlr) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( kMaxBitrate - DataRate::BitsPerSec(1), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Wait long enough to time out exponential probing. fixture.AdvanceTime(kExponentialProbingTimeout); probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); // Probe when in alr. probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); probes = probe_controller->OnMaxTotalAllocatedBitrate( kMaxBitrate + DataRate::BitsPerSec(1), fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); + EXPECT_EQ(probes.at(0).target_data_rate, kMaxBitrate); // Do not probe when not in alr. probe_controller->SetAlrStartTimeMs(absl::nullopt); @@ -187,7 +188,7 @@ TEST(ProbeControllerTest, CanDisableProbingOnMaxTotalAllocatedBitrateIncrease) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( kMaxBitrate - DataRate::BitsPerSec(1), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); fixture.AdvanceTime(kExponentialProbingTimeout); probes = probe_controller->Process(fixture.CurrentTime()); ASSERT_TRUE(probes.empty()); @@ -209,11 +210,11 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) { // Long enough to time out exponential probing. fixture.AdvanceTime(kExponentialProbingTimeout); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate + DataRate::BitsPerSec(100), @@ -233,13 +234,13 @@ TEST(ProbeControllerTest, TestExponentialProbing) { // Repeated probe should only be sent when estimated bitrate climbs above // 0.7 * 6 * kStartBitrate = 1260. probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(1000), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + DataRate::BitsPerSec(1000), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(1800), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800); } @@ -255,9 +256,9 @@ TEST(ProbeControllerTest, TestExponentialProbingTimeout) { probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(1800), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, RequestProbeInAlr) { @@ -268,15 +269,15 @@ TEST(ProbeControllerTest, RequestProbeInAlr) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_GE(probes.size(), 2u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(250), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(250), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probes = probe_controller->RequestProbe(fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); @@ -291,15 +292,15 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrStartTimeMs(absl::nullopt); fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(250), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(250), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms()); fixture.AdvanceTime(kAlrEndedTimeout - TimeDelta::Millis(1)); probes = probe_controller->RequestProbe(fixture.CurrentTime()); @@ -316,19 +317,19 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrStartTimeMs(absl::nullopt); fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(250), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(250), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms()); fixture.AdvanceTime(kAlrEndedTimeout + TimeDelta::Millis(1)); probes = probe_controller->RequestProbe(fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) { @@ -339,18 +340,18 @@ TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(250), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(250), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); fixture.AdvanceTime(kBitrateDropTimeout + TimeDelta::Millis(1)); probes = probe_controller->RequestProbe(fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, PeriodicProbing) { @@ -362,8 +363,8 @@ TEST(ProbeControllerTest, PeriodicProbing) { kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); Timestamp start_time = fixture.CurrentTime(); @@ -375,26 +376,26 @@ TEST(ProbeControllerTest, PeriodicProbing) { EXPECT_EQ(probes[0].target_data_rate.bps(), 1000); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); // The following probe should be sent at 10s into ALR. probe_controller->SetAlrStartTimeMs(start_time.ms()); fixture.AdvanceTime(TimeDelta::Seconds(4)); probes = probe_controller->Process(fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); probe_controller->SetAlrStartTimeMs(start_time.ms()); fixture.AdvanceTime(TimeDelta::Seconds(1)); probes = probe_controller->Process(fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, PeriodicProbingAfterReset) { @@ -413,7 +414,7 @@ TEST(ProbeControllerTest, PeriodicProbingAfterReset) { probes = probe_controller->Process(fixture.CurrentTime()); // Since bitrates are not yet set, no probe is sent event though we are in ALR // mode. - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -437,15 +438,15 @@ TEST(ProbeControllerTest, TestExponentialProbingOverflow) { fixture.CurrentTime()); // Verify that probe bitrate is capped at the specified max bitrate. probes = probe_controller->SetEstimatedBitrate( - 60 * kMbpsMultiplier, /*bwe_limited_due_to_packet_loss=*/false, + 60 * kMbpsMultiplier, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate, 100 * kMbpsMultiplier); // Verify that repeated probes aren't sent. probes = probe_controller->SetEstimatedBitrate( - 100 * kMbpsMultiplier, /*bwe_limited_due_to_packet_loss=*/false, + 100 * kMbpsMultiplier, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); - EXPECT_EQ(probes.size(), 0u); + EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, TestAllocatedBitrateCap) { @@ -464,7 +465,7 @@ TEST(ProbeControllerTest, TestAllocatedBitrateCap) { DataRate estimated_bitrate = kMaxBitrate / 10; probes = probe_controller->SetEstimatedBitrate( - estimated_bitrate, /*bwe_limited_due_to_packet_loss=*/false, + estimated_bitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Set a max allocated bitrate below the current estimate. @@ -510,13 +511,13 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { // Repeated probe should only be sent when estimated bitrate climbs above // 0.8 * 5 * kStartBitrateBps = 1200. probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(1100), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(1100), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); EXPECT_EQ(probes.size(), 0u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(1250), - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + DataRate::BitsPerSec(1250), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 3 * 1250); @@ -540,7 +541,7 @@ TEST(ProbeControllerTest, LimitAlrProbeWhenLossBasedBweLimited) { auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false, + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Expect the controller to send a new probe after 5s has passed. probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); @@ -549,20 +550,20 @@ TEST(ProbeControllerTest, LimitAlrProbeWhenLossBasedBweLimited) { ASSERT_EQ(probes.size(), 1u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss*/ true, - fixture.CurrentTime()); + DataRate::BitsPerSec(500), + BandwidthLimitedCause::kLossLimitedBweIncreasing, fixture.CurrentTime()); fixture.AdvanceTime(TimeDelta::Seconds(6)); probes = probe_controller->Process(fixture.CurrentTime()); ASSERT_EQ(probes.size(), 1u); - EXPECT_EQ(probes[0].target_data_rate, DataRate::BitsPerSec(500)); + EXPECT_EQ(probes[0].target_data_rate, 1.5 * DataRate::BitsPerSec(500)); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false, - fixture.CurrentTime()); + 1.5 * DataRate::BitsPerSec(500), + BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); fixture.AdvanceTime(TimeDelta::Seconds(6)); probes = probe_controller->Process(fixture.CurrentTime()); - ASSERT_TRUE(!probes.empty()); - EXPECT_GT(probes[0].target_data_rate, DataRate::BitsPerSec(500)); + ASSERT_FALSE(probes.empty()); + EXPECT_GT(probes[0].target_data_rate, 1.5 * 1.5 * DataRate::BitsPerSec(500)); } TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { @@ -574,7 +575,7 @@ TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(5000), /*bwe_limited_due_to_packet_loss=*/false, + DataRate::BitsPerSec(5000), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Expect the controller to send a new probe after 5s has passed. NetworkStateEstimate state_estimate; @@ -602,32 +603,24 @@ TEST(ProbeControllerTest, auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false, + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Expect the controller to send a new probe after 5s has passed. NetworkStateEstimate state_estimate; - state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(600); + state_estimate.link_capacity_upper = DataRate::BitsPerSec(700); probe_controller->SetNetworkStateEstimate(state_estimate); fixture.AdvanceTime(TimeDelta::Seconds(5)); probes = probe_controller->Process(fixture.CurrentTime()); ASSERT_EQ(probes.size(), 1u); probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/true, - fixture.CurrentTime()); + DataRate::BitsPerSec(500), + BandwidthLimitedCause::kLossLimitedBweIncreasing, fixture.CurrentTime()); // Expect the controller to send a new probe after 5s has passed. fixture.AdvanceTime(TimeDelta::Seconds(5)); probes = probe_controller->Process(fixture.CurrentTime()); - ASSERT_TRUE(!probes.empty()); - EXPECT_EQ(probes[0].target_data_rate, DataRate::BitsPerSec(500)); - - probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false, - fixture.CurrentTime()); - fixture.AdvanceTime(TimeDelta::Seconds(5)); - probes = probe_controller->Process(fixture.CurrentTime()); - ASSERT_TRUE(!probes.empty()); - EXPECT_GT(probes[0].target_data_rate, DataRate::BitsPerSec(500)); + ASSERT_FALSE(probes.empty()); + EXPECT_EQ(probes[0].target_data_rate, DataRate::BitsPerSec(700)); } TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { @@ -639,7 +632,7 @@ TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::KilobitsPerSec(6), /*bwe_limited_due_to_packet_loss=*/false, + DataRate::KilobitsPerSec(6), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); @@ -667,7 +660,7 @@ TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - DataRate::KilobitsPerSec(5), /*bwe_limited_due_to_packet_loss=*/false, + DataRate::KilobitsPerSec(5), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); ASSERT_FALSE(probes.empty()); EXPECT_LT(probes[0].target_duration, TimeDelta::Millis(100)); @@ -681,6 +674,147 @@ TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100)); } +TEST(ProbeControllerTest, ProbeInAlrIfLossBasedIncreasing) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "limit_probe_target_rate_to_loss_bwe:true/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probe_controller->EnablePeriodicAlrProbing(true); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + + // Wait long enough to time out exponential probing. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_TRUE(probes.empty()); + + // Probe when in alr. + probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); + fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes.at(0).target_data_rate, 1.5 * kStartBitrate); +} + +TEST(ProbeControllerTest, ProbeFurtherInAlrIfLossBasedIncreasing) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "limit_probe_target_rate_to_loss_bwe:true/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probe_controller->EnablePeriodicAlrProbing(true); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + + // Wait long enough to time out exponential probing. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_TRUE(probes.empty()); + + // Probe when in alr. + probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); + fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + ASSERT_EQ(probes.at(0).target_data_rate, 1.5 * kStartBitrate); + + probes = probe_controller->SetEstimatedBitrate( + 1.5 * kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, 1.5 * 1.5 * kStartBitrate); +} + +TEST(ProbeControllerTest, NotProbeWhenInAlrIfLossBasedDecreases) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probe_controller->EnablePeriodicAlrProbing(true); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweDecreasing, + fixture.CurrentTime()); + + // Wait long enough to time out exponential probing. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_TRUE(probes.empty()); + + // Not probe in alr when loss based estimate decreases. + probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); + fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); +} + +TEST(ProbeControllerTest, NotProbeIfLossBasedIncreasingOutsideAlr) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "limit_probe_target_rate_to_loss_bwe:true/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probe_controller->EnablePeriodicAlrProbing(true); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + + // Wait long enough to time out exponential probing. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_TRUE(probes.empty()); + + probe_controller->SetAlrStartTimeMs(absl::nullopt); + fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1)); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); +} + +TEST(ProbeControllerTest, ProbeFurtherWhenLossBasedIsSameAsDelayBasedEstimate) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + ASSERT_FALSE(probes.empty()); + + // Need to wait at least one second before process can trigger a new probe. + fixture.AdvanceTime(TimeDelta::Millis(1100)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_TRUE(probes.empty()); + + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = 5 * kStartBitrate; + probe_controller->SetNetworkStateEstimate(state_estimate); + fixture.AdvanceTime(TimeDelta::Seconds(5)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_FALSE(probes.empty()); + + DataRate probe_target_rate = probes[0].target_data_rate; + EXPECT_LT(probe_target_rate, state_estimate.link_capacity_upper); + // Expect that more probes are sent if BWE is the same as delay based + // estimate. + probes = probe_controller->SetEstimatedBitrate( + probe_target_rate, BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + ASSERT_FALSE(probes.empty()); + EXPECT_EQ(probes[0].target_data_rate, 2 * probe_target_rate); +} + TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) { // Periodic probe every 1 second if estimate is lower than 50% of the // NetworkStateEstimate. @@ -694,7 +828,7 @@ TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) { auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); // Need to wait at least one second before process can trigger a new probe. fixture.AdvanceTime(TimeDelta::Millis(1100)); @@ -720,8 +854,8 @@ TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) { // Stop probing if estimate increase. We might probe further here though. probes = probe_controller->SetEstimatedBitrate( - 2 * kStartBitrate, - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + 2 * kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); // No more periodic probes. fixture.AdvanceTime(TimeDelta::Millis(1100)); probes = probe_controller->Process(fixture.CurrentTime()); @@ -753,8 +887,8 @@ TEST(ProbeControllerTest, DontProbeFurtherWhenLossLimited) { EXPECT_LT(probes[0].target_data_rate, state_estimate.link_capacity_upper); // Expect that no more probes are sent immediately if BWE is loss limited. probes = probe_controller->SetEstimatedBitrate( - probes[0].target_data_rate, /*bwe_limited_due_to_packet_loss=*/true, - fixture.CurrentTime()); + probes[0].target_data_rate, + BandwidthLimitedCause::kLossLimitedBweDecreasing, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); } @@ -783,7 +917,7 @@ TEST(ProbeControllerTest, ProbeFurtherWhenDelayBasedLimited) { EXPECT_LT(probes[0].target_data_rate, state_estimate.link_capacity_upper); // Since the probe was successfull, expect to continue probing. probes = probe_controller->SetEstimatedBitrate( - probes[0].target_data_rate, /*bwe_limited_due_to_packet_loss=*/false, + probes[0].target_data_rate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_FALSE(probes.empty()); EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); @@ -804,7 +938,7 @@ TEST(ProbeControllerTest, probe_controller->SetNetworkStateEstimate(state_estimate); // No immediate further probing since probe result is low. probes = probe_controller->SetEstimatedBitrate( - probes[0].target_data_rate / 2, /*bwe_limited_due_to_packet_loss=*/false, + probes[0].target_data_rate / 2, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); ASSERT_TRUE(probes.empty()); @@ -817,14 +951,14 @@ TEST(ProbeControllerTest, state_estimate.link_capacity_upper = 3 * kStartBitrate; probe_controller->SetNetworkStateEstimate(state_estimate); probes = probe_controller->SetEstimatedBitrate( - probes[0].target_data_rate, /*bwe_limited_due_to_packet_loss=*/false, + probes[0].target_data_rate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_FALSE(probes.empty()); // But no more probes if estimate is close to the link capacity. probes = probe_controller->SetEstimatedBitrate( state_estimate.link_capacity_upper * 0.9, - /*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime()); + BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); } @@ -840,7 +974,7 @@ TEST(ProbeControllerTest, SkipAlrProbeIfEstimateLargerThanMaxProbe) { ASSERT_FALSE(probes.empty()); probes = probe_controller->SetEstimatedBitrate( - kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); @@ -867,7 +1001,7 @@ TEST(ProbeControllerTest, kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_FALSE(probes.empty()); probes = probe_controller->SetEstimatedBitrate( - kMaxBitrate / 2, /*bwe_limited_due_to_packet_loss=*/false, + kMaxBitrate / 2, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); fixture.AdvanceTime(TimeDelta::Seconds(10)); @@ -899,7 +1033,7 @@ TEST(ProbeControllerTest, SkipNetworkStateProbeIfEstimateLargerThanMaxProbe) { probe_controller->SetNetworkStateEstimate( {.link_capacity_upper = 2 * kMaxBitrate}); probes = probe_controller->SetEstimatedBitrate( - kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); @@ -921,7 +1055,7 @@ TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) { probe_controller->SetNetworkStateEstimate( {.link_capacity_upper = 2 * kMaxBitrate}); probes = probe_controller->SetEstimatedBitrate( - kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); @@ -929,7 +1063,7 @@ TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) { fixture.AdvanceTime(TimeDelta::Millis(2100)); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); probe_controller->SetNetworkStateEstimate( @@ -941,14 +1075,13 @@ TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) { TEST(ProbeControllerTest, DontSendProbeIfNetworkStateEstimateIsZero) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_" - "target_rate_to_loss_bwe:true/"); + "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); std::unique_ptr probe_controller = fixture.CreateController(); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); probe_controller->SetNetworkStateEstimate( {.link_capacity_upper = kStartBitrate});