diff --git a/modules/audio_coding/neteq/nack_tracker.cc b/modules/audio_coding/neteq/nack_tracker.cc index 0edefa58df..35afb736c8 100644 --- a/modules/audio_coding/neteq/nack_tracker.cc +++ b/modules/audio_coding/neteq/nack_tracker.cc @@ -32,15 +32,17 @@ NackTracker::Config::Config() { 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 @@ int64_t NackTracker::TimeToPlay(uint32_t timestamp) const { std::vector NackTracker::GetNackList(int64_t round_trip_time_ms) { RTC_DCHECK_GE(round_trip_time_ms, 0); std::vector sequence_numbers; + if (config_.require_valid_rtt && round_trip_time_ms == 0) { + return sequence_numbers; + } + if (packet_loss_rate_ > + static_cast(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 f95aa0b490..0cc95b0882 100644 --- a/modules/audio_coding/neteq/nack_tracker.h +++ b/modules/audio_coding/neteq/nack_tracker.h @@ -109,6 +109,10 @@ class NackTracker { 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 4639727cad..bcc5120ff3 100644 --- a/modules/audio_coding/neteq/nack_tracker_unittest.cc +++ b/modules/audio_coding/neteq/nack_tracker_unittest.cc @@ -480,19 +480,19 @@ TEST(NackTrackerTest, PacketLossRateCorrect) { nack.SetMaxNackListSize(kNackListSize); uint16_t seq_num = 0; uint32_t timestamp = 0x87654321; - auto add_packet = [&nack, &seq_num, ×tamp] { - nack.UpdateLastReceivedPacket(seq_num, timestamp); + auto add_packet = [&nack, &seq_num, ×tamp](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 @@ TEST(NackTrackerTest, DoNotNackAfterDtx) { 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, ×tamp](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, ×tamp](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