summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc')
-rw-r--r--third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc1313
1 files changed, 1313 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
new file mode 100644
index 0000000000..94025b30ea
--- /dev/null
+++ b/third_party/libwebrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/congestion_controller/goog_cc/probe_controller.h"
+
+#include <memory>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/transport/network_types.h"
+#include "api/units/data_rate.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
+#include "system_wrappers/include/clock.h"
+#include "test/explicit_key_value_config.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using ::testing::IsEmpty;
+using ::testing::NiceMock;
+
+namespace webrtc {
+namespace test {
+
+namespace {
+
+constexpr DataRate kMinBitrate = DataRate::BitsPerSec(100);
+constexpr DataRate kStartBitrate = DataRate::BitsPerSec(300);
+constexpr DataRate kMaxBitrate = DataRate::BitsPerSec(10000);
+
+constexpr TimeDelta kExponentialProbingTimeout = TimeDelta::Seconds(5);
+
+constexpr TimeDelta kAlrProbeInterval = TimeDelta::Seconds(5);
+constexpr TimeDelta kAlrEndedTimeout = TimeDelta::Seconds(3);
+constexpr TimeDelta kBitrateDropTimeout = TimeDelta::Seconds(5);
+} // namespace
+
+class ProbeControllerFixture {
+ public:
+ explicit ProbeControllerFixture(absl::string_view field_trials = "")
+ : field_trial_config_(field_trials), clock_(100000000L) {}
+
+ std::unique_ptr<ProbeController> CreateController() {
+ return std::make_unique<ProbeController>(&field_trial_config_,
+ &mock_rtc_event_log);
+ }
+
+ Timestamp CurrentTime() { return clock_.CurrentTime(); }
+ void AdvanceTime(TimeDelta delta) { clock_.AdvanceTime(delta); }
+
+ ExplicitKeyValueConfig field_trial_config_;
+ SimulatedClock clock_;
+ NiceMock<MockRtcEventLog> mock_rtc_event_log;
+};
+
+TEST(ProbeControllerTest, InitiatesProbingAfterSetBitrates) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_GE(probes.size(), 2u);
+}
+
+TEST(ProbeControllerTest, InitiatesProbingWhenNetworkAvailable) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+
+ std::vector<ProbeClusterConfig> probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_THAT(probes, IsEmpty());
+ probes = probe_controller->OnNetworkAvailability({.network_available = true});
+ EXPECT_GE(probes.size(), 2u);
+}
+
+TEST(ProbeControllerTest, SetsDefaultTargetDurationAndTargetProbeCount) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ std::vector<ProbeClusterConfig> probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_GE(probes.size(), 2u);
+
+ EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(15));
+ EXPECT_EQ(probes[0].target_probe_count, 5);
+}
+
+TEST(ProbeControllerTest,
+ FieldTrialsOverrideDefaultTargetDurationAndTargetProbeCount) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingBehavior/"
+ "min_probe_packets_sent:2,min_probe_duration:123ms/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ std::vector<ProbeClusterConfig> probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_GE(probes.size(), 2u);
+
+ EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(123));
+ EXPECT_EQ(probes[0].target_probe_count, 2);
+}
+
+TEST(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ auto probes = probe_controller->OnNetworkAvailability(
+ {.at_time = fixture.CurrentTime(), .network_available = false});
+ probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
+ kMaxBitrate, fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+ probes = probe_controller->OnNetworkAvailability(
+ {.at_time = fixture.CurrentTime(), .network_available = true});
+ EXPECT_GE(probes.size(), 2u);
+}
+
+TEST(ProbeControllerTest, CanConfigureInitialProbeRateFactor) {
+ ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:3/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ 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<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ 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<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ // Long enough to time out exponential probing.
+ fixture.AdvanceTime(kExponentialProbingTimeout);
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probes = probe_controller->Process(fixture.CurrentTime());
+ probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate + DataRate::BitsPerSec(100),
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrate.bps() + 100);
+}
+
+TEST(ProbeControllerTest, ProbesOnMaxAllocatedBitrateIncreaseOnlyWhenInAlr) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate - DataRate::BitsPerSec(1),
+ BandwidthLimitedCause::kDelayBasedLimited, 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());
+ 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);
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(
+ kMaxBitrate + DataRate::BitsPerSec(2), fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, CanDisableProbingOnMaxTotalAllocatedBitrateIncrease) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "probe_max_allocation:false/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate - DataRate::BitsPerSec(1),
+ BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime());
+ fixture.AdvanceTime(kExponentialProbingTimeout);
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_TRUE(probes.empty());
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+
+ // Do no probe, since probe_max_allocation:false.
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(
+ kMaxBitrate + DataRate::BitsPerSec(1), fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ // Long enough to time out exponential probing.
+ fixture.AdvanceTime(kExponentialProbingTimeout);
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probes = probe_controller->Process(fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate + DataRate::BitsPerSec(100),
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate,
+ kMaxBitrate + DataRate::BitsPerSec(100));
+}
+
+TEST(ProbeControllerTest, TestExponentialProbing) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+
+ // Repeated probe should only be sent when estimated bitrate climbs above
+ // 0.7 * 6 * kStartBitrate = 1260.
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(1000), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800);
+}
+
+TEST(ProbeControllerTest, TestExponentialProbingTimeout) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ // Advance far enough to cause a time out in waiting for probing result.
+ fixture.AdvanceTime(kExponentialProbingTimeout);
+ probes = probe_controller->Process(fixture.CurrentTime());
+
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, RequestProbeInAlr) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_GE(probes.size(), 2u);
+ probes = probe_controller->SetEstimatedBitrate(
+ 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), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probes = probe_controller->RequestProbe(fixture.CurrentTime());
+
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 0.85 * 500);
+}
+
+TEST(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+ probes = probe_controller->SetEstimatedBitrate(
+ 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), 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(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 0.85 * 500);
+}
+
+TEST(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+ probes = probe_controller->SetEstimatedBitrate(
+ 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), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms());
+ fixture.AdvanceTime(kAlrEndedTimeout + TimeDelta::Millis(1));
+ probes = probe_controller->RequestProbe(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+ probes = probe_controller->SetEstimatedBitrate(
+ 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), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ fixture.AdvanceTime(kBitrateDropTimeout + TimeDelta::Millis(1));
+ probes = probe_controller->RequestProbe(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, PeriodicProbing) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+
+ Timestamp start_time = fixture.CurrentTime();
+
+ // Expect the controller to send a new probe after 5s has passed.
+ probe_controller->SetAlrStartTimeMs(start_time.ms());
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 1000);
+
+ probes = probe_controller->SetEstimatedBitrate(
+ 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), 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), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, PeriodicProbingAfterReset) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ Timestamp alr_start_time = fixture.CurrentTime();
+
+ probe_controller->SetAlrStartTimeMs(alr_start_time.ms());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probe_controller->Reset(fixture.CurrentTime());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ // Since bitrates are not yet set, no probe is sent event though we are in ALR
+ // mode.
+ EXPECT_TRUE(probes.empty());
+
+ probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
+ kMaxBitrate, fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+
+ // Make sure we use `kStartBitrateBps` as the estimated bitrate
+ // until SetEstimatedBitrate is called with an updated estimate.
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2);
+}
+
+TEST(ProbeControllerTest, NoProbesWhenTransportIsNotWritable) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ probe_controller->EnablePeriodicAlrProbing(true);
+
+ std::vector<ProbeClusterConfig> probes =
+ probe_controller->OnNetworkAvailability({.network_available = false});
+ EXPECT_THAT(probes, IsEmpty());
+ EXPECT_THAT(probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
+ kMaxBitrate, fixture.CurrentTime()),
+ IsEmpty());
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ EXPECT_THAT(probe_controller->Process(fixture.CurrentTime()), IsEmpty());
+
+ // Controller is reset after a network route change.
+ // But, a probe should not be sent since the transport is not writable.
+ // Transport is not writable until after DTLS negotiation completes.
+ // However, the bitrate constraints may change.
+ probe_controller->Reset(fixture.CurrentTime());
+ EXPECT_THAT(
+ probe_controller->SetBitrates(2 * kMinBitrate, 2 * kStartBitrate,
+ 2 * kMaxBitrate, fixture.CurrentTime()),
+ IsEmpty());
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ EXPECT_THAT(probe_controller->Process(fixture.CurrentTime()), IsEmpty());
+}
+
+TEST(ProbeControllerTest, TestExponentialProbingOverflow) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000);
+ auto probes = probe_controller->SetBitrates(kMinBitrate, 10 * kMbpsMultiplier,
+ 100 * kMbpsMultiplier,
+ fixture.CurrentTime());
+ // Verify that probe bitrate is capped at the specified max bitrate.
+ probes = probe_controller->SetEstimatedBitrate(
+ 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, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, TestAllocatedBitrateCap) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000);
+ const DataRate kMaxBitrate = 100 * kMbpsMultiplier;
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, 10 * kMbpsMultiplier, kMaxBitrate, fixture.CurrentTime());
+
+ // Configure ALR for periodic probing.
+ probe_controller->EnablePeriodicAlrProbing(true);
+ Timestamp alr_start_time = fixture.CurrentTime();
+ probe_controller->SetAlrStartTimeMs(alr_start_time.ms());
+
+ DataRate estimated_bitrate = kMaxBitrate / 10;
+ probes = probe_controller->SetEstimatedBitrate(
+ estimated_bitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+
+ // Set a max allocated bitrate below the current estimate.
+ DataRate max_allocated = estimated_bitrate - 1 * kMbpsMultiplier;
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(max_allocated,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty()); // No probe since lower than current max.
+
+ // Probes such as ALR capped at 2x the max allocation limit.
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, 2 * max_allocated);
+
+ // Remove allocation limit.
+ EXPECT_TRUE(
+ probe_controller
+ ->OnMaxTotalAllocatedBitrate(DataRate::Zero(), fixture.CurrentTime())
+ .empty());
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, estimated_bitrate * 2);
+}
+
+TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "p1:2,p2:5,step_size:3,further_probe_threshold:0.8,"
+ "alloc_p1:2,alloc_p2,min_probe_packets_sent:2/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
+ DataRate::KilobitsPerSec(5000),
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 2u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 600);
+ EXPECT_EQ(probes[0].target_probe_count, 2);
+ EXPECT_EQ(probes[1].target_data_rate.bps(), 1500);
+ EXPECT_EQ(probes[1].target_probe_count, 2);
+
+ // Repeated probe should only be sent when estimated bitrate climbs above
+ // 0.8 * 5 * kStartBitrateBps = 1200.
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(1100), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 0u);
+
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(1250), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 3 * 1250);
+
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(
+ DataRate::KilobitsPerSec(200), fixture.CurrentTime());
+ EXPECT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate.bps(), 400'000);
+}
+
+TEST(ProbeControllerTest, LimitAlrProbeWhenLossBasedBweLimited) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ 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());
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(500),
+ BandwidthLimitedCause::kLossLimitedBweIncreasing, 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, 1.5 * DataRate::BitsPerSec(500));
+
+ probes = probe_controller->SetEstimatedBitrate(
+ 1.5 * DataRate::BitsPerSec(500),
+ BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime());
+ fixture.AdvanceTime(TimeDelta::Seconds(6));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ EXPECT_GT(probes[0].target_data_rate, 1.5 * 1.5 * DataRate::BitsPerSec(500));
+}
+
+TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(5000), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ // Expect the controller to send a new probe after 5s has passed.
+ 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_data_rate, state_estimate.link_capacity_upper);
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper);
+}
+
+TEST(ProbeControllerTest,
+ LimitProbeAtUpperNetworkStateEstimateIfLossBasedLimited) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(500), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ // Expect the controller to send a new probe after 5s has passed.
+ NetworkStateEstimate state_estimate;
+ state_estimate.link_capacity_upper = DataRate::BitsPerSec(700);
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::BitsPerSec(500),
+ BandwidthLimitedCause::kLossLimitedBweIncreasing, 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_FALSE(probes.empty());
+ EXPECT_EQ(probes[0].target_data_rate, DataRate::BitsPerSec(700));
+}
+
+TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::KilobitsPerSec(6), BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, kMaxBitrate);
+
+ NetworkStateEstimate state_estimate;
+ state_estimate.link_capacity_upper = DataRate::BitsPerSec(8000);
+ 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_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<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ DataRate::KilobitsPerSec(5), BandwidthLimitedCause::kDelayBasedLimited,
+ 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, ProbeInAlrIfLossBasedIncreasing) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ 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());
+ ASSERT_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());
+ ASSERT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes.at(0).target_data_rate, 1.5 * kStartBitrate);
+}
+
+TEST(ProbeControllerTest, ProbeFurtherInAlrIfLossBasedIncreasing) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ 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());
+ ASSERT_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());
+ ASSERT_EQ(probes.size(), 1u);
+ ASSERT_EQ(probes.at(0).target_data_rate, 1.5 * kStartBitrate);
+
+ probes = probe_controller->SetEstimatedBitrate(
+ 1.5 * kStartBitrate, BandwidthLimitedCause::kLossLimitedBweIncreasing,
+ fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+ EXPECT_EQ(probes[0].target_data_rate, 1.5 * 1.5 * kStartBitrate);
+}
+
+TEST(ProbeControllerTest, NotProbeWhenInAlrIfLossBasedDecreases) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kLossLimitedBwe,
+ fixture.CurrentTime());
+
+ // Wait long enough to time out exponential probing.
+ fixture.AdvanceTime(kExponentialProbingTimeout);
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_TRUE(probes.empty());
+
+ // Not probe in alr when loss based estimate decreases.
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, NotProbeIfLossBasedIncreasingOutsideAlr) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ 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());
+ ASSERT_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, ProbeFurtherWhenLossBasedIsSameAsDelayBasedEstimate) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ 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());
+ ASSERT_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());
+ ASSERT_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());
+ ASSERT_FALSE(probes.empty());
+ EXPECT_EQ(probes[0].target_data_rate, 2 * probe_target_rate);
+}
+
+TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) {
+ // Periodic probe every 1 second if estimate is lower than 50% of the
+ // NetworkStateEstimate.
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/est_lower_than_network_interval:1s,"
+ "est_lower_than_network_ratio:0.5,limit_probe_"
+ "target_rate_to_loss_bwe:true/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ 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());
+
+ state_estimate.link_capacity_upper = kStartBitrate * 3;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_EQ(probes.size(), 1u);
+ EXPECT_GT(probes[0].target_data_rate, kStartBitrate);
+
+ // If network state not increased, send another probe.
+ fixture.AdvanceTime(TimeDelta::Millis(1100));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+
+ // Stop probing if estimate increase. We might probe further here though.
+ probes = probe_controller->SetEstimatedBitrate(
+ 2 * kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ // No more periodic probes.
+ fixture.AdvanceTime(TimeDelta::Millis(1100));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, DontProbeFurtherWhenLossLimited) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ 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 = 3 * kStartBitrate;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+ 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, BandwidthLimitedCause::kLossLimitedBwe,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, ProbeFurtherWhenDelayBasedLimited) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ 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 = 3 * kStartBitrate;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+ 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, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+ EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper);
+}
+
+TEST(ProbeControllerTest,
+ ProbeFurtherIfNetworkStateEstimateIncreaseAfterProbeSent) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ NetworkStateEstimate state_estimate;
+ state_estimate.link_capacity_upper = 1.2 * probes[0].target_data_rate / 2;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ // No immediate further probing since probe result is low.
+ probes = probe_controller->SetEstimatedBitrate(
+ probes[0].target_data_rate / 2, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ ASSERT_TRUE(probes.empty());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ EXPECT_LE(probes[0].target_data_rate, state_estimate.link_capacity_upper);
+ // If the network state estimate increase above the threshold to probe
+ // further, and the probe suceeed, expect a new probe.
+ state_estimate.link_capacity_upper = 3 * kStartBitrate;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ probes = probe_controller->SetEstimatedBitrate(
+ probes[0].target_data_rate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+
+ // But no more probes if estimate is close to the link capacity.
+ probes = probe_controller->SetEstimatedBitrate(
+ state_estimate.link_capacity_upper * 0.9,
+ BandwidthLimitedCause::kDelayBasedLimited, fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, SkipAlrProbeIfEstimateLargerThanMaxProbe) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "skip_if_est_larger_than_fraction_of_max:0.9/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ // But if the max rate increase, A new probe is sent.
+ probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, 2 * kMaxBitrate, fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+}
+
+TEST(ProbeControllerTest,
+ SkipAlrProbeIfEstimateLargerThanFractionOfMaxAllocated) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "skip_if_est_larger_than_fraction_of_max:1.0/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate / 2, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(kMaxBitrate / 2,
+ fixture.CurrentTime());
+ // No probes since total allocated is not higher than the current estimate.
+ EXPECT_TRUE(probes.empty());
+ fixture.AdvanceTime(TimeDelta::Seconds(2));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ // But if the max allocated increase, A new probe is sent.
+ probes = probe_controller->OnMaxTotalAllocatedBitrate(
+ kMaxBitrate / 2 + DataRate::BitsPerSec(1), fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+}
+
+TEST(ProbeControllerTest, SkipNetworkStateProbeIfEstimateLargerThanMaxProbe) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:2s,skip_if_est_larger_than_fraction_of_max:0.9/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+
+ probe_controller->SetNetworkStateEstimate(
+ {.link_capacity_upper = 2 * kMaxBitrate});
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(10));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:2s,skip_if_est_larger_than_fraction_of_max:0.9,"
+ "/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ probe_controller->SetNetworkStateEstimate(
+ {.link_capacity_upper = 2 * kMaxBitrate});
+ probes = probe_controller->SetEstimatedBitrate(
+ kMaxBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+
+ // Need to wait at least two seconds before process can trigger a new probe.
+ fixture.AdvanceTime(TimeDelta::Millis(2100));
+
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+ probe_controller->SetNetworkStateEstimate(
+ {.link_capacity_upper = 2 * kStartBitrate});
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_FALSE(probes.empty());
+}
+
+TEST(ProbeControllerTest,
+ ProbeNotLimitedByNetworkStateEsimateIfLowerThantCurrent) {
+ ProbeControllerFixture fixture(
+ "WebRTC-Bwe-ProbingConfiguration/"
+ "network_state_interval:5s/");
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+ probe_controller->EnablePeriodicAlrProbing(true);
+ auto probes = probe_controller->SetBitrates(
+ kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimited,
+ fixture.CurrentTime());
+ probe_controller->SetNetworkStateEstimate(
+ {.link_capacity_upper = kStartBitrate});
+ // 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());
+ ASSERT_TRUE(probes.empty());
+
+ probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
+ probe_controller->SetNetworkStateEstimate(
+ {.link_capacity_upper = kStartBitrate / 2});
+ fixture.AdvanceTime(TimeDelta::Seconds(6));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ ASSERT_FALSE(probes.empty());
+ EXPECT_EQ(probes[0].target_data_rate, kStartBitrate);
+}
+
+TEST(ProbeControllerTest, DontProbeIfDelayIncreased) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ 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());
+ ASSERT_TRUE(probes.empty());
+
+ NetworkStateEstimate state_estimate;
+ state_estimate.link_capacity_upper = 3 * kStartBitrate;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased,
+ fixture.CurrentTime());
+ ASSERT_TRUE(probes.empty());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+
+TEST(ProbeControllerTest, DontProbeIfHighRtt) {
+ ProbeControllerFixture fixture;
+ std::unique_ptr<ProbeController> probe_controller =
+ fixture.CreateController();
+ ASSERT_THAT(
+ probe_controller->OnNetworkAvailability({.network_available = true}),
+ IsEmpty());
+
+ 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());
+ ASSERT_TRUE(probes.empty());
+
+ NetworkStateEstimate state_estimate;
+ state_estimate.link_capacity_upper = 3 * kStartBitrate;
+ probe_controller->SetNetworkStateEstimate(state_estimate);
+ probes = probe_controller->SetEstimatedBitrate(
+ kStartBitrate, BandwidthLimitedCause::kRttBasedBackOffHighRtt,
+ fixture.CurrentTime());
+ ASSERT_TRUE(probes.empty());
+
+ fixture.AdvanceTime(TimeDelta::Seconds(5));
+ probes = probe_controller->Process(fixture.CurrentTime());
+ EXPECT_TRUE(probes.empty());
+}
+} // namespace test
+} // namespace webrtc