diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index 23dc0d47d6..e60c72224d 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -24,7 +24,6 @@ #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "rtc_base/numerics/safe_conversions.h" #include "system_wrappers/include/metrics.h" namespace webrtc { @@ -88,7 +87,12 @@ ProbeControllerConfig::ProbeControllerConfig( alr_probe_scale("alr_scale", 2), network_state_estimate_probing_interval("network_state_interval", TimeDelta::PlusInfinity()), + network_state_estimate_fast_rampup_rate("network_state_fast_rampup_rate", + 0), network_state_probe_scale("network_state_scale", 1.0), + network_state_probe_duration("network_state_probe_duration", + TimeDelta::Millis(15)), + first_allocation_probe_scale("alloc_p1", 1), second_allocation_probe_scale("alloc_p2", 2), allocation_allow_further_probing("alloc_probe_further", false), @@ -103,7 +107,8 @@ ProbeControllerConfig::ProbeControllerConfig( &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_probe_scale, &probe_if_bwe_limited_due_to_loss}, + &network_state_estimate_fast_rampup_rate, &network_state_probe_scale, + &network_state_probe_duration, &probe_if_bwe_limited_due_to_loss}, key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration @@ -249,7 +254,8 @@ std::vector ProbeController::InitiateExponentialProbing( // 1.2 Mbps to continue probing. std::vector probes = {config_.first_exponential_probe_scale * start_bitrate_}; - if (config_.second_exponential_probe_scale) { + if (config_.second_exponential_probe_scale && + config_.second_exponential_probe_scale.GetOptional().value() > 0) { probes.push_back(config_.second_exponential_probe_scale.Value() * start_bitrate_); } @@ -350,6 +356,14 @@ void ProbeController::SetMaxBitrate(DataRate max_bitrate) { void ProbeController::SetNetworkStateEstimate( webrtc::NetworkStateEstimate estimate) { + if (config_.network_state_estimate_fast_rampup_rate > 0 && + estimated_bitrate_ < estimate.link_capacity_upper && + (!network_estimate_ || + estimate.link_capacity_upper >= + config_.network_state_estimate_fast_rampup_rate * + network_estimate_->link_capacity_upper)) { + send_probe_on_next_process_interval_ = true; + } network_estimate_ = estimate; } @@ -370,6 +384,7 @@ void ProbeController::Reset(Timestamp at_time) { time_of_last_large_drop_ = now; bitrate_before_last_large_drop_ = DataRate::Zero(); max_total_allocated_bitrate_ = DataRate::Zero(); + send_probe_on_next_process_interval_ = false; } bool ProbeController::TimeForAlrProbe(Timestamp at_time) const { @@ -407,7 +422,8 @@ std::vector ProbeController::Process(Timestamp at_time) { if (estimated_bitrate_.IsZero() || state_ != State::kProbingComplete) { return {}; } - if (TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(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); } @@ -440,6 +456,7 @@ std::vector ProbeController::InitiateProbing( max_probe_bitrate = std::min(max_probe_bitrate, max_total_allocated_bitrate_ * 2); } + send_probe_on_next_process_interval_ = false; std::vector pending_probes; for (DataRate bitrate : bitrates_to_probe) { @@ -453,7 +470,13 @@ std::vector ProbeController::InitiateProbing( ProbeClusterConfig config; config.at_time = now; config.target_data_rate = bitrate; - config.target_duration = config_.min_probe_duration; + if (network_estimate_ && + config_.network_state_estimate_probing_interval->IsFinite()) { + config.target_duration = config_.network_state_probe_duration; + } else { + config.target_duration = config_.min_probe_duration; + } + config.target_probe_count = config_.min_probe_packets_sent; config.id = next_probe_cluster_id_; next_probe_cluster_id_++; diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index 489a335200..399b38ebca 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -50,7 +50,13 @@ struct ProbeControllerConfig { // Configures how often we send probes if NetworkStateEstimate is available. FieldTrialParameter network_state_estimate_probing_interval; + // 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; FieldTrialParameter network_state_probe_scale; + // Overrides min_probe_duration if network_state_estimate_probing_interval + // is set and a network state estimate is known. + FieldTrialParameter network_state_probe_duration; // Configures the probes emitted by changed to the allocated bitrate. FieldTrialOptional first_allocation_probe_scale; @@ -142,6 +148,7 @@ class ProbeController { DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity(); DataRate estimated_bitrate_ = DataRate::Zero(); + bool send_probe_on_next_process_interval_; absl::optional network_estimate_; DataRate start_bitrate_ = DataRate::Zero(); DataRate max_bitrate_ = DataRate::PlusInfinity(); diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 8070820a77..8860a0f106 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -108,6 +108,27 @@ TEST(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) { EXPECT_GE(probes.size(), 2u); } +TEST(ProbeControllerTest, CanConfigureInitialProbeRateFactor) { + ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:3/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 2u); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2); + EXPECT_EQ(probes[1].target_data_rate, kStartBitrate * 3); +} + +TEST(ProbeControllerTest, DisableSecondInitialProbeIfRateFactorZero) { + ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:0/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2); +} + TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = @@ -632,5 +653,68 @@ TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); } +TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_probe_duration:100ms/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probes = probe_controller->SetEstimatedBitrate( + DataRate::KilobitsPerSec(5), /*bwe_limited_due_to_packet_loss=*/false, + fixture.CurrentTime()); + ASSERT_FALSE(probes.empty()); + EXPECT_LT(probes[0].target_duration, TimeDelta::Millis(100)); + + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(6); + probe_controller->SetNetworkStateEstimate(state_estimate); + fixture.AdvanceTime(TimeDelta::Seconds(5)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100)); +} + +TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateChange) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_fast_rampup_rate:2.0/"); + 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 higher than the set + // estimated bitrate. + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState increase just a bit, dont expect the probe to be sent + // immediately. + state_estimate.link_capacity_upper = kStartBitrate * 1.4; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState increase dramatically, expect a probe to be sent. + state_estimate.link_capacity_upper = kStartBitrate * 1.4 * 2; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); +} + } // namespace test } // namespace webrtc