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

Remove unused member noise_var from RateControlInput struct. Rename incoming_bitrate to estimated_throughput_bps to reflect that the AimdRateControl may be running on either the send side or the receive side. Bug: webrtc:9411 Change-Id: Ie1ae0c29dc9559ef389993144e69fcd41684f1a4 Reviewed-on: https://webrtc-review.googlesource.com/83728 Reviewed-by: Stefan Holmer <stefan@webrtc.org> Reviewed-by: Anastasia Koloskova <koloskova@webrtc.org> Commit-Queue: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23783}
272 lines
12 KiB
C++
272 lines
12 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 "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;
|
|
};
|
|
|
|
AimdRateControlStates CreateAimdRateControlStates() {
|
|
AimdRateControlStates states;
|
|
states.aimd_rate_control.reset(new AimdRateControl());
|
|
states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
|
|
return states;
|
|
}
|
|
|
|
void UpdateRateControl(const AimdRateControlStates& states,
|
|
const BandwidthUsage& bandwidth_usage,
|
|
absl::optional<uint32_t> throughput_estimate,
|
|
int64_t now_ms) {
|
|
RateControlInput input(bandwidth_usage, throughput_estimate);
|
|
states.aimd_rate_control->Update(&input, now_ms);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 30000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_EQ(4000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 90000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kBitrate = 60000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
states.aimd_rate_control->SetRtt(100);
|
|
EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) {
|
|
// Smoothing experiment disabled
|
|
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(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) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kAckedBitrate = 10000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
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());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kAckedBitrate = 100000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
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();
|
|
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate / 2,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
uint32_t new_estimate = states.aimd_rate_control->LatestEstimate();
|
|
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(300000);
|
|
EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
|
|
states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
|
|
states.simulated_clock->AdvanceTimeMilliseconds(100);
|
|
UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
|
|
states.simulated_clock->TimeInMilliseconds());
|
|
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());
|
|
}
|
|
|
|
TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) {
|
|
auto states = CreateAimdRateControlStates();
|
|
constexpr int kInitialBitrate = 110000;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
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->GetNearMaxIncreaseRateBps());
|
|
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;
|
|
states.aimd_rate_control->SetEstimate(
|
|
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
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->GetExpectedBandwidthPeriodMs());
|
|
}
|
|
|
|
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(
|
|
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
|
|
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->GetExpectedBandwidthPeriodMs());
|
|
}
|
|
|
|
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(),
|
|
kInitialBitrateBps * 1.5 + 10000);
|
|
}
|
|
|
|
} // namespace webrtc
|