mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

This ensure upper link capacity estimate upper limit an increase in delay based estimate, but the delay based estimate is not decreased if link capacity estimate decrease. Bug: webrtc:10498, b/300868877 Change-Id: I87e76e2a869e6f721cc8fe9d422e0194371d4e45 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/327801 Reviewed-by: Björn Terelius <terelius@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41196}
316 lines
14 KiB
C++
316 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);
|
|
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
|