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)