Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: webrtc/modules/audio_coding/main/acm2/nack_unittest.cc

Issue 1410073006: ACM: Move NACK functionality inside NetEq (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: rebase Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
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
11 #include "webrtc/modules/audio_coding/main/acm2/nack.h"
12
13 #include <stdint.h>
14
15 #include <algorithm>
16
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webrtc/base/scoped_ptr.h"
19 #include "webrtc/typedefs.h"
20 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs. h"
21
22 namespace webrtc {
23
24 namespace acm2 {
25
26 namespace {
27
28 const int kNackThreshold = 3;
29 const int kSampleRateHz = 16000;
30 const int kPacketSizeMs = 30;
31 const uint32_t kTimestampIncrement = 480; // 30 ms.
32 const int64_t kShortRoundTripTimeMs = 1;
33
34 bool IsNackListCorrect(const std::vector<uint16_t>& nack_list,
35 const uint16_t* lost_sequence_numbers,
36 size_t num_lost_packets) {
37 if (nack_list.size() != num_lost_packets)
38 return false;
39
40 if (num_lost_packets == 0)
41 return true;
42
43 for (size_t k = 0; k < nack_list.size(); ++k) {
44 int seq_num = nack_list[k];
45 bool seq_num_matched = false;
46 for (size_t n = 0; n < num_lost_packets; ++n) {
47 if (seq_num == lost_sequence_numbers[n]) {
48 seq_num_matched = true;
49 break;
50 }
51 }
52 if (!seq_num_matched)
53 return false;
54 }
55 return true;
56 }
57
58 } // namespace
59
60 TEST(NackTest, EmptyListWhenNoPacketLoss) {
61 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
62 nack->UpdateSampleRate(kSampleRateHz);
63
64 int seq_num = 1;
65 uint32_t timestamp = 0;
66
67 std::vector<uint16_t> nack_list;
68 for (int n = 0; n < 100; n++) {
69 nack->UpdateLastReceivedPacket(seq_num, timestamp);
70 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
71 seq_num++;
72 timestamp += kTimestampIncrement;
73 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
74 EXPECT_TRUE(nack_list.empty());
75 }
76 }
77
78 TEST(NackTest, NoNackIfReorderWithinNackThreshold) {
79 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
80 nack->UpdateSampleRate(kSampleRateHz);
81
82 int seq_num = 1;
83 uint32_t timestamp = 0;
84 std::vector<uint16_t> nack_list;
85
86 nack->UpdateLastReceivedPacket(seq_num, timestamp);
87 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
88 EXPECT_TRUE(nack_list.empty());
89 int num_late_packets = kNackThreshold + 1;
90
91 // Push in reverse order
92 while (num_late_packets > 0) {
93 nack->UpdateLastReceivedPacket(seq_num + num_late_packets, timestamp +
94 num_late_packets * kTimestampIncrement);
95 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
96 EXPECT_TRUE(nack_list.empty());
97 num_late_packets--;
98 }
99 }
100
101 TEST(NackTest, LatePacketsMovedToNackThenNackListDoesNotChange) {
102 const uint16_t kSequenceNumberLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
103 static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
104 sizeof(kSequenceNumberLostPackets[0]);
105
106 for (int k = 0; k < 2; k++) { // Two iteration with/without wrap around.
107 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
108 nack->UpdateSampleRate(kSampleRateHz);
109
110 uint16_t sequence_num_lost_packets[kNumAllLostPackets];
111 for (int n = 0; n < kNumAllLostPackets; n++) {
112 sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] + k *
113 65531; // Have wrap around in sequence numbers for |k == 1|.
114 }
115 uint16_t seq_num = sequence_num_lost_packets[0] - 1;
116
117 uint32_t timestamp = 0;
118 std::vector<uint16_t> nack_list;
119
120 nack->UpdateLastReceivedPacket(seq_num, timestamp);
121 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
122 EXPECT_TRUE(nack_list.empty());
123
124 seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1;
125 timestamp += kTimestampIncrement * (kNumAllLostPackets + 1);
126 int num_lost_packets = std::max(0, kNumAllLostPackets - kNackThreshold);
127
128 for (int n = 0; n < kNackThreshold + 1; ++n) {
129 nack->UpdateLastReceivedPacket(seq_num, timestamp);
130 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
131 EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets,
132 num_lost_packets));
133 seq_num++;
134 timestamp += kTimestampIncrement;
135 num_lost_packets++;
136 }
137
138 for (int n = 0; n < 100; ++n) {
139 nack->UpdateLastReceivedPacket(seq_num, timestamp);
140 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
141 EXPECT_TRUE(IsNackListCorrect(nack_list, sequence_num_lost_packets,
142 kNumAllLostPackets));
143 seq_num++;
144 timestamp += kTimestampIncrement;
145 }
146 }
147 }
148
149 TEST(NackTest, ArrivedPacketsAreRemovedFromNackList) {
150 const uint16_t kSequenceNumberLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
151 static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
152 sizeof(kSequenceNumberLostPackets[0]);
153
154 for (int k = 0; k < 2; ++k) { // Two iteration with/without wrap around.
155 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
156 nack->UpdateSampleRate(kSampleRateHz);
157
158 uint16_t sequence_num_lost_packets[kNumAllLostPackets];
159 for (int n = 0; n < kNumAllLostPackets; ++n) {
160 sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] + k *
161 65531; // Wrap around for |k == 1|.
162 }
163
164 uint16_t seq_num = sequence_num_lost_packets[0] - 1;
165 uint32_t timestamp = 0;
166
167 nack->UpdateLastReceivedPacket(seq_num, timestamp);
168 std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
169 EXPECT_TRUE(nack_list.empty());
170
171 size_t index_retransmitted_rtp = 0;
172 uint32_t timestamp_retransmitted_rtp = timestamp + kTimestampIncrement;
173
174 seq_num = sequence_num_lost_packets[kNumAllLostPackets - 1] + 1;
175 timestamp += kTimestampIncrement * (kNumAllLostPackets + 1);
176 size_t num_lost_packets = std::max(0, kNumAllLostPackets - kNackThreshold);
177 for (int n = 0; n < kNumAllLostPackets; ++n) {
178 // Number of lost packets does not change for the first
179 // |kNackThreshold + 1| packets, one is added to the list and one is
180 // removed. Thereafter, the list shrinks every iteration.
181 if (n >= kNackThreshold + 1)
182 num_lost_packets--;
183
184 nack->UpdateLastReceivedPacket(seq_num, timestamp);
185 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
186 EXPECT_TRUE(IsNackListCorrect(
187 nack_list, &sequence_num_lost_packets[index_retransmitted_rtp],
188 num_lost_packets));
189 seq_num++;
190 timestamp += kTimestampIncrement;
191
192 // Retransmission of a lost RTP.
193 nack->UpdateLastReceivedPacket(
194 sequence_num_lost_packets[index_retransmitted_rtp],
195 timestamp_retransmitted_rtp);
196 index_retransmitted_rtp++;
197 timestamp_retransmitted_rtp += kTimestampIncrement;
198
199 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
200 EXPECT_TRUE(IsNackListCorrect(
201 nack_list, &sequence_num_lost_packets[index_retransmitted_rtp],
202 num_lost_packets - 1)); // One less lost packet in the list.
203 }
204 ASSERT_TRUE(nack_list.empty());
205 }
206 }
207
208 // Assess if estimation of timestamps and time-to-play is correct. Introduce all
209 // combinations that timestamps and sequence numbers might have wrap around.
210 TEST(NackTest, EstimateTimestampAndTimeToPlay) {
211 const uint16_t kLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10,
212 11, 12, 13, 14, 15 };
213 static const int kNumAllLostPackets = sizeof(kLostPackets) /
214 sizeof(kLostPackets[0]);
215
216
217 for (int k = 0; k < 4; ++k) {
218 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
219 nack->UpdateSampleRate(kSampleRateHz);
220
221 // Sequence number wrap around if |k| is 2 or 3;
222 int seq_num_offset = (k < 2) ? 0 : 65531;
223
224 // Timestamp wrap around if |k| is 1 or 3.
225 uint32_t timestamp_offset = (k & 0x1) ?
226 static_cast<uint32_t>(0xffffffff) - 6 : 0;
227
228 uint32_t timestamp_lost_packets[kNumAllLostPackets];
229 uint16_t seq_num_lost_packets[kNumAllLostPackets];
230 for (int n = 0; n < kNumAllLostPackets; ++n) {
231 timestamp_lost_packets[n] = timestamp_offset + kLostPackets[n] *
232 kTimestampIncrement;
233 seq_num_lost_packets[n] = seq_num_offset + kLostPackets[n];
234 }
235
236 // We and to push two packets before lost burst starts.
237 uint16_t seq_num = seq_num_lost_packets[0] - 2;
238 uint32_t timestamp = timestamp_lost_packets[0] - 2 * kTimestampIncrement;
239
240 const uint16_t first_seq_num = seq_num;
241 const uint32_t first_timestamp = timestamp;
242
243 // Two consecutive packets to have a correct estimate of timestamp increase.
244 nack->UpdateLastReceivedPacket(seq_num, timestamp);
245 seq_num++;
246 timestamp += kTimestampIncrement;
247 nack->UpdateLastReceivedPacket(seq_num, timestamp);
248
249 // A packet after the last one which is supposed to be lost.
250 seq_num = seq_num_lost_packets[kNumAllLostPackets - 1] + 1;
251 timestamp = timestamp_lost_packets[kNumAllLostPackets - 1] +
252 kTimestampIncrement;
253 nack->UpdateLastReceivedPacket(seq_num, timestamp);
254
255 Nack::NackList nack_list = nack->GetNackList();
256 EXPECT_EQ(static_cast<size_t>(kNumAllLostPackets), nack_list.size());
257
258 // Pretend the first packet is decoded.
259 nack->UpdateLastDecodedPacket(first_seq_num, first_timestamp);
260 nack_list = nack->GetNackList();
261
262 Nack::NackList::iterator it = nack_list.begin();
263 while (it != nack_list.end()) {
264 seq_num = it->first - seq_num_offset;
265 int index = seq_num - kLostPackets[0];
266 EXPECT_EQ(timestamp_lost_packets[index], it->second.estimated_timestamp);
267 EXPECT_EQ((index + 2) * kPacketSizeMs, it->second.time_to_play_ms);
268 ++it;
269 }
270
271 // Pretend 10 ms is passed, and we had pulled audio from NetEq, it still
272 // reports the same sequence number as decoded, time-to-play should be
273 // updated by 10 ms.
274 nack->UpdateLastDecodedPacket(first_seq_num, first_timestamp);
275 nack_list = nack->GetNackList();
276 it = nack_list.begin();
277 while (it != nack_list.end()) {
278 seq_num = it->first - seq_num_offset;
279 int index = seq_num - kLostPackets[0];
280 EXPECT_EQ((index + 2) * kPacketSizeMs - 10, it->second.time_to_play_ms);
281 ++it;
282 }
283 }
284 }
285
286 TEST(NackTest, MissingPacketsPriorToLastDecodedRtpShouldNotBeInNackList) {
287 for (int m = 0; m < 2; ++m) {
288 uint16_t seq_num_offset = (m == 0) ? 0 : 65531; // Wrap around if |m| is 1.
289 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
290 nack->UpdateSampleRate(kSampleRateHz);
291
292 // Two consecutive packets to have a correct estimate of timestamp increase.
293 uint16_t seq_num = 0;
294 nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
295 seq_num * kTimestampIncrement);
296 seq_num++;
297 nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
298 seq_num * kTimestampIncrement);
299
300 // Skip 10 packets (larger than NACK threshold).
301 const int kNumLostPackets = 10;
302 seq_num += kNumLostPackets + 1;
303 nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
304 seq_num * kTimestampIncrement);
305
306 const size_t kExpectedListSize = kNumLostPackets - kNackThreshold;
307 std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
308 EXPECT_EQ(kExpectedListSize, nack_list.size());
309
310 for (int k = 0; k < 2; ++k) {
311 // Decoding of the first and the second arrived packets.
312 for (int n = 0; n < kPacketSizeMs / 10; ++n) {
313 nack->UpdateLastDecodedPacket(seq_num_offset + k,
314 k * kTimestampIncrement);
315 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
316 EXPECT_EQ(kExpectedListSize, nack_list.size());
317 }
318 }
319
320 // Decoding of the last received packet.
321 nack->UpdateLastDecodedPacket(seq_num + seq_num_offset,
322 seq_num * kTimestampIncrement);
323 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
324 EXPECT_TRUE(nack_list.empty());
325
326 // Make sure list of late packets is also empty. To check that, push few
327 // packets, if the late list is not empty its content will pop up in NACK
328 // list.
329 for (int n = 0; n < kNackThreshold + 10; ++n) {
330 seq_num++;
331 nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
332 seq_num * kTimestampIncrement);
333 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
334 EXPECT_TRUE(nack_list.empty());
335 }
336 }
337 }
338
339 TEST(NackTest, Reset) {
340 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
341 nack->UpdateSampleRate(kSampleRateHz);
342
343 // Two consecutive packets to have a correct estimate of timestamp increase.
344 uint16_t seq_num = 0;
345 nack->UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
346 seq_num++;
347 nack->UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
348
349 // Skip 10 packets (larger than NACK threshold).
350 const int kNumLostPackets = 10;
351 seq_num += kNumLostPackets + 1;
352 nack->UpdateLastReceivedPacket(seq_num, seq_num * kTimestampIncrement);
353
354 const size_t kExpectedListSize = kNumLostPackets - kNackThreshold;
355 std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
356 EXPECT_EQ(kExpectedListSize, nack_list.size());
357
358 nack->Reset();
359 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
360 EXPECT_TRUE(nack_list.empty());
361 }
362
363 TEST(NackTest, ListSizeAppliedFromBeginning) {
364 const size_t kNackListSize = 10;
365 for (int m = 0; m < 2; ++m) {
366 uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if |m| is 1.
367 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
368 nack->UpdateSampleRate(kSampleRateHz);
369 nack->SetMaxNackListSize(kNackListSize);
370
371 uint16_t seq_num = seq_num_offset;
372 uint32_t timestamp = 0x12345678;
373 nack->UpdateLastReceivedPacket(seq_num, timestamp);
374
375 // Packet lost more than NACK-list size limit.
376 uint16_t num_lost_packets = kNackThreshold + kNackListSize + 5;
377
378 seq_num += num_lost_packets + 1;
379 timestamp += (num_lost_packets + 1) * kTimestampIncrement;
380 nack->UpdateLastReceivedPacket(seq_num, timestamp);
381
382 std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
383 EXPECT_EQ(kNackListSize - kNackThreshold, nack_list.size());
384 }
385 }
386
387 TEST(NackTest, ChangeOfListSizeAppliedAndOldElementsRemoved) {
388 const size_t kNackListSize = 10;
389 for (int m = 0; m < 2; ++m) {
390 uint16_t seq_num_offset = (m == 0) ? 0 : 65525; // Wrap around if |m| is 1.
391 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
392 nack->UpdateSampleRate(kSampleRateHz);
393
394 uint16_t seq_num = seq_num_offset;
395 uint32_t timestamp = 0x87654321;
396 nack->UpdateLastReceivedPacket(seq_num, timestamp);
397
398 // Packet lost more than NACK-list size limit.
399 uint16_t num_lost_packets = kNackThreshold + kNackListSize + 5;
400
401 rtc::scoped_ptr<uint16_t[]> seq_num_lost(new uint16_t[num_lost_packets]);
402 for (int n = 0; n < num_lost_packets; ++n) {
403 seq_num_lost[n] = ++seq_num;
404 }
405
406 ++seq_num;
407 timestamp += (num_lost_packets + 1) * kTimestampIncrement;
408 nack->UpdateLastReceivedPacket(seq_num, timestamp);
409 size_t expected_size = num_lost_packets - kNackThreshold;
410
411 std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
412 EXPECT_EQ(expected_size, nack_list.size());
413
414 nack->SetMaxNackListSize(kNackListSize);
415 expected_size = kNackListSize - kNackThreshold;
416 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
417 EXPECT_TRUE(IsNackListCorrect(
418 nack_list, &seq_num_lost[num_lost_packets - kNackListSize],
419 expected_size));
420
421 // NACK list does not change size but the content is changing. The oldest
422 // element is removed and one from late list is inserted.
423 size_t n;
424 for (n = 1; n <= static_cast<size_t>(kNackThreshold); ++n) {
425 ++seq_num;
426 timestamp += kTimestampIncrement;
427 nack->UpdateLastReceivedPacket(seq_num, timestamp);
428 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
429 EXPECT_TRUE(IsNackListCorrect(
430 nack_list, &seq_num_lost[num_lost_packets - kNackListSize + n],
431 expected_size));
432 }
433
434 // NACK list should shrink.
435 for (; n < kNackListSize; ++n) {
436 ++seq_num;
437 timestamp += kTimestampIncrement;
438 nack->UpdateLastReceivedPacket(seq_num, timestamp);
439 --expected_size;
440 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
441 EXPECT_TRUE(IsNackListCorrect(
442 nack_list, &seq_num_lost[num_lost_packets - kNackListSize + n],
443 expected_size));
444 }
445
446 // After this packet, NACK list should be empty.
447 ++seq_num;
448 timestamp += kTimestampIncrement;
449 nack->UpdateLastReceivedPacket(seq_num, timestamp);
450 nack_list = nack->GetNackList(kShortRoundTripTimeMs);
451 EXPECT_TRUE(nack_list.empty());
452 }
453 }
454
455 TEST(NackTest, RoudTripTimeIsApplied) {
456 const int kNackListSize = 200;
457 rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
458 nack->UpdateSampleRate(kSampleRateHz);
459 nack->SetMaxNackListSize(kNackListSize);
460
461 uint16_t seq_num = 0;
462 uint32_t timestamp = 0x87654321;
463 nack->UpdateLastReceivedPacket(seq_num, timestamp);
464
465 // Packet lost more than NACK-list size limit.
466 uint16_t kNumLostPackets = kNackThreshold + 5;
467
468 seq_num += (1 + kNumLostPackets);
469 timestamp += (1 + kNumLostPackets) * kTimestampIncrement;
470 nack->UpdateLastReceivedPacket(seq_num, timestamp);
471
472 // Expected time-to-play are:
473 // kPacketSizeMs - 10, 2*kPacketSizeMs - 10, 3*kPacketSizeMs - 10, ...
474 //
475 // sequence number: 1, 2, 3, 4, 5
476 // time-to-play: 20, 50, 80, 110, 140
477 //
478 std::vector<uint16_t> nack_list = nack->GetNackList(100);
479 ASSERT_EQ(2u, nack_list.size());
480 EXPECT_EQ(4, nack_list[0]);
481 EXPECT_EQ(5, nack_list[1]);
482 }
483
484 } // namespace acm2
485
486 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_coding/main/acm2/nack.cc ('k') | webrtc/modules/audio_coding/main/audio_coding_module.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698