mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

The idea is that when ALR is detected, the encoder can not produce the bitrate needed for the delay based estimator to detect overuse and thus the delay based estimator should not be allowed to increase further. Likewise, if ALR is not detected, the delay based estimator is allowed to increase the BWE to ensure that there is no region where the BWE can get stuck. BUG=webrtc:10542 Change-Id: Ic94b708461c9077fd09132ee4ecb6279ffcd5f99 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133190 Commit-Queue: Per Kjellander <perkj@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27661}
340 lines
15 KiB
C++
340 lines
15 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 <memory>
|
|
|
|
#include "api/transport/field_trial_based_config.h"
|
|
#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 {
|
|
namespace {
|
|
|
|
constexpr int64_t kClockInitialTime = 123456;
|
|
|
|
constexpr int kMinBwePeriodMsSmoothingExp = 500;
|
|
constexpr int kMinBwePeriodMsNoSmoothingExp = 2000;
|
|
constexpr int kDefaultPeriodMsNoSmoothingExp = 3000;
|
|
constexpr int kMaxBwePeriodMs = 50000;
|
|
constexpr char kSmoothingExpFieldTrial[] =
|
|
"WebRTC-Audio-BandwidthSmoothing/Enabled/";
|
|
|
|
// After an overuse, we back off to 85% to the received bitrate.
|
|
constexpr double kFractionAfterOveruse = 0.85;
|
|
|
|
struct AimdRateControlStates {
|
|
std::unique_ptr<AimdRateControl> aimd_rate_control;
|
|
std::unique_ptr<SimulatedClock> simulated_clock;
|
|
FieldTrialBasedConfig field_trials;
|
|
};
|
|
|
|
AimdRateControlStates CreateAimdRateControlStates(bool send_side = false) {
|
|
AimdRateControlStates states;
|
|
states.aimd_rate_control.reset(
|
|
new AimdRateControl(&states.field_trials, send_side));
|
|
states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
|
|
return states;
|
|
}
|
|
absl::optional<DataRate> OptionalRateFromOptionalBps(
|
|
absl::optional<int> bitrate_bps) {
|
|
if (bitrate_bps) {
|
|
return DataRate::bps(*bitrate_bps);
|
|
} else {
|
|
return absl::nullopt;
|
|
}
|
|
}
|
|
void UpdateRateControl(const AimdRateControlStates& states,
|
|
const BandwidthUsage& bandwidth_usage,
|
|
absl::optional<uint32_t> throughput_estimate,
|
|
int64_t now_ms) {
|
|
RateControlInput input(bandwidth_usage,
|
|
OptionalRateFromOptionalBps(throughput_estimate));
|
|
states.aimd_rate_control->Update(&input, Timestamp::ms(now_ms));
|
|
}
|
|
void SetEstimate(const AimdRateControlStates& states, int bitrate_bps) {
|
|
states.aimd_rate_control->SetEstimate(
|
|
DataRate::bps(bitrate_bps),
|
|
Timestamp::ms(states.simulated_clock->TimeInMilliseconds()));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 30000;
|
|
SetEstimate(states, kBitrate);
|
|
EXPECT_EQ(4000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 90000;
|
|
SetEstimate(states, kBitrate);
|
|
EXPECT_EQ(5000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 60000;
|
|
SetEstimate(states, kBitrate);
|
|
states.aimd_rate_control->SetRtt(TimeDelta::ms(100));
|
|
EXPECT_EQ(5000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) {
|
|
// Smoothing experiment disabled
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 300000;
|
|
SetEstimate(states, kBitrate);
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_NEAR(14000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
|
|
1000);
|
|
EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) {
|
|
// Smoothing experiment enabled
|
|
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 300000;
|
|
SetEstimate(states, kBitrate);
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_NEAR(14000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
|
|
1000);
|
|
EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BweLimitedByAckedBitrate) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kAckedBitrate = 10000;
|
|
SetEstimate(states, kAckedBitrate);
|
|
while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
|
|
20000) {
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
}
|
|
ASSERT_TRUE(states.aimd_rate_control->ValidEstimate());
|
|
EXPECT_EQ(static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
|
|
states.aimd_rate_control->LatestEstimate().bps());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kAckedBitrate = 100000;
|
|
SetEstimate(states, kAckedBitrate);
|
|
while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
|
|
20000) {
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
}
|
|
ASSERT_TRUE(states.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.
|
|
uint32_t prev_estimate = states.aimd_rate_control->LatestEstimate().bps();
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate / 2,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
uint32_t new_estimate = states.aimd_rate_control->LatestEstimate().bps();
|
|
EXPECT_NEAR(new_estimate, static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
|
|
2000);
|
|
EXPECT_EQ(new_estimate, prev_estimate);
|
|
}
|
|
|
|
TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) {
|
|
// Smoothing experiment disabled
|
|
auto states = CreateAimdRateControlStates();
|
|
states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
|
|
EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_NE(kDefaultPeriodMsNoSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, MinPeriodUntilFirstOveruseSmoothingExp) {
|
|
// Smoothing experiment enabled
|
|
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
|
|
auto states = CreateAimdRateControlStates();
|
|
states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
|
|
EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_NE(kMinBwePeriodMsSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 110000;
|
|
SetEstimate(states, kInitialBitrate);
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
// Make the bitrate drop by 20 kbps to get to 90 kbps.
|
|
// The rate increase at 90 kbps should be 5 kbps, so the period should be 4 s.
|
|
constexpr int kAckedBitrate =
|
|
(kInitialBitrate - 20000) / kFractionAfterOveruse;
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_EQ(5000,
|
|
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
|
|
EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) {
|
|
// Smoothing experiment enabled
|
|
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 110000;
|
|
SetEstimate(states, kInitialBitrate);
|
|
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->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 10000;
|
|
SetEstimate(states, kInitialBitrate);
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
// Make a small (1.5 kbps) bitrate drop to 8.5 kbps.
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kInitialBitrate - 1,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_EQ(kMinBwePeriodMsNoSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) {
|
|
// Smoothing experiment enabled
|
|
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 50000000;
|
|
SetEstimate(states, kInitialBitrate);
|
|
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->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 10010000;
|
|
SetEstimate(states, kInitialBitrate);
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
// Make a large (10 Mbps) bitrate drop to 10 kbps.
|
|
constexpr int kAckedBitrate = 10000 / kFractionAfterOveruse;
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_EQ(kMaxBwePeriodMs,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrateBps = 123000;
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kInitialBitrateBps,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
// 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 int kInitializationTimeMs = 5000;
|
|
states.simulated_clock->AdvanceTimeMilliseconds(kInitializationTimeMs + 1);
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kInitialBitrateBps,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
for (int i = 0; i < 100; ++i) {
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
}
|
|
EXPECT_LE(states.aimd_rate_control->LatestEstimate().bps(),
|
|
kInitialBitrateBps * 1.5 + 10000);
|
|
}
|
|
|
|
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.
|
|
test::ScopedFieldTrials override_field_trials(
|
|
"WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
|
|
auto states = CreateAimdRateControlStates(/*send_side=*/true);
|
|
constexpr int kInitialBitrateBps = 123000;
|
|
SetEstimate(states, kInitialBitrateBps);
|
|
states.aimd_rate_control->SetInApplicationLimitedRegion(true);
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kInitialBitrateBps,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
ASSERT_EQ(states.aimd_rate_control->LatestEstimate().bps(),
|
|
kInitialBitrateBps);
|
|
|
|
for (int i = 0; i < 100; ++i) {
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
}
|
|
EXPECT_EQ(states.aimd_rate_control->LatestEstimate().bps(),
|
|
kInitialBitrateBps);
|
|
}
|
|
|
|
TEST(AimdRateControlTest, SetEstimateIncreaseBweInAlr) {
|
|
test::ScopedFieldTrials override_field_trials(
|
|
"WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
|
|
auto states = CreateAimdRateControlStates(/*send_side=*/true);
|
|
constexpr int kInitialBitrateBps = 123000;
|
|
SetEstimate(states, kInitialBitrateBps);
|
|
states.aimd_rate_control->SetInApplicationLimitedRegion(true);
|
|
ASSERT_EQ(states.aimd_rate_control->LatestEstimate().bps(),
|
|
kInitialBitrateBps);
|
|
SetEstimate(states, 2 * kInitialBitrateBps);
|
|
EXPECT_EQ(states.aimd_rate_control->LatestEstimate().bps(),
|
|
2 * kInitialBitrateBps);
|
|
}
|
|
|
|
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.
|
|
test::ScopedFieldTrials override_field_trials(
|
|
"WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/");
|
|
auto states = CreateAimdRateControlStates(/*send_side=*/true);
|
|
constexpr int kInitialBitrateBps = 123000;
|
|
SetEstimate(states, kInitialBitrateBps);
|
|
states.aimd_rate_control->SetInApplicationLimitedRegion(false);
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kInitialBitrateBps,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
for (int i = 0; i < 100; ++i) {
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
}
|
|
EXPECT_GT(states.aimd_rate_control->LatestEstimate().bps(),
|
|
kInitialBitrateBps);
|
|
}
|
|
|
|
} // namespace webrtc
|