Adding DTX controller to audio network adaptor.

BUG=webrtc:6303

Review-Url: https://codereview.webrtc.org/2320093002
Cr-Commit-Position: refs/heads/master@{#14260}
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
index 1ded309..8995934 100644
--- a/webrtc/modules/BUILD.gn
+++ b/webrtc/modules/BUILD.gn
@@ -248,6 +248,7 @@
       "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",
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index b25b97a..b6e2db3 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -705,6 +705,8 @@
     "audio_network_adaptor/controller.h",
     "audio_network_adaptor/controller_manager.cc",
     "audio_network_adaptor/controller_manager.h",
+    "audio_network_adaptor/dtx_controller.cc",
+    "audio_network_adaptor/dtx_controller.h",
     "audio_network_adaptor/include/audio_network_adaptor.h",
   ]
   configs += [ "../..:common_config" ]
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 4538255..6f20d61 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
@@ -20,6 +20,8 @@
         'controller.cc',
         'controller_manager.cc',
         'controller_manager.h',
+        'dtx_controller.h',
+        'dtx_controller.cc',
         'include/audio_network_adaptor.h'
       ], # source
     },
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.cc b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.cc
new file mode 100644
index 0000000..30030d1
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.cc
@@ -0,0 +1,45 @@
+/*
+ *  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/dtx_controller.h"
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+DtxController::Config::Config(bool initial_dtx_enabled,
+                              int dtx_enabling_bandwidth_bps,
+                              int dtx_disabling_bandwidth_bps)
+    : initial_dtx_enabled(initial_dtx_enabled),
+      dtx_enabling_bandwidth_bps(dtx_enabling_bandwidth_bps),
+      dtx_disabling_bandwidth_bps(dtx_disabling_bandwidth_bps) {}
+
+DtxController::DtxController(const Config& config)
+    : config_(config), dtx_enabled_(config_.initial_dtx_enabled) {}
+
+void DtxController::MakeDecision(
+    const NetworkMetrics& metrics,
+    AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
+  // Decision on |enable_dtx| should not have been made.
+  RTC_DCHECK(!config->enable_dtx);
+
+  if (metrics.uplink_bandwidth_bps) {
+    if (dtx_enabled_ &&
+        *metrics.uplink_bandwidth_bps >= config_.dtx_disabling_bandwidth_bps) {
+      dtx_enabled_ = false;
+    } else if (!dtx_enabled_ &&
+               *metrics.uplink_bandwidth_bps <=
+                   config_.dtx_enabling_bandwidth_bps) {
+      dtx_enabled_ = true;
+    }
+  }
+  config->enable_dtx = rtc::Optional<bool>(dtx_enabled_);
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h
new file mode 100644
index 0000000..bb8faf4
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h
@@ -0,0 +1,45 @@
+/*
+ *  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_DTX_CONTROLLER_H_
+#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_DTX_CONTROLLER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/controller.h"
+
+namespace webrtc {
+
+class DtxController final : public Controller {
+ public:
+  struct Config {
+    Config(bool initial_dtx_enabled,
+           int dtx_enabling_bandwidth_bps,
+           int dtx_disabling_bandwidth_bps);
+    bool initial_dtx_enabled;
+    // Uplink bandwidth below which DTX should be switched on.
+    int dtx_enabling_bandwidth_bps;
+    // Uplink bandwidth above which DTX should be switched off.
+    int dtx_disabling_bandwidth_bps;
+  };
+
+  explicit DtxController(const Config& config);
+
+  void MakeDecision(const NetworkMetrics& metrics,
+                    AudioNetworkAdaptor::EncoderRuntimeConfig* config) override;
+
+ private:
+  const Config config_;
+  bool dtx_enabled_;
+  RTC_DISALLOW_COPY_AND_ASSIGN(DtxController);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_DTX_CONTROLLER_H_
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc
new file mode 100644
index 0000000..e8fda9e
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc
@@ -0,0 +1,86 @@
+/*
+ *  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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr int kDtxEnablingBandwidthBps = 55000;
+constexpr int kDtxDisablingBandwidthBps = 65000;
+constexpr int kMediumBandwidthBps =
+    (kDtxEnablingBandwidthBps + kDtxDisablingBandwidthBps) / 2;
+
+std::unique_ptr<DtxController> CreateController(int initial_dtx_enabled) {
+  std::unique_ptr<DtxController> controller(new DtxController(
+      DtxController::Config(initial_dtx_enabled, kDtxEnablingBandwidthBps,
+                            kDtxDisablingBandwidthBps)));
+  return controller;
+}
+
+void CheckDecision(DtxController* controller,
+                   const rtc::Optional<int>& uplink_bandwidth_bps,
+                   bool expected_dtx_enabled) {
+  AudioNetworkAdaptor::EncoderRuntimeConfig config;
+  Controller::NetworkMetrics metrics;
+  metrics.uplink_bandwidth_bps = uplink_bandwidth_bps;
+  controller->MakeDecision(metrics, &config);
+  EXPECT_EQ(rtc::Optional<bool>(expected_dtx_enabled), config.enable_dtx);
+}
+
+}  // namespace
+
+TEST(DtxControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
+  constexpr bool kInitialDtxEnabled = true;
+  auto controller = CreateController(kInitialDtxEnabled);
+  CheckDecision(controller.get(), rtc::Optional<int>(), kInitialDtxEnabled);
+}
+
+TEST(DtxControllerTest, TurnOnDtxForLowUplinkBandwidth) {
+  auto controller = CreateController(false);
+  CheckDecision(controller.get(), rtc::Optional<int>(kDtxEnablingBandwidthBps),
+                true);
+}
+
+TEST(DtxControllerTest, TurnOffDtxForHighUplinkBandwidth) {
+  auto controller = CreateController(true);
+  CheckDecision(controller.get(), rtc::Optional<int>(kDtxDisablingBandwidthBps),
+                false);
+}
+
+TEST(DtxControllerTest, MaintainDtxOffForMediumUplinkBandwidth) {
+  auto controller = CreateController(false);
+  CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps),
+                false);
+}
+
+TEST(DtxControllerTest, MaintainDtxOnForMediumUplinkBandwidth) {
+  auto controller = CreateController(true);
+  CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps),
+                true);
+}
+
+TEST(DtxControllerTest, CheckBehaviorOnChangingUplinkBandwidth) {
+  auto controller = CreateController(false);
+  CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps),
+                false);
+  CheckDecision(controller.get(), rtc::Optional<int>(kDtxEnablingBandwidthBps),
+                true);
+  CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps),
+                true);
+  CheckDecision(controller.get(), rtc::Optional<int>(kDtxDisablingBandwidthBps),
+                false);
+}
+
+}  // namespace webrtc