diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index 143c8ff315..b914cf4ba2 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -397,6 +397,7 @@ if (rtc_include_tests) { "congestion_controller/delay_based_bwe_unittest_helper.h", "congestion_controller/probe_bitrate_estimator_unittest.cc", "congestion_controller/probe_controller_unittest.cc", + "congestion_controller/probing_interval_estimator_unittest.cc", "congestion_controller/transport_feedback_adapter_unittest.cc", "media_file/media_file_unittest.cc", "module_common_types_unittest.cc", @@ -404,6 +405,7 @@ if (rtc_include_tests) { "pacing/bitrate_prober_unittest.cc", "pacing/paced_sender_unittest.cc", "pacing/packet_router_unittest.cc", + "remote_bitrate_estimator/aimd_rate_control_unittest.cc", "remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h", "remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h", "remote_bitrate_estimator/inter_arrival_unittest.cc", diff --git a/webrtc/modules/congestion_controller/BUILD.gn b/webrtc/modules/congestion_controller/BUILD.gn index 84c344b7f2..e25c992a78 100644 --- a/webrtc/modules/congestion_controller/BUILD.gn +++ b/webrtc/modules/congestion_controller/BUILD.gn @@ -18,6 +18,8 @@ rtc_static_library("congestion_controller") { "probe_bitrate_estimator.h", "probe_controller.cc", "probe_controller.h", + "probing_interval_estimator.cc", + "probing_interval_estimator.h", "transport_feedback_adapter.cc", "transport_feedback_adapter.h", ] diff --git a/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc b/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc index 287746980a..d439a2b9cb 100644 --- a/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc +++ b/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc @@ -129,7 +129,7 @@ TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) { } TEST_F(DelayBasedBweTest, CapacityDropOneStream) { - CapacityDropTestHelper(1, false, 633, 0); + CapacityDropTestHelper(1, false, 567, 0); } TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) { @@ -141,7 +141,7 @@ TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) { } TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) { - CapacityDropTestHelper(1, true, 633, 0); + CapacityDropTestHelper(1, true, 567, 0); } TEST_F(DelayBasedBweTest, TestTimestampGrouping) { diff --git a/webrtc/modules/congestion_controller/probing_interval_estimator.cc b/webrtc/modules/congestion_controller/probing_interval_estimator.cc new file mode 100644 index 0000000000..ed1134737e --- /dev/null +++ b/webrtc/modules/congestion_controller/probing_interval_estimator.cc @@ -0,0 +1,50 @@ +/* + * 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 "webrtc/modules/congestion_controller/probing_interval_estimator.h" + +#include +#include + +namespace webrtc { + +namespace { +constexpr int kMinIntervalMs = 2000; +constexpr int kMaxIntervalMs = 50000; +} + +ProbingIntervalEstimator::ProbingIntervalEstimator( + const AimdRateControl* aimd_rate_control) + : ProbingIntervalEstimator(kMinIntervalMs, + kMaxIntervalMs, + aimd_rate_control) {} + +ProbingIntervalEstimator::ProbingIntervalEstimator( + int min_interval_ms, + int max_interval_ms, + const AimdRateControl* aimd_rate_control) + : min_interval_ms_(min_interval_ms), + max_interval_ms_(max_interval_ms), + aimd_rate_control_(aimd_rate_control) {} + +rtc::Optional ProbingIntervalEstimator::GetIntervalMs() const { + rtc::Optional bitrate_drop = + aimd_rate_control_->GetLastBitrateDecreaseBps(); + int increase_rate = aimd_rate_control_->GetNearMaxIncreaseRateBps(); + + if (!bitrate_drop || increase_rate <= 0) + return rtc::Optional(); + + return rtc::Optional(std::min( + max_interval_ms_, + std::max(1000 * (*bitrate_drop) / increase_rate, min_interval_ms_))); +} + +} // namespace webrtc diff --git a/webrtc/modules/congestion_controller/probing_interval_estimator.h b/webrtc/modules/congestion_controller/probing_interval_estimator.h new file mode 100644 index 0000000000..daa6b91a8c --- /dev/null +++ b/webrtc/modules/congestion_controller/probing_interval_estimator.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBING_INTERVAL_ESTIMATOR_H_ +#define WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBING_INTERVAL_ESTIMATOR_H_ + +#include "webrtc/base/constructormagic.h" +#include "webrtc/base/optional.h" +#include "webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h" + +namespace webrtc { + +class ProbingIntervalEstimator { + public: + explicit ProbingIntervalEstimator(const AimdRateControl* aimd_rate_control); + + ProbingIntervalEstimator(int min_interval_ms, + int max_interval_ms, + const AimdRateControl* aimd_rate_control); + rtc::Optional GetIntervalMs() const; + + private: + const int min_interval_ms_; + const int max_interval_ms_; + const AimdRateControl* const aimd_rate_control_; + RTC_DISALLOW_COPY_AND_ASSIGN(ProbingIntervalEstimator); +}; + +} // namespace webrtc +#endif // WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBING_INTERVAL_ESTIMATOR_H_ diff --git a/webrtc/modules/congestion_controller/probing_interval_estimator_unittest.cc b/webrtc/modules/congestion_controller/probing_interval_estimator_unittest.cc new file mode 100644 index 0000000000..051f3561d3 --- /dev/null +++ b/webrtc/modules/congestion_controller/probing_interval_estimator_unittest.cc @@ -0,0 +1,87 @@ +/* + * 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 +#include + +#include "webrtc/modules/congestion_controller/probing_interval_estimator.h" +#include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_aimd_rate_control.h" +#include "webrtc/test/gmock.h" +#include "webrtc/test/gtest.h" + +using ::testing::Return; + +namespace webrtc { + +namespace { + +constexpr int kMinIntervalMs = 2000; +constexpr int kMaxIntervalMs = 50000; + +struct ProbingIntervalEstimatorStates { + std::unique_ptr probing_interval_estimator; + std::unique_ptr aimd_rate_control; +}; + +ProbingIntervalEstimatorStates CreateProbingIntervalEstimatorStates() { + ProbingIntervalEstimatorStates states; + states.aimd_rate_control.reset(new MockAimdRateControl()); + states.probing_interval_estimator.reset(new ProbingIntervalEstimator( + kMinIntervalMs, kMaxIntervalMs, states.aimd_rate_control.get())); + return states; +} +} // namespace + +TEST(ProbingIntervalEstimatorTest, NoIntervalUntillWeHaveDrop) { + auto states = CreateProbingIntervalEstimatorStates(); + + EXPECT_CALL(*states.aimd_rate_control, GetLastBitrateDecreaseBps()) + .WillOnce(Return(rtc::Optional())) + .WillOnce(Return(rtc::Optional(5000))); + EXPECT_CALL(*states.aimd_rate_control, GetNearMaxIncreaseRateBps()) + .WillOnce(Return(4000)) + .WillOnce(Return(4000)); + + EXPECT_EQ(rtc::Optional(), + states.probing_interval_estimator->GetIntervalMs()); + EXPECT_NE(rtc::Optional(), + states.probing_interval_estimator->GetIntervalMs()); +} + +TEST(ProbingIntervalEstimatorTest, CalcInterval) { + auto states = CreateProbingIntervalEstimatorStates(); + EXPECT_CALL(*states.aimd_rate_control, GetLastBitrateDecreaseBps()) + .WillOnce(Return(rtc::Optional(20000))); + EXPECT_CALL(*states.aimd_rate_control, GetNearMaxIncreaseRateBps()) + .WillOnce(Return(5000)); + EXPECT_EQ(rtc::Optional(4000), + states.probing_interval_estimator->GetIntervalMs()); +} + +TEST(ProbingIntervalEstimatorTest, IntervalDoesNotExceedMin) { + auto states = CreateProbingIntervalEstimatorStates(); + EXPECT_CALL(*states.aimd_rate_control, GetLastBitrateDecreaseBps()) + .WillOnce(Return(rtc::Optional(1000))); + EXPECT_CALL(*states.aimd_rate_control, GetNearMaxIncreaseRateBps()) + .WillOnce(Return(5000)); + EXPECT_EQ(rtc::Optional(kMinIntervalMs), + states.probing_interval_estimator->GetIntervalMs()); +} + +TEST(ProbingIntervalEstimatorTest, IntervalDoesNotExceedMax) { + auto states = CreateProbingIntervalEstimatorStates(); + EXPECT_CALL(*states.aimd_rate_control, GetLastBitrateDecreaseBps()) + .WillOnce(Return(rtc::Optional(50000))); + EXPECT_CALL(*states.aimd_rate_control, GetNearMaxIncreaseRateBps()) + .WillOnce(Return(100)); + EXPECT_EQ(rtc::Optional(kMaxIntervalMs), + states.probing_interval_estimator->GetIntervalMs()); +} +} // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc index f4835f57c1..530453d74c 100644 --- a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -130,6 +130,23 @@ void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) { current_bitrate_bps_ = ChangeBitrate(bitrate_bps, bitrate_bps, now_ms); } +int AimdRateControl::GetNearMaxIncreaseRateBps() const { + RTC_DCHECK_GT(current_bitrate_bps_, 0); + double bits_per_frame = static_cast(current_bitrate_bps_) / 30.0; + double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0)); + double avg_packet_size_bits = bits_per_frame / packets_per_frame; + // Approximate the over-use estimator delay to 100 ms. + const int64_t response_time = in_experiment_ ? (rtt_ + 100) * 2 : rtt_ + 100; + + constexpr double kMinIncreaseRateBps = 4000; + return static_cast(std::max( + kMinIncreaseRateBps, (avg_packet_size_bits * 1000) / response_time)); +} + +rtc::Optional AimdRateControl::GetLastBitrateDecreaseBps() const { + return last_decrease_; +} + uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps, uint32_t incoming_bitrate_bps, int64_t now_ms) { @@ -161,12 +178,9 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps, avg_max_bitrate_kbps_ = -1.0; } if (rate_control_region_ == kRcNearMax) { - // Approximate the over-use estimator delay to 100 ms. - const int64_t response_time = rtt_ + 100; - uint32_t additive_increase_bps = AdditiveRateIncrease( - now_ms, time_last_bitrate_change_, response_time); + uint32_t additive_increase_bps = + AdditiveRateIncrease(now_ms, time_last_bitrate_change_); current_bitrate_bps += additive_increase_bps; - } else { uint32_t multiplicative_increase_bps = MultiplicativeRateIncrease( now_ms, time_last_bitrate_change_, current_bitrate_bps); @@ -196,6 +210,10 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps, } ChangeRegion(kRcNearMax); + if (incoming_bitrate_bps < current_bitrate_bps_) { + last_decrease_ = + rtc::Optional(current_bitrate_bps_ - current_bitrate_bps); + } if (incoming_bitrate_kbps < avg_max_bitrate_kbps_ - 3 * std_max_bit_rate) { avg_max_bitrate_kbps_ = -1.0f; @@ -234,22 +252,10 @@ uint32_t AimdRateControl::MultiplicativeRateIncrease( return multiplicative_increase_bps; } -uint32_t AimdRateControl::AdditiveRateIncrease( - int64_t now_ms, int64_t last_ms, int64_t response_time_ms) const { - assert(response_time_ms > 0); - double beta = 0.0; - if (last_ms > 0) { - beta = std::min((now_ms - last_ms) / static_cast(response_time_ms), - 1.0); - if (in_experiment_) - beta /= 2.0; - } - double bits_per_frame = static_cast(current_bitrate_bps_) / 30.0; - double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0)); - double avg_packet_size_bits = bits_per_frame / packets_per_frame; - uint32_t additive_increase_bps = std::max( - 1000.0, beta * avg_packet_size_bits); - return additive_increase_bps; +uint32_t AimdRateControl::AdditiveRateIncrease(int64_t now_ms, + int64_t last_ms) const { + return static_cast((now_ms - last_ms) * + GetNearMaxIncreaseRateBps() / 1000); } void AimdRateControl::UpdateMaxBitRateEstimate(float incoming_bitrate_kbps) { diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h index 2b2e85bf91..6e5410dd00 100644 --- a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -43,6 +43,12 @@ class AimdRateControl { void Update(const RateControlInput* input, int64_t now_ms); void SetEstimate(int bitrate_bps, int64_t now_ms); + // Returns the increase rate which is used when used bandwidth is near the + // maximal available bandwidth. + virtual int GetNearMaxIncreaseRateBps() const; + + virtual rtc::Optional GetLastBitrateDecreaseBps() const; + private: // Update the target bitrate according based on, among other things, // the current rate control state, the current target bitrate and the incoming @@ -56,8 +62,7 @@ class AimdRateControl { int64_t now_ms); uint32_t MultiplicativeRateIncrease(int64_t now_ms, int64_t last_ms, uint32_t current_bitrate_bps) const; - uint32_t AdditiveRateIncrease(int64_t now_ms, int64_t last_ms, - int64_t response_time_ms) const; + uint32_t AdditiveRateIncrease(int64_t now_ms, int64_t last_ms) const; void UpdateChangePeriod(int64_t now_ms); void UpdateMaxBitRateEstimate(float incoming_bit_rate_kbps); void ChangeState(const RateControlInput& input, int64_t now_ms); @@ -79,6 +84,7 @@ class AimdRateControl { float beta_; int64_t rtt_; bool in_experiment_; + rtc::Optional last_decrease_; }; } // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc new file mode 100644 index 0000000000..2966c29372 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc @@ -0,0 +1,92 @@ +/* + * 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 + +#include "webrtc/modules/audio_coding/audio_network_adaptor/smoothing_filter.h" +#include "webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h" +#include "webrtc/test/gtest.h" + +namespace webrtc { +namespace { + +constexpr int64_t kClockInitialTime = 123456; + +struct AimdRateControlStates { + std::unique_ptr aimd_rate_control; + std::unique_ptr simulated_clock; +}; + +AimdRateControlStates CreateAimdRateControlStates() { + AimdRateControlStates states; + states.aimd_rate_control.reset(new AimdRateControl()); + states.simulated_clock.reset(new SimulatedClock(kClockInitialTime)); + return states; +} + +void InitBitrate(const AimdRateControlStates& states, + int bitrate, + int64_t now_ms) { + // Reduce the bitrate by 1000 to compensate for the Update after SetEstimate. + bitrate -= 1000; + + states.aimd_rate_control->SetEstimate(bitrate, now_ms); +} + +void UpdateRateControl(const AimdRateControlStates& states, + const BandwidthUsage& bandwidth_usage, + int bitrate, + int64_t now_ms) { + RateControlInput input(bandwidth_usage, rtc::Optional(bitrate), + now_ms); + states.aimd_rate_control->Update(&input, now_ms); + states.aimd_rate_control->UpdateBandwidthEstimate(now_ms); +} + +} // namespace + +TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) { + auto states = CreateAimdRateControlStates(); + constexpr int kBitrate = 30000; + InitBitrate(states, kBitrate, states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(4000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); +} + +TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) { + auto states = CreateAimdRateControlStates(); + constexpr int kBitrate = 90000; + InitBitrate(states, kBitrate, states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); +} + +TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) { + auto states = CreateAimdRateControlStates(); + constexpr int kBitrate = 60000; + InitBitrate(states, kBitrate, states.simulated_clock->TimeInMilliseconds()); + states.aimd_rate_control->SetRtt(100); + EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); +} + +TEST(AimdRateControlTest, UnknownBitrateDecreaseBeforeFirstOveruse) { + auto states = CreateAimdRateControlStates(); + EXPECT_EQ(rtc::Optional(), + states.aimd_rate_control->GetLastBitrateDecreaseBps()); +} + +TEST(AimdRateControlTest, GetLastBitrateDecrease) { + auto states = CreateAimdRateControlStates(); + constexpr int kBitrate = 300000; + InitBitrate(states, kBitrate, states.simulated_clock->TimeInMilliseconds()); + UpdateRateControl(states, kBwOverusing, kBitrate - 2000, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(rtc::Optional(46700), + states.aimd_rate_control->GetLastBitrateDecreaseBps()); +} + +} // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/include/mock/mock_aimd_rate_control.h b/webrtc/modules/remote_bitrate_estimator/include/mock/mock_aimd_rate_control.h new file mode 100644 index 0000000000..822f91afd3 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/include/mock/mock_aimd_rate_control.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_AIMD_RATE_CONTROL_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_AIMD_RATE_CONTROL_H_ + +#include "webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h" +#include "webrtc/test/gmock.h" + +namespace webrtc { + +class MockAimdRateControl : public AimdRateControl { + public: + MOCK_CONST_METHOD0(GetNearMaxIncreaseRateBps, int()); + MOCK_CONST_METHOD0(GetLastBitrateDecreaseBps, rtc::Optional()); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_AIMD_RATE_CONTROL_H_ diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc index fcfb8f4f83..2105e329dd 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc @@ -55,7 +55,7 @@ TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStreamWrap) { } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropTwoStreamsWrap) { - CapacityDropTestHelper(2, true, 633, 0); + CapacityDropTestHelper(2, true, 700, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThreeStreamsWrap) { diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc index 86c272b7f5..42b5acbedf 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc @@ -55,7 +55,7 @@ TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) { } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) { - CapacityDropTestHelper(13, true, 567, 0); + CapacityDropTestHelper(13, true, 733, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {