Creating controller manager from config string in audio network adaptor.

BUG=webrtc:6303

Review-Url: https://codereview.webrtc.org/2364403004
Cr-Commit-Position: refs/heads/master@{#14466}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index bafeffb..ef5ea96 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -701,6 +701,12 @@
     ]
     proto_out_dir = "webrtc/modules/audio_coding/audio_network_adaptor"
   }
+  proto_library("ana_config_proto") {
+    sources = [
+      "audio_network_adaptor/config.proto",
+    ]
+    proto_out_dir = "webrtc/modules/audio_coding/audio_network_adaptor"
+  }
 }
 
 source_set("audio_network_adaptor") {
@@ -733,6 +739,7 @@
 
   if (rtc_enable_protobuf) {
     deps = [
+      ":ana_config_proto",
       ":ana_debug_dump_proto",
     ]
     defines = [ "WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP" ]
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 f29992d..7750276 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
@@ -36,7 +36,10 @@
       ], # sources
       'conditions': [
         ['enable_protobuf==1', {
-          'dependencies': ['ana_debug_dump_proto'],
+          'dependencies': [
+            'ana_config_proto',
+            'ana_debug_dump_proto',
+          ],
           'defines': ['WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP'],
         }],
       ], # conditions
@@ -58,6 +61,18 @@
           },
           'includes': ['../../../build/protoc.gypi',],
         },
+        { 'target_name': 'ana_config_proto',
+          'type': 'static_library',
+          'sources': ['config.proto',],
+          'variables': {
+            'proto_in_dir': '.',
+            # Workaround to protect against gyp's pathname relativization when
+            # this file is included by modules.gyp.
+            'proto_out_protected': 'webrtc/modules/audio_coding/audio_network_adaptor',
+            'proto_out_dir': '<(proto_out_protected)',
+          },
+          'includes': ['../../../build/protoc.gypi',],
+        },
       ], # targets
     }],
   ], # conditions
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
index a8068db..f363d3f 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
@@ -20,7 +20,7 @@
 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);
     ~Config();
     int initial_bitrate_bps;
     int initial_frame_length_ms;
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/config.proto b/webrtc/modules/audio_coding/audio_network_adaptor/config.proto
new file mode 100644
index 0000000..3c678fc
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/config.proto
@@ -0,0 +1,108 @@
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package webrtc.audio_network_adaptor.config;
+
+message FecController {
+  message Threshold {
+    // Threshold defines a curve in the bandwidth/packet-loss domain. The
+    // curve is characterized by the two conjunction points: A and B.
+    //
+    // packet ^  |
+    //  loss  | A|
+    //        |   \        A: (low_bandwidth_bps, low_bandwidth_packet_loss)
+    //        |    \       B: (high_bandwidth_bps, high_bandwidth_packet_loss)
+    //        |    B\________
+    //        |---------------> bandwidth
+    optional int32 low_bandwidth_bps = 1;
+    optional float low_bandwidth_packet_loss = 2;
+    optional int32 high_bandwidth_bps = 3;
+    optional float high_bandwidth_packet_loss = 4;
+  }
+
+  // |fec_enabling_threshold| defines a curve, above which FEC should be
+  // enabled. |fec_disabling_threshold| defines a curve, under which FEC
+  // should be disabled. See below
+  //
+  // packet-loss ^   |  |
+  //             |   |  |   FEC
+  //             |    \  \   ON
+  //             | FEC \  \_______ fec_enabling_threshold
+  //             | OFF  \_________ fec_disabling_threshold
+  //             |-----------------> bandwidth
+  optional Threshold fec_enabling_threshold = 1;
+  optional Threshold fec_disabling_threshold = 2;
+
+  // |time_constant_ms| is the time constant for an exponential filter, which
+  // is used for smoothing the packet loss fraction.
+  optional int32 time_constant_ms = 3;
+}
+
+message FrameLengthController {
+  // Uplink packet loss fraction below which frame length can increase.
+  optional float fl_increasing_packet_loss_fraction = 1;
+
+  // Uplink packet loss fraction below which frame length should decrease.
+  optional float fl_decreasing_packet_loss_fraction = 2;
+
+  // Uplink bandwidth below which frame length can switch from 20ms to 60ms.
+  optional int32 fl_20ms_to_60ms_bandwidth_bps = 3;
+
+  // Uplink bandwidth above which frame length should switch from 60ms to 20ms.
+  optional int32 fl_60ms_to_20ms_bandwidth_bps = 4;
+}
+
+message ChannelController {
+  // Uplink bandwidth above which the number of encoded channels should switch
+  // from 1 to 2.
+  optional int32 channel_1_to_2_bandwidth_bps = 1;
+
+  // Uplink bandwidth below which the number of encoded channels should switch
+  // from 2 to 1.
+  optional int32 channel_2_to_1_bandwidth_bps = 2;
+}
+
+message DtxController {
+  // Uplink bandwidth below which DTX should be switched on.
+  optional int32 dtx_enabling_bandwidth_bps = 1;
+
+  // Uplink bandwidth above which DTX should be switched off.
+  optional int32 dtx_disabling_bandwidth_bps = 2;
+}
+
+message BitrateController {}
+
+message Controller {
+  message ScoringPoint {
+    // |ScoringPoint| is a subspace of network condition. It is used for
+    // comparing the significance of controllers.
+    optional int32 uplink_bandwidth_bps = 1;
+    optional float uplink_packet_loss_fraction = 2;
+  }
+
+  // The distance from |scoring_point| to a given network condition defines
+  // the significance of this controller with respect that network condition.
+  // Shorter distance means higher significance. The significances of
+  // controllers determine their order in the processing pipeline. Controllers
+  // without |scoring_point| follow their default order in
+  // |ControllerManager::controllers|.
+  optional ScoringPoint scoring_point = 1;
+
+  oneof controller {
+    FecController fec_controller = 21;
+    FrameLengthController frame_length_controller = 22;
+    ChannelController channel_controller = 23;
+    DtxController dtx_controller = 24;
+    BitrateController bitrate_controller = 25;
+  }
+}
+
+message ControllerManager {
+  repeated Controller controllers = 1;
+
+  // Least time since last reordering for a new reordering to be made.
+  optional int32 min_reordering_time_ms = 2;
+
+  // Least squared distance from last scoring point for a new reordering to be
+  // made.
+  optional float min_reordering_squared_distance = 3;
+}
\ No newline at end of file
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.cc b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.cc
index 9f05b7e..5343ace 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.cc
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.cc
@@ -13,10 +13,123 @@
 #include <cmath>
 #include <utility>
 
+#include "webrtc/base/ignore_wundef.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/channel_controller.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
+#include "webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h"
 #include "webrtc/system_wrappers/include/clock.h"
 
+#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+RTC_PUSH_IGNORING_WUNDEF()
+#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
+#include "external/webrtc/webrtc/modules/audio_coding/audio_network_adaptor/config.pb.h"
+#else
+#include "webrtc/modules/audio_coding/audio_network_adaptor/config.pb.h"
+#endif
+RTC_POP_IGNORING_WUNDEF()
+#endif
+
 namespace webrtc {
 
+namespace {
+
+#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+
+std::unique_ptr<FecController> CreateFecController(
+    const audio_network_adaptor::config::FecController& config,
+    bool initial_fec_enabled,
+    const Clock* clock) {
+  RTC_CHECK(config.has_fec_enabling_threshold());
+  RTC_CHECK(config.has_fec_disabling_threshold());
+  RTC_CHECK(config.has_time_constant_ms());
+
+  auto& fec_enabling_threshold = config.fec_enabling_threshold();
+  RTC_CHECK(fec_enabling_threshold.has_low_bandwidth_bps());
+  RTC_CHECK(fec_enabling_threshold.has_low_bandwidth_packet_loss());
+  RTC_CHECK(fec_enabling_threshold.has_high_bandwidth_bps());
+  RTC_CHECK(fec_enabling_threshold.has_high_bandwidth_packet_loss());
+
+  auto& fec_disabling_threshold = config.fec_disabling_threshold();
+  RTC_CHECK(fec_disabling_threshold.has_low_bandwidth_bps());
+  RTC_CHECK(fec_disabling_threshold.has_low_bandwidth_packet_loss());
+  RTC_CHECK(fec_disabling_threshold.has_high_bandwidth_bps());
+  RTC_CHECK(fec_disabling_threshold.has_high_bandwidth_packet_loss());
+
+  return std::unique_ptr<FecController>(new FecController(FecController::Config(
+      initial_fec_enabled,
+      FecController::Config::Threshold(
+          fec_enabling_threshold.low_bandwidth_bps(),
+          fec_enabling_threshold.low_bandwidth_packet_loss(),
+          fec_enabling_threshold.high_bandwidth_bps(),
+          fec_enabling_threshold.high_bandwidth_packet_loss()),
+      FecController::Config::Threshold(
+          fec_disabling_threshold.low_bandwidth_bps(),
+          fec_disabling_threshold.low_bandwidth_packet_loss(),
+          fec_disabling_threshold.high_bandwidth_bps(),
+          fec_disabling_threshold.high_bandwidth_packet_loss()),
+      config.has_time_constant_ms(), clock)));
+}
+
+std::unique_ptr<FrameLengthController> CreateFrameLengthController(
+    const audio_network_adaptor::config::FrameLengthController& config,
+    rtc::ArrayView<const int> encoder_frame_lengths_ms,
+    int initial_frame_length_ms) {
+  RTC_CHECK(config.has_fl_increasing_packet_loss_fraction());
+  RTC_CHECK(config.has_fl_decreasing_packet_loss_fraction());
+  RTC_CHECK(config.has_fl_20ms_to_60ms_bandwidth_bps());
+  RTC_CHECK(config.has_fl_60ms_to_20ms_bandwidth_bps());
+
+  FrameLengthController::Config ctor_config(
+      std::vector<int>(), initial_frame_length_ms,
+      config.fl_increasing_packet_loss_fraction(),
+      config.fl_decreasing_packet_loss_fraction(),
+      config.fl_20ms_to_60ms_bandwidth_bps(),
+      config.fl_60ms_to_20ms_bandwidth_bps());
+
+  for (auto frame_length : encoder_frame_lengths_ms)
+    ctor_config.encoder_frame_lengths_ms.push_back(frame_length);
+
+  return std::unique_ptr<FrameLengthController>(
+      new FrameLengthController(ctor_config));
+}
+
+std::unique_ptr<ChannelController> CreateChannelController(
+    const audio_network_adaptor::config::ChannelController& config,
+    size_t num_encoder_channels,
+    size_t intial_channels_to_encode) {
+  RTC_CHECK(config.has_channel_1_to_2_bandwidth_bps());
+  RTC_CHECK(config.has_channel_2_to_1_bandwidth_bps());
+
+  return std::unique_ptr<ChannelController>(new ChannelController(
+      ChannelController::Config(num_encoder_channels, intial_channels_to_encode,
+                                config.channel_1_to_2_bandwidth_bps(),
+                                config.channel_2_to_1_bandwidth_bps())));
+}
+
+std::unique_ptr<DtxController> CreateDtxController(
+    const audio_network_adaptor::config::DtxController& dtx_config,
+    bool initial_dtx_enabled) {
+  RTC_CHECK(dtx_config.has_dtx_enabling_bandwidth_bps());
+  RTC_CHECK(dtx_config.has_dtx_disabling_bandwidth_bps());
+
+  return std::unique_ptr<DtxController>(new DtxController(DtxController::Config(
+      initial_dtx_enabled, dtx_config.dtx_enabling_bandwidth_bps(),
+      dtx_config.dtx_disabling_bandwidth_bps())));
+}
+
+using audio_network_adaptor::BitrateController;
+std::unique_ptr<BitrateController> CreateBitrateController(
+    int initial_bitrate_bps,
+    int initial_frame_length_ms) {
+  return std::unique_ptr<BitrateController>(new BitrateController(
+      BitrateController::Config(initial_bitrate_bps, initial_frame_length_ms)));
+}
+#endif  // WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+
+}  // namespace
+
 ControllerManagerImpl::Config::Config(int min_reordering_time_ms,
                                       float min_reordering_squared_distance,
                                       const Clock* clock)
@@ -26,6 +139,76 @@
 
 ControllerManagerImpl::Config::~Config() = default;
 
+std::unique_ptr<ControllerManager> ControllerManagerImpl::Create(
+    const std::string& config_string,
+    size_t num_encoder_channels,
+    rtc::ArrayView<const int> encoder_frame_lengths_ms,
+    size_t intial_channels_to_encode,
+    int initial_frame_length_ms,
+    int initial_bitrate_bps,
+    bool initial_fec_enabled,
+    bool initial_dtx_enabled,
+    const Clock* clock) {
+#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+  audio_network_adaptor::config::ControllerManager controller_manager_config;
+  controller_manager_config.ParseFromString(config_string);
+
+  std::vector<std::unique_ptr<Controller>> controllers;
+  std::map<const Controller*, std::pair<int, float>> chracteristic_points;
+
+  for (int i = 0; i < controller_manager_config.controllers_size(); ++i) {
+    auto& controller_config = controller_manager_config.controllers(i);
+    std::unique_ptr<Controller> controller;
+    switch (controller_config.controller_case()) {
+      case audio_network_adaptor::config::Controller::kFecController:
+        controller = CreateFecController(controller_config.fec_controller(),
+                                         initial_fec_enabled, clock);
+        break;
+      case audio_network_adaptor::config::Controller::kFrameLengthController:
+        controller = CreateFrameLengthController(
+            controller_config.frame_length_controller(),
+            encoder_frame_lengths_ms, initial_frame_length_ms);
+        break;
+      case audio_network_adaptor::config::Controller::kChannelController:
+        controller = CreateChannelController(
+            controller_config.channel_controller(), num_encoder_channels,
+            intial_channels_to_encode);
+        break;
+      case audio_network_adaptor::config::Controller::kDtxController:
+        controller = CreateDtxController(controller_config.dtx_controller(),
+                                         initial_dtx_enabled);
+        break;
+      case audio_network_adaptor::config::Controller::kBitrateController:
+        controller = CreateBitrateController(initial_bitrate_bps,
+                                             initial_frame_length_ms);
+        break;
+      default:
+        RTC_NOTREACHED();
+    }
+    if (controller_config.has_scoring_point()) {
+      auto& characteristic_point = controller_config.scoring_point();
+      RTC_CHECK(characteristic_point.has_uplink_bandwidth_bps());
+      RTC_CHECK(characteristic_point.has_uplink_packet_loss_fraction());
+      chracteristic_points[controller.get()] = std::make_pair<int, float>(
+          characteristic_point.uplink_bandwidth_bps(),
+          characteristic_point.uplink_packet_loss_fraction());
+    }
+    controllers.push_back(std::move(controller));
+  }
+
+  RTC_CHECK(controller_manager_config.has_min_reordering_time_ms());
+  RTC_CHECK(controller_manager_config.has_min_reordering_squared_distance());
+  return std::unique_ptr<ControllerManagerImpl>(new ControllerManagerImpl(
+      ControllerManagerImpl::Config(
+          controller_manager_config.min_reordering_time_ms(),
+          controller_manager_config.min_reordering_squared_distance(), clock),
+      std::move(controllers), chracteristic_points));
+#else
+  RTC_NOTREACHED();
+  return nullptr;
+#endif  // WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+}
+
 ControllerManagerImpl::ControllerManagerImpl(const Config& config)
     : ControllerManagerImpl(
           config,
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h
index c2ac9e3..806042e 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h
@@ -40,11 +40,25 @@
            float min_reordering_squared_distance,
            const Clock* clock);
     ~Config();
+    // Least time since last reordering for a new reordering to be made.
     int min_reordering_time_ms;
+    // Least squared distance from last scoring point for a new reordering to be
+    // made.
     float min_reordering_squared_distance;
     const Clock* clock;
   };
 
+  static std::unique_ptr<ControllerManager> Create(
+      const std::string& config_string,
+      size_t num_encoder_channels,
+      rtc::ArrayView<const int> encoder_frame_lengths_ms,
+      size_t intial_channels_to_encode,
+      int initial_frame_length_ms,
+      int initial_bitrate_bps,
+      bool initial_fec_enabled,
+      bool initial_dtx_enabled,
+      const Clock* clock);
+
   explicit ControllerManagerImpl(const Config& config);
 
   // Dependency injection for testing.
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
index a175910..414aabf 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
@@ -10,11 +10,22 @@
 
 #include <utility>
 
+#include "webrtc/base/ignore_wundef.h"
 #include "webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h"
 #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_controller.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/test/gtest.h"
 
+#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+RTC_PUSH_IGNORING_WUNDEF()
+#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
+#include "external/webrtc/webrtc/modules/audio_coding/audio_network_adaptor/config.pb.h"
+#else
+#include "webrtc/modules/audio_coding/audio_network_adaptor/config.pb.h"
+#endif
+RTC_POP_IGNORING_WUNDEF()
+#endif
+
 namespace webrtc {
 
 using ::testing::NiceMock;
@@ -190,4 +201,220 @@
       {kNumControllers - 2, kNumControllers - 1, 0, 1});
 }
 
+#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+
+namespace {
+
+void AddBitrateControllerConfig(
+    audio_network_adaptor::config::ControllerManager* config) {
+  config->add_controllers()->mutable_bitrate_controller();
+}
+
+void AddChannelControllerConfig(
+    audio_network_adaptor::config::ControllerManager* config) {
+  auto controller_config =
+      config->add_controllers()->mutable_channel_controller();
+  controller_config->set_channel_1_to_2_bandwidth_bps(31000);
+  controller_config->set_channel_2_to_1_bandwidth_bps(29000);
+}
+
+void AddDtxControllerConfig(
+    audio_network_adaptor::config::ControllerManager* config) {
+  auto controller_config = config->add_controllers()->mutable_dtx_controller();
+  controller_config->set_dtx_enabling_bandwidth_bps(55000);
+  controller_config->set_dtx_disabling_bandwidth_bps(65000);
+}
+
+void AddFecControllerConfig(
+    audio_network_adaptor::config::ControllerManager* config) {
+  auto controller_config_ext = config->add_controllers();
+  auto controller_config = controller_config_ext->mutable_fec_controller();
+  auto fec_enabling_threshold =
+      controller_config->mutable_fec_enabling_threshold();
+  fec_enabling_threshold->set_low_bandwidth_bps(17000);
+  fec_enabling_threshold->set_low_bandwidth_packet_loss(0.1f);
+  fec_enabling_threshold->set_high_bandwidth_bps(64000);
+  fec_enabling_threshold->set_high_bandwidth_packet_loss(0.05f);
+  auto fec_disabling_threshold =
+      controller_config->mutable_fec_disabling_threshold();
+  fec_disabling_threshold->set_low_bandwidth_bps(15000);
+  fec_disabling_threshold->set_low_bandwidth_packet_loss(0.08f);
+  fec_disabling_threshold->set_high_bandwidth_bps(64000);
+  fec_disabling_threshold->set_high_bandwidth_packet_loss(0.01f);
+  controller_config->set_time_constant_ms(500);
+
+  auto scoring_point = controller_config_ext->mutable_scoring_point();
+  scoring_point->set_uplink_bandwidth_bps(kChracteristicBandwithBps[0]);
+  scoring_point->set_uplink_packet_loss_fraction(
+      kChracteristicPacketLossFraction[0]);
+}
+
+void AddFrameLengthControllerConfig(
+    audio_network_adaptor::config::ControllerManager* config) {
+  auto controller_config_ext = config->add_controllers();
+  auto controller_config =
+      controller_config_ext->mutable_frame_length_controller();
+  controller_config->set_fl_decreasing_packet_loss_fraction(0.05f);
+  controller_config->set_fl_increasing_packet_loss_fraction(0.04f);
+  controller_config->set_fl_20ms_to_60ms_bandwidth_bps(72000);
+  controller_config->set_fl_60ms_to_20ms_bandwidth_bps(88000);
+
+  auto scoring_point = controller_config_ext->mutable_scoring_point();
+  scoring_point->set_uplink_bandwidth_bps(kChracteristicBandwithBps[1]);
+  scoring_point->set_uplink_packet_loss_fraction(
+      kChracteristicPacketLossFraction[1]);
+}
+
+constexpr int kInitialBitrateBps = 24000;
+constexpr size_t kIntialChannelsToEncode = 1;
+constexpr bool kInitialDtxEnabled = true;
+constexpr bool kInitialFecEnabled = true;
+constexpr int kInitialFrameLengthMs = 60;
+
+ControllerManagerStates CreateControllerManager(
+    const std::string& config_string) {
+  ControllerManagerStates states;
+  states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
+  constexpr size_t kNumEncoderChannels = 2;
+  const std::vector<int> encoder_frame_lengths_ms = {20, 60};
+  states.controller_manager = ControllerManagerImpl::Create(
+      config_string, kNumEncoderChannels, encoder_frame_lengths_ms,
+      kIntialChannelsToEncode, kInitialFrameLengthMs, kInitialBitrateBps,
+      kInitialFecEnabled, kInitialDtxEnabled, states.simulated_clock.get());
+  return states;
+}
+
+enum class ControllerType : int8_t {
+  FEC,
+  CHANNEL,
+  DTX,
+  FRAME_LENGTH,
+  BIT_RATE
+};
+
+void CheckControllersOrder(const std::vector<Controller*>& controllers,
+                           const std::vector<ControllerType>& expected_types) {
+  ASSERT_EQ(expected_types.size(), controllers.size());
+
+  // We also check that the controllers follow the initial settings.
+  AudioNetworkAdaptor::EncoderRuntimeConfig encoder_config;
+
+  // We do not check the internal logic of controllers. We only check that
+  // when no network metrics are known, controllers provide the initial values.
+  Controller::NetworkMetrics metrics;
+
+  for (size_t i = 0; i < controllers.size(); ++i) {
+    AudioNetworkAdaptor::EncoderRuntimeConfig encoder_config;
+    // We check the order of |controllers| by judging their decisions.
+    controllers[i]->MakeDecision(metrics, &encoder_config);
+    switch (expected_types[i]) {
+      case ControllerType::FEC:
+        EXPECT_EQ(rtc::Optional<bool>(kInitialFecEnabled),
+                  encoder_config.enable_fec);
+        break;
+      case ControllerType::CHANNEL:
+        EXPECT_EQ(rtc::Optional<size_t>(kIntialChannelsToEncode),
+                  encoder_config.num_channels);
+        break;
+      case ControllerType::DTX:
+        EXPECT_EQ(rtc::Optional<bool>(kInitialDtxEnabled),
+                  encoder_config.enable_dtx);
+        break;
+      case ControllerType::FRAME_LENGTH:
+        EXPECT_EQ(rtc::Optional<int>(kInitialFrameLengthMs),
+                  encoder_config.frame_length_ms);
+        break;
+      case ControllerType::BIT_RATE:
+        EXPECT_EQ(rtc::Optional<int>(kInitialBitrateBps),
+                  encoder_config.bitrate_bps);
+    }
+  }
+}
+
+}  // namespace
+
+TEST(ControllerManagerTest, CreateFromConfigStringAndCheckDefaultOrder) {
+  audio_network_adaptor::config::ControllerManager config;
+  config.set_min_reordering_time_ms(kMinReorderingTimeMs);
+  config.set_min_reordering_squared_distance(kMinReorderingSquareDistance);
+
+  AddFecControllerConfig(&config);
+  AddChannelControllerConfig(&config);
+  AddDtxControllerConfig(&config);
+  AddFrameLengthControllerConfig(&config);
+  AddBitrateControllerConfig(&config);
+
+  std::string config_string;
+  config.SerializeToString(&config_string);
+
+  auto states = CreateControllerManager(config_string);
+  Controller::NetworkMetrics metrics;
+
+  auto controllers = states.controller_manager->GetSortedControllers(metrics);
+  CheckControllersOrder(
+      controllers,
+      std::vector<ControllerType>{
+          ControllerType::FEC, ControllerType::CHANNEL, ControllerType::DTX,
+          ControllerType::FRAME_LENGTH, ControllerType::BIT_RATE});
+}
+
+TEST(ControllerManagerTest, CreateFromConfigStringAndCheckReordering) {
+  audio_network_adaptor::config::ControllerManager config;
+  config.set_min_reordering_time_ms(kMinReorderingTimeMs);
+  config.set_min_reordering_squared_distance(kMinReorderingSquareDistance);
+
+  AddChannelControllerConfig(&config);
+
+  // Internally associated with characteristic point 0.
+  AddFecControllerConfig(&config);
+
+  AddDtxControllerConfig(&config);
+
+  // Internally associated with characteristic point 1.
+  AddFrameLengthControllerConfig(&config);
+
+  AddBitrateControllerConfig(&config);
+
+  std::string config_string;
+  config.SerializeToString(&config_string);
+
+  auto states = CreateControllerManager(config_string);
+
+  Controller::NetworkMetrics metrics;
+  metrics.uplink_bandwidth_bps =
+      rtc::Optional<int>(kChracteristicBandwithBps[0]);
+  metrics.uplink_packet_loss_fraction =
+      rtc::Optional<float>(kChracteristicPacketLossFraction[0]);
+
+  auto controllers = states.controller_manager->GetSortedControllers(metrics);
+  CheckControllersOrder(controllers,
+                        std::vector<ControllerType>{
+                            ControllerType::FEC, ControllerType::FRAME_LENGTH,
+                            ControllerType::CHANNEL, ControllerType::DTX,
+                            ControllerType::BIT_RATE});
+
+  metrics.uplink_bandwidth_bps =
+      rtc::Optional<int>(kChracteristicBandwithBps[1]);
+  metrics.uplink_packet_loss_fraction =
+      rtc::Optional<float>(kChracteristicPacketLossFraction[1]);
+  states.simulated_clock->AdvanceTimeMilliseconds(kMinReorderingTimeMs - 1);
+  controllers = states.controller_manager->GetSortedControllers(metrics);
+  // Should not reorder since min reordering time is not met.
+  CheckControllersOrder(controllers,
+                        std::vector<ControllerType>{
+                            ControllerType::FEC, ControllerType::FRAME_LENGTH,
+                            ControllerType::CHANNEL, ControllerType::DTX,
+                            ControllerType::BIT_RATE});
+
+  states.simulated_clock->AdvanceTimeMilliseconds(1);
+  controllers = states.controller_manager->GetSortedControllers(metrics);
+  // Reorder now.
+  CheckControllersOrder(controllers,
+                        std::vector<ControllerType>{
+                            ControllerType::FRAME_LENGTH, ControllerType::FEC,
+                            ControllerType::CHANNEL, ControllerType::DTX,
+                            ControllerType::BIT_RATE});
+}
+#endif  // WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc b/webrtc/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
index a2f258b..7770e65 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
@@ -63,7 +63,7 @@
 DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle)
     : dump_file_(FileWrapper::Create()) {
 #ifndef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
-  RTC_DCHECK(false);
+  RTC_NOTREACHED();
 #endif
   dump_file_->OpenFromFileHandle(file_handle);
   RTC_CHECK(dump_file_->is_open());
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc
index fcf1959..07495f0 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc
@@ -30,7 +30,7 @@
                               const Threshold& fec_enabling_threshold,
                               const Threshold& fec_disabling_threshold,
                               int time_constant_ms,
-                              Clock* clock)
+                              const Clock* clock)
     : initial_fec_enabled(initial_fec_enabled),
       fec_enabling_threshold(fec_enabling_threshold),
       fec_disabling_threshold(fec_disabling_threshold),
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h
index 17aa65f..0c2388b 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h
@@ -56,12 +56,12 @@
            const Threshold& fec_enabling_threshold,
            const Threshold& fec_disabling_threshold,
            int time_constant_ms,
-           Clock* clock);
+           const Clock* clock);
     bool initial_fec_enabled;
     Threshold fec_enabling_threshold;
     Threshold fec_disabling_threshold;
     int time_constant_ms;
-    Clock* clock;
+    const Clock* clock;
   };
 
   explicit FecController(const Config& config);
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
index 82baa60..d197102 100644
--- a/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
@@ -34,9 +34,14 @@
     ~Config();
     std::vector<int> encoder_frame_lengths_ms;
     int initial_frame_length_ms;
+    // Uplink packet loss fraction below which frame length can increase.
     float fl_increasing_packet_loss_fraction;
+    // Uplink packet loss fraction below which frame length should decrease.
     float fl_decreasing_packet_loss_fraction;
+    // Uplink bandwidth below which frame length can switch from 20ms to 60ms.
     int fl_20ms_to_60ms_bandwidth_bps;
+    // Uplink bandwidth above which frame length should switch from 60ms to
+    // 20ms.
     int fl_60ms_to_20ms_bandwidth_bps;
   };