From 6d47f2e1fa4f6da491bfb3768129598cb710aed2 Mon Sep 17 00:00:00 2001 From: Per Kjellander Date: Thu, 25 Aug 2022 17:57:23 +0200 Subject: [PATCH] Add field trial to periodically probe at networkstate estimate. Add field trial to not probe if loss based limited MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If both Alr probing and periodic probing of networkstate estimate is enabled, probes are limited by the network state estimate * factor controlled by field trial. Bug: webrtc:14392 Change-Id: I46e1dbdd8b14f63a7c223b4c03c114717b802023 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/272805 Reviewed-by: Erik Språng Commit-Queue: Per Kjellander Reviewed-by: Diep Bui Cr-Commit-Position: refs/heads/main@{#37915} --- .../goog_cc/goog_cc_network_control.cc | 7 +- .../goog_cc/probe_controller.cc | 89 +++++-- .../goog_cc/probe_controller.h | 15 +- .../goog_cc/probe_controller_unittest.cc | 231 +++++++++++++++--- .../goog_cc/send_side_bandwidth_estimation.cc | 4 + .../goog_cc/send_side_bandwidth_estimation.h | 1 + 6 files changed, 291 insertions(+), 56 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 4d56ea6695..5647145d2c 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -513,6 +513,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( prev_estimate->last_feed_time)) { event_log_->Log(std::make_unique( estimate_->link_capacity_lower, estimate_->link_capacity_upper)); + probe_controller_->SetNetworkStateEstimate(*estimate_); } } absl::optional probe_bitrate = @@ -617,6 +618,8 @@ 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 < bandwidth_estimation_->delay_based_limit(); DataRate pushback_target_rate = loss_based_target_rate; BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(), @@ -679,11 +682,11 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( update->target_rate = target_rate_msg; auto probes = probe_controller_->SetEstimatedBitrate( - loss_based_target_rate.bps(), at_time.ms()); + loss_based_target_rate.bps(), bwe_limited_due_to_packet_loss, + at_time.ms()); update->probe_cluster_configs.insert(update->probe_cluster_configs.end(), probes.begin(), probes.end()); update->pacer_config = GetPacingRates(at_time); - RTC_LOG(LS_VERBOSE) << "bwe " << at_time.ms() << " pushback_target_bps=" << last_pushback_target_rate_.bps() << " estimate_bps=" << loss_based_target_rate.bps(); diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index e70f2b310c..287f717d84 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -16,6 +16,7 @@ #include #include "absl/strings/match.h" +#include "absl/types/optional.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -89,17 +90,24 @@ ProbeControllerConfig::ProbeControllerConfig( further_probe_threshold("further_probe_threshold", 0.7), alr_probing_interval("alr_interval", TimeDelta::Seconds(5)), alr_probe_scale("alr_scale", 2), + network_state_estimate_probing_interval("network_state_interval", + TimeDelta::PlusInfinity()), + network_state_probe_scale("network_state_scale", 1.0), first_allocation_probe_scale("alloc_p1", 1), second_allocation_probe_scale("alloc_p2", 2), allocation_allow_further_probing("alloc_probe_further", false), allocation_probe_max("alloc_probe_max", DataRate::PlusInfinity()), min_probe_packets_sent("min_probe_packets_sent", 5), - min_probe_duration("min_probe_duration", TimeDelta::Millis(15)) { + min_probe_duration("min_probe_duration", TimeDelta::Millis(15)), + probe_if_bwe_limited_due_to_loss("probe_if_bwe_limited_due_to_loss", + true) { ParseFieldTrial( {&first_exponential_probe_scale, &second_exponential_probe_scale, &further_exponential_probe_scale, &further_probe_threshold, &alr_probing_interval, &alr_probe_scale, &first_allocation_probe_scale, - &second_allocation_probe_scale, &allocation_allow_further_probing}, + &second_allocation_probe_scale, &allocation_allow_further_probing, + &min_probe_duration, &network_state_estimate_probing_interval, + &network_state_probe_scale, &probe_if_bwe_limited_due_to_loss}, key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration @@ -256,7 +264,15 @@ std::vector ProbeController::InitiateExponentialProbing( std::vector ProbeController::SetEstimatedBitrate( int64_t bitrate_bps, + bool bwe_limited_due_to_packet_loss, int64_t at_time_ms) { + bwe_limited_due_to_packet_loss_ = bwe_limited_due_to_packet_loss; + if (bitrate_bps < kBitrateDropThreshold * estimated_bitrate_bps_) { + time_of_last_large_drop_ms_ = at_time_ms; + bitrate_before_last_large_drop_bps_ = estimated_bitrate_bps_; + } + estimated_bitrate_bps_ = bitrate_bps; + if (mid_call_probing_waiting_for_result_ && bitrate_bps >= mid_call_probing_succcess_threshold_) { RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Success", @@ -283,12 +299,6 @@ std::vector ProbeController::SetEstimatedBitrate( } } - if (bitrate_bps < kBitrateDropThreshold * estimated_bitrate_bps_) { - time_of_last_large_drop_ms_ = at_time_ms; - bitrate_before_last_large_drop_bps_ = estimated_bitrate_bps_; - } - - estimated_bitrate_bps_ = bitrate_bps; return pending_probes; } @@ -344,12 +354,19 @@ void ProbeController::SetMaxBitrate(int64_t max_bitrate_bps) { max_bitrate_bps_ = max_bitrate_bps; } +void ProbeController::SetNetworkStateEstimate( + webrtc::NetworkStateEstimate estimate) { + network_estimate_ = estimate; +} + void ProbeController::Reset(int64_t at_time_ms) { network_available_ = true; + bwe_limited_due_to_packet_loss_ = false; state_ = State::kInit; min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; time_last_probing_initiated_ms_ = 0; estimated_bitrate_bps_ = 0; + network_estimate_ = absl::nullopt; start_bitrate_bps_ = 0; max_bitrate_bps_ = 0; int64_t now_ms = at_time_ms; @@ -361,6 +378,28 @@ void ProbeController::Reset(int64_t at_time_ms) { max_total_allocated_bitrate_ = 0; } +bool ProbeController::TimeForAlrProbe(int64_t at_time_ms) const { + if (enable_periodic_alr_probing_ && alr_start_time_ms_) { + int64_t next_probe_time_ms = + std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) + + config_.alr_probing_interval->ms(); + return at_time_ms >= next_probe_time_ms; + } + return false; +} + +bool ProbeController::TimeForNetworkStateProbe(int64_t at_time_ms) const { + if (config_.network_state_estimate_probing_interval->IsFinite() && + network_estimate_ && network_estimate_->link_capacity_upper.IsFinite() && + estimated_bitrate_bps_ < network_estimate_->link_capacity_upper.bps()) { + int64_t next_probe_time_ms = + time_last_probing_initiated_ms_ + + config_.network_state_estimate_probing_interval->ms(); + return at_time_ms >= next_probe_time_ms; + } + return false; +} + std::vector ProbeController::Process(int64_t at_time_ms) { if (at_time_ms - time_last_probing_initiated_ms_ > kMaxWaitingTimeForProbingResultMs) { @@ -372,20 +411,14 @@ std::vector ProbeController::Process(int64_t at_time_ms) { min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; } } - - if (enable_periodic_alr_probing_ && state_ == State::kProbingComplete) { - // Probe bandwidth periodically when in ALR state. - if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) { - int64_t next_probe_time_ms = - std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) + - config_.alr_probing_interval->ms(); - if (at_time_ms >= next_probe_time_ms) { - return InitiateProbing(at_time_ms, - {static_cast(estimated_bitrate_bps_ * - config_.alr_probe_scale)}, - true); - } - } + if (estimated_bitrate_bps_ <= 0 || state_ != State::kProbingComplete) { + return {}; + } + if (TimeForAlrProbe(at_time_ms) || TimeForNetworkStateProbe(at_time_ms)) { + return InitiateProbing(at_time_ms, + {static_cast(estimated_bitrate_bps_ * + config_.alr_probe_scale)}, + true); } return std::vector(); } @@ -394,8 +427,20 @@ std::vector ProbeController::InitiateProbing( int64_t now_ms, std::vector bitrates_to_probe, bool probe_further) { + if (bwe_limited_due_to_packet_loss_ && + !config_.probe_if_bwe_limited_due_to_loss) { + return {}; + } int64_t max_probe_bitrate_bps = max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps; + if (config_.network_state_estimate_probing_interval->IsFinite() && + network_estimate_ && + network_estimate_->link_capacity_upper > DataRate::Zero()) { + max_probe_bitrate_bps = std::min( + max_probe_bitrate_bps, + static_cast(network_estimate_->link_capacity_upper.bps() * + config_.network_state_probe_scale)); + } if (max_total_allocated_bitrate_ > 0) { // If a max allocated bitrate has been configured, allow probing up to 2x // that rate. This allows some overhead to account for bursty streams, diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index d71c045d2b..14cbb6af1d 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -21,6 +21,7 @@ #include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/network_control.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -46,6 +47,10 @@ struct ProbeControllerConfig { FieldTrialParameter alr_probing_interval; FieldTrialParameter alr_probe_scale; + // Configures how often we send probes if NetworkStateEstimate is available. + FieldTrialParameter network_state_estimate_probing_interval; + FieldTrialParameter network_state_probe_scale; + // Configures the probes emitted by changed to the allocated bitrate. FieldTrialOptional first_allocation_probe_scale; FieldTrialOptional second_allocation_probe_scale; @@ -56,6 +61,8 @@ struct ProbeControllerConfig { FieldTrialParameter min_probe_packets_sent; // The minimum probing duration. FieldTrialParameter min_probe_duration; + + FieldTrialParameter probe_if_bwe_limited_due_to_loss; }; // This class controls initiation of probing to estimate initial channel @@ -86,7 +93,8 @@ class ProbeController { NetworkAvailability msg); ABSL_MUST_USE_RESULT std::vector SetEstimatedBitrate( - int64_t bitrate_bps, + int64_t target_bitrate_bps, + bool bwe_limited_due_to_packet_loss, int64_t at_time_ms); void EnablePeriodicAlrProbing(bool enable); @@ -99,6 +107,7 @@ class ProbeController { // Sets a new maximum probing bitrate, without generating a new probe cluster. void SetMaxBitrate(int64_t max_bitrate_bps); + void SetNetworkStateEstimate(webrtc::NetworkStateEstimate estimate); // Resets the ProbeController to a state equivalent to as if it was just // created EXCEPT for `enable_periodic_alr_probing_`. @@ -123,12 +132,16 @@ class ProbeController { int64_t now_ms, std::vector bitrates_to_probe, bool probe_further); + bool TimeForAlrProbe(int64_t at_time_ms) const; + bool TimeForNetworkStateProbe(int64_t at_time_ms) const; bool network_available_; + bool bwe_limited_due_to_packet_loss_; State state_; int64_t min_bitrate_to_probe_further_bps_; int64_t time_last_probing_initiated_ms_; int64_t estimated_bitrate_bps_; + absl::optional network_estimate_; int64_t start_bitrate_bps_; int64_t max_bitrate_bps_; int64_t last_bwe_drop_probing_time_ms_; diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 23329ee041..4587ecd014 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -121,12 +121,13 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); // Long enough to time out exponential probing. fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); - probes = - probe_controller->SetEstimatedBitrate(kStartBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probes = probe_controller->Process(fixture.NowMs()); probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps + 100, fixture.NowMs()); @@ -138,10 +139,11 @@ TEST(ProbeControllerTest, ProbesOnMaxBitrateIncreaseOnlyWhenInAlr) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(kMaxBitrateBps - 1, - fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + kMaxBitrateBps - 1, kBweLimitedDuetoPacketLoss, fixture.NowMs()); // Wait long enough to time out exponential probing. fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); @@ -165,15 +167,16 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); // Long enough to time out exponential probing. fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); - probes = - probe_controller->SetEstimatedBitrate(kStartBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probes = probe_controller->Process(fixture.NowMs()); - probes = - probe_controller->SetEstimatedBitrate(kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + kMaxBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps + 100, fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); @@ -184,15 +187,18 @@ TEST(ProbeControllerTest, TestExponentialProbing) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); // Repeated probe should only be sent when estimated bitrate climbs above // 0.7 * 6 * kStartBitrateBps = 1260. - probes = probe_controller->SetEstimatedBitrate(1000, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 1000, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); - probes = probe_controller->SetEstimatedBitrate(1800, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 1800, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800); } @@ -201,13 +207,15 @@ TEST(ProbeControllerTest, TestExponentialProbingTimeout) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); // Advance far enough to cause a time out in waiting for probing result. fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(1800, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 1800, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); } @@ -215,15 +223,18 @@ TEST(ProbeControllerTest, RequestProbeInAlr) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); EXPECT_GE(probes.size(), 2u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrStartTimeMs(fixture.NowMs()); fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(250, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 250, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probes = probe_controller->RequestProbe(fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); @@ -234,15 +245,18 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); EXPECT_EQ(probes.size(), 2u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrStartTimeMs(absl::nullopt); fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(250, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 250, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrEndedTimeMs(fixture.NowMs()); fixture.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1); probes = probe_controller->RequestProbe(fixture.NowMs()); @@ -255,15 +269,18 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); EXPECT_EQ(probes.size(), 2u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrStartTimeMs(absl::nullopt); fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(250, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 250, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrEndedTimeMs(fixture.NowMs()); fixture.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1); probes = probe_controller->RequestProbe(fixture.NowMs()); @@ -274,15 +291,18 @@ TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); EXPECT_EQ(probes.size(), 2u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); probe_controller->SetAlrStartTimeMs(fixture.NowMs()); fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(250, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 250, kBweLimitedDuetoPacketLoss, fixture.NowMs()); fixture.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1); probes = probe_controller->RequestProbe(fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); @@ -292,11 +312,13 @@ TEST(ProbeControllerTest, PeriodicProbing) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs()); EXPECT_EQ(probes.size(), 2u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); int64_t start_time = fixture.NowMs(); @@ -307,20 +329,23 @@ TEST(ProbeControllerTest, PeriodicProbing) { EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 1000); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); // The following probe should be sent at 10s into ALR. probe_controller->SetAlrStartTimeMs(start_time); fixture.AdvanceTimeMilliseconds(4000); probes = probe_controller->Process(fixture.NowMs()); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); probe_controller->SetAlrStartTimeMs(start_time); fixture.AdvanceTimeMilliseconds(1000); probes = probe_controller->Process(fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); - probes = probe_controller->SetEstimatedBitrate(500, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); } @@ -358,18 +383,19 @@ TEST(ProbeControllerTest, TestExponentialProbingOverflow) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; const int64_t kMbpsMultiplier = 1000000; auto probes = probe_controller->SetBitrates(kMinBitrateBps, 10 * kMbpsMultiplier, 100 * kMbpsMultiplier, fixture.NowMs()); // Verify that probe bitrate is capped at the specified max bitrate. - probes = probe_controller->SetEstimatedBitrate(60 * kMbpsMultiplier, - fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 60 * kMbpsMultiplier, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 100 * kMbpsMultiplier); // Verify that repeated probes aren't sent. - probes = probe_controller->SetEstimatedBitrate(100 * kMbpsMultiplier, - fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 100 * kMbpsMultiplier, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); } @@ -377,6 +403,7 @@ TEST(ProbeControllerTest, TestAllocatedBitrateCap) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; const int64_t kMbpsMultiplier = 1000000; const int64_t kMaxBitrateBps = 100 * kMbpsMultiplier; auto probes = probe_controller->SetBitrates( @@ -388,8 +415,8 @@ TEST(ProbeControllerTest, TestAllocatedBitrateCap) { probe_controller->SetAlrStartTimeMs(alr_start_time); int64_t estimated_bitrate_bps = kMaxBitrateBps / 10; - probes = probe_controller->SetEstimatedBitrate(estimated_bitrate_bps, - fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + estimated_bitrate_bps, kBweLimitedDuetoPacketLoss, fixture.NowMs()); // Set a max allocated bitrate below the current estimate. int64_t max_allocated_bps = estimated_bitrate_bps - 1 * kMbpsMultiplier; @@ -419,6 +446,7 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { "alloc_p1:2,alloc_p2/"); std::unique_ptr probe_controller = fixture.CreateController(); + const bool kBweLimitedDuetoPacketLoss = false; auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, 5000000, fixture.NowMs()); @@ -428,10 +456,12 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { // Repeated probe should only be sent when estimated bitrate climbs above // 0.8 * 5 * kStartBitrateBps = 1200. - probes = probe_controller->SetEstimatedBitrate(1100, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 1100, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 0u); - probes = probe_controller->SetEstimatedBitrate(1250, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 1250, kBweLimitedDuetoPacketLoss, fixture.NowMs()); EXPECT_EQ(probes.size(), 1u); EXPECT_EQ(probes[0].target_data_rate.bps(), 3 * 1250); @@ -445,5 +475,144 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { EXPECT_EQ(probes[0].target_data_rate.bps(), 400000); } +TEST(ProbeControllerTest, PauseAlrProbeWhenLossBasedBweLimited) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "probe_if_bwe_limited_due_to_loss:false/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + probe_controller->EnablePeriodicAlrProbing(true); + auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, + kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + // Expect the controller to send a new probe after 5s has passed. + probe_controller->SetAlrStartTimeMs(fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss*/ true, fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(6000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_TRUE(probes.empty()); + // ALR probing resumed when estimate is no longer restricted by loss based + // BWE. + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(6000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_TRUE(!probes.empty()); +} + +TEST(ProbeControllerTest, AlrProbeStartWhenNotLossBasedBweLimited) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "probe_if_bwe_limited_due_to_loss:false/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + probe_controller->EnablePeriodicAlrProbing(true); + auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, + kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/true, fixture.NowMs()); + // Expect the controller to send a new probe after 5s has passed. + probe_controller->SetAlrStartTimeMs(fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_TRUE(probes.empty()); + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss*/ false, fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(1000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_TRUE(!probes.empty()); +} + +TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, + kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 5000, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + // Expect the controller to send a new probe after 5s has passed. + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = DataRate::BitsPerSec(6000); + probe_controller->SetNetworkStateEstimate(state_estimate); + + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); +} + +TEST(ProbeControllerTest, + PausePeriodicProbeAtUpperNetworkStateEstimateIfLossBasedLimited) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,probe_if_bwe_limited_due_to_loss:false/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, + kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + // Expect the controller to send a new probe after 5s has passed. + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(600); + probe_controller->SetNetworkStateEstimate(state_estimate); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/true, fixture.NowMs()); + // Expect the controller to send a new probe after 5s has passed. + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_TRUE(probes.empty()); + + probes = probe_controller->SetEstimatedBitrate( + 500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + EXPECT_FALSE(probes.empty()); +} + +TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + probe_controller->EnablePeriodicAlrProbing(true); + auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps, + kMaxBitrateBps, fixture.NowMs()); + probes = probe_controller->SetEstimatedBitrate( + 6000, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs()); + probe_controller->SetAlrStartTimeMs(fixture.NowMs()); + + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps); + + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = DataRate::BitsPerSec(8000); + probe_controller->SetNetworkStateEstimate(state_estimate); + fixture.AdvanceTimeMilliseconds(5000); + probes = probe_controller->Process(fixture.NowMs()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); +} + } // namespace test } // namespace webrtc 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 cc117b998a..e61e839d59 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -317,6 +317,10 @@ DataRate SendSideBandwidthEstimation::target_rate() const { return std::max(min_bitrate_configured_, target); } +DataRate SendSideBandwidthEstimation::delay_based_limit() const { + return delay_based_limit_; +} + DataRate SendSideBandwidthEstimation::GetEstimatedLinkCapacity() const { return link_capacity_.estimate(); } 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 d79d285c19..4b60689302 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; + DataRate delay_based_limit() const; uint8_t fraction_loss() const { return last_fraction_loss_; } TimeDelta round_trip_time() const { return last_round_trip_time_; }