webrtc/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
Per Kjellander 43e11c881b Field trials for ProbeController when a network state estimate is known.
Ensure initial second probe can be disabled.
Can configure separate probe duration if the network state estimate is known.
Can probe immediately if network state estimate increase more than a factor

Bug: webrtc:14392
Change-Id: Iefb980f0b10c7c51db62793c3bd3f187fc67593d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273349
Reviewed-by: Diep Bui <diepbp@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37966}
2022-08-31 09:49:36 +00:00

720 lines
30 KiB
C++

/*
* 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 "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 "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"
#include "test/explicit_key_value_config.h"
#include "test/gmock.h"
#include "test/gtest.h"
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, InitiatesProbingAtStart) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
EXPECT_GE(probes.size(), 2u);
}
TEST(ProbeControllerTest, SetsDefaultTargetDurationAndTargetProbeCount) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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();
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_EQ(probes.size(), 0u);
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();
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();
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();
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, /*bwe_limited_due_to_packet_loss=*/false,
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, ProbesOnMaxBitrateIncreaseOnlyWhenInAlr) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
kMaxBitrate - DataRate::BitsPerSec(1),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
// Wait long enough to time out exponential probing.
fixture.AdvanceTime(kExponentialProbingTimeout);
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
// 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);
// 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, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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, /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
probes = probe_controller->Process(fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false,
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();
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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(1800),
/*bwe_limited_due_to_packet_loss=*/false, 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();
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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
}
TEST(ProbeControllerTest, RequestProbeInAlr) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
EXPECT_GE(probes.size(), 2u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, 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();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 2u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, 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();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 2u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms());
fixture.AdvanceTime(kAlrEndedTimeout + TimeDelta::Millis(1));
probes = probe_controller->RequestProbe(fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
}
TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 2u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
fixture.AdvanceTime(kBitrateDropTimeout + TimeDelta::Millis(1));
probes = probe_controller->RequestProbe(fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
}
TEST(ProbeControllerTest, PeriodicProbing) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, 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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
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),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
}
TEST(ProbeControllerTest, PeriodicProbingAfterReset) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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_EQ(probes.size(), 0u);
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, TestExponentialProbingOverflow) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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, /*bwe_limited_due_to_packet_loss=*/false,
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, /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
}
TEST(ProbeControllerTest, TestAllocatedBitrateCap) {
ProbeControllerFixture fixture;
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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, /*bwe_limited_due_to_packet_loss=*/false,
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/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
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[1].target_data_rate.bps(), 1500);
// Repeated probe should only be sent when estimated bitrate climbs above
// 0.8 * 5 * kStartBitrateBps = 1200.
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(1100),
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
EXPECT_EQ(probes.size(), 0u);
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(1250),
/*bwe_limited_due_to_packet_loss=*/false, 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, PauseAlrProbeWhenLossBasedBweLimited) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/"
"probe_if_bwe_limited_due_to_loss:false/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
probe_controller->EnablePeriodicAlrProbing(true);
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
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), /*bwe_limited_due_to_packet_loss*/ true,
fixture.CurrentTime());
fixture.AdvanceTime(TimeDelta::Seconds(6));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(probes.empty());
// ALR probing resumed when estimate is no longer restricted by loss based
// BWE.
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
fixture.AdvanceTime(TimeDelta::Seconds(6));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(!probes.empty());
}
TEST(ProbeControllerTest, AlrProbeStartWhenNotLossBasedBweLimited) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/"
"probe_if_bwe_limited_due_to_loss:false/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
probe_controller->EnablePeriodicAlrProbing(true);
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/true,
fixture.CurrentTime());
// Expect the controller to send a new probe after 5s has passed.
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
fixture.AdvanceTime(TimeDelta::Seconds(5));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(probes.empty());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss*/ false,
fixture.CurrentTime());
fixture.AdvanceTime(TimeDelta::Seconds(1));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(!probes.empty());
}
TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(5000), /*bwe_limited_due_to_packet_loss=*/false,
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,
PausePeriodicProbeAtUpperNetworkStateEstimateIfLossBasedLimited) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/"
"network_state_interval:5s,probe_if_bwe_limited_due_to_loss:false/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
// Expect the controller to send a new probe after 5s has passed.
NetworkStateEstimate state_estimate;
state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(600);
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), /*bwe_limited_due_to_packet_loss=*/true,
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());
EXPECT_TRUE(probes.empty());
probes = probe_controller->SetEstimatedBitrate(
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
fixture.AdvanceTime(TimeDelta::Seconds(5));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_FALSE(probes.empty());
}
TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
probe_controller->EnablePeriodicAlrProbing(true);
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::KilobitsPerSec(6), /*bwe_limited_due_to_packet_loss=*/false,
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();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
DataRate::KilobitsPerSec(5), /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
ASSERT_FALSE(probes.empty());
EXPECT_LT(probes[0].target_duration, TimeDelta::Millis(100));
NetworkStateEstimate state_estimate;
state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(6);
probe_controller->SetNetworkStateEstimate(state_estimate);
fixture.AdvanceTime(TimeDelta::Seconds(5));
probes = probe_controller->Process(fixture.CurrentTime());
ASSERT_EQ(probes.size(), 1u);
EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100));
}
TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateChange) {
ProbeControllerFixture fixture(
"WebRTC-Bwe-ProbingConfiguration/"
"network_state_interval:5s,network_state_fast_rampup_rate:2.0/");
std::unique_ptr<ProbeController> probe_controller =
fixture.CreateController();
auto probes = probe_controller->SetBitrates(
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
probes = probe_controller->SetEstimatedBitrate(
kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false,
fixture.CurrentTime());
// Need to wait at least one second before process can trigger a new probe.
fixture.AdvanceTime(TimeDelta::Millis(1100));
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(probes.empty());
NetworkStateEstimate state_estimate;
state_estimate.link_capacity_upper = kStartBitrate;
probe_controller->SetNetworkStateEstimate(state_estimate);
// No probe since NetworkStateEstimate is not higher than the set
// estimated bitrate.
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(probes.empty());
// If NetworkState increase just a bit, dont expect the probe to be sent
// immediately.
state_estimate.link_capacity_upper = kStartBitrate * 1.4;
probe_controller->SetNetworkStateEstimate(state_estimate);
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_TRUE(probes.empty());
// If NetworkState increase dramatically, expect a probe to be sent.
state_estimate.link_capacity_upper = kStartBitrate * 1.4 * 2;
probe_controller->SetNetworkStateEstimate(state_estimate);
probes = probe_controller->Process(fixture.CurrentTime());
EXPECT_EQ(probes.size(), 1u);
}
} // namespace test
} // namespace webrtc