Add DecelerationTargetLevelOffset Field Trial.

This change allows NetEq to reach preferred jitter buffer size much faster
for high target delays because it uses absolute units instead of relative ones
during computation of lower_limit.

More details can be found here:
https://docs.google.com/document/d/12qPMJYFhGXrA_o_nvz9VshpzAJX6aULxFig1fTzBzDI/edit

Change-Id: I21ce0e35e25166d935fdf0325c083bcf990899f5

Bug: webrtc:10619
Change-Id: I21ce0e35e25166d935fdf0325c083bcf990899f5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135745
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Commit-Queue: Ruslan Burakov <kuddai@google.com>
Cr-Commit-Position: refs/heads/master@{#27970}
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index 9340b81..dd0d759 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -100,6 +100,29 @@
   return absl::nullopt;
 }
 
+absl::optional<int> GetDecelerationTargetLevelOffsetMs() {
+  constexpr char kDecelerationTargetLevelOffsetFieldTrial[] =
+      "WebRTC-Audio-NetEqDecelerationTargetLevelOffset";
+  if (!webrtc::field_trial::IsEnabled(
+          kDecelerationTargetLevelOffsetFieldTrial)) {
+    return absl::nullopt;
+  }
+
+  const auto field_trial_string = webrtc::field_trial::FindFullName(
+      kDecelerationTargetLevelOffsetFieldTrial);
+  int deceleration_target_level_offset_ms = -1;
+  sscanf(field_trial_string.c_str(), "Enabled-%d",
+         &deceleration_target_level_offset_ms);
+  if (deceleration_target_level_offset_ms >= 0) {
+    RTC_LOG(LS_INFO) << "NetEq deceleration_target_level_offset "
+                     << "in milliseconds "
+                     << deceleration_target_level_offset_ms;
+    // Convert into Q8.
+    return deceleration_target_level_offset_ms << 8;
+  }
+  return absl::nullopt;
+}
+
 }  // namespace
 
 namespace webrtc {
@@ -133,10 +156,14 @@
       last_pack_cng_or_dtmf_(1),
       frame_length_change_experiment_(
           field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")),
-      enable_rtx_handling_(enable_rtx_handling) {
+      enable_rtx_handling_(enable_rtx_handling),
+      deceleration_target_level_offset_ms_(
+          GetDecelerationTargetLevelOffsetMs()) {
   assert(peak_detector);  // Should never be NULL.
   RTC_CHECK(histogram_);
   RTC_DCHECK_GE(base_minimum_delay_ms_, 0);
+  RTC_DCHECK(!deceleration_target_level_offset_ms_ ||
+             *deceleration_target_level_offset_ms_ >= 0);
 
   Reset();
 }
@@ -404,26 +431,39 @@
   packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
 }
 
+void DelayManager::BufferLimits(int* lower_limit, int* higher_limit) const {
+  BufferLimits(target_level_, lower_limit, higher_limit);
+}
+
 // Note that |low_limit| and |higher_limit| are not assigned to
 // |minimum_delay_ms_| and |maximum_delay_ms_| defined by the client of this
-// class. They are computed from |target_level_| and used for decision making.
-void DelayManager::BufferLimits(int* lower_limit, int* higher_limit) const {
+// class. They are computed from |target_level| in Q8 and used for decision
+// making.
+void DelayManager::BufferLimits(int target_level,
+                                int* lower_limit,
+                                int* higher_limit) const {
   if (!lower_limit || !higher_limit) {
     RTC_LOG_F(LS_ERROR) << "NULL pointers supplied as input";
     assert(false);
     return;
   }
 
+  // |target_level| is in Q8 already.
+  *lower_limit = (target_level * 3) / 4;
+
+  if (deceleration_target_level_offset_ms_ && packet_len_ms_ > 0) {
+    *lower_limit = std::max(
+        *lower_limit,
+        target_level - *deceleration_target_level_offset_ms_ / packet_len_ms_);
+  }
+
   int window_20ms = 0x7FFF;  // Default large value for legacy bit-exactness.
   if (packet_len_ms_ > 0) {
     window_20ms = (20 << 8) / packet_len_ms_;
   }
-
-  // |target_level_| is in Q8 already.
-  *lower_limit = (target_level_ * 3) / 4;
-  // |higher_limit| is equal to |target_level_|, but should at
-  // least be 20 ms higher than |lower_limit_|.
-  *higher_limit = std::max(target_level_, *lower_limit + window_20ms);
+  // |higher_limit| is equal to |target_level|, but should at
+  // least be 20 ms higher than |lower_limit|.
+  *higher_limit = std::max(target_level, *lower_limit + window_20ms);
 }
 
 int DelayManager::TargetLevel() const {
diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h
index 9066f7f..279e608 100644
--- a/modules/audio_coding/neteq/delay_manager.h
+++ b/modules/audio_coding/neteq/delay_manager.h
@@ -101,6 +101,9 @@
   // within to the corresponding pointers. The values are in (fractions of)
   // packets in Q8.
   virtual void BufferLimits(int* lower_limit, int* higher_limit) const;
+  virtual void BufferLimits(int target_level,
+                            int* lower_limit,
+                            int* higher_limit) const;
 
   // Gets the target buffer level, in (fractions of) packets in Q8.
   virtual int TargetLevel() const;
@@ -130,6 +133,11 @@
   }
 
   // This accessor is only intended for testing purposes.
+  absl::optional<int> deceleration_target_level_offset_ms() const {
+    return deceleration_target_level_offset_ms_;
+  }
+
+  // These accessors are only intended for testing purposes.
   HistogramMode histogram_mode() const { return histogram_mode_; }
   int histogram_quantile() const { return histogram_quantile_; }
   int histogram_forget_factor() const { return histogram_->forget_factor(); }
@@ -196,6 +204,11 @@
   const bool enable_rtx_handling_;
   int num_reordered_packets_ = 0;  // Number of consecutive reordered packets.
   std::deque<int> delay_history_;
+  // When current buffer level is more than
+  // |deceleration_target_level_offset_ms_| below the target level, NetEq will
+  // impose deceleration to increase the buffer level. The value is in Q8, and
+  // measured in milliseconds.
+  const absl::optional<int> deceleration_target_level_offset_ms_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(DelayManager);
 };
diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc
index c57f074..eb1fabc 100644
--- a/modules/audio_coding/neteq/delay_manager_unittest.cc
+++ b/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -107,6 +107,7 @@
     tick_timer_.Increment();
   }
 }
+
 void DelayManagerTest::TearDown() {
   EXPECT_CALL(detector_, Die());
 }
@@ -725,4 +726,93 @@
   InsertNextPacket();
 }
 
+TEST_F(DelayManagerTest, DecelerationTargetLevelOffsetFieldTrial) {
+  {
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled-105/");
+    RecreateDelayManager();
+    EXPECT_EQ(dm_->deceleration_target_level_offset_ms().value(), 105 << 8);
+  }
+  {
+    // Negative number.
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled--105/");
+    RecreateDelayManager();
+    EXPECT_FALSE(dm_->deceleration_target_level_offset_ms().has_value());
+  }
+  {
+    // Disabled.
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Disabled/");
+    RecreateDelayManager();
+    EXPECT_FALSE(dm_->deceleration_target_level_offset_ms().has_value());
+  }
+  {
+    // Float number.
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled-105.5/");
+    RecreateDelayManager();
+    EXPECT_EQ(dm_->deceleration_target_level_offset_ms().value(), 105 << 8);
+  }
+  {
+    // Several numbers.
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled-20-40/");
+    RecreateDelayManager();
+    EXPECT_EQ(dm_->deceleration_target_level_offset_ms().value(), 20 << 8);
+  }
+}
+
+TEST_F(DelayManagerTest, DecelerationTargetLevelOffset) {
+  // Border value where 1/4 target buffer level meets
+  // WebRTC-Audio-NetEqDecelerationTargetLevelOffset.
+  constexpr int kBoarderTargetLevel = 100 * 4;
+  {
+    // Test that for a low target level, default behaviour is intact.
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled-100/");
+    const int target_level_ms = ((kBoarderTargetLevel - 1) << 8) / kFrameSizeMs;
+    RecreateDelayManager();
+    SetPacketAudioLength(kFrameSizeMs);
+
+    int lower, higher;  // In Q8.
+    dm_->BufferLimits(target_level_ms, &lower, &higher);
+
+    // Default behaviour of taking 75% of target level.
+    EXPECT_EQ(target_level_ms * 3 / 4, lower);
+    EXPECT_EQ(target_level_ms, higher);
+  }
+
+  {
+    // Test that for the high target level, |lower| is below target level by
+    // fixed constant (100 ms in this Field Trial setup).
+    test::ScopedFieldTrials field_trial(
+        "WebRTC-Audio-NetEqDecelerationTargetLevelOffset/Enabled-100/");
+    const int target_level_ms = ((kBoarderTargetLevel + 1) << 8) / kFrameSizeMs;
+    RecreateDelayManager();
+    SetPacketAudioLength(kFrameSizeMs);
+
+    int lower, higher;  // In Q8.
+    dm_->BufferLimits(target_level_ms, &lower, &higher);
+
+    EXPECT_EQ(target_level_ms - ((100 << 8) / kFrameSizeMs), lower);
+    EXPECT_EQ(target_level_ms, higher);
+  }
+
+  {
+    // Test that for the high target level, without Field Trial the behaviour
+    // will remain the same.
+    const int target_level_ms = ((kBoarderTargetLevel + 1) << 8) / kFrameSizeMs;
+    RecreateDelayManager();
+    SetPacketAudioLength(kFrameSizeMs);
+
+    int lower, higher;  // In Q8.
+    dm_->BufferLimits(target_level_ms, &lower, &higher);
+
+    // Default behaviour of taking 75% of target level.
+    EXPECT_EQ(target_level_ms * 3 / 4, lower);
+    EXPECT_EQ(target_level_ms, higher);
+  }
+}
+
 }  // namespace webrtc