blob: bcc5120ff326fcdc4fca8157b9fc9adad40fcd04 [file] [log] [blame]
turaj@webrtc.org7959e162013-09-12 18:30:26 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/nack_tracker.h"
turaj@webrtc.org7959e162013-09-12 18:30:26 +000012
13#include <stdint.h>
14
15#include <algorithm>
kwiberg2d0c3322016-02-14 09:28:33 -080016#include <memory>
turaj@webrtc.org7959e162013-09-12 18:30:26 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
Ivo Creusen3a9640a2021-09-10 11:45:47 +000019#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "test/gtest.h"
turaj@webrtc.org7959e162013-09-12 18:30:26 +000021
22namespace webrtc {
turaj@webrtc.org7959e162013-09-12 18:30:26 +000023namespace {
24
turaj@webrtc.org7959e162013-09-12 18:30:26 +000025const int kSampleRateHz = 16000;
26const int kPacketSizeMs = 30;
27const uint32_t kTimestampIncrement = 480; // 30 ms.
pkasting@chromium.org16825b12015-01-12 21:51:21 +000028const int64_t kShortRoundTripTimeMs = 1;
turaj@webrtc.org7959e162013-09-12 18:30:26 +000029
30bool IsNackListCorrect(const std::vector<uint16_t>& nack_list,
31 const uint16_t* lost_sequence_numbers,
32 size_t num_lost_packets) {
33 if (nack_list.size() != num_lost_packets)
34 return false;
35
36 if (num_lost_packets == 0)
37 return true;
38
39 for (size_t k = 0; k < nack_list.size(); ++k) {
40 int seq_num = nack_list[k];
41 bool seq_num_matched = false;
42 for (size_t n = 0; n < num_lost_packets; ++n) {
43 if (seq_num == lost_sequence_numbers[n]) {
44 seq_num_matched = true;
45 break;
46 }
47 }
48 if (!seq_num_matched)
49 return false;
50 }
51 return true;
52}
53
54} // namespace
55
henrik.lundin91951862016-06-08 06:43:41 -070056TEST(NackTrackerTest, EmptyListWhenNoPacketLoss) {
Ivo Creusenbc503c92021-09-14 15:17:23 +000057 NackTracker nack;
58 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000059
60 int seq_num = 1;
61 uint32_t timestamp = 0;
62
63 std::vector<uint16_t> nack_list;
64 for (int n = 0; n < 100; n++) {
Ivo Creusenbc503c92021-09-14 15:17:23 +000065 nack.UpdateLastReceivedPacket(seq_num, timestamp);
66 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000067 seq_num++;
68 timestamp += kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +000069 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000070 EXPECT_TRUE(nack_list.empty());
71 }
72}
73
henrik.lundin91951862016-06-08 06:43:41 -070074TEST(NackTrackerTest, LatePacketsMovedToNackThenNackListDoesNotChange) {
henrik.lundin48ed9302015-10-29 05:36:24 -070075 const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9};
turaj@webrtc.org7959e162013-09-12 18:30:26 +000076 static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
henrik.lundin48ed9302015-10-29 05:36:24 -070077 sizeof(kSequenceNumberLostPackets[0]);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000078
79 for (int k = 0; k < 2; k++) { // Two iteration with/without wrap around.
Ivo Creusenbc503c92021-09-14 15:17:23 +000080 NackTracker nack;
81 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000082
83 uint16_t sequence_num_lost_packets[kNumAllLostPackets];
84 for (int n = 0; n < kNumAllLostPackets; n++) {
henrik.lundin48ed9302015-10-29 05:36:24 -070085 sequence_num_lost_packets[n] =
86 kSequenceNumberLostPackets[n] +
87 k * 65531; // Have wrap around in sequence numbers for |k == 1|.
turaj@webrtc.org7959e162013-09-12 18:30:26 +000088 }
89 uint16_t seq_num = sequence_num_lost_packets[0] - 1;
90
91 uint32_t timestamp = 0;
92 std::vector<uint16_t> nack_list;
93
Ivo Creusenbc503c92021-09-14 15:17:23 +000094 nack.UpdateLastReceivedPacket(seq_num, timestamp);
95 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000096 EXPECT_TRUE(nack_list.empty());
97
98 seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1;
99 timestamp += kTimestampIncrement * (kNumAllLostPackets + 1);
Ivo Creusenbc503c92021-09-14 15:17:23 +0000100 int num_lost_packets = std::max(0, kNumAllLostPackets);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000101
Ivo Creusenbc503c92021-09-14 15:17:23 +0000102 nack.UpdateLastReceivedPacket(seq_num, timestamp);
103 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
104 EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets,
105 num_lost_packets));
106 seq_num++;
107 timestamp += kTimestampIncrement;
108 num_lost_packets++;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000109
110 for (int n = 0; n < 100; ++n) {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000111 nack.UpdateLastReceivedPacket(seq_num, timestamp);
112 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000113 EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets,
114 kNumAllLostPackets));
115 seq_num++;
116 timestamp += kTimestampIncrement;
117 }
118 }
119}
120
henrik.lundin91951862016-06-08 06:43:41 -0700121TEST(NackTrackerTest, ArrivedPacketsAreRemovedFromNackList) {
henrik.lundin48ed9302015-10-29 05:36:24 -0700122 const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9};
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000123 static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
henrik.lundin48ed9302015-10-29 05:36:24 -0700124 sizeof(kSequenceNumberLostPackets[0]);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000125
126 for (int k = 0; k < 2; ++k) { // Two iteration with/without wrap around.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000127 NackTracker nack;
128 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000129
130 uint16_t sequence_num_lost_packets[kNumAllLostPackets];
131 for (int n = 0; n < kNumAllLostPackets; ++n) {
henrik.lundin48ed9302015-10-29 05:36:24 -0700132 sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] +
133 k * 65531; // Wrap around for |k == 1|.
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000134 }
135
136 uint16_t seq_num = sequence_num_lost_packets[0] - 1;
137 uint32_t timestamp = 0;
138
Ivo Creusenbc503c92021-09-14 15:17:23 +0000139 nack.UpdateLastReceivedPacket(seq_num, timestamp);
140 std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000141 EXPECT_TRUE(nack_list.empty());
142
143 size_t index_retransmitted_rtp = 0;
144 uint32_t timestamp_retransmitted_rtp = timestamp + kTimestampIncrement;
145
146 seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1;
147 timestamp += kTimestampIncrement * (kNumAllLostPackets + 1);
Ivo Creusenbc503c92021-09-14 15:17:23 +0000148 size_t num_lost_packets = kNumAllLostPackets;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000149 for (int n = 0; n < kNumAllLostPackets; ++n) {
150 // Number of lost packets does not change for the first
151 // |kNackThreshold + 1| packets, one is added to the list and one is
152 // removed. Thereafter, the list shrinks every iteration.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000153 if (n >= 1)
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000154 num_lost_packets--;
155
Ivo Creusenbc503c92021-09-14 15:17:23 +0000156 nack.UpdateLastReceivedPacket(seq_num, timestamp);
157 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000158 EXPECT_TRUE(IsNackListCorrect(
159 nack_list, &sequence_num_lost_packets[index_retransmitted_rtp],
160 num_lost_packets));
161 seq_num++;
162 timestamp += kTimestampIncrement;
163
164 // Retransmission of a lost RTP.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000165 nack.UpdateLastReceivedPacket(
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000166 sequence_num_lost_packets[index_retransmitted_rtp],
167 timestamp_retransmitted_rtp);
168 index_retransmitted_rtp++;
169 timestamp_retransmitted_rtp += kTimestampIncrement;
170
Ivo Creusenbc503c92021-09-14 15:17:23 +0000171 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000172 EXPECT_TRUE(IsNackListCorrect(
173 nack_list, &sequence_num_lost_packets[index_retransmitted_rtp],
174 num_lost_packets - 1)); // One less lost packet in the list.
175 }
176 ASSERT_TRUE(nack_list.empty());
177 }
178}
179
180// Assess if estimation of timestamps and time-to-play is correct. Introduce all
181// combinations that timestamps and sequence numbers might have wrap around.
henrik.lundin91951862016-06-08 06:43:41 -0700182TEST(NackTrackerTest, EstimateTimestampAndTimeToPlay) {
henrik.lundin48ed9302015-10-29 05:36:24 -0700183 const uint16_t kLostPackets[] = {2, 3, 4, 5, 6, 7, 8,
184 9, 10, 11, 12, 13, 14, 15};
185 static const int kNumAllLostPackets =
186 sizeof(kLostPackets) / sizeof(kLostPackets[0]);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000187
188 for (int k = 0; k < 4; ++k) {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000189 NackTracker nack;
190 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000191
Artem Titovd00ce742021-07-28 20:00:17 +0200192 // Sequence number wrap around if `k` is 2 or 3;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000193 int seq_num_offset = (k < 2) ? 0 : 65531;
194
Artem Titovd00ce742021-07-28 20:00:17 +0200195 // Timestamp wrap around if `k` is 1 or 3.
henrik.lundin48ed9302015-10-29 05:36:24 -0700196 uint32_t timestamp_offset =
197 (k & 0x1) ? static_cast<uint32_t>(0xffffffff) - 6 : 0;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000198
199 uint32_t timestamp_lost_packets[kNumAllLostPackets];
200 uint16_t seq_num_lost_packets[kNumAllLostPackets];
201 for (int n = 0; n < kNumAllLostPackets; ++n) {
henrik.lundin48ed9302015-10-29 05:36:24 -0700202 timestamp_lost_packets[n] =
203 timestamp_offset + kLostPackets[n] * kTimestampIncrement;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000204 seq_num_lost_packets[n] = seq_num_offset + kLostPackets[n];
205 }
206
207 // We and to push two packets before lost burst starts.
208 uint16_t seq_num = seq_num_lost_packets[0] - 2;
209 uint32_t timestamp = timestamp_lost_packets[0] - 2 * kTimestampIncrement;
210
211 const uint16_t first_seq_num = seq_num;
212 const uint32_t first_timestamp = timestamp;
213
214 // Two consecutive packets to have a correct estimate of timestamp increase.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000215 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000216 seq_num++;
217 timestamp += kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000218 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000219
220 // A packet after the last one which is supposed to be lost.
221 seq_num = seq_num_lost_packets[kNumAllLostPackets - 1] + 1;
henrik.lundin48ed9302015-10-29 05:36:24 -0700222 timestamp =
223 timestamp_lost_packets[kNumAllLostPackets - 1] + kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000224 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000225
Ivo Creusenbc503c92021-09-14 15:17:23 +0000226 NackTracker::NackList nack_list = nack.GetNackList();
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000227 EXPECT_EQ(static_cast<size_t>(kNumAllLostPackets), nack_list.size());
228
229 // Pretend the first packet is decoded.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000230 nack.UpdateLastDecodedPacket(first_seq_num, first_timestamp);
231 nack_list = nack.GetNackList();
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000232
henrik.lundin91951862016-06-08 06:43:41 -0700233 NackTracker::NackList::iterator it = nack_list.begin();
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000234 while (it != nack_list.end()) {
235 seq_num = it->first - seq_num_offset;
236 int index = seq_num - kLostPackets[0];
237 EXPECT_EQ(timestamp_lost_packets[index], it->second.estimated_timestamp);
238 EXPECT_EQ((index + 2) * kPacketSizeMs, it->second.time_to_play_ms);
239 ++it;
240 }
241
242 // Pretend 10 ms is passed, and we had pulled audio from NetEq, it still
243 // reports the same sequence number as decoded, time-to-play should be
244 // updated by 10 ms.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000245 nack.UpdateLastDecodedPacket(first_seq_num, first_timestamp);
246 nack_list = nack.GetNackList();
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000247 it = nack_list.begin();
248 while (it != nack_list.end()) {
249 seq_num = it->first - seq_num_offset;
250 int index = seq_num - kLostPackets[0];
251 EXPECT_EQ((index + 2) * kPacketSizeMs - 10, it->second.time_to_play_ms);
252 ++it;
253 }
254 }
255}
256
henrik.lundin91951862016-06-08 06:43:41 -0700257TEST(NackTrackerTest,
258 MissingPacketsPriorToLastDecodedRtpShouldNotBeInNackList) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000259 for (int m = 0; m < 2; ++m) {
Artem Titovd00ce742021-07-28 20:00:17 +0200260 uint16_t seq_num_offset = (m == 0) ? 0 : 65531; // Wrap around if `m` is 1.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000261 NackTracker nack;
262 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000263
264 // Two consecutive packets to have a correct estimate of timestamp increase.
265 uint16_t seq_num = 0;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000266 nack.UpdateLastReceivedPacket(seq_num_offset + seq_num,
267 seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000268 seq_num++;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000269 nack.UpdateLastReceivedPacket(seq_num_offset + seq_num,
270 seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000271
272 // Skip 10 packets (larger than NACK threshold).
273 const int kNumLostPackets = 10;
274 seq_num += kNumLostPackets + 1;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000275 nack.UpdateLastReceivedPacket(seq_num_offset + seq_num,
276 seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000277
Ivo Creusenbc503c92021-09-14 15:17:23 +0000278 const size_t kExpectedListSize = kNumLostPackets;
279 std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000280 EXPECT_EQ(kExpectedListSize, nack_list.size());
281
282 for (int k = 0; k < 2; ++k) {
283 // Decoding of the first and the second arrived packets.
284 for (int n = 0; n < kPacketSizeMs / 10; ++n) {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000285 nack.UpdateLastDecodedPacket(seq_num_offset + k,
286 k * kTimestampIncrement);
287 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000288 EXPECT_EQ(kExpectedListSize, nack_list.size());
289 }
290 }
291
292 // Decoding of the last received packet.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000293 nack.UpdateLastDecodedPacket(seq_num + seq_num_offset,
294 seq_num * kTimestampIncrement);
295 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000296 EXPECT_TRUE(nack_list.empty());
297
298 // Make sure list of late packets is also empty. To check that, push few
299 // packets, if the late list is not empty its content will pop up in NACK
300 // list.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000301 for (int n = 0; n < 10; ++n) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000302 seq_num++;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000303 nack.UpdateLastReceivedPacket(seq_num_offset + seq_num,
304 seq_num * kTimestampIncrement);
305 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000306 EXPECT_TRUE(nack_list.empty());
307 }
308 }
309}
310
henrik.lundin91951862016-06-08 06:43:41 -0700311TEST(NackTrackerTest, Reset) {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000312 NackTracker nack;
313 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000314
315 // Two consecutive packets to have a correct estimate of timestamp increase.
316 uint16_t seq_num = 0;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000317 nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000318 seq_num++;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000319 nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000320
321 // Skip 10 packets (larger than NACK threshold).
322 const int kNumLostPackets = 10;
323 seq_num += kNumLostPackets + 1;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000324 nack.UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000325
Ivo Creusenbc503c92021-09-14 15:17:23 +0000326 const size_t kExpectedListSize = kNumLostPackets;
327 std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000328 EXPECT_EQ(kExpectedListSize, nack_list.size());
329
Ivo Creusenbc503c92021-09-14 15:17:23 +0000330 nack.Reset();
331 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000332 EXPECT_TRUE(nack_list.empty());
333}
334
henrik.lundin91951862016-06-08 06:43:41 -0700335TEST(NackTrackerTest, ListSizeAppliedFromBeginning) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000336 const size_t kNackListSize = 10;
337 for (int m = 0; m < 2; ++m) {
Artem Titovd00ce742021-07-28 20:00:17 +0200338 uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if `m` is 1.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000339 NackTracker nack;
340 nack.UpdateSampleRate(kSampleRateHz);
341 nack.SetMaxNackListSize(kNackListSize);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000342
343 uint16_t seq_num = seq_num_offset;
344 uint32_t timestamp = 0x12345678;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000345 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000346
347 // Packet lost more than NACK-list size limit.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000348 uint16_t num_lost_packets = kNackListSize + 5;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000349
350 seq_num += num_lost_packets + 1;
351 timestamp += (num_lost_packets + 1) * kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000352 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000353
Ivo Creusenbc503c92021-09-14 15:17:23 +0000354 std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs);
355 EXPECT_EQ(kNackListSize, nack_list.size());
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000356 }
357}
358
henrik.lundin91951862016-06-08 06:43:41 -0700359TEST(NackTrackerTest, ChangeOfListSizeAppliedAndOldElementsRemoved) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000360 const size_t kNackListSize = 10;
361 for (int m = 0; m < 2; ++m) {
Artem Titovd00ce742021-07-28 20:00:17 +0200362 uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if `m` is 1.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000363 NackTracker nack;
364 nack.UpdateSampleRate(kSampleRateHz);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000365
366 uint16_t seq_num = seq_num_offset;
367 uint32_t timestamp = 0x87654321;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000368 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000369
370 // Packet lost more than NACK-list size limit.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000371 uint16_t num_lost_packets = kNackListSize + 5;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000372
kwiberg2d0c3322016-02-14 09:28:33 -0800373 std::unique_ptr<uint16_t[]> seq_num_lost(new uint16_t[num_lost_packets]);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000374 for (int n = 0; n < num_lost_packets; ++n) {
375 seq_num_lost[n] = ++seq_num;
376 }
377
378 ++seq_num;
379 timestamp += (num_lost_packets + 1) * kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000380 nack.UpdateLastReceivedPacket(seq_num, timestamp);
381 size_t expected_size = num_lost_packets;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000382
Ivo Creusenbc503c92021-09-14 15:17:23 +0000383 std::vector<uint16_t> nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000384 EXPECT_EQ(expected_size, nack_list.size());
385
Ivo Creusenbc503c92021-09-14 15:17:23 +0000386 nack.SetMaxNackListSize(kNackListSize);
387 expected_size = kNackListSize;
388 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000389 EXPECT_TRUE(IsNackListCorrect(
390 nack_list, &seq_num_lost[num_lost_packets - kNackListSize],
391 expected_size));
392
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000393 // NACK list should shrink.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000394 for (size_t n = 1; n < kNackListSize; ++n) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000395 ++seq_num;
396 timestamp += kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000397 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000398 --expected_size;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000399 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000400 EXPECT_TRUE(IsNackListCorrect(
401 nack_list, &seq_num_lost[num_lost_packets - kNackListSize + n],
402 expected_size));
403 }
404
405 // After this packet, NACK list should be empty.
406 ++seq_num;
407 timestamp += kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000408 nack.UpdateLastReceivedPacket(seq_num, timestamp);
409 nack_list = nack.GetNackList(kShortRoundTripTimeMs);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000410 EXPECT_TRUE(nack_list.empty());
411 }
412}
413
henrik.lundin91951862016-06-08 06:43:41 -0700414TEST(NackTrackerTest, RoudTripTimeIsApplied) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000415 const int kNackListSize = 200;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000416 NackTracker nack;
417 nack.UpdateSampleRate(kSampleRateHz);
418 nack.SetMaxNackListSize(kNackListSize);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000419
420 uint16_t seq_num = 0;
421 uint32_t timestamp = 0x87654321;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000422 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000423
424 // Packet lost more than NACK-list size limit.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000425 uint16_t kNumLostPackets = 5;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000426
427 seq_num += (1 + kNumLostPackets);
428 timestamp += (1 + kNumLostPackets) * kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000429 nack.UpdateLastReceivedPacket(seq_num, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000430
431 // Expected time-to-play are:
432 // kPacketSizeMs - 10, 2*kPacketSizeMs - 10, 3*kPacketSizeMs - 10, ...
433 //
434 // sequence number: 1, 2, 3, 4, 5
435 // time-to-play: 20, 50, 80, 110, 140
436 //
Ivo Creusenbc503c92021-09-14 15:17:23 +0000437 std::vector<uint16_t> nack_list = nack.GetNackList(100);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000438 ASSERT_EQ(2u, nack_list.size());
439 EXPECT_EQ(4, nack_list[0]);
440 EXPECT_EQ(5, nack_list[1]);
441}
442
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000443// Set never_nack_multiple_times to true with a field trial and verify that
444// packets are not nacked multiple times.
445TEST(NackTrackerTest, DoNotNackMultipleTimes) {
446 test::ScopedFieldTrials field_trials(
447 "WebRTC-Audio-NetEqNackTrackerConfig/"
448 "packet_loss_forget_factor:0.996,ms_per_loss_percent:20,"
449 "never_nack_multiple_times:true/");
450 const int kNackListSize = 200;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000451 NackTracker nack;
452 nack.UpdateSampleRate(kSampleRateHz);
453 nack.SetMaxNackListSize(kNackListSize);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000454
455 uint16_t seq_num = 0;
456 uint32_t timestamp = 0x87654321;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000457 nack.UpdateLastReceivedPacket(seq_num, timestamp);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000458
459 uint16_t kNumLostPackets = 3;
460
461 seq_num += (1 + kNumLostPackets);
462 timestamp += (1 + kNumLostPackets) * kTimestampIncrement;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000463 nack.UpdateLastReceivedPacket(seq_num, timestamp);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000464
Ivo Creusenbc503c92021-09-14 15:17:23 +0000465 std::vector<uint16_t> nack_list = nack.GetNackList(10);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000466 ASSERT_EQ(3u, nack_list.size());
467 EXPECT_EQ(1, nack_list[0]);
468 EXPECT_EQ(2, nack_list[1]);
469 EXPECT_EQ(3, nack_list[2]);
470 // When we get the nack list again, it should be empty.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000471 std::vector<uint16_t> nack_list2 = nack.GetNackList(10);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000472 EXPECT_TRUE(nack_list2.empty());
473}
474
475// Test if estimated packet loss rate is correct.
476TEST(NackTrackerTest, PacketLossRateCorrect) {
477 const int kNackListSize = 200;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000478 NackTracker nack;
479 nack.UpdateSampleRate(kSampleRateHz);
480 nack.SetMaxNackListSize(kNackListSize);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000481 uint16_t seq_num = 0;
482 uint32_t timestamp = 0x87654321;
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100483 auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
484 if (received) {
485 nack.UpdateLastReceivedPacket(seq_num, timestamp);
486 }
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000487 seq_num++;
488 timestamp += kTimestampIncrement;
489 };
490 // Add some packets, but every fourth packet is lost.
491 for (int i = 0; i < 300; i++) {
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100492 add_packet(true);
493 add_packet(true);
494 add_packet(true);
495 add_packet(false);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000496 }
497 // 1 << 28 is 0.25 in Q30. We expect the packet loss estimate to be within
498 // 0.01 of that.
Ivo Creusenbc503c92021-09-14 15:17:23 +0000499 EXPECT_NEAR(nack.GetPacketLossRateForTest(), 1 << 28, (1 << 30) / 100);
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000500}
501
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200502TEST(NackTrackerTest, DoNotNackAfterDtx) {
503 const int kNackListSize = 200;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000504 NackTracker nack;
505 nack.UpdateSampleRate(kSampleRateHz);
506 nack.SetMaxNackListSize(kNackListSize);
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200507 uint16_t seq_num = 0;
508 uint32_t timestamp = 0x87654321;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000509 nack.UpdateLastReceivedPacket(seq_num, timestamp);
510 EXPECT_TRUE(nack.GetNackList(0).empty());
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200511 constexpr int kDtxPeriod = 400;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000512 nack.UpdateLastReceivedPacket(seq_num + 2,
513 timestamp + kDtxPeriod * kSampleRateHz / 1000);
514 EXPECT_TRUE(nack.GetNackList(0).empty());
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200515}
516
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100517TEST(NackTrackerTest, DoNotNackIfLossRateIsTooHigh) {
518 test::ScopedFieldTrials field_trials(
519 "WebRTC-Audio-NetEqNackTrackerConfig/max_loss_rate:0.4/");
520 const int kNackListSize = 200;
521 NackTracker nack;
522 nack.UpdateSampleRate(kSampleRateHz);
523 nack.SetMaxNackListSize(kNackListSize);
524 uint16_t seq_num = 0;
525 uint32_t timestamp = 0x87654321;
526 auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
527 if (received) {
528 nack.UpdateLastReceivedPacket(seq_num, timestamp);
529 }
530 seq_num++;
531 timestamp += kTimestampIncrement;
532 };
533 for (int i = 0; i < 500; i++) {
534 add_packet(true);
535 add_packet(false);
536 }
537 // Expect 50% loss rate which is higher that the configured maximum 40%.
538 EXPECT_NEAR(nack.GetPacketLossRateForTest(), 1 << 29, (1 << 30) / 100);
539 EXPECT_TRUE(nack.GetNackList(0).empty());
540}
541
542TEST(NackTrackerTest, OnlyNackIfRttIsValid) {
543 test::ScopedFieldTrials field_trials(
544 "WebRTC-Audio-NetEqNackTrackerConfig/require_valid_rtt:true/");
545 const int kNackListSize = 200;
546 NackTracker nack;
547 nack.UpdateSampleRate(kSampleRateHz);
548 nack.SetMaxNackListSize(kNackListSize);
549 uint16_t seq_num = 0;
550 uint32_t timestamp = 0x87654321;
551 auto add_packet = [&nack, &seq_num, &timestamp](bool received) {
552 if (received) {
553 nack.UpdateLastReceivedPacket(seq_num, timestamp);
554 }
555 seq_num++;
556 timestamp += kTimestampIncrement;
557 };
558 add_packet(true);
559 add_packet(false);
560 add_packet(true);
561 EXPECT_TRUE(nack.GetNackList(0).empty());
562 EXPECT_FALSE(nack.GetNackList(10).empty());
563}
564
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000565} // namespace webrtc