diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.cc b/modules/remote_bitrate_estimator/aimd_rate_control.cc index 96b0534cde..37c25290bd 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -68,7 +68,9 @@ AimdRateControl::AimdRateControl() ? ReadTrendlineFilterWindowSize() : kDefaultBackoffFactor), rtt_(kDefaultRttMs), - in_experiment_(!AdaptiveThresholdExperimentIsDisabled()) { + in_experiment_(!AdaptiveThresholdExperimentIsDisabled()), + smoothing_experiment_( + webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")) { LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_; } @@ -166,13 +168,13 @@ int AimdRateControl::GetNearMaxIncreaseRateBps() const { } int AimdRateControl::GetExpectedBandwidthPeriodMs() const { - constexpr int kMinPeriodMs = 2000; + const int kMinPeriodMs = smoothing_experiment_ ? 500 : 2000; constexpr int kDefaultPeriodMs = 3000; constexpr int kMaxPeriodMs = 50000; int increase_rate = GetNearMaxIncreaseRateBps(); if (!last_decrease_) - return kDefaultPeriodMs; + return smoothing_experiment_ ? kMinPeriodMs : kDefaultPeriodMs; return std::min(kMaxPeriodMs, std::max(1000 * static_cast(*last_decrease_) / @@ -241,8 +243,18 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps, if (bitrate_is_initialized_ && incoming_bitrate_bps < current_bitrate_bps_) { - last_decrease_ = - rtc::Optional(current_bitrate_bps_ - new_bitrate_bps); + constexpr float kDegradationFactor = 0.9f; + if (smoothing_experiment_ && + new_bitrate_bps < + kDegradationFactor * beta_ * current_bitrate_bps_) { + // If bitrate decreases more than a normal back off after overuse, it + // indicates a real network degradation. We do not let such a decrease + // to determine the bandwidth estimation period. + last_decrease_ = rtc::Optional(); + } else { + last_decrease_ = + rtc::Optional(current_bitrate_bps_ - new_bitrate_bps); + } } if (incoming_bitrate_kbps < avg_max_bitrate_kbps_ - 3 * std_max_bit_rate) { diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.h b/modules/remote_bitrate_estimator/aimd_rate_control.h index 769429a280..a9ecb67c34 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -85,6 +85,7 @@ class AimdRateControl { float beta_; int64_t rtt_; bool in_experiment_; + bool smoothing_experiment_; rtc::Optional last_decrease_; }; } // namespace webrtc diff --git a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc index 690eb688f0..1e894d93d3 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc @@ -11,6 +11,7 @@ #include "modules/remote_bitrate_estimator/aimd_rate_control.h" #include "system_wrappers/include/clock.h" +#include "test/field_trial.h" #include "test/gtest.h" namespace webrtc { @@ -18,9 +19,12 @@ namespace { constexpr int64_t kClockInitialTime = 123456; -constexpr int kMinBwePeriodMs = 2000; +constexpr int kMinBwePeriodMsSmoothingExp = 500; +constexpr int kMinBwePeriodMsNoSmoothingExp = 2000; +constexpr int kDefaultPeriodMsNoSmoothingExp = 3000; constexpr int kMaxBwePeriodMs = 50000; -constexpr int kDefaultPeriodMs = 3000; +constexpr char kSmoothingExpFieldTrial[] = + "WebRTC-Audio-BandwidthSmoothing/Enabled/"; // After an overuse, we back off to 85% to the received bitrate. constexpr double kFractionAfterOveruse = 0.85; @@ -74,6 +78,7 @@ TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) { } TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) { + // Smoothing experiment disabled auto states = CreateAimdRateControlStates(); constexpr int kBitrate = 300000; states.aimd_rate_control->SetEstimate( @@ -82,7 +87,23 @@ TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) { states.simulated_clock->TimeInMilliseconds()); EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(), 1000); - EXPECT_EQ(3000, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); + EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); +} + +TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) { + // Smoothing experiment enabled + test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); + auto states = CreateAimdRateControlStates(); + constexpr int kBitrate = 300000; + states.aimd_rate_control->SetEstimate( + kBitrate, states.simulated_clock->TimeInMilliseconds()); + UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(), + 1000); + EXPECT_EQ(kMinBwePeriodMsSmoothingExp, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); } TEST(AimdRateControlTest, BweLimitedByAckedBitrate) { @@ -125,14 +146,29 @@ TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) { } TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) { + // Smoothing experiment disabled auto states = CreateAimdRateControlStates(); states.aimd_rate_control->SetStartBitrate(300000); - EXPECT_EQ(kDefaultPeriodMs, + EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.simulated_clock->AdvanceTimeMilliseconds(100); - UpdateRateControl(states, BandwidthUsage::kBwOverusing, 100000, + UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000, states.simulated_clock->TimeInMilliseconds()); - EXPECT_NE(kDefaultPeriodMs, + EXPECT_NE(kDefaultPeriodMsNoSmoothingExp, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); +} + +TEST(AimdRateControlTest, MinPeriodUntilFirstOveruseSmoothingExp) { + // Smoothing experiment enabled + test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); + auto states = CreateAimdRateControlStates(); + states.aimd_rate_control->SetStartBitrate(300000); + EXPECT_EQ(kMinBwePeriodMsSmoothingExp, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); + states.simulated_clock->AdvanceTimeMilliseconds(100); + UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_NE(kMinBwePeriodMsSmoothingExp, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); } @@ -152,6 +188,23 @@ TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) { EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); } +TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) { + // Smoothing experiment enabled + test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); + auto states = CreateAimdRateControlStates(); + constexpr int kInitialBitrate = 110000; + states.aimd_rate_control->SetEstimate( + kInitialBitrate, states.simulated_clock->TimeInMilliseconds()); + states.simulated_clock->AdvanceTimeMilliseconds(100); + // Make such a large drop in bitrate that should be treated as network + // degradation. + constexpr int kAckedBitrate = kInitialBitrate * 3 / 4 / kFractionAfterOveruse; + UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(kMinBwePeriodMsSmoothingExp, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); +} + TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) { auto states = CreateAimdRateControlStates(); constexpr int kInitialBitrate = 10000; @@ -161,11 +214,27 @@ TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) { // Make a small (1.5 kbps) bitrate drop to 8.5 kbps. UpdateRateControl(states, BandwidthUsage::kBwOverusing, kInitialBitrate - 1, states.simulated_clock->TimeInMilliseconds()); - EXPECT_EQ(kMinBwePeriodMs, + EXPECT_EQ(kMinBwePeriodMsNoSmoothingExp, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); } -TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMax) { +TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) { + // Smoothing experiment enabled + test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); + auto states = CreateAimdRateControlStates(); + constexpr int kInitialBitrate = 50000000; + states.aimd_rate_control->SetEstimate( + kInitialBitrate, states.simulated_clock->TimeInMilliseconds()); + states.simulated_clock->AdvanceTimeMilliseconds(100); + // Make a large (10 Mbps) bitrate drop to 10 kbps. + constexpr int kAckedBitrate = 40000000 / kFractionAfterOveruse; + UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(kMaxBwePeriodMs, + states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); +} + +TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) { auto states = CreateAimdRateControlStates(); constexpr int kInitialBitrate = 10010000; states.aimd_rate_control->SetEstimate(