diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc index e54c213e58..ebc24d444b 100644 --- a/modules/audio_coding/neteq/decision_logic_unittest.cc +++ b/modules/audio_coding/neteq/decision_logic_unittest.cc @@ -31,7 +31,7 @@ TEST(DecisionLogic, CreateAndDestroy) { TickTimer tick_timer; PacketBuffer packet_buffer(10, &tick_timer); DelayPeakDetector delay_peak_detector(&tick_timer, false); - DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer); + DelayManager delay_manager(240, 0, false, &delay_peak_detector, &tick_timer); BufferLevelFilter buffer_level_filter; DecisionLogic* logic = DecisionLogic::Create( fs_hz, output_size_samples, false, &decoder_database, packet_buffer, @@ -48,7 +48,7 @@ TEST(DecisionLogic, PostponeDecodingAfterExpansionSettings) { TickTimer tick_timer; PacketBuffer packet_buffer(10, &tick_timer); DelayPeakDetector delay_peak_detector(&tick_timer, false); - DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer); + DelayManager delay_manager(240, 0, false, &delay_peak_detector, &tick_timer); BufferLevelFilter buffer_level_filter; { test::ScopedFieldTrials field_trial( diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc index 4ca545d176..c97d5356d4 100644 --- a/modules/audio_coding/neteq/delay_manager.cc +++ b/modules/audio_coding/neteq/delay_manager.cc @@ -34,6 +34,8 @@ constexpr int kCumulativeSumDrift = 2; // Drift term for cumulative sum // Steady-state forgetting factor for |iat_vector_|, 0.9993 in Q15. constexpr int kIatFactor_ = 32745; constexpr int kMaxIat = 64; // Max inter-arrival time to register. +constexpr int kMaxReorderedPackets = + 10; // Max number of consecutive reordered packets. absl::optional GetForcedLimitProbability() { constexpr char kForceTargetDelayPercentileFieldTrial[] = @@ -63,6 +65,7 @@ namespace webrtc { DelayManager::DelayManager(size_t max_packets_in_buffer, int base_min_target_delay_ms, + bool enable_rtx_handling, DelayPeakDetector* peak_detector, const TickTimer* tick_timer) : first_packet_received_(false), @@ -85,7 +88,8 @@ DelayManager::DelayManager(size_t max_packets_in_buffer, last_pack_cng_or_dtmf_(1), frame_length_change_experiment_( field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")), - forced_limit_probability_(GetForcedLimitProbability()) { + forced_limit_probability_(GetForcedLimitProbability()), + enable_rtx_handling_(enable_rtx_handling) { assert(peak_detector); // Should never be NULL. RTC_DCHECK_GE(base_min_target_delay_ms_, 0); RTC_DCHECK_LE(minimum_delay_ms_, maximum_delay_ms_); @@ -146,6 +150,7 @@ int DelayManager::Update(uint16_t sequence_number, rtc::saturated_cast(1000 * packet_len_samp / sample_rate_hz); } + bool reordered = false; if (packet_len_ms > 0) { // Cannot update statistics unless |packet_len_ms| is valid. // Calculate inter-arrival time (IAT) in integer "packet times" @@ -158,7 +163,6 @@ int DelayManager::Update(uint16_t sequence_number, } // 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 @@ -183,6 +187,12 @@ int DelayManager::Update(uint16_t sequence_number, LimitTargetLevel(); } // End if (packet_len_ms > 0). + if (enable_rtx_handling_ && reordered && + num_reordered_packets_ < kMaxReorderedPackets) { + ++num_reordered_packets_; + return 0; + } + num_reordered_packets_ = 0; // Prepare for next packet arrival. packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); last_seq_no_ = sequence_number; diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h index 8eee49c5fc..652a7736b7 100644 --- a/modules/audio_coding/neteq/delay_manager.h +++ b/modules/audio_coding/neteq/delay_manager.h @@ -36,6 +36,7 @@ class DelayManager { // PeakDetector object to the DelayManager. DelayManager(size_t max_packets_in_buffer, int base_min_target_delay_ms, + bool enable_rtx_handling, DelayPeakDetector* peak_detector, const TickTimer* tick_timer); @@ -177,6 +178,8 @@ class DelayManager { int last_pack_cng_or_dtmf_; const bool frame_length_change_experiment_; const absl::optional forced_limit_probability_; + const bool enable_rtx_handling_; + int num_reordered_packets_ = 0; // Number of consecutive reordered packets. 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 b0e23a979c..e33b2aa894 100644 --- a/modules/audio_coding/neteq/delay_manager_unittest.cc +++ b/modules/audio_coding/neteq/delay_manager_unittest.cc @@ -46,6 +46,7 @@ class DelayManagerTest : public ::testing::Test { MockDelayPeakDetector detector_; uint16_t seq_no_; uint32_t ts_; + bool enable_rtx_handling_ = false; }; DelayManagerTest::DelayManagerTest() @@ -60,8 +61,8 @@ void DelayManagerTest::SetUp() { void DelayManagerTest::RecreateDelayManager() { EXPECT_CALL(detector_, Reset()).Times(1); - dm_.reset(new DelayManager(kMaxNumberOfPackets, kMinDelayMs, &detector_, - &tick_timer_)); + dm_.reset(new DelayManager(kMaxNumberOfPackets, kMinDelayMs, + enable_rtx_handling_, &detector_, &tick_timer_)); } void DelayManagerTest::SetPacketAudioLength(int lengt_ms) { @@ -320,6 +321,31 @@ TEST_F(DelayManagerTest, UpdateReorderedPacket) { EXPECT_EQ(0, dm_->Update(seq_no_ - 1, ts_ - kFrameSizeMs, kFs)); } +TEST_F(DelayManagerTest, EnableRtxHandling) { + enable_rtx_handling_ = true; + RecreateDelayManager(); + + // Insert first packet. + SetPacketAudioLength(kFrameSizeMs); + InsertNextPacket(); + + // Insert reordered packet. + // TODO(jakobi): Test estimated inter-arrival time by mocking the histogram + // instead of checking the call to the peak detector. + EXPECT_CALL(detector_, Update(3, true, _)); + EXPECT_EQ(0, dm_->Update(seq_no_ - 3, ts_ - 3 * kFrameSizeMs, kFs)); + + // Insert another reordered packet. + EXPECT_CALL(detector_, Update(2, true, _)); + EXPECT_EQ(0, dm_->Update(seq_no_ - 2, ts_ - 2 * kFrameSizeMs, kFs)); + + // Insert the next packet in order and verify that the inter-arrival time is + // estimated correctly. + IncreaseTime(kFrameSizeMs); + EXPECT_CALL(detector_, Update(1, false, _)); + InsertNextPacket(); +} + // Tests that skipped sequence numbers (simulating empty packets) are handled // correctly. TEST_F(DelayManagerTest, EmptyPacketsReported) { diff --git a/modules/audio_coding/neteq/mock/mock_delay_manager.h b/modules/audio_coding/neteq/mock/mock_delay_manager.h index 51c8300b1d..67c7a8a34b 100644 --- a/modules/audio_coding/neteq/mock/mock_delay_manager.h +++ b/modules/audio_coding/neteq/mock/mock_delay_manager.h @@ -21,10 +21,12 @@ class MockDelayManager : public DelayManager { public: MockDelayManager(size_t max_packets_in_buffer, int base_min_target_delay_ms, + bool enable_rtx_handling, DelayPeakDetector* peak_detector, const TickTimer* tick_timer) : DelayManager(max_packets_in_buffer, base_min_target_delay_ms, + enable_rtx_handling, peak_detector, tick_timer) {} virtual ~MockDelayManager() { Die(); } diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index 8b87d0727d..8115135f77 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc @@ -65,6 +65,7 @@ NetEqImpl::Dependencies::Dependencies( new DelayPeakDetector(tick_timer.get(), config.enable_rtx_handling)), delay_manager(new DelayManager(config.max_packets_in_buffer, config.min_delay_ms, + config.enable_rtx_handling, delay_peak_detector.get(), tick_timer.get())), dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)), diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc index a970104e30..cf627d91e7 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -97,7 +97,7 @@ class NetEqImplTest : public ::testing::Test { if (use_mock_delay_manager_) { std::unique_ptr mock(new MockDelayManager( config_.max_packets_in_buffer, config_.min_delay_ms, - delay_peak_detector_, tick_timer_)); + config_.enable_rtx_handling, delay_peak_detector_, tick_timer_)); mock_delay_manager_ = mock.get(); EXPECT_CALL(*mock_delay_manager_, set_streaming_mode(false)).Times(1); deps.delay_manager = std::move(mock); diff --git a/modules/audio_coding/neteq/tools/neteq_test.cc b/modules/audio_coding/neteq/tools/neteq_test.cc index b12a407bea..97e71bf21f 100644 --- a/modules/audio_coding/neteq/tools/neteq_test.cc +++ b/modules/audio_coding/neteq/tools/neteq_test.cc @@ -136,6 +136,7 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() { : -1; *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms << ", delta wc: " << std::setw(4) << delta_wallclock + << ", seq_no: " << packet_data->header.sequenceNumber << ", timestamp: " << std::setw(10) << packet_data->header.timestamp << ", delta ts: " << std::setw(4) << delta_timestamp