From aa71259b06b72ba0fc5a28c0ffa4891c69c09441 Mon Sep 17 00:00:00 2001 From: Diep Bui Date: Thu, 13 Oct 2022 15:52:14 +0000 Subject: [PATCH] Probe when network is loss limited. Trigger probes next process intervals if the loss based current state is either increasing or decreasing. 0/ first probe at the loss based estimate. 1/ if increasing: allow further probing. 2/ if decreasing: not allow further probing. Bug: webrtc:12707 Change-Id: I4e99edcbe4e2c315e8498ffb7fb2e589cdb4e666 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/279041 Commit-Queue: Diep Bui Reviewed-by: Per Kjellander Cr-Commit-Position: refs/heads/main@{#38395} --- .../congestion_controller/goog_cc/BUILD.gn | 1 + .../goog_cc/goog_cc_network_control.cc | 22 +- .../goog_cc/probe_controller.cc | 23 +- .../goog_cc/probe_controller.h | 15 +- .../goog_cc/probe_controller_unittest.cc | 341 +++++++++++++----- 5 files changed, 303 insertions(+), 99 deletions(-) diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 1335a1ebc7..150201e1bd 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -27,6 +27,7 @@ rtc_library("goog_cc") { ":alr_detector", ":delay_based_bwe", ":estimators", + ":loss_based_bwe_v2", ":probe_controller", ":pushback_controller", ":send_side_bwe", 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 9cc9da27c1..700fa3af49 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -27,6 +27,7 @@ #include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_remote_estimate.h" #include "modules/congestion_controller/goog_cc/alr_detector.h" +#include "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h" #include "modules/congestion_controller/goog_cc/probe_controller.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" @@ -59,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, @@ -614,10 +628,6 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( uint8_t fraction_loss = bandwidth_estimation_->fraction_loss(); TimeDelta round_trip_time = bandwidth_estimation_->round_trip_time(); DataRate loss_based_target_rate = bandwidth_estimation_->target_rate(); - bool bwe_limited_due_to_packet_loss = - loss_based_target_rate.IsFinite() && - bandwidth_estimation_->delay_based_limit().IsFinite() && - loss_based_target_rate < bandwidth_estimation_->delay_based_limit(); DataRate pushback_target_rate = loss_based_target_rate; BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(), @@ -680,7 +690,9 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( update->target_rate = target_rate_msg; auto probes = probe_controller_->SetEstimatedBitrate( - loss_based_target_rate, bwe_limited_due_to_packet_loss, at_time); + loss_based_target_rate, + GetBandwidthLimitedCause(bandwidth_estimation_->loss_based_state()), + at_time); update->probe_cluster_configs.insert(update->probe_cluster_configs.end(), probes.begin(), probes.end()); update->pacer_config = GetPacingRates(at_time); diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index 501f14b874..a1237d56de 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -271,13 +271,14 @@ 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_ && + bandwidth_limited_cause_ = bandwidth_limited_cause; + if (bandwidth_limited_cause_ == + BandwidthLimitedCause::kLossLimitedBweDecreasing && config_.limit_probe_target_rate_to_loss_bwe) { state_ = State::kProbingComplete; } - bwe_limited_due_to_packet_loss_ = bwe_limited_due_to_packet_loss; if (bitrate < kBitrateDropThreshold * estimated_bitrate_) { time_of_last_large_drop_ = at_time; bitrate_before_last_large_drop_ = estimated_bitrate_; @@ -378,7 +379,8 @@ void ProbeController::SetNetworkStateEstimate( if (config_.network_state_estimate_drop_down_rate > 0 && network_estimate_ && !estimate.link_capacity_upper.IsZero() && (estimated_bitrate_ > estimate.link_capacity_upper || - bwe_limited_due_to_packet_loss_) && + bandwidth_limited_cause_ == + BandwidthLimitedCause::kLossLimitedBweDecreasing) && estimate.link_capacity_upper <= config_.network_state_estimate_drop_down_rate * network_estimate_->link_capacity_upper) { @@ -390,7 +392,6 @@ void ProbeController::SetNetworkStateEstimate( void ProbeController::Reset(Timestamp at_time) { network_available_ = true; - bwe_limited_due_to_packet_loss_ = false; state_ = State::kInit; min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); time_last_probing_initiated_ = Timestamp::Zero(); @@ -406,6 +407,7 @@ void ProbeController::Reset(Timestamp at_time) { bitrate_before_last_large_drop_ = DataRate::Zero(); max_total_allocated_bitrate_ = DataRate::Zero(); send_probe_on_next_process_interval_ = false; + bandwidth_limited_cause_ = BandwidthLimitedCause::kDelayBasedLimited; } bool ProbeController::TimeForAlrProbe(Timestamp at_time) const { @@ -445,8 +447,12 @@ std::vector ProbeController::Process(Timestamp at_time) { } if (send_probe_on_next_process_interval_ || TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(at_time)) { - return InitiateProbing( - at_time, {estimated_bitrate_ * config_.alr_probe_scale}, true); + DataRate suggested_probe = estimated_bitrate_ * config_.alr_probe_scale; + if (config_.limit_probe_target_rate_to_loss_bwe && + bandwidth_limited_cause_ != BandwidthLimitedCause::kDelayBasedLimited) { + suggested_probe = estimated_bitrate_; + } + return InitiateProbing(at_time, {suggested_probe}, true); } return std::vector(); } @@ -466,7 +472,8 @@ std::vector ProbeController::InitiateProbing( } DataRate max_probe_bitrate = max_bitrate_; - if (bwe_limited_due_to_packet_loss_ && + if (bandwidth_limited_cause_ == + BandwidthLimitedCause::kLossLimitedBweDecreasing && config_.limit_probe_target_rate_to_loss_bwe) { max_probe_bitrate = std::min(estimated_bitrate_, max_bitrate_); } diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index e1ee08fc99..cf631a8a5e 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -79,6 +79,15 @@ struct ProbeControllerConfig { 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. @@ -108,7 +117,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); @@ -150,7 +159,6 @@ class ProbeController { bool TimeForNetworkStateProbe(Timestamp at_time) const; bool network_available_; - bool bwe_limited_due_to_packet_loss_; State state_; DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity(); @@ -175,7 +183,8 @@ class ProbeController { RtcEventLog* event_log_; int32_t next_probe_cluster_id_ = 1; - + BandwidthLimitedCause bandwidth_limited_cause_ = + BandwidthLimitedCause::kDelayBasedLimited; ProbeControllerConfig config_; }; diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 2b2d71205e..f453047d21 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, ProbesOnMaxBitrateIncreaseOnlyWhenInAlr) { 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); @@ -185,11 +186,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), @@ -209,13 +210,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); } @@ -231,9 +232,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) { @@ -244,15 +245,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); @@ -267,15 +268,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()); @@ -292,19 +293,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) { @@ -315,18 +316,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) { @@ -338,8 +339,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(); @@ -351,26 +352,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) { @@ -389,7 +390,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()); @@ -413,15 +414,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) { @@ -440,7 +441,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. @@ -486,13 +487,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); @@ -516,7 +517,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()); @@ -525,20 +526,12 @@ 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::kLossLimitedBweDecreasing, 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)); - - probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false, - 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)); } TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { @@ -550,7 +543,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; @@ -578,7 +571,7 @@ 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; @@ -589,20 +582,20 @@ TEST(ProbeControllerTest, 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::kLossLimitedBweDecreasing, 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()); + ASSERT_FALSE(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, + DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); fixture.AdvanceTime(TimeDelta::Seconds(5)); probes = probe_controller->Process(fixture.CurrentTime()); - ASSERT_TRUE(!probes.empty()); + ASSERT_FALSE(probes.empty()); EXPECT_GT(probes[0].target_data_rate, DataRate::BitsPerSec(500)); } @@ -615,7 +608,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()); @@ -643,7 +636,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)); @@ -667,7 +660,7 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateIncrease) { 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)); @@ -706,7 +699,7 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDrop) { 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)); @@ -746,7 +739,7 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDropLossLimited) { 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)); @@ -761,7 +754,7 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDropLossLimited) { // Loss limited. probes = probe_controller->SetEstimatedBitrate( - kStartBitrate / 3, /*bwe_limited_due_to_packet_loss=*/true, + kStartBitrate / 3, BandwidthLimitedCause::kLossLimitedBweDecreasing, fixture.CurrentTime()); // If NetworkState decrease dramatically, expect a probe to be sent. // But limited to loss based estimate. @@ -772,7 +765,189 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDropLossLimited) { EXPECT_EQ(probes[0].target_data_rate, kStartBitrate / 3); } -TEST(ProbeControllerTest, DontProbeFurtherWhenLossLimited) { +TEST(ProbeControllerTest, + ProbesAtEstimatedBitrateWhenInAlrIfLossBasedIncreasing) { + 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()); + EXPECT_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()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes.at(0).target_data_rate, kStartBitrate); +} + +TEST(ProbeControllerTest, ProbesFurtherWhenInAlrIfLossBasedIncreasing) { + 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()); + EXPECT_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()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes.at(0).target_data_rate, kStartBitrate); + + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, 2 * kStartBitrate); +} + +TEST(ProbeControllerTest, NotProbeFurtherWhenInAlrIfLossBasedDecreases) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_drop_down_rate:0.5,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()); + EXPECT_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()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes.at(0).target_data_rate, kStartBitrate); + + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, BandwidthLimitedCause::kLossLimitedBweDecreasing, + 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()); + EXPECT_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, ProbeFurtherWhenLossBasedIncreases) { + 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()); + EXPECT_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()); + EXPECT_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 increasing. + probes = probe_controller->SetEstimatedBitrate( + probe_target_rate, BandwidthLimitedCause::kLossLimitedBweIncreasing, + fixture.CurrentTime()); + EXPECT_FALSE(probes.empty()); + EXPECT_EQ(probes[0].target_data_rate, 2 * probe_target_rate); +} + +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()); + EXPECT_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()); + EXPECT_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()); + EXPECT_FALSE(probes.empty()); + EXPECT_EQ(probes[0].target_data_rate, 2 * probe_target_rate); +} + +TEST(ProbeControllerTest, DontProbeFurtherWhenLossBasedDecreases) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); @@ -797,8 +972,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()); } @@ -827,7 +1002,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); @@ -845,7 +1020,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()); @@ -873,7 +1048,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()); @@ -895,7 +1070,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()); @@ -919,7 +1094,7 @@ TEST(ProbeControllerTest, DontSendProbeIfNetworkStateEstimateIsZero) { 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});