diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index 36d61bf9fc..8961675f9c 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -476,6 +476,14 @@ std::vector ProbeController::Process(Timestamp at_time) { if (at_time - time_last_probing_initiated_ > kMaxWaitingTimeForProbingResult) { if (state_ == State::kWaitingForProbingResult) { + // If the initial probe timed out, and the estimate has not changed by + // other means, (likely because normal media packets are not being sent + // yet), then send a probe again. + if (waiting_for_initial_probe_result_ && + estimated_bitrate_ == start_bitrate_ && first_probe_to_max_bitrate_) { + UpdateState(State::kInit); + return InitiateExponentialProbing(at_time); + } RTC_LOG(LS_INFO) << "kWaitingForProbingResult: timeout"; UpdateState(State::kProbingComplete); } diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 8024fec4dd..6691e87d3d 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -438,7 +438,7 @@ TEST(ProbeControllerTest, EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * kStartBitrate.bps()); } -TEST(ProbeControllerTest, TestExponentialProbingTimeout) { +TEST(ProbeControllerTest, InitialProbingTimeout) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); @@ -447,14 +447,57 @@ TEST(ProbeControllerTest, TestExponentialProbingTimeout) { IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_THAT(probes, SizeIs(Gt(0))); // Advance far enough to cause a time out in waiting for probing result. fixture.AdvanceTime(kExponentialProbingTimeout); probes = probe_controller->Process(fixture.CurrentTime()); - + EXPECT_THAT(probes, IsEmpty()); probes = probe_controller->SetEstimatedBitrate( DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); + EXPECT_THAT(probes, IsEmpty()); +} + +TEST( + ProbeControllerTest, + InitialProbingRetriedAfterTimeoutIfFirstProbeToMaxBitrateAndBweNotUpdated) { + ProbeControllerFixture fixture; + std::unique_ptr probe_controller = + fixture.CreateController(); + probe_controller->SetFirstProbeToMaxBitrate(true); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_THAT(probes, SizeIs(Gt(0))); + // Advance far enough to cause a time out in waiting for probing result. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_THAT(probes, SizeIs(Gt(0))); +} + +TEST(ProbeControllerTest, + InitialProbingNotRetriedAfterTimeoutIfFirstProbeAndBweUpdated) { + ProbeControllerFixture fixture; + std::unique_ptr probe_controller = + fixture.CreateController(); + probe_controller->SetFirstProbeToMaxBitrate(true); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_THAT(probes, SizeIs(Gt(0))); + fixture.AdvanceTime(TimeDelta::Millis(700)); + probes = probe_controller->SetEstimatedBitrate( + DataRate::BitsPerSec(180), BandwidthLimitedCause::kDelayBasedLimited, + fixture.CurrentTime()); + EXPECT_THAT(probes, IsEmpty()); + // Advance far enough to cause a time out in waiting for probing result. + fixture.AdvanceTime(kExponentialProbingTimeout); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_THAT(probes, IsEmpty()); } TEST(ProbeControllerTest, RequestProbeInAlr) {