| /* |
| * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "modules/audio_coding/neteq/nack_tracker.h" |
| |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "modules/audio_coding/include/audio_coding_module_typedefs.h" |
| #include "test/explicit_key_value_config.h" |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| using test::ExplicitKeyValueConfig; |
| |
| const int kSampleRateHz = 16000; |
| const int kPacketSizeMs = 30; |
| const uint32_t kTimestampIncrement = 480; // 30 ms. |
| const int64_t kShortRoundTripTimeMs = 1; |
| |
| bool IsNackListCorrect(const std::vector<uint16_t>& nack_list, |
| const uint16_t* lost_sequence_numbers, |
| size_t num_lost_packets) { |
| if (nack_list.size() != num_lost_packets) |
| return false; |
| |
| if (num_lost_packets == 0) |
| return true; |
| |
| for (size_t k = 0; k < nack_list.size(); ++k) { |
| int seq_num = nack_list[k]; |
| bool seq_num_matched = false; |
| for (size_t n = 0; n < num_lost_packets; ++n) { |
| if (seq_num == lost_sequence_numbers[n]) { |
| seq_num_matched = true; |
| break; |
| } |
| } |
| if (!seq_num_matched) |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| TEST(NackTrackerTest, EmptyListWhenNoPacketLoss) { |
| ExplicitKeyValueConfig field_trials(""); |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| int seq_num = 1; |
| uint32_t timestamp = 0; |
| |
| std::vector<uint16_t> nack_list; |
| for (int n = 0; n < 100; n++) { |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| seq_num++; |
| timestamp += kTimestampIncrement; |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| } |
| } |
| |
| TEST(NackTrackerTest, LatePacketsMovedToNackThenNackListDoesNotChange) { |
| ExplicitKeyValueConfig field_trials(""); |
| const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9}; |
| static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) / |
| sizeof(kSequenceNumberLostPackets[0]); |
| |
| for (int k = 0; k < 2; k++) { // Two iteration with/without wrap around. |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| uint16_t sequence_num_lost_packets[kNumAllLostPackets]; |
| for (int n = 0; n < kNumAllLostPackets; n++) { |
| sequence_num_lost_packets[n] = |
| kSequenceNumberLostPackets[n] + |
| k * 65531; // Have wrap around in sequence numbers for |k == 1|. |
| } |
| uint16_t seq_num = sequence_num_lost_packets[0] - 1; |
| |
| uint32_t timestamp = 0; |
| std::vector<uint16_t> nack_list; |
| |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| |
| seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1; |
| timestamp += kTimestampIncrement * (kNumAllLostPackets + 1); |
| int num_lost_packets = std::max(0, kNumAllLostPackets); |
| |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets, |
| num_lost_packets)); |
| seq_num++; |
| timestamp += kTimestampIncrement; |
| num_lost_packets++; |
| |
| for (int n = 0; n < 100; ++n) { |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets, |
| kNumAllLostPackets)); |
| seq_num++; |
| timestamp += kTimestampIncrement; |
| } |
| } |
| } |
| |
| TEST(NackTrackerTest, ArrivedPacketsAreRemovedFromNackList) { |
| ExplicitKeyValueConfig field_trials(""); |
| const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9}; |
| static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) / |
| sizeof(kSequenceNumberLostPackets[0]); |
| |
| for (int k = 0; k < 2; ++k) { // Two iteration with/without wrap around. |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| uint16_t sequence_num_lost_packets[kNumAllLostPackets]; |
| for (int n = 0; n < kNumAllLostPackets; ++n) { |
| sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] + |
| k * 65531; // Wrap around for |k == 1|. |
| } |
| |
| uint16_t seq_num = sequence_num_lost_packets[0] - 1; |
| uint32_t timestamp = 0; |
| |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| |
| size_t index_retransmitted_rtp = 0; |
| uint32_t timestamp_retransmitted_rtp = timestamp + kTimestampIncrement; |
| |
| seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1; |
| timestamp += kTimestampIncrement * (kNumAllLostPackets + 1); |
| size_t num_lost_packets = kNumAllLostPackets; |
| for (int n = 0; n < kNumAllLostPackets; ++n) { |
| // Number of lost packets does not change for the first |
| // |kNackThreshold + 1| packets, one is added to the list and one is |
| // removed. Thereafter, the list shrinks every iteration. |
| if (n >= 1) |
| num_lost_packets--; |
| |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect( |
| nack_list, &sequence_num_lost_packets[index_retransmitted_rtp], |
| num_lost_packets)); |
| seq_num++; |
| timestamp += kTimestampIncrement; |
| |
| // Retransmission of a lost RTP. |
| nack.UpdateLastReceivedPacket( |
| sequence_num_lost_packets[index_retransmitted_rtp], |
| timestamp_retransmitted_rtp); |
| index_retransmitted_rtp++; |
| timestamp_retransmitted_rtp += kTimestampIncrement; |
| |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect( |
| nack_list, &sequence_num_lost_packets[index_retransmitted_rtp], |
| num_lost_packets - 1)); // One less lost packet in the list. |
| } |
| ASSERT_TRUE(nack_list.empty()); |
| } |
| } |
| |
| // Assess if estimation of timestamps and time-to-play is correct. Introduce all |
| // combinations that timestamps and sequence numbers might have wrap around. |
| TEST(NackTrackerTest, EstimateTimestampAndTimeToPlay) { |
| ExplicitKeyValueConfig field_trials(""); |
| const uint16_t kLostPackets[] = {2, 3, 4, 5, 6, 7, 8, |
| 9, 10, 11, 12, 13, 14, 15}; |
| static const int kNumAllLostPackets = |
| sizeof(kLostPackets) / sizeof(kLostPackets[0]); |
| |
| for (int k = 0; k < 4; ++k) { |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| // Sequence number wrap around if `k` is 2 or 3; |
| int seq_num_offset = (k < 2) ? 0 : 65531; |
| |
| // Timestamp wrap around if `k` is 1 or 3. |
| uint32_t timestamp_offset = |
| (k & 0x1) ? static_cast<uint32_t>(0xffffffff) - 6 : 0; |
| |
| uint32_t timestamp_lost_packets[kNumAllLostPackets]; |
| uint16_t seq_num_lost_packets[kNumAllLostPackets]; |
| for (int n = 0; n < kNumAllLostPackets; ++n) { |
| timestamp_lost_packets[n] = |
| timestamp_offset + kLostPackets[n] * kTimestampIncrement; |
| seq_num_lost_packets[n] = seq_num_offset + kLostPackets[n]; |
| } |
| |
| // We and to push two packets before lost burst starts. |
| uint16_t seq_num = seq_num_lost_packets[0] - 2; |
| uint32_t timestamp = timestamp_lost_packets[0] - 2 * kTimestampIncrement; |
| |
| const uint16_t first_seq_num = seq_num; |
| const uint32_t first_timestamp = timestamp; |
| |
| // Two consecutive packets to have a correct estimate of timestamp increase. |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| seq_num++; |
| timestamp += kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| // A packet after the last one which is supposed to be lost. |
| seq_num = seq_num_lost_packets[kNumAllLostPackets - 1] + 1; |
| timestamp = |
| timestamp_lost_packets[kNumAllLostPackets - 1] + kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| NackTracker::NackList nack_list = nack.GetNackList(); |
| EXPECT_EQ(static_cast<size_t>(kNumAllLostPackets), nack_list.size()); |
| |
| // Pretend the first packet is decoded. |
| nack.UpdateLastDecodedPacket(first_seq_num, first_timestamp); |
| nack_list = nack.GetNackList(); |
| |
| NackTracker::NackList::iterator it = nack_list.begin(); |
| while (it != nack_list.end()) { |
| seq_num = it->first - seq_num_offset; |
| int index = seq_num - kLostPackets[0]; |
| EXPECT_EQ(timestamp_lost_packets[index], it->second.estimated_timestamp); |
| EXPECT_EQ((index + 2) * kPacketSizeMs, it->second.time_to_play_ms); |
| ++it; |
| } |
| } |
| } |
| |
| TEST(NackTrackerTest, |
| MissingPacketsPriorToLastDecodedRtpShouldNotBeInNackList) { |
| ExplicitKeyValueConfig field_trials(""); |
| for (int m = 0; m < 2; ++m) { |
| uint16_t seq_num_offset = (m == 0) ? 0 : 65531; // Wrap around if `m` is 1. |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| // Two consecutive packets to have a correct estimate of timestamp increase. |
| uint16_t seq_num = 0; |
| nack.UpdateLastReceivedPacket(seq_num_offset + seq_num, |
| seq_num * kTimestampIncrement); |
| seq_num++; |
| nack.UpdateLastReceivedPacket(seq_num_offset + seq_num, |
| seq_num * kTimestampIncrement); |
| |
| // Skip 10 packets (larger than NACK threshold). |
| const int kNumLostPackets = 10; |
| seq_num += kNumLostPackets + 1; |
| nack.UpdateLastReceivedPacket(seq_num_offset + seq_num, |
| seq_num * kTimestampIncrement); |
| |
| const size_t kExpectedListSize = kNumLostPackets; |
| std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_EQ(kExpectedListSize, nack_list.size()); |
| |
| for (int k = 0; k < 2; ++k) { |
| // Decoding of the first and the second arrived packets. |
| for (int n = 0; n < kPacketSizeMs / 10; ++n) { |
| nack.UpdateLastDecodedPacket(seq_num_offset + k, |
| k * kTimestampIncrement); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_EQ(kExpectedListSize, nack_list.size()); |
| } |
| } |
| |
| // Decoding of the last received packet. |
| nack.UpdateLastDecodedPacket(seq_num + seq_num_offset, |
| seq_num * kTimestampIncrement); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| |
| // Make sure list of late packets is also empty. To check that, push few |
| // packets, if the late list is not empty its content will pop up in NACK |
| // list. |
| for (int n = 0; n < 10; ++n) { |
| seq_num++; |
| nack.UpdateLastReceivedPacket(seq_num_offset + seq_num, |
| seq_num * kTimestampIncrement); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| } |
| } |
| } |
| |
| TEST(NackTrackerTest, Reset) { |
| ExplicitKeyValueConfig field_trials(""); |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| // Two consecutive packets to have a correct estimate of timestamp increase. |
| uint16_t seq_num = 0; |
| nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement); |
| seq_num++; |
| nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement); |
| |
| // Skip 10 packets (larger than NACK threshold). |
| const int kNumLostPackets = 10; |
| seq_num += kNumLostPackets + 1; |
| nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement); |
| |
| const size_t kExpectedListSize = kNumLostPackets; |
| std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_EQ(kExpectedListSize, nack_list.size()); |
| |
| nack.Reset(); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| } |
| |
| TEST(NackTrackerTest, ListSizeAppliedFromBeginning) { |
| ExplicitKeyValueConfig field_trials(""); |
| const size_t kNackListSize = 10; |
| for (int m = 0; m < 2; ++m) { |
| uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if `m` is 1. |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| nack.SetMaxNackListSize(kNackListSize); |
| |
| uint16_t seq_num = seq_num_offset; |
| uint32_t timestamp = 0x12345678; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| // Packet lost more than NACK-list size limit. |
| uint16_t num_lost_packets = kNackListSize + 5; |
| |
| seq_num += num_lost_packets + 1; |
| timestamp += (num_lost_packets + 1) * kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_EQ(kNackListSize, nack_list.size()); |
| } |
| } |
| |
| TEST(NackTrackerTest, ChangeOfListSizeAppliedAndOldElementsRemoved) { |
| ExplicitKeyValueConfig field_trials(""); |
| const size_t kNackListSize = 10; |
| for (int m = 0; m < 2; ++m) { |
| uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if `m` is 1. |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| |
| uint16_t seq_num = seq_num_offset; |
| uint32_t timestamp = 0x87654321; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| // Packet lost more than NACK-list size limit. |
| uint16_t num_lost_packets = kNackListSize + 5; |
| |
| std::unique_ptr<uint16_t[]> seq_num_lost(new uint16_t[num_lost_packets]); |
| for (int n = 0; n < num_lost_packets; ++n) { |
| seq_num_lost[n] = ++seq_num; |
| } |
| |
| ++seq_num; |
| timestamp += (num_lost_packets + 1) * kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| size_t expected_size = num_lost_packets; |
| |
| std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_EQ(expected_size, nack_list.size()); |
| |
| nack.SetMaxNackListSize(kNackListSize); |
| expected_size = kNackListSize; |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect( |
| nack_list, &seq_num_lost[num_lost_packets - kNackListSize], |
| expected_size)); |
| |
| // NACK list should shrink. |
| for (size_t n = 1; n < kNackListSize; ++n) { |
| ++seq_num; |
| timestamp += kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| --expected_size; |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(IsNackListCorrect( |
| nack_list, &seq_num_lost[num_lost_packets - kNackListSize + n], |
| expected_size)); |
| } |
| |
| // After this packet, NACK list should be empty. |
| ++seq_num; |
| timestamp += kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| nack_list = nack.GetNackList(kShortRoundTripTimeMs); |
| EXPECT_TRUE(nack_list.empty()); |
| } |
| } |
| |
| TEST(NackTrackerTest, RoudTripTimeIsApplied) { |
| ExplicitKeyValueConfig field_trials(""); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| nack.SetMaxNackListSize(kNackListSize); |
| |
| uint16_t seq_num = 0; |
| uint32_t timestamp = 0x87654321; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| // Packet lost more than NACK-list size limit. |
| uint16_t kNumLostPackets = 5; |
| |
| seq_num += (1 + kNumLostPackets); |
| timestamp += (1 + kNumLostPackets) * kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| // Expected time-to-play are: |
| // kPacketSizeMs - 10, 2*kPacketSizeMs - 10, 3*kPacketSizeMs - 10, ... |
| // |
| // sequence number: 1, 2, 3, 4, 5 |
| // time-to-play: 20, 50, 80, 110, 140 |
| // |
| std::vector<uint16_t> nack_list = nack.GetNackList(100); |
| ASSERT_EQ(2u, nack_list.size()); |
| EXPECT_EQ(4, nack_list[0]); |
| EXPECT_EQ(5, nack_list[1]); |
| } |
| |
| // Set never_nack_multiple_times to true with a field trial and verify that |
| // packets are not nacked multiple times. |
| TEST(NackTrackerTest, DoNotNackMultipleTimes) { |
| ExplicitKeyValueConfig field_trials( |
| "WebRTC-Audio-NetEqNackTrackerConfig/" |
| "packet_loss_forget_factor:0.996,ms_per_loss_percent:20," |
| "never_nack_multiple_times:true/"); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| nack.SetMaxNackListSize(kNackListSize); |
| |
| uint16_t seq_num = 0; |
| uint32_t timestamp = 0x87654321; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| uint16_t kNumLostPackets = 3; |
| |
| seq_num += (1 + kNumLostPackets); |
| timestamp += (1 + kNumLostPackets) * kTimestampIncrement; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| |
| std::vector<uint16_t> nack_list = nack.GetNackList(10); |
| ASSERT_EQ(3u, nack_list.size()); |
| EXPECT_EQ(1, nack_list[0]); |
| EXPECT_EQ(2, nack_list[1]); |
| EXPECT_EQ(3, nack_list[2]); |
| // When we get the nack list again, it should be empty. |
| std::vector<uint16_t> nack_list2 = nack.GetNackList(10); |
| EXPECT_TRUE(nack_list2.empty()); |
| } |
| |
| // Test if estimated packet loss rate is correct. |
| TEST(NackTrackerTest, PacketLossRateCorrect) { |
| ExplicitKeyValueConfig field_trials(""); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| 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 some packets, but every fourth packet is lost. |
| for (int i = 0; i < 300; i++) { |
| 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. |
| EXPECT_NEAR(nack.GetPacketLossRateForTest(), 1 << 28, (1 << 30) / 100); |
| } |
| |
| TEST(NackTrackerTest, DoNotNackAfterDtx) { |
| ExplicitKeyValueConfig field_trials(""); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| nack.UpdateSampleRate(kSampleRateHz); |
| nack.SetMaxNackListSize(kNackListSize); |
| uint16_t seq_num = 0; |
| uint32_t timestamp = 0x87654321; |
| nack.UpdateLastReceivedPacket(seq_num, timestamp); |
| EXPECT_TRUE(nack.GetNackList(0).empty()); |
| constexpr int kDtxPeriod = 400; |
| nack.UpdateLastReceivedPacket(seq_num + 2, |
| timestamp + kDtxPeriod * kSampleRateHz / 1000); |
| EXPECT_TRUE(nack.GetNackList(0).empty()); |
| } |
| |
| TEST(NackTrackerTest, DoNotNackIfLossRateIsTooHigh) { |
| ExplicitKeyValueConfig field_trials( |
| "WebRTC-Audio-NetEqNackTrackerConfig/max_loss_rate:0.4/"); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| 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) { |
| ExplicitKeyValueConfig field_trials( |
| "WebRTC-Audio-NetEqNackTrackerConfig/require_valid_rtt:true/"); |
| const int kNackListSize = 200; |
| NackTracker nack(field_trials); |
| 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 |