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