Allowing 40ms audio frame length.

Currently 20ms, 60ms and 120ms frame length are supported. The motivation is to better adapt audio bit rate to network conditions with more frame length choices.

This is continuation of https://webrtc-review.googlesource.com/c/src/+/146206, since crodbro is out of office, I created this commit for continuing the code review.

Bug: webrtc:10820
Change-Id: I0e35e91b524f63686bfdf767b7a95c51aeb24716
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/146780
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Alex Narest <alexnarest@webrtc.org>
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28882}
diff --git a/modules/audio_coding/audio_network_adaptor/config.proto b/modules/audio_coding/audio_network_adaptor/config.proto
index 6d1cd42..90c58e5 100644
--- a/modules/audio_coding/audio_network_adaptor/config.proto
+++ b/modules/audio_coding/audio_network_adaptor/config.proto
@@ -98,6 +98,22 @@
 
   // Offset to apply to the per-packet overhead when decreasing frame length.
   optional int32 fl_decrease_overhead_offset = 8;
+
+  // Uplink bandwidth below which frame length can switch from 20ms to 40ms. In
+  // current implementation, defining this will invalidate
+  // fl_20ms_to_60ms_bandwidth_bps.
+  optional int32 fl_20ms_to_40ms_bandwidth_bps = 9;
+
+  // Uplink bandwidth above which frame length should switch from 40ms to 20ms.
+  optional int32 fl_40ms_to_20ms_bandwidth_bps = 10;
+
+  // Uplink bandwidth below which frame length can switch from 40ms to 60ms.
+  optional int32 fl_40ms_to_60ms_bandwidth_bps = 11;
+
+  // Uplink bandwidth above which frame length should switch from 60ms to 40ms.
+  // In current implementation, defining this will invalidate
+  // fl_60ms_to_20ms_bandwidth_bps.
+  optional int32 fl_60ms_to_40ms_bandwidth_bps = 12;
 }
 
 message ChannelController {
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.cc b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
index 4c0e61c..f22df54 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
@@ -118,21 +118,53 @@
     int min_encoder_bitrate_bps) {
   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());
 
   std::map<FrameLengthController::Config::FrameLengthChange, int>
-      fl_changing_bandwidths_bps = {
-          {FrameLengthController::Config::FrameLengthChange(20, 60),
-           config.fl_20ms_to_60ms_bandwidth_bps()},
-          {FrameLengthController::Config::FrameLengthChange(60, 20),
-           config.fl_60ms_to_20ms_bandwidth_bps()}};
+      fl_changing_bandwidths_bps;
 
-  if (config.has_fl_60ms_to_120ms_bandwidth_bps() &&
-      config.has_fl_120ms_to_60ms_bandwidth_bps()) {
+  if (config.has_fl_20ms_to_60ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(20, 60),
+                       config.fl_20ms_to_60ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_60ms_to_20ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(60, 20),
+                       config.fl_60ms_to_20ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_20ms_to_40ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(20, 40),
+                       config.fl_20ms_to_40ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_40ms_to_20ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(40, 20),
+                       config.fl_40ms_to_20ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_40ms_to_60ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(40, 60),
+                       config.fl_40ms_to_60ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_60ms_to_40ms_bandwidth_bps()) {
+    fl_changing_bandwidths_bps.insert(
+        std::make_pair(FrameLengthController::Config::FrameLengthChange(60, 40),
+                       config.fl_60ms_to_40ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_60ms_to_120ms_bandwidth_bps()) {
     fl_changing_bandwidths_bps.insert(std::make_pair(
         FrameLengthController::Config::FrameLengthChange(60, 120),
         config.fl_60ms_to_120ms_bandwidth_bps()));
+  }
+
+  if (config.has_fl_120ms_to_60ms_bandwidth_bps()) {
     fl_changing_bandwidths_bps.insert(std::make_pair(
         FrameLengthController::Config::FrameLengthChange(120, 60),
         config.fl_120ms_to_60ms_bandwidth_bps()));
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
index 7fa4096..c267b79 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
@@ -249,8 +249,10 @@
       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);
+  controller_config->set_fl_20ms_to_40ms_bandwidth_bps(80000);
+  controller_config->set_fl_40ms_to_20ms_bandwidth_bps(88000);
+  controller_config->set_fl_40ms_to_60ms_bandwidth_bps(72000);
+  controller_config->set_fl_60ms_to_40ms_bandwidth_bps(80000);
 
   auto scoring_point = controller_config_ext->mutable_scoring_point();
   scoring_point->set_uplink_bandwidth_bps(kChracteristicBandwithBps[1]);
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
index 9db9853..0ffa54a 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
@@ -30,8 +30,13 @@
 constexpr int kFl60msTo20msBandwidthBps = 50000;
 constexpr int kFl60msTo120msBandwidthBps = 30000;
 constexpr int kFl120msTo60msBandwidthBps = 40000;
+constexpr int kFl20msTo40msBandwidthBps = 45000;
+constexpr int kFl40msTo20msBandwidthBps = 50000;
+constexpr int kFl40msTo60msBandwidthBps = 40000;
+constexpr int kFl60msTo40msBandwidthBps = 45000;
+
 constexpr int kMediumBandwidthBps =
-    (kFl60msTo20msBandwidthBps + kFl20msTo60msBandwidthBps) / 2;
+    (kFl40msTo20msBandwidthBps + kFl20msTo40msBandwidthBps) / 2;
 constexpr float kMediumPacketLossFraction =
     (kFlDecreasingPacketLossFraction + kFlIncreasingPacketLossFraction) / 2;
 const std::set<int> kDefaultEncoderFrameLengthsMs = {20, 40, 60, 120};
@@ -66,6 +71,15 @@
 }
 
 std::map<FrameLengthController::Config::FrameLengthChange, int>
+CreateChangeCriteriaFor20msAnd40ms() {
+  return std::map<FrameLengthController::Config::FrameLengthChange, int>{
+      {FrameLengthController::Config::FrameLengthChange(20, 40),
+       kFl20msTo40msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(40, 20),
+       kFl40msTo20msBandwidthBps}};
+}
+
+std::map<FrameLengthController::Config::FrameLengthChange, int>
 CreateChangeCriteriaFor20ms60msAnd120ms() {
   return std::map<FrameLengthController::Config::FrameLengthChange, int>{
       {FrameLengthController::Config::FrameLengthChange(20, 60),
@@ -78,6 +92,36 @@
        kFl120msTo60msBandwidthBps}};
 }
 
+std::map<FrameLengthController::Config::FrameLengthChange, int>
+CreateChangeCriteriaFor20ms40ms60msAnd120ms() {
+  return std::map<FrameLengthController::Config::FrameLengthChange, int>{
+      {FrameLengthController::Config::FrameLengthChange(20, 60),
+       kFl20msTo60msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(60, 20),
+       kFl60msTo20msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(20, 40),
+       kFl20msTo40msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(40, 20),
+       kFl40msTo20msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(40, 60),
+       kFl40msTo60msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(60, 40),
+       kFl60msTo40msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(60, 120),
+       kFl60msTo120msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(120, 60),
+       kFl120msTo60msBandwidthBps}};
+}
+
+std::map<FrameLengthController::Config::FrameLengthChange, int>
+CreateChangeCriteriaFor40msAnd60ms() {
+  return std::map<FrameLengthController::Config::FrameLengthChange, int>{
+      {FrameLengthController::Config::FrameLengthChange(40, 60),
+       kFl40msTo60msBandwidthBps},
+      {FrameLengthController::Config::FrameLengthChange(60, 40),
+       kFl60msTo40msBandwidthBps}};
+}
+
 void UpdateNetworkMetrics(
     FrameLengthController* controller,
     const absl::optional<int>& uplink_bandwidth_bps,
@@ -138,6 +182,28 @@
   CheckDecision(controller.get(), 60);
 }
 
+TEST(FrameLengthControllerTest, IncreaseTo40MsOnMultipleConditions) {
+  // Increase to 40ms frame length if
+  // 1. |uplink_bandwidth_bps| is known to be smaller than a threshold AND
+  // 2. |uplink_packet_loss_fraction| is known to be smaller than a threshold
+  //    AND
+  // 3. FEC is not decided or OFF.
+  auto controller = CreateController(CreateChangeCriteriaFor20msAnd40ms(),
+                                     kDefaultEncoderFrameLengthsMs, 20);
+  UpdateNetworkMetrics(controller.get(), kFl20msTo40msBandwidthBps,
+                       kFlIncreasingPacketLossFraction,
+                       kOverheadBytesPerPacket);
+  CheckDecision(controller.get(), 40);
+}
+
+TEST(FrameLengthControllerTest, DecreaseTo40MsOnHighUplinkBandwidth) {
+  auto controller = CreateController(CreateChangeCriteriaFor40msAnd60ms(),
+                                     kDefaultEncoderFrameLengthsMs, 40);
+  UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
+                       absl::nullopt, kOverheadBytesPerPacket);
+  CheckDecision(controller.get(), 40);
+}
+
 TEST(FrameLengthControllerTest, Maintain60MsOnMultipleConditions) {
   // Maintain 60ms frame length if
   // 1. |uplink_bandwidth_bps| is at medium level,
@@ -328,13 +394,23 @@
 }
 
 TEST(FrameLengthControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
-  auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
-                                     kDefaultEncoderFrameLengthsMs, 20);
+  auto controller =
+      CreateController(CreateChangeCriteriaFor20ms40ms60msAnd120ms(),
+                       kDefaultEncoderFrameLengthsMs, 20);
   UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
                        kFlIncreasingPacketLossFraction,
                        kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 20);
 
+  UpdateNetworkMetrics(controller.get(), kFl20msTo40msBandwidthBps,
+                       kFlIncreasingPacketLossFraction,
+                       kOverheadBytesPerPacket);
+  CheckDecision(controller.get(), 40);
+
+  UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
+                       kMediumPacketLossFraction, kOverheadBytesPerPacket);
+  CheckDecision(controller.get(), 40);
+
   UpdateNetworkMetrics(controller.get(), kFl20msTo60msBandwidthBps,
                        kFlIncreasingPacketLossFraction,
                        kOverheadBytesPerPacket);
@@ -354,6 +430,11 @@
                        kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 60);
 
+  UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
+                       kFlDecreasingPacketLossFraction,
+                       kOverheadBytesPerPacket);
+  CheckDecision(controller.get(), 40);
+
   UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
                        kFlDecreasingPacketLossFraction,
                        kOverheadBytesPerPacket);