| /* |
| * 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 |