Add options to only NACK if there is a valid RTT and if loss rate is below a configured value.

Bug: webrtc:10178
Change-Id: I16a74ed6fb380cecaf82a303bb14bf215c944a73
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/238988
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35419}
diff --git a/modules/audio_coding/neteq/nack_tracker.cc b/modules/audio_coding/neteq/nack_tracker.cc
index 0edefa5..35afb73 100644
--- a/modules/audio_coding/neteq/nack_tracker.cc
+++ b/modules/audio_coding/neteq/nack_tracker.cc
@@ -32,15 +32,17 @@
   auto parser = StructParametersParser::Create(
       "packet_loss_forget_factor", &packet_loss_forget_factor,
       "ms_per_loss_percent", &ms_per_loss_percent, "never_nack_multiple_times",
-      &never_nack_multiple_times);
+      &never_nack_multiple_times, "require_valid_rtt", &require_valid_rtt,
+      "max_loss_rate", &max_loss_rate);
   parser->Parse(
       webrtc::field_trial::FindFullName(kNackTrackerConfigFieldTrial));
   RTC_LOG(LS_INFO) << "Nack tracker config:"
                       " packet_loss_forget_factor="
                    << packet_loss_forget_factor
                    << " ms_per_loss_percent=" << ms_per_loss_percent
-                   << " never_nack_multiple_times="
-                   << never_nack_multiple_times;
+                   << " never_nack_multiple_times=" << never_nack_multiple_times
+                   << " require_valid_rtt=" << require_valid_rtt
+                   << " max_loss_rate=" << max_loss_rate;
 }
 
 NackTracker::NackTracker()
@@ -223,6 +225,13 @@
 std::vector<uint16_t> NackTracker::GetNackList(int64_t round_trip_time_ms) {
   RTC_DCHECK_GE(round_trip_time_ms, 0);
   std::vector<uint16_t> sequence_numbers;
+  if (config_.require_valid_rtt && round_trip_time_ms == 0) {
+    return sequence_numbers;
+  }
+  if (packet_loss_rate_ >
+      static_cast<uint32_t>(config_.max_loss_rate * (1 << 30))) {
+    return sequence_numbers;
+  }
   // The estimated packet loss is between 0 and 1, so we need to multiply by 100
   // here.
   int max_wait_ms =
diff --git a/modules/audio_coding/neteq/nack_tracker.h b/modules/audio_coding/neteq/nack_tracker.h
index f95aa0b..0cc95b0 100644
--- a/modules/audio_coding/neteq/nack_tracker.h
+++ b/modules/audio_coding/neteq/nack_tracker.h
@@ -109,6 +109,10 @@
     int ms_per_loss_percent = 20;
     // If true, never nack packets more than once.
     bool never_nack_multiple_times = false;
+    // Only nack if the RTT is valid.
+    bool require_valid_rtt = false;
+    // Do not nack if the loss rate is above this value.
+    double max_loss_rate = 1.0;
   };
 
   struct NackElement {
diff --git a/modules/audio_coding/neteq/nack_tracker_unittest.cc b/modules/audio_coding/neteq/nack_tracker_unittest.cc
index 4639727..bcc5120 100644
--- a/modules/audio_coding/neteq/nack_tracker_unittest.cc
+++ b/modules/audio_coding/neteq/nack_tracker_unittest.cc
@@ -480,19 +480,19 @@
   nack.SetMaxNackListSize(kNackListSize);
   uint16_t seq_num = 0;
   uint32_t timestamp = 0x87654321;
-  auto add_packet = [&nack, &seq_num, &timestamp] {
-    nack.UpdateLastReceivedPacket(seq_num, timestamp);
+  auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
+    if (received) {
+      nack.UpdateLastReceivedPacket(seq_num, timestamp);
+    }
     seq_num++;
     timestamp += kTimestampIncrement;
   };
   // Add some packets, but every fourth packet is lost.
   for (int i = 0; i < 300; i++) {
-    add_packet();
-    add_packet();
-    add_packet();
-    // The next packet is lost.
-    seq_num++;
-    timestamp += kTimestampIncrement;
+    add_packet(true);
+    add_packet(true);
+    add_packet(true);
+    add_packet(false);
   }
   // 1 << 28 is 0.25 in Q30. We expect the packet loss estimate to be within
   // 0.01 of that.
@@ -514,4 +514,52 @@
   EXPECT_TRUE(nack.GetNackList(0).empty());
 }
 
+TEST(NackTrackerTest, DoNotNackIfLossRateIsTooHigh) {
+  test::ScopedFieldTrials field_trials(
+      "WebRTC-Audio-NetEqNackTrackerConfig/max_loss_rate:0.4/");
+  const int kNackListSize = 200;
+  NackTracker nack;
+  nack.UpdateSampleRate(kSampleRateHz);
+  nack.SetMaxNackListSize(kNackListSize);
+  uint16_t seq_num = 0;
+  uint32_t timestamp = 0x87654321;
+  auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
+    if (received) {
+      nack.UpdateLastReceivedPacket(seq_num, timestamp);
+    }
+    seq_num++;
+    timestamp += kTimestampIncrement;
+  };
+  for (int i = 0; i < 500; i++) {
+    add_packet(true);
+    add_packet(false);
+  }
+  // Expect 50% loss rate which is higher that the configured maximum 40%.
+  EXPECT_NEAR(nack.GetPacketLossRateForTest(), 1 << 29, (1 << 30) / 100);
+  EXPECT_TRUE(nack.GetNackList(0).empty());
+}
+
+TEST(NackTrackerTest, OnlyNackIfRttIsValid) {
+  test::ScopedFieldTrials field_trials(
+      "WebRTC-Audio-NetEqNackTrackerConfig/require_valid_rtt:true/");
+  const int kNackListSize = 200;
+  NackTracker nack;
+  nack.UpdateSampleRate(kSampleRateHz);
+  nack.SetMaxNackListSize(kNackListSize);
+  uint16_t seq_num = 0;
+  uint32_t timestamp = 0x87654321;
+  auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
+    if (received) {
+      nack.UpdateLastReceivedPacket(seq_num, timestamp);
+    }
+    seq_num++;
+    timestamp += kTimestampIncrement;
+  };
+  add_packet(true);
+  add_packet(false);
+  add_packet(true);
+  EXPECT_TRUE(nack.GetNackList(0).empty());
+  EXPECT_FALSE(nack.GetNackList(10).empty());
+}
+
 }  // namespace webrtc