Adding BitrateController to audio network adaptor.
BUG=webrtc:6303
Review-Url: https://codereview.webrtc.org/2334613002
Cr-Commit-Position: refs/heads/master@{#14293}
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
index 8995934..36ae692 100644
--- a/webrtc/modules/BUILD.gn
+++ b/webrtc/modules/BUILD.gn
@@ -233,6 +233,30 @@
}
}
+ rtc_source_set("audio_network_adaptor_unittests") {
+ # Put sources for unittests of audio network adaptor in a separate
+ # rtc_source_set to solve name collision on bitrate_controller_unittest.cc.
+ testonly = true
+ sources = [
+ "audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc",
+ "audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc",
+ "audio_coding/audio_network_adaptor/channel_controller_unittest.cc",
+ "audio_coding/audio_network_adaptor/controller_manager_unittest.cc",
+ "audio_coding/audio_network_adaptor/dtx_controller_unittest.cc",
+ "audio_coding/audio_network_adaptor/mock/mock_controller.h",
+ "audio_coding/audio_network_adaptor/mock/mock_controller_manager.h",
+ ]
+ deps = [
+ "audio_coding:audio_network_adaptor",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+ if (is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+ }
+
rtc_test("modules_unittests") {
testonly = true
@@ -245,12 +269,6 @@
"audio_coding/acm2/codec_manager_unittest.cc",
"audio_coding/acm2/initial_delay_manager_unittest.cc",
"audio_coding/acm2/rent_a_codec_unittest.cc",
- "audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc",
- "audio_coding/audio_network_adaptor/channel_controller_unittest.cc",
- "audio_coding/audio_network_adaptor/controller_manager_unittest.cc",
- "audio_coding/audio_network_adaptor/dtx_controller_unittest.cc",
- "audio_coding/audio_network_adaptor/mock/mock_controller.h",
- "audio_coding/audio_network_adaptor/mock/mock_controller_manager.h",
"audio_coding/codecs/audio_decoder_factory_unittest.cc",
"audio_coding/codecs/cng/audio_encoder_cng_unittest.cc",
"audio_coding/codecs/cng/cng_unittest.cc",
@@ -592,6 +610,7 @@
}
deps += [
+ ":audio_network_adaptor_unittests",
"..:webrtc_common",
"../base:rtc_base", # TODO(kjellander): Cleanup in bugs.webrtc.org/3806.
"../common_audio",
@@ -605,7 +624,6 @@
"audio_coding",
"audio_coding:acm_receive_test",
"audio_coding:acm_send_test",
- "audio_coding:audio_network_adaptor",
"audio_coding:builtin_audio_decoder_factory",
"audio_coding:cng",
"audio_coding:isac_fix",
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index b6e2db3..4fe49e5 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -699,6 +699,8 @@
"audio_network_adaptor/audio_network_adaptor.cc",
"audio_network_adaptor/audio_network_adaptor_impl.cc",
"audio_network_adaptor/audio_network_adaptor_impl.h",
+ "audio_network_adaptor/bitrate_controller.cc",
+ "audio_network_adaptor/bitrate_controller.h",
"audio_network_adaptor/channel_controller.cc",
"audio_network_adaptor/channel_controller.h",
"audio_network_adaptor/controller.cc",
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi
index 6f20d61..8e87815 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi
@@ -14,6 +14,8 @@
'audio_network_adaptor.cc',
'audio_network_adaptor_impl.cc',
'audio_network_adaptor_impl.h',
+ 'bitrate_controller.h',
+ 'bitrate_controller.cc',
'channel_controller.cc',
'channel_controller.h',
'controller.h',
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
index c17d389..6562674 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
@@ -28,6 +28,7 @@
MATCHER_P(NetworkMetricsIs, metric, "") {
return arg.uplink_bandwidth_bps == metric.uplink_bandwidth_bps &&
+ arg.target_audio_bitrate_bps == metric.target_audio_bitrate_bps &&
arg.uplink_packet_loss_fraction == metric.uplink_packet_loss_fraction;
}
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.cc b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.cc
new file mode 100644
index 0000000..4cc49e8
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.cc
@@ -0,0 +1,68 @@
+/*
+ * 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/audio_coding/audio_network_adaptor/bitrate_controller.h"
+
+#include <algorithm>
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+namespace {
+// TODO(minyue): consider passing this from a higher layer through
+// SetConstraints().
+// L2(14B) + IPv4(20B) + UDP(8B) + RTP(12B) + SRTP_AUTH(10B) = 64B = 512 bits
+constexpr int kPacketOverheadBits = 512;
+}
+
+BitrateController::Config::Config(int initial_bitrate_bps,
+ int initial_frame_length_ms)
+ : initial_bitrate_bps(initial_bitrate_bps),
+ initial_frame_length_ms(initial_frame_length_ms) {}
+
+BitrateController::Config::~Config() = default;
+
+BitrateController::BitrateController(const Config& config)
+ : config_(config),
+ bitrate_bps_(config_.initial_bitrate_bps),
+ overhead_rate_bps_(kPacketOverheadBits * 1000 /
+ config_.initial_frame_length_ms) {
+ RTC_DCHECK_GT(bitrate_bps_, 0);
+ RTC_DCHECK_GT(overhead_rate_bps_, 0);
+}
+
+void BitrateController::MakeDecision(
+ const NetworkMetrics& metrics,
+ AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
+ // Decision on |bitrate_bps| should not have been made.
+ RTC_DCHECK(!config->bitrate_bps);
+
+ if (metrics.target_audio_bitrate_bps) {
+ int overhead_rate =
+ config->frame_length_ms
+ ? kPacketOverheadBits * 1000 / *config->frame_length_ms
+ : overhead_rate_bps_;
+ // If |metrics.target_audio_bitrate_bps| had included overhead, we would
+ // simply do:
+ // bitrate_bps_ = metrics.target_audio_bitrate_bps - overhead_rate;
+ // Follow https://bugs.chromium.org/p/webrtc/issues/detail?id=6315 to track
+ // progress regarding this.
+ // Now we assume that |metrics.target_audio_bitrate_bps| can handle the
+ // overhead of most recent packets.
+ bitrate_bps_ = std::max(0, *metrics.target_audio_bitrate_bps +
+ overhead_rate_bps_ - overhead_rate);
+ // TODO(minyue): apply a smoothing on the |overhead_rate_bps_|.
+ overhead_rate_bps_ = overhead_rate;
+ }
+ config->bitrate_bps = rtc::Optional<int>(bitrate_bps_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
new file mode 100644
index 0000000..cfc6fa8
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
@@ -0,0 +1,42 @@
+/*
+ * 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_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_BITRATE_CONTROLLER_H_
+#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_BITRATE_CONTROLLER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/controller.h"
+
+namespace webrtc {
+
+class BitrateController final : public Controller {
+ public:
+ struct Config {
+ Config(int initial_bitrate_bps, int frame_length_ms);
+ ~Config();
+ int initial_bitrate_bps;
+ int initial_frame_length_ms;
+ };
+
+ explicit BitrateController(const Config& config);
+
+ void MakeDecision(const NetworkMetrics& metrics,
+ AudioNetworkAdaptor::EncoderRuntimeConfig* config) override;
+
+ private:
+ const Config config_;
+ int bitrate_bps_;
+ int overhead_rate_bps_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(BitrateController);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_BITRATE_CONTROLLER_H_
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc
new file mode 100644
index 0000000..5a3a74a
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc
@@ -0,0 +1,142 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h"
+
+namespace webrtc {
+
+namespace {
+
+// L2(14B) + IPv4(20B) + UDP(8B) + RTP(12B) + SRTP_AUTH(10B) = 64B = 512 bits
+constexpr int kPacketOverheadBits = 512;
+
+void CheckDecision(BitrateController* controller,
+ const rtc::Optional<int>& target_audio_bitrate_bps,
+ const rtc::Optional<int>& frame_length_ms,
+ int expected_bitrate_bps) {
+ Controller::NetworkMetrics metrics;
+ metrics.target_audio_bitrate_bps = target_audio_bitrate_bps;
+ AudioNetworkAdaptor::EncoderRuntimeConfig config;
+ config.frame_length_ms = frame_length_ms;
+ controller->MakeDecision(metrics, &config);
+ EXPECT_EQ(rtc::Optional<int>(expected_bitrate_bps), config.bitrate_bps);
+}
+
+} // namespace
+
+// These tests are named AnaBitrateControllerTest to distinguish from
+// BitrateControllerTest in
+// modules/bitrate_controller/bitrate_controller_unittest.cc.
+
+TEST(AnaBitrateControllerTest, OutputInitValueWhenTargetBitrateUnknown) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 20;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+ CheckDecision(&controller, rtc::Optional<int>(),
+ rtc::Optional<int>(kInitialFrameLengthMs * 2),
+ kInitialBitrateBps);
+}
+
+TEST(AnaBitrateControllerTest, ChangeBitrateOnTargetBitrateChanged) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 20;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+ constexpr int kTargetBitrateBps = 48000;
+ // Frame length unchanged, bitrate changes in accordance with
+ // |metrics.target_audio_bitrate_bps|
+ CheckDecision(&controller, rtc::Optional<int>(kTargetBitrateBps),
+ rtc::Optional<int>(kInitialFrameLengthMs), kTargetBitrateBps);
+}
+
+TEST(AnaBitrateControllerTest, TreatUnknownFrameLengthAsFrameLengthUnchanged) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 20;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+ constexpr int kTargetBitrateBps = 48000;
+ CheckDecision(&controller, rtc::Optional<int>(kTargetBitrateBps),
+ rtc::Optional<int>(), kTargetBitrateBps);
+}
+
+TEST(AnaBitrateControllerTest, IncreaseBitrateOnFrameLengthIncreased) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 20;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+ constexpr int kFrameLengthMs = 60;
+ constexpr int kPacketOverheadRateDiff =
+ kPacketOverheadBits * 1000 / kInitialFrameLengthMs -
+ kPacketOverheadBits * 1000 / kFrameLengthMs;
+ CheckDecision(&controller, rtc::Optional<int>(kInitialBitrateBps),
+ rtc::Optional<int>(kFrameLengthMs),
+ kInitialBitrateBps + kPacketOverheadRateDiff);
+}
+
+TEST(AnaBitrateControllerTest, DecreaseBitrateOnFrameLengthDecreased) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 60;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+ constexpr int kFrameLengthMs = 20;
+ constexpr int kPacketOverheadRateDiff =
+ kPacketOverheadBits * 1000 / kInitialFrameLengthMs -
+ kPacketOverheadBits * 1000 / kFrameLengthMs;
+ CheckDecision(&controller, rtc::Optional<int>(kInitialBitrateBps),
+ rtc::Optional<int>(kFrameLengthMs),
+ kInitialBitrateBps + kPacketOverheadRateDiff);
+}
+
+TEST(AnaBitrateControllerTest, CheckBehaviorOnChangingCondition) {
+ constexpr int kInitialBitrateBps = 32000;
+ constexpr int kInitialFrameLengthMs = 20;
+ BitrateController controller(
+ BitrateController::Config(kInitialBitrateBps, kInitialFrameLengthMs));
+
+ int last_overhead_bitrate =
+ kPacketOverheadBits * 1000 / kInitialFrameLengthMs;
+ int current_overhead_bitrate = kPacketOverheadBits * 1000 / 20;
+ // Start from an arbitrary overall bitrate.
+ int overall_bitrate = 34567;
+ CheckDecision(
+ &controller, rtc::Optional<int>(overall_bitrate - last_overhead_bitrate),
+ rtc::Optional<int>(20), overall_bitrate - current_overhead_bitrate);
+
+ // Next: increase overall bitrate.
+ overall_bitrate += 100;
+ CheckDecision(
+ &controller, rtc::Optional<int>(overall_bitrate - last_overhead_bitrate),
+ rtc::Optional<int>(20), overall_bitrate - current_overhead_bitrate);
+
+ // Next: change frame length.
+ current_overhead_bitrate = kPacketOverheadBits * 1000 / 60;
+ CheckDecision(
+ &controller, rtc::Optional<int>(overall_bitrate - last_overhead_bitrate),
+ rtc::Optional<int>(60), overall_bitrate - current_overhead_bitrate);
+ last_overhead_bitrate = current_overhead_bitrate;
+
+ // Next: change frame length.
+ current_overhead_bitrate = kPacketOverheadBits * 1000 / 20;
+ CheckDecision(
+ &controller, rtc::Optional<int>(overall_bitrate - last_overhead_bitrate),
+ rtc::Optional<int>(20), overall_bitrate - current_overhead_bitrate);
+ last_overhead_bitrate = current_overhead_bitrate;
+
+ // Next: decrease overall bitrate and frame length.
+ overall_bitrate -= 100;
+ current_overhead_bitrate = kPacketOverheadBits * 1000 / 60;
+ CheckDecision(
+ &controller, rtc::Optional<int>(overall_bitrate - last_overhead_bitrate),
+ rtc::Optional<int>(60), overall_bitrate - current_overhead_bitrate);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/controller.h
index f6a6079..c1b16c7 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/controller.h
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/controller.h
@@ -23,6 +23,7 @@
~NetworkMetrics();
rtc::Optional<int> uplink_bandwidth_bps;
rtc::Optional<float> uplink_packet_loss_fraction;
+ rtc::Optional<int> target_audio_bitrate_bps;
};
struct Constraints {