summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc')
-rw-r--r--third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc314
1 files changed, 314 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
new file mode 100644
index 0000000000..f26afe995c
--- /dev/null
+++ b/third_party/libwebrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
@@ -0,0 +1,314 @@
+/*
+ * 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/remote_bitrate_estimator/aimd_rate_control.h"
+
+#include "api/units/data_rate.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "test/explicit_key_value_config.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::webrtc::test::ExplicitKeyValueConfig;
+
+constexpr Timestamp kInitialTime = Timestamp::Millis(123'456);
+
+constexpr TimeDelta kMinBwePeriod = TimeDelta::Seconds(2);
+constexpr TimeDelta kDefaultPeriod = TimeDelta::Seconds(3);
+constexpr TimeDelta kMaxBwePeriod = TimeDelta::Seconds(50);
+
+// After an overuse, we back off to 85% to the received bitrate.
+constexpr double kFractionAfterOveruse = 0.85;
+
+} // namespace
+
+TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(30'000), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 4'000);
+}
+
+TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(90'000), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 5'000);
+}
+
+TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(60'000), kInitialTime);
+ aimd_rate_control.SetRtt(TimeDelta::Millis(100));
+ EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 5'000);
+}
+
+TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kBitrate = DataRate::BitsPerSec(300'000);
+ aimd_rate_control.SetEstimate(kBitrate, kInitialTime);
+ aimd_rate_control.Update({BandwidthUsage::kBwOverusing, kBitrate},
+ kInitialTime);
+ EXPECT_NEAR(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 14'000,
+ 1'000);
+ EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(), kDefaultPeriod);
+}
+
+TEST(AimdRateControlTest, BweLimitedByAckedBitrate) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kAckedBitrate = DataRate::BitsPerSec(10'000);
+ Timestamp now = kInitialTime;
+ aimd_rate_control.SetEstimate(kAckedBitrate, now);
+ while (now - kInitialTime < TimeDelta::Seconds(20)) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kAckedBitrate}, now);
+ now += TimeDelta::Millis(100);
+ }
+ ASSERT_TRUE(aimd_rate_control.ValidEstimate());
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(),
+ 1.5 * kAckedBitrate + DataRate::BitsPerSec(10'000));
+}
+
+TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kAckedBitrate = DataRate::BitsPerSec(10'000);
+ Timestamp now = kInitialTime;
+ aimd_rate_control.SetEstimate(kAckedBitrate, now);
+ while (now - kInitialTime < TimeDelta::Seconds(20)) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kAckedBitrate}, now);
+ now += TimeDelta::Millis(100);
+ }
+ ASSERT_TRUE(aimd_rate_control.ValidEstimate());
+ // If the acked bitrate decreases the BWE shouldn't be reduced to 1.5x
+ // what's being acked, but also shouldn't get to increase more.
+ DataRate prev_estimate = aimd_rate_control.LatestEstimate();
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kAckedBitrate / 2}, now);
+ DataRate new_estimate = aimd_rate_control.LatestEstimate();
+ EXPECT_EQ(new_estimate, prev_estimate);
+ EXPECT_NEAR(new_estimate.bps(),
+ (1.5 * kAckedBitrate + DataRate::BitsPerSec(10'000)).bps(),
+ 2'000);
+}
+
+TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ aimd_rate_control.SetStartBitrate(DataRate::KilobitsPerSec(300));
+ EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(), kDefaultPeriod);
+ aimd_rate_control.Update(
+ {BandwidthUsage::kBwOverusing, DataRate::KilobitsPerSec(280)},
+ kInitialTime);
+ EXPECT_NE(aimd_rate_control.GetExpectedBandwidthPeriod(), kDefaultPeriod);
+}
+
+TEST(AimdRateControlTest, ExpectedPeriodAfterTypicalDrop) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ // The rate increase at 216 kbps should be 12 kbps. If we drop from
+ // 216 + 4*12 = 264 kbps, it should take 4 seconds to recover. Since we
+ // back off to 0.85*acked_rate-5kbps, the acked bitrate needs to be 260
+ // kbps to end up at 216 kbps.
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(264'000);
+ constexpr DataRate kUpdatedBitrate = DataRate::BitsPerSec(216'000);
+ const DataRate kAckedBitrate =
+ (kUpdatedBitrate + DataRate::BitsPerSec(5'000)) / kFractionAfterOveruse;
+ Timestamp now = kInitialTime;
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ now += TimeDelta::Millis(100);
+ aimd_rate_control.Update({BandwidthUsage::kBwOverusing, kAckedBitrate}, now);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(), kUpdatedBitrate);
+ EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 12'000);
+ EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(),
+ TimeDelta::Seconds(4));
+}
+
+TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(10'000);
+ Timestamp now = kInitialTime;
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ now += TimeDelta::Millis(100);
+ // Make a small (1.5 kbps) bitrate drop to 8.5 kbps.
+ aimd_rate_control.Update(
+ {BandwidthUsage::kBwOverusing, kInitialBitrate - DataRate::BitsPerSec(1)},
+ now);
+ EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(), kMinBwePeriod);
+}
+
+TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(10'010'000);
+ Timestamp now = kInitialTime;
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ now += TimeDelta::Millis(100);
+ // Make a large (10 Mbps) bitrate drop to 10 kbps.
+ const DataRate kAckedBitrate =
+ DataRate::BitsPerSec(10'000) / kFractionAfterOveruse;
+ aimd_rate_control.Update({BandwidthUsage::kBwOverusing, kAckedBitrate}, now);
+ EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(), kMaxBwePeriod);
+}
+
+TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""));
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(123'000);
+ Timestamp now = kInitialTime;
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kInitialBitrate}, now);
+ // AimdRateControl sets the initial bit rate to what it receives after
+ // five seconds has passed.
+ // TODO(bugs.webrtc.org/9379): The comment in the AimdRateControl does not
+ // match the constant.
+ constexpr TimeDelta kInitializationTime = TimeDelta::Seconds(5);
+ now += (kInitializationTime + TimeDelta::Millis(1));
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kInitialBitrate}, now);
+ for (int i = 0; i < 100; ++i) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, absl::nullopt}, now);
+ now += TimeDelta::Millis(100);
+ }
+ EXPECT_LE(aimd_rate_control.LatestEstimate(),
+ kInitialBitrate * 1.5 + DataRate::BitsPerSec(10'000));
+}
+
+TEST(AimdRateControlTest, EstimateDoesNotIncreaseInAlr) {
+ // When alr is detected, the delay based estimator is not allowed to increase
+ // bwe since there will be no feedback from the network if the new estimate
+ // is correct.
+ ExplicitKeyValueConfig field_trials(
+ "WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
+ AimdRateControl aimd_rate_control(field_trials, /*send_side=*/true);
+ Timestamp now = kInitialTime;
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(123'000);
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ aimd_rate_control.SetInApplicationLimitedRegion(true);
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kInitialBitrate}, now);
+ ASSERT_EQ(aimd_rate_control.LatestEstimate(), kInitialBitrate);
+
+ for (int i = 0; i < 100; ++i) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, absl::nullopt}, now);
+ now += TimeDelta::Millis(100);
+ }
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(), kInitialBitrate);
+}
+
+TEST(AimdRateControlTest, SetEstimateIncreaseBweInAlr) {
+ ExplicitKeyValueConfig field_trials(
+ "WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
+ AimdRateControl aimd_rate_control(field_trials, /*send_side=*/true);
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(123'000);
+ aimd_rate_control.SetEstimate(kInitialBitrate, kInitialTime);
+ aimd_rate_control.SetInApplicationLimitedRegion(true);
+ ASSERT_EQ(aimd_rate_control.LatestEstimate(), kInitialBitrate);
+ aimd_rate_control.SetEstimate(2 * kInitialBitrate, kInitialTime);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(), 2 * kInitialBitrate);
+}
+
+TEST(AimdRateControlTest, SetEstimateUpperLimitedByNetworkEstimate) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""),
+ /*send_side=*/true);
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_upper = DataRate::BitsPerSec(400'000);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(500'000), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(),
+ network_estimate.link_capacity_upper);
+}
+
+TEST(AimdRateControlTest,
+ SetEstimateUpperLimitedByCurrentBitrateIfNetworkEstimateIsLow) {
+ AimdRateControl aimd_rate_control(
+ ExplicitKeyValueConfig(
+ "WebRTC-Bwe-EstimateBoundedIncrease/c_upper:true/"),
+ /*send_side=*/true);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(500'000), kInitialTime);
+ ASSERT_EQ(aimd_rate_control.LatestEstimate(), DataRate::BitsPerSec(500'000));
+
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_upper = DataRate::BitsPerSec(300'000);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(700'000), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(), DataRate::BitsPerSec(500'000));
+}
+
+TEST(AimdRateControlTest,
+ SetEstimateDefaultNotUpperLimitedByCurrentBitrateIfNetworkEstimateIsLow) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""),
+ /*send_side=*/true);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(500'000), kInitialTime);
+ ASSERT_EQ(aimd_rate_control.LatestEstimate(), DataRate::BitsPerSec(500'000));
+
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_upper = DataRate::BitsPerSec(300'000);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(700'000), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(), DataRate::BitsPerSec(300'000));
+}
+
+TEST(AimdRateControlTest, SetEstimateLowerLimitedByNetworkEstimate) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""),
+ /*send_side=*/true);
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_lower = DataRate::BitsPerSec(400'000);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+ aimd_rate_control.SetEstimate(DataRate::BitsPerSec(100'000), kInitialTime);
+ // 0.85 is default backoff factor. (`beta_`)
+ EXPECT_EQ(aimd_rate_control.LatestEstimate(),
+ network_estimate.link_capacity_lower * 0.85);
+}
+
+TEST(AimdRateControlTest,
+ SetEstimateIgnoredIfLowerThanNetworkEstimateAndCurrent) {
+ AimdRateControl aimd_rate_control(ExplicitKeyValueConfig(""),
+ /*send_side=*/true);
+ aimd_rate_control.SetEstimate(DataRate::KilobitsPerSec(200), kInitialTime);
+ ASSERT_EQ(aimd_rate_control.LatestEstimate().kbps(), 200);
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_lower = DataRate::KilobitsPerSec(400);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+ // Ignore the next SetEstimate, since the estimate is lower than 85% of
+ // the network estimate.
+ aimd_rate_control.SetEstimate(DataRate::KilobitsPerSec(100), kInitialTime);
+ EXPECT_EQ(aimd_rate_control.LatestEstimate().kbps(), 200);
+}
+
+TEST(AimdRateControlTest, EstimateIncreaseWhileNotInAlr) {
+ // Allow the estimate to increase as long as alr is not detected to ensure
+ // tha BWE can not get stuck at a certain bitrate.
+ ExplicitKeyValueConfig field_trials(
+ "WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
+ AimdRateControl aimd_rate_control(field_trials, /*send_side=*/true);
+ Timestamp now = kInitialTime;
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(123'000);
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ aimd_rate_control.SetInApplicationLimitedRegion(false);
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, kInitialBitrate}, now);
+ for (int i = 0; i < 100; ++i) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, absl::nullopt}, now);
+ now += TimeDelta::Millis(100);
+ }
+ EXPECT_GT(aimd_rate_control.LatestEstimate(), kInitialBitrate);
+}
+
+TEST(AimdRateControlTest, EstimateNotLimitedByNetworkEstimateIfDisabled) {
+ ExplicitKeyValueConfig field_trials(
+ "WebRTC-Bwe-EstimateBoundedIncrease/Disabled/");
+ AimdRateControl aimd_rate_control(field_trials, /*send_side=*/true);
+ Timestamp now = kInitialTime;
+ constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(123'000);
+ aimd_rate_control.SetEstimate(kInitialBitrate, now);
+ aimd_rate_control.SetInApplicationLimitedRegion(false);
+ NetworkStateEstimate network_estimate;
+ network_estimate.link_capacity_upper = DataRate::KilobitsPerSec(150);
+ aimd_rate_control.SetNetworkStateEstimate(network_estimate);
+
+ for (int i = 0; i < 100; ++i) {
+ aimd_rate_control.Update({BandwidthUsage::kBwNormal, absl::nullopt}, now);
+ now += TimeDelta::Millis(100);
+ }
+ EXPECT_GT(aimd_rate_control.LatestEstimate(),
+ network_estimate.link_capacity_upper);
+}
+
+} // namespace webrtc