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 {