mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-16 23:30:48 +01:00

Traditionally, we'd back off to 85% of the measured throughput in response to an overuse. However, this backoff doesn't appear to be sufficient to drain the queues in some low-bitrate scenarios, and the problem has gotten a bit worse with the RobustThroughputEstimator. (The new estimate looks more stable. The old estimator had more variation, the lowest points were lower, causing backoffs to lower rates.) With this change, we back off to 0.85*thoughput-5kbps. The difference is negligible except at low bitrates. Bug: webrtc:13402,b/298636540 Change-Id: I53328953c056b8ad77f6c7561d6017f171b2dfbc Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/321701 Commit-Queue: Björn Terelius <terelius@webrtc.org> Reviewed-by: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40827}
314 lines
14 KiB
C++
314 lines
14 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/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
|