/* * 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); aimd_rate_control.SetEstimate(DataRate::BitsPerSec(300'000), kInitialTime); 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, SetEstimateDefaultUpperLimitedByCurrentBitrateIfNetworkEstimateIsLow) { 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(500'000)); } TEST(AimdRateControlTest, SetEstimateNotUpperLimitedByCurrentBitrateIfNetworkEstimateIsLowIf) { AimdRateControl aimd_rate_control( ExplicitKeyValueConfig( "WebRTC-Bwe-EstimateBoundedIncrease/c_upper:false/"), /*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