diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index e60c72224d..b9e6151877 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -89,6 +89,7 @@ ProbeControllerConfig::ProbeControllerConfig( TimeDelta::PlusInfinity()), network_state_estimate_fast_rampup_rate("network_state_fast_rampup_rate", 0), + network_state_estimate_drop_down_rate("network_state_drop_down_rate", 0), network_state_probe_scale("network_state_scale", 1.0), network_state_probe_duration("network_state_probe_duration", TimeDelta::Millis(15)), @@ -99,16 +100,17 @@ ProbeControllerConfig::ProbeControllerConfig( 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)), - probe_if_bwe_limited_due_to_loss("probe_if_bwe_limited_due_to_loss", - true) { + limit_probe_target_rate_to_loss_bwe("limit_probe_target_rate_to_loss_bwe", + false) { 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, &min_probe_duration, &network_state_estimate_probing_interval, - &network_state_estimate_fast_rampup_rate, &network_state_probe_scale, - &network_state_probe_duration, &probe_if_bwe_limited_due_to_loss}, + &network_state_estimate_fast_rampup_rate, + &network_state_estimate_drop_down_rate, &network_state_probe_scale, + &network_state_probe_duration, &limit_probe_target_rate_to_loss_bwe}, key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration @@ -364,6 +366,15 @@ void ProbeController::SetNetworkStateEstimate( network_estimate_->link_capacity_upper)) { send_probe_on_next_process_interval_ = true; } + if (config_.network_state_estimate_drop_down_rate > 0 && network_estimate_ && + (estimated_bitrate_ > estimate.link_capacity_upper || + bwe_limited_due_to_packet_loss_) && + estimate.link_capacity_upper <= + config_.network_state_estimate_drop_down_rate * + network_estimate_->link_capacity_upper) { + send_probe_on_next_process_interval_ = true; + } + network_estimate_ = estimate; } @@ -434,11 +445,11 @@ std::vector ProbeController::InitiateProbing( Timestamp now, std::vector bitrates_to_probe, bool probe_further) { - if (bwe_limited_due_to_packet_loss_ && - !config_.probe_if_bwe_limited_due_to_loss) { - return {}; - } DataRate max_probe_bitrate = max_bitrate_; + if (bwe_limited_due_to_packet_loss_ && + config_.limit_probe_target_rate_to_loss_bwe) { + max_probe_bitrate = estimated_bitrate_; + } if (config_.network_state_estimate_probing_interval->IsFinite() && network_estimate_ && network_estimate_->link_capacity_upper > DataRate::Zero()) { diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index 399b38ebca..c32f25e00a 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -53,6 +53,9 @@ struct ProbeControllerConfig { // If the network state estimate increase more than this rate, a probe is sent // the next process interval. FieldTrialParameter network_state_estimate_fast_rampup_rate; + // If the network state estimate decreases more than this rate, a probe is + // sent the next process interval. + FieldTrialParameter network_state_estimate_drop_down_rate; FieldTrialParameter network_state_probe_scale; // Overrides min_probe_duration if network_state_estimate_probing_interval // is set and a network state estimate is known. @@ -68,8 +71,9 @@ struct ProbeControllerConfig { FieldTrialParameter min_probe_packets_sent; // The minimum probing duration. FieldTrialParameter min_probe_duration; - - FieldTrialParameter probe_if_bwe_limited_due_to_loss; + // Max limit the target rate of a probe to current estimate if BWE is loss + // limited. + FieldTrialParameter limit_probe_target_rate_to_loss_bwe; }; // This class controls initiation of probing to estimate initial channel diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 8860a0f106..290760607d 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -504,10 +504,10 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { EXPECT_EQ(probes[0].target_data_rate.bps(), 400'000); } -TEST(ProbeControllerTest, PauseAlrProbeWhenLossBasedBweLimited) { +TEST(ProbeControllerTest, LimitAlrProbeWhenLossBasedBweLimited) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "probe_if_bwe_limited_due_to_loss:false/"); + "limit_probe_target_rate_to_loss_bwe:true/"); std::unique_ptr probe_controller = fixture.CreateController(); probe_controller->EnablePeriodicAlrProbing(true); @@ -527,40 +527,16 @@ TEST(ProbeControllerTest, PauseAlrProbeWhenLossBasedBweLimited) { fixture.CurrentTime()); fixture.AdvanceTime(TimeDelta::Seconds(6)); probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); - // ALR probing resumed when estimate is no longer restricted by loss based - // BWE. + 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()); - 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( - kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); - probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/true, - fixture.CurrentTime()); - // Expect the controller to send a new probe after 5s has passed. - probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); - fixture.AdvanceTime(TimeDelta::Seconds(5)); - probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); - probes = probe_controller->SetEstimatedBitrate( - DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss*/ false, - fixture.CurrentTime()); - fixture.AdvanceTime(TimeDelta::Seconds(1)); - probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(!probes.empty()); + ASSERT_TRUE(!probes.empty()); + EXPECT_GT(probes[0].target_data_rate, DataRate::BitsPerSec(500)); } TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { @@ -590,10 +566,10 @@ TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { } TEST(ProbeControllerTest, - PausePeriodicProbeAtUpperNetworkStateEstimateIfLossBasedLimited) { + LimitProbeAtUpperNetworkStateEstimateIfLossBasedLimited) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,probe_if_bwe_limited_due_to_loss:false/"); + "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); std::unique_ptr probe_controller = fixture.CreateController(); @@ -616,14 +592,16 @@ TEST(ProbeControllerTest, // Expect the controller to send a new probe after 5s has passed. fixture.AdvanceTime(TimeDelta::Seconds(5)); probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); + 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()); - EXPECT_FALSE(probes.empty()); + ASSERT_TRUE(!probes.empty()); + EXPECT_GT(probes[0].target_data_rate, DataRate::BitsPerSec(500)); } TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { @@ -677,7 +655,7 @@ TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100)); } -TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateChange) { +TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateIncrease) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" "network_state_interval:5s,network_state_fast_rampup_rate:2.0/"); @@ -716,5 +694,81 @@ TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateChange) { EXPECT_EQ(probes.size(), 1u); } +TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDrop) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_drop_down_rate:0.5/"); + 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, + fixture.CurrentTime()); + // 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 = kStartBitrate; + probe_controller->SetNetworkStateEstimate(state_estimate); + // No probe since NetworkStateEstimate is not lower than the set + // estimated bitrate. + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState decrease just a bit, dont expect the probe to be sent + // immediately. + state_estimate.link_capacity_upper = kStartBitrate * 0.9; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState decrease dramatically, expect a probe to be sent. + state_estimate.link_capacity_upper = kStartBitrate * 0.9 * 0.5; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); +} + +TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateDropLossLimited) { + 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()); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + fixture.CurrentTime()); + // 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 = kStartBitrate; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // Loss limited. + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate / 3, /*bwe_limited_due_to_packet_loss=*/true, + fixture.CurrentTime()); + // If NetworkState decrease dramatically, expect a probe to be sent. + // But limited to loss based estimate. + state_estimate.link_capacity_upper = kStartBitrate / 2; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate / 3); +} + } // namespace test } // namespace webrtc