Add NetEq config flag that enables RTX handling.

When enabled, the delay manager is updated with reordered packets. It also makes the peak detector ignore the reordered packets.

Change-Id: I2bdc99764cc76b15e613ed3dc75f83aaf66eee4e
Bug: webrtc:10178
Reviewed-on: https://webrtc-review.googlesource.com/c/116481
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26187}
diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc
index 183b9c7..e54c213 100644
--- a/modules/audio_coding/neteq/decision_logic_unittest.cc
+++ b/modules/audio_coding/neteq/decision_logic_unittest.cc
@@ -30,7 +30,7 @@
       new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
   TickTimer tick_timer;
   PacketBuffer packet_buffer(10, &tick_timer);
-  DelayPeakDetector delay_peak_detector(&tick_timer);
+  DelayPeakDetector delay_peak_detector(&tick_timer, false);
   DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
   BufferLevelFilter buffer_level_filter;
   DecisionLogic* logic = DecisionLogic::Create(
@@ -47,7 +47,7 @@
       new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
   TickTimer tick_timer;
   PacketBuffer packet_buffer(10, &tick_timer);
-  DelayPeakDetector delay_peak_detector(&tick_timer);
+  DelayPeakDetector delay_peak_detector(&tick_timer, false);
   DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
   BufferLevelFilter buffer_level_filter;
   {
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index 67e6a13..cbf3da1 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -158,6 +158,7 @@
     }
 
     // Check for discontinuous packet sequence and re-ordering.
+    bool reordered = false;
     if (IsNewerSequenceNumber(sequence_number, last_seq_no_ + 1)) {
       // Compensate for gap in the sequence numbers. Reduce IAT with the
       // expected extra time due to lost packets, but ensure that the IAT is
@@ -166,6 +167,7 @@
       iat_packets = std::max(iat_packets, 0);
     } else if (!IsNewerSequenceNumber(sequence_number, last_seq_no_)) {
       iat_packets += static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number);
+      reordered = true;
     }
 
     // Saturate IAT at maximum value.
@@ -173,7 +175,7 @@
     iat_packets = std::min(iat_packets, max_iat);
     UpdateHistogram(iat_packets);
     // Calculate new |target_level_| based on updated statistics.
-    target_level_ = CalculateTargetLevel(iat_packets);
+    target_level_ = CalculateTargetLevel(iat_packets, reordered);
     if (streaming_mode_) {
       target_level_ = std::max(target_level_, max_iat_cumulative_sum_);
     }
@@ -294,7 +296,7 @@
   target_level_ = std::max(target_level_, 1 << 8);
 }
 
-int DelayManager::CalculateTargetLevel(int iat_packets) {
+int DelayManager::CalculateTargetLevel(int iat_packets, bool reordered) {
   int limit_probability = forced_limit_probability_.value_or(kLimitProbability);
   if (streaming_mode_) {
     limit_probability = kLimitProbabilityStreaming;
@@ -325,7 +327,8 @@
   base_target_level_ = static_cast<int>(index);
 
   // Update detector for delay peaks.
-  bool delay_peak_found = peak_detector_.Update(iat_packets, target_level);
+  bool delay_peak_found =
+      peak_detector_.Update(iat_packets, reordered, target_level);
   if (delay_peak_found) {
     target_level = std::max(target_level, peak_detector_.MaxPeakHeight());
   }
diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h
index 2c8081b..ce05bcc 100644
--- a/modules/audio_coding/neteq/delay_manager.h
+++ b/modules/audio_coding/neteq/delay_manager.h
@@ -57,7 +57,7 @@
   // Sets target_level_ (in Q8) and returns the same value. Also calculates
   // and updates base_target_level_, which is the target buffer level before
   // taking delay peaks into account.
-  virtual int CalculateTargetLevel(int iat_packets);
+  virtual int CalculateTargetLevel(int iat_packets, bool reordered);
 
   // Notifies the DelayManager of how much audio data is carried in each packet.
   // The method updates the DelayPeakDetector too, and resets the inter-arrival
diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc
index 6281a15..e1cca89 100644
--- a/modules/audio_coding/neteq/delay_manager_unittest.cc
+++ b/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -49,7 +49,10 @@
 };
 
 DelayManagerTest::DelayManagerTest()
-    : dm_(nullptr), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {}
+    : dm_(nullptr),
+      detector_(&tick_timer_, false),
+      seq_no_(0x1234),
+      ts_(0x12345678) {}
 
 void DelayManagerTest::SetUp() {
   RecreateDelayManager();
@@ -126,7 +129,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
   InsertNextPacket();
   EXPECT_EQ(1 << 8, dm_->TargetLevel());  // In Q8.
   EXPECT_EQ(1, dm_->base_target_level());
@@ -149,7 +152,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(2, 2)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(2, false, 2)).WillOnce(Return(false));
   InsertNextPacket();
   EXPECT_EQ(2 << 8, dm_->TargetLevel());  // In Q8.
   EXPECT_EQ(2, dm_->base_target_level());
@@ -172,7 +175,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return true to indicate that peaks are found. Let the peak height be 5.
-  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(true));
+  EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(true));
   EXPECT_CALL(detector_, MaxPeakHeight()).WillOnce(Return(5));
   InsertNextPacket();
   EXPECT_EQ(5 << 8, dm_->TargetLevel());
@@ -194,7 +197,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
   InsertNextPacket();
   const int kExpectedTarget = 1;
   EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel());  // In Q8.
@@ -216,7 +219,7 @@
   // Second packet arrival.
   // Expect detector update method to be called once with inter-arrival time
   // equal to |kExpectedTarget| packet. Return true to indicate peaks found.
-  EXPECT_CALL(detector_, Update(kExpectedTarget, _))
+  EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(detector_, MaxPeakHeight())
       .WillRepeatedly(Return(kExpectedTarget));
@@ -246,7 +249,7 @@
   // Second packet arrival.
   // Expect detector update method to be called once with inter-arrival time
   // equal to |kExpectedTarget| packet. Return true to indicate peaks found.
-  EXPECT_CALL(detector_, Update(kExpectedTarget, _))
+  EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(detector_, MaxPeakHeight())
       .WillRepeatedly(Return(kExpectedTarget));
@@ -264,6 +267,15 @@
   EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel());
 }
 
+TEST_F(DelayManagerTest, UpdateReorderedPacket) {
+  SetPacketAudioLength(kFrameSizeMs);
+  InsertNextPacket();
+
+  // Insert packet that was sent before the previous packet.
+  EXPECT_CALL(detector_, Update(_, true, _));
+  EXPECT_EQ(0, dm_->Update(seq_no_ - 1, ts_ - kFrameSizeMs, kFs));
+}
+
 // Tests that skipped sequence numbers (simulating empty packets) are handled
 // correctly.
 TEST_F(DelayManagerTest, EmptyPacketsReported) {
@@ -285,7 +297,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
   InsertNextPacket();
 
   EXPECT_EQ(1 << 8, dm_->TargetLevel());  // In Q8.
@@ -309,7 +321,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(10, 10)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(10, false, 10)).WillOnce(Return(false));
   InsertNextPacket();
 
   // Note 10 times higher target value.
@@ -348,7 +360,7 @@
   // Second packet arrival.
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet.
-  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
   InsertNextPacket();
   constexpr int kExpectedTarget = 1;
   EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel());  // In Q8.
diff --git a/modules/audio_coding/neteq/delay_peak_detector.cc b/modules/audio_coding/neteq/delay_peak_detector.cc
index 893ce3e..5669d72 100644
--- a/modules/audio_coding/neteq/delay_peak_detector.cc
+++ b/modules/audio_coding/neteq/delay_peak_detector.cc
@@ -26,10 +26,12 @@
 
 DelayPeakDetector::~DelayPeakDetector() = default;
 
-DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer)
+DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer,
+                                     bool ignore_reordered_packets)
     : peak_found_(false),
       peak_detection_threshold_(0),
       tick_timer_(tick_timer),
+      ignore_reordered_packets_(ignore_reordered_packets),
       frame_length_change_experiment_(
           field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) {
   RTC_DCHECK(!peak_period_stopwatch_);
@@ -79,7 +81,12 @@
   return max_period_element->period_ms;
 }
 
-bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
+bool DelayPeakDetector::Update(int inter_arrival_time,
+                               bool reordered,
+                               int target_level) {
+  if (ignore_reordered_packets_ && reordered) {
+    return CheckPeakConditions();
+  }
   if (inter_arrival_time > target_level + peak_detection_threshold_ ||
       inter_arrival_time > 2 * target_level) {
     // A delay peak is observed.
diff --git a/modules/audio_coding/neteq/delay_peak_detector.h b/modules/audio_coding/neteq/delay_peak_detector.h
index 272d50e..5c74117 100644
--- a/modules/audio_coding/neteq/delay_peak_detector.h
+++ b/modules/audio_coding/neteq/delay_peak_detector.h
@@ -23,7 +23,7 @@
 
 class DelayPeakDetector {
  public:
-  DelayPeakDetector(const TickTimer* tick_timer);
+  DelayPeakDetector(const TickTimer* tick_timer, bool ignore_reordered_packets);
   virtual ~DelayPeakDetector();
   virtual void Reset();
 
@@ -43,10 +43,11 @@
   // larger than 0), or 0 if no delay peaks have been observed recently.
   virtual uint64_t MaxPeakPeriod() const;
 
-  // Updates the DelayPeakDetector with a new inter-arrival time (in packets)
-  // and the current target buffer level (needed to decide if a peak is observed
-  // or not). Returns true if peak-mode is active, false if not.
-  virtual bool Update(int inter_arrival_time, int target_level);
+  // Updates the DelayPeakDetector with a new inter-arrival time (in packets),
+  // the current target buffer level (needed to decide if a peak is observed or
+  // not) and if the new inter-arrival time includes a compensation for
+  // reordering. Returns true if peak-mode is active, false if not.
+  virtual bool Update(int inter_arrival_time, bool reordered, int target_level);
 
  private:
   static const size_t kMaxNumPeaks = 8;
@@ -66,6 +67,7 @@
   int peak_detection_threshold_;
   const TickTimer* tick_timer_;
   std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_;
+  const bool ignore_reordered_packets_;
   const bool frame_length_change_experiment_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
diff --git a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
index fd4dded..6590dc2 100644
--- a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
+++ b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
@@ -18,14 +18,14 @@
 
 TEST(DelayPeakDetector, CreateAndDestroy) {
   TickTimer tick_timer;
-  DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer);
+  DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer, false);
   EXPECT_FALSE(detector->peak_found());
   delete detector;
 }
 
 TEST(DelayPeakDetector, EmptyHistory) {
   TickTimer tick_timer;
-  DelayPeakDetector detector(&tick_timer);
+  DelayPeakDetector detector(&tick_timer, false);
   EXPECT_EQ(-1, detector.MaxPeakHeight());
   EXPECT_EQ(0u, detector.MaxPeakPeriod());
 }
@@ -35,7 +35,7 @@
 // start. This should then continue until it is disengaged due to lack of peaks.
 TEST(DelayPeakDetector, TriggerPeakMode) {
   TickTimer tick_timer;
-  DelayPeakDetector detector(&tick_timer);
+  DelayPeakDetector detector(&tick_timer, false);
   const int kPacketSizeMs = 30;
   detector.SetPacketAudioLength(kPacketSizeMs);
 
@@ -69,9 +69,9 @@
           (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
       const int kTargetBufferLevel = 1;  // Define peaks to be iat > 2.
       if (time < peak_mode_start_ms || time > peak_mode_end_ms) {
-        EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
+        EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
       } else {
-        EXPECT_TRUE(detector.Update(iat_packets, kTargetBufferLevel));
+        EXPECT_TRUE(detector.Update(iat_packets, false, kTargetBufferLevel));
         EXPECT_EQ(kWorstPeakPeriod, detector.MaxPeakPeriod());
         EXPECT_EQ(kPeakDelayMs / kPacketSizeMs + 1, detector.MaxPeakHeight());
       }
@@ -87,7 +87,7 @@
 // The delay pattern has peaks with delay = 3, thus should not trigger.
 TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
   TickTimer tick_timer;
-  DelayPeakDetector detector(&tick_timer);
+  DelayPeakDetector detector(&tick_timer, false);
   const int kPacketSizeMs = 30;
   detector.SetPacketAudioLength(kPacketSizeMs);
 
@@ -115,7 +115,7 @@
       int iat_packets =
           (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
       const int kTargetBufferLevel = 2;  // Define peaks to be iat > 4.
-      EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
+      EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
       ++next;
     }
     tick_timer.Increment();
@@ -129,15 +129,33 @@
 // problems.
 TEST(DelayPeakDetector, ZeroDistancePeaks) {
   TickTimer tick_timer;
-  DelayPeakDetector detector(&tick_timer);
+  DelayPeakDetector detector(&tick_timer, false);
   const int kPacketSizeMs = 30;
   detector.SetPacketAudioLength(kPacketSizeMs);
 
   const int kTargetBufferLevel = 2;  // Define peaks to be iat > 4.
-  const int kInterArrivalTime = 3 * kTargetBufferLevel;  // Will trigger a peak.
-  EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
-  EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
-  EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
+  const int kInterArrivalTime =
+      3 * kTargetBufferLevel;  // Above peak threshold.
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+  tick_timer.Increment();
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+  // The following would fail if there were non-zero time between the updates.
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+}
+
+TEST(DelayPeakDetector, IgnoreReorderedPacket) {
+  TickTimer tick_timer;
+  DelayPeakDetector detector(&tick_timer, true);
+
+  const int kTargetBufferLevel = 2;  // Define peaks to be iat > 4.
+  const int kInterArrivalTime =
+      3 * kTargetBufferLevel;  // Above peak threshold.
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+  tick_timer.Increment();
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+  tick_timer.Increment();
+  // The following would fail if the packet was not reordered.
+  EXPECT_FALSE(detector.Update(kInterArrivalTime, true, kTargetBufferLevel));
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/include/neteq.h b/modules/audio_coding/neteq/include/neteq.h
index bc4490d..70bedfb 100644
--- a/modules/audio_coding/neteq/include/neteq.h
+++ b/modules/audio_coding/neteq/include/neteq.h
@@ -117,6 +117,7 @@
     int min_delay_ms = 0;
     bool enable_fast_accelerate = false;
     bool enable_muted_state = false;
+    bool enable_rtx_handling = false;
     absl::optional<AudioCodecPairId> codec_pair_id;
     bool for_test_no_time_stretching = false;  // Use only for testing.
   };
diff --git a/modules/audio_coding/neteq/mock/mock_delay_manager.h b/modules/audio_coding/neteq/mock/mock_delay_manager.h
index 206cea7..1671741 100644
--- a/modules/audio_coding/neteq/mock/mock_delay_manager.h
+++ b/modules/audio_coding/neteq/mock/mock_delay_manager.h
@@ -34,7 +34,7 @@
                int(uint16_t sequence_number,
                    uint32_t timestamp,
                    int sample_rate_hz));
-  MOCK_METHOD1(CalculateTargetLevel, int(int iat_packets));
+  MOCK_METHOD2(CalculateTargetLevel, int(int iat_packets, bool reordered));
   MOCK_METHOD1(SetPacketAudioLength, int(int length_ms));
   MOCK_METHOD0(Reset, void());
   MOCK_CONST_METHOD0(PeakFound, bool());
diff --git a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
index f6cdea0..f7f0465 100644
--- a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
+++ b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
@@ -19,8 +19,9 @@
 
 class MockDelayPeakDetector : public DelayPeakDetector {
  public:
-  MockDelayPeakDetector(const TickTimer* tick_timer)
-      : DelayPeakDetector(tick_timer) {}
+  MockDelayPeakDetector(const TickTimer* tick_timer,
+                        bool ignore_reordered_packets)
+      : DelayPeakDetector(tick_timer, ignore_reordered_packets) {}
   virtual ~MockDelayPeakDetector() { Die(); }
   MOCK_METHOD0(Die, void());
   MOCK_METHOD0(Reset, void());
@@ -28,7 +29,8 @@
   MOCK_METHOD0(peak_found, bool());
   MOCK_CONST_METHOD0(MaxPeakHeight, int());
   MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t());
-  MOCK_METHOD2(Update, bool(int inter_arrival_time, int target_level));
+  MOCK_METHOD3(Update,
+               bool(int inter_arrival_time, bool reordered, int target_level));
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq.cc b/modules/audio_coding/neteq/neteq.cc
index 0e6147e..a84c942 100644
--- a/modules/audio_coding/neteq/neteq.cc
+++ b/modules/audio_coding/neteq/neteq.cc
@@ -28,9 +28,10 @@
   ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
      << (enable_post_decode_vad ? "true" : "false")
      << ", max_packets_in_buffer=" << max_packets_in_buffer
-     << ", enable_fast_accelerate="
-     << (enable_fast_accelerate ? " true" : "false")
-     << ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
+     << ", min_delay_ms=" << min_delay_ms << ", enable_fast_accelerate="
+     << (enable_fast_accelerate ? "true" : "false")
+     << ", enable_muted_state=" << (enable_muted_state ? "true" : "false")
+     << ", enable_rtx_handling=" << (enable_rtx_handling ? "true" : "false");
   return ss.str();
 }
 
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index e1b3bc1..00c9172 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -61,7 +61,8 @@
       buffer_level_filter(new BufferLevelFilter),
       decoder_database(
           new DecoderDatabase(decoder_factory, config.codec_pair_id)),
-      delay_peak_detector(new DelayPeakDetector(tick_timer.get())),
+      delay_peak_detector(
+          new DelayPeakDetector(tick_timer.get(), config.enable_rtx_handling)),
       delay_manager(new DelayManager(config.max_packets_in_buffer,
                                      config.min_delay_ms,
                                      delay_peak_detector.get(),
@@ -112,7 +113,8 @@
       speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
                                 10,  // Report once every 10 s.
                                 tick_timer_.get()),
-      no_time_stretching_(config.for_test_no_time_stretching) {
+      no_time_stretching_(config.for_test_no_time_stretching),
+      enable_rtx_handling_(config.enable_rtx_handling) {
   RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
   int fs = config.sample_rate_hz;
   if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
@@ -737,9 +739,11 @@
     }
 
     // Update statistics.
-    if ((int32_t)(main_timestamp - timestamp_) >= 0 && !new_codec_) {
+    if ((enable_rtx_handling_ || (int32_t)(main_timestamp - timestamp_) >= 0) &&
+        !new_codec_) {
       // Only update statistics if incoming packet is not older than last played
-      // out packet, and if new codec flag is not set.
+      // out packet or RTX handling is enabled, and if new codec flag is not
+      // set.
       delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz_);
     }
   } else if (delay_manager_->last_pack_cng_or_dtmf() == -1) {
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index 1c730d7..e695c6f 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -408,6 +408,7 @@
   ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
   bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_);  // Only used for test.
   rtc::BufferT<int16_t> concealment_audio_ RTC_GUARDED_BY(crit_sect_);
+  const bool enable_rtx_handling_ RTC_GUARDED_BY(crit_sect_);
 
  private:
   RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 15ec1f4..43b134b 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -87,7 +87,7 @@
 
     if (use_mock_delay_peak_detector_) {
       std::unique_ptr<MockDelayPeakDetector> mock(
-          new MockDelayPeakDetector(tick_timer_));
+          new MockDelayPeakDetector(tick_timer_, config_.enable_rtx_handling));
       mock_delay_peak_detector_ = mock.get();
       EXPECT_CALL(*mock_delay_peak_detector_, Reset()).Times(1);
       deps.delay_peak_detector = std::move(mock);
@@ -1301,6 +1301,43 @@
   neteq_->InsertEmptyPacket(rtp_header);
 }
 
+TEST_F(NetEqImplTest, EnableRtxHandling) {
+  UseNoMocks();
+  use_mock_delay_manager_ = true;
+  config_.enable_rtx_handling = true;
+  CreateInstance();
+  EXPECT_CALL(*mock_delay_manager_, BufferLimits(_, _))
+      .Times(1)
+      .WillOnce(DoAll(SetArgPointee<0>(0), SetArgPointee<1>(0)));
+
+  const int kPayloadLengthSamples = 80;
+  const size_t kPayloadLengthBytes = 2 * kPayloadLengthSamples;  // PCM 16-bit.
+  const uint8_t kPayloadType = 17;  // Just an arbitrary number.
+  const uint32_t kReceiveTime = 17;
+  uint8_t payload[kPayloadLengthBytes] = {0};
+  RTPHeader rtp_header;
+  rtp_header.payloadType = kPayloadType;
+  rtp_header.sequenceNumber = 0x1234;
+  rtp_header.timestamp = 0x12345678;
+  rtp_header.ssrc = 0x87654321;
+
+  EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
+                            NetEqDecoder::kDecoderPCM16B, "", kPayloadType));
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
+  AudioFrame output;
+  bool muted;
+  EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
+
+  // Insert second packet that was sent before the first packet.
+  rtp_header.sequenceNumber -= 1;
+  rtp_header.timestamp -= kPayloadLengthSamples;
+  EXPECT_CALL(*mock_delay_manager_,
+              Update(rtp_header.sequenceNumber, rtp_header.timestamp, _));
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
+}
+
 class Decoder120ms : public AudioDecoder {
  public:
   Decoder120ms(int sample_rate_hz, SpeechType speech_type)