Home | History | Annotate | Download | only in rtcp_packet
      1 /*
      2  *  Copyright (c) 2015 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/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
     12 
     13 #include <limits>
     14 
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
     18 
     19 using webrtc::rtcp::TransportFeedback;
     20 
     21 namespace webrtc {
     22 namespace {
     23 
     24 static const int kHeaderSize = 20;
     25 static const int kStatusChunkSize = 2;
     26 static const int kSmallDeltaSize = 1;
     27 static const int kLargeDeltaSize = 2;
     28 
     29 static const int64_t kDeltaLimit = 0xFF * TransportFeedback::kDeltaScaleFactor;
     30 
     31 class FeedbackTester {
     32  public:
     33   FeedbackTester()
     34       : expected_size_(kAnySize),
     35         default_delta_(TransportFeedback::kDeltaScaleFactor * 4) {}
     36 
     37   void WithExpectedSize(size_t expected_size) {
     38     expected_size_ = expected_size;
     39   }
     40 
     41   void WithDefaultDelta(int64_t delta) { default_delta_ = delta; }
     42 
     43   void WithInput(const uint16_t received_seq[],
     44                  const int64_t received_ts[],
     45                  uint16_t length) {
     46     rtc::scoped_ptr<int64_t[]> temp_deltas;
     47     if (received_ts == nullptr) {
     48       temp_deltas.reset(new int64_t[length]);
     49       GenerateDeltas(received_seq, length, temp_deltas.get());
     50       received_ts = temp_deltas.get();
     51     }
     52 
     53     expected_seq_.clear();
     54     expected_deltas_.clear();
     55     feedback_.reset(new TransportFeedback());
     56 
     57     feedback_->WithBase(received_seq[0], received_ts[0]);
     58     int64_t last_time = feedback_->GetBaseTimeUs();
     59     for (int i = 0; i < length; ++i) {
     60       int64_t time = received_ts[i];
     61       EXPECT_TRUE(feedback_->WithReceivedPacket(received_seq[i], time));
     62 
     63       if (last_time != -1) {
     64         int64_t delta = time - last_time;
     65         expected_deltas_.push_back(delta);
     66       }
     67       last_time = time;
     68     }
     69     expected_seq_.insert(expected_seq_.begin(), &received_seq[0],
     70                          &received_seq[length]);
     71   }
     72 
     73   void VerifyPacket() {
     74     serialized_ = feedback_->Build();
     75     VerifyInternal();
     76     feedback_ = TransportFeedback::ParseFrom(serialized_->Buffer(),
     77                                              serialized_->Length());
     78     ASSERT_NE(nullptr, feedback_.get());
     79     VerifyInternal();
     80   }
     81 
     82   static const size_t kAnySize = static_cast<size_t>(0) - 1;
     83 
     84  private:
     85   void VerifyInternal() {
     86     if (expected_size_ != kAnySize) {
     87       // Round up to whole 32-bit words.
     88       size_t expected_size_words = (expected_size_ + 3) / 4;
     89       size_t expected_size_bytes = expected_size_words * 4;
     90       EXPECT_EQ(expected_size_bytes, serialized_->Length());
     91     }
     92 
     93     std::vector<TransportFeedback::StatusSymbol> symbols =
     94         feedback_->GetStatusVector();
     95     uint16_t seq = feedback_->GetBaseSequence();
     96     auto seq_it = expected_seq_.begin();
     97     for (TransportFeedback::StatusSymbol symbol : symbols) {
     98       bool received =
     99           (symbol == TransportFeedback::StatusSymbol::kReceivedSmallDelta ||
    100            symbol == TransportFeedback::StatusSymbol::kReceivedLargeDelta);
    101       if (seq_it != expected_seq_.end()) {
    102         if (seq == *seq_it) {
    103           ASSERT_NE(expected_seq_.end(), seq_it);
    104           ASSERT_TRUE(received) << "Expected received packet @ " << seq;
    105           ++seq_it;
    106         } else {
    107           ASSERT_FALSE(received) << "Did not expect received packet @ " << seq;
    108         }
    109       }
    110       ++seq;
    111     }
    112     ASSERT_EQ(expected_seq_.end(), seq_it);
    113 
    114     std::vector<int64_t> deltas = feedback_->GetReceiveDeltasUs();
    115     ASSERT_EQ(expected_deltas_.size(), deltas.size());
    116     for (size_t i = 0; i < expected_deltas_.size(); ++i)
    117       EXPECT_EQ(expected_deltas_[i], deltas[i]) << "Delta mismatch @ " << i;
    118   }
    119 
    120   void GenerateDeltas(const uint16_t seq[],
    121                       const size_t length,
    122                       int64_t* deltas) {
    123     uint16_t last_seq = seq[0];
    124     int64_t offset = 0;
    125 
    126     for (size_t i = 0; i < length; ++i) {
    127       if (seq[i] < last_seq)
    128         offset += 0x10000 * default_delta_;
    129       last_seq = seq[i];
    130 
    131       deltas[i] = offset + (last_seq * default_delta_);
    132     }
    133   }
    134 
    135   std::vector<uint16_t> expected_seq_;
    136   std::vector<int64_t> expected_deltas_;
    137   size_t expected_size_;
    138   int64_t default_delta_;
    139   rtc::scoped_ptr<TransportFeedback> feedback_;
    140   rtc::scoped_ptr<rtcp::RawPacket> serialized_;
    141 };
    142 
    143 TEST(RtcpPacketTest, TransportFeedback_OneBitVector) {
    144   const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
    145   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    146   const size_t kExpectedSizeBytes =
    147       kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
    148 
    149   FeedbackTester test;
    150   test.WithExpectedSize(kExpectedSizeBytes);
    151   test.WithInput(kReceived, nullptr, kLength);
    152   test.VerifyPacket();
    153 }
    154 
    155 TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) {
    156   const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14};
    157   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    158   const size_t kExpectedSizeBytes =
    159       kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
    160 
    161   FeedbackTester test;
    162   test.WithExpectedSize(kExpectedSizeBytes);
    163   test.WithInput(kReceived, nullptr, kLength);
    164   test.VerifyPacket();
    165 }
    166 
    167 TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) {
    168   const uint16_t kMax = 0xFFFF;
    169   const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2};
    170   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    171   const size_t kExpectedSizeBytes =
    172       kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
    173 
    174   FeedbackTester test;
    175   test.WithExpectedSize(kExpectedSizeBytes);
    176   test.WithInput(kReceived, nullptr, kLength);
    177   test.VerifyPacket();
    178 }
    179 
    180 TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) {
    181   const uint16_t kMax = 0xFFFF;
    182   const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2};
    183   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    184   const size_t kExpectedSizeBytes =
    185       kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
    186 
    187   FeedbackTester test;
    188   test.WithExpectedSize(kExpectedSizeBytes);
    189   test.WithInput(kReceived, nullptr, kLength);
    190   test.VerifyPacket();
    191 }
    192 
    193 TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) {
    194   const uint16_t kReceived[] = {1, 2, 6, 7};
    195   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    196   const size_t kExpectedSizeBytes =
    197       kHeaderSize + kStatusChunkSize + (kLength * kLargeDeltaSize);
    198 
    199   FeedbackTester test;
    200   test.WithExpectedSize(kExpectedSizeBytes);
    201   test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor);
    202   test.WithInput(kReceived, nullptr, kLength);
    203   test.VerifyPacket();
    204 }
    205 
    206 TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) {
    207   const uint16_t kReceived[] = {1, 2, 6, 7, 8};
    208   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    209   const size_t kExpectedSizeBytes =
    210       kHeaderSize + (2 * kStatusChunkSize) + (kLength * kLargeDeltaSize);
    211 
    212   FeedbackTester test;
    213   test.WithExpectedSize(kExpectedSizeBytes);
    214   test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor);
    215   test.WithInput(kReceived, nullptr, kLength);
    216   test.VerifyPacket();
    217 }
    218 
    219 TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) {
    220   const uint16_t kReceived[] = {1, 2, 6, 7, 8};
    221   const int64_t kReceiveTimes[] = {
    222       2000,
    223       1000,
    224       4000,
    225       3000,
    226       3000 + TransportFeedback::kDeltaScaleFactor * (1 << 8)};
    227   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    228   const size_t kExpectedSizeBytes =
    229       kHeaderSize + kStatusChunkSize + (3 * kLargeDeltaSize) + kSmallDeltaSize;
    230 
    231   FeedbackTester test;
    232   test.WithExpectedSize(kExpectedSizeBytes);
    233   test.WithInput(kReceived, kReceiveTimes, kLength);
    234   test.VerifyPacket();
    235 }
    236 
    237 TEST(RtcpPacketTest, TransportFeedback_MaxRle) {
    238   // Expected chunks created:
    239   // * 1-bit vector chunk (1xreceived + 13xdropped)
    240   // * RLE chunk of max length for dropped symbol
    241   // * 1-bit vector chunk (1xreceived + 13xdropped)
    242 
    243   const size_t kPacketCount = (1 << 13) - 1 + 14;
    244   const uint16_t kReceived[] = {0, kPacketCount};
    245   const int64_t kReceiveTimes[] = {1000, 2000};
    246   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    247   const size_t kExpectedSizeBytes =
    248       kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
    249 
    250   FeedbackTester test;
    251   test.WithExpectedSize(kExpectedSizeBytes);
    252   test.WithInput(kReceived, kReceiveTimes, kLength);
    253   test.VerifyPacket();
    254 }
    255 
    256 TEST(RtcpPacketTest, TransportFeedback_MinRle) {
    257   // Expected chunks created:
    258   // * 1-bit vector chunk (1xreceived + 13xdropped)
    259   // * RLE chunk of length 15 for dropped symbol
    260   // * 1-bit vector chunk (1xreceived + 13xdropped)
    261 
    262   const uint16_t kReceived[] = {0, (14 * 2) + 1};
    263   const int64_t kReceiveTimes[] = {1000, 2000};
    264   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    265   const size_t kExpectedSizeBytes =
    266       kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
    267 
    268   FeedbackTester test;
    269   test.WithExpectedSize(kExpectedSizeBytes);
    270   test.WithInput(kReceived, kReceiveTimes, kLength);
    271   test.VerifyPacket();
    272 }
    273 
    274 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) {
    275   const size_t kTwoBitVectorCapacity = 7;
    276   const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1};
    277   const int64_t kReceiveTimes[] = {
    278       0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor};
    279   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    280   const size_t kExpectedSizeBytes =
    281       kHeaderSize + kStatusChunkSize + kSmallDeltaSize + kLargeDeltaSize;
    282 
    283   FeedbackTester test;
    284   test.WithExpectedSize(kExpectedSizeBytes);
    285   test.WithInput(kReceived, kReceiveTimes, kLength);
    286   test.VerifyPacket();
    287 }
    288 
    289 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) {
    290   const size_t kTwoBitVectorCapacity = 7;
    291   const uint16_t kReceived[] = {0, kTwoBitVectorCapacity};
    292   const int64_t kReceiveTimes[] = {
    293       0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor};
    294   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
    295   const size_t kExpectedSizeBytes =
    296       kHeaderSize + (kStatusChunkSize * 2) + kSmallDeltaSize + kLargeDeltaSize;
    297 
    298   FeedbackTester test;
    299   test.WithExpectedSize(kExpectedSizeBytes);
    300   test.WithInput(kReceived, kReceiveTimes, kLength);
    301   test.VerifyPacket();
    302 }
    303 
    304 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) {
    305   // With received small delta = S, received large delta = L, use input
    306   // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L.
    307   // After split there will be two symbols in symbol_vec: SL.
    308 
    309   const int64_t kLargeDelta = TransportFeedback::kDeltaScaleFactor * (1 << 8);
    310   const size_t kNumPackets = (3 * 7) + 1;
    311   const size_t kExpectedSizeBytes = kHeaderSize + (kStatusChunkSize * 3) +
    312                                     (kSmallDeltaSize * (kNumPackets - 1)) +
    313                                     (kLargeDeltaSize * 1);
    314 
    315   uint16_t kReceived[kNumPackets];
    316   for (size_t i = 0; i < kNumPackets; ++i)
    317     kReceived[i] = i;
    318 
    319   int64_t kReceiveTimes[kNumPackets];
    320   kReceiveTimes[0] = 1000;
    321   for (size_t i = 1; i < kNumPackets; ++i) {
    322     int delta = (i == 8) ? kLargeDelta : 1000;
    323     kReceiveTimes[i] = kReceiveTimes[i - 1] + delta;
    324   }
    325 
    326   FeedbackTester test;
    327   test.WithExpectedSize(kExpectedSizeBytes);
    328   test.WithInput(kReceived, kReceiveTimes, kNumPackets);
    329   test.VerifyPacket();
    330 }
    331 
    332 TEST(RtcpPacketTest, TransportFeedback_Aliasing) {
    333   TransportFeedback feedback;
    334   feedback.WithBase(0, 0);
    335 
    336   const int kSamples = 100;
    337   const int64_t kTooSmallDelta = TransportFeedback::kDeltaScaleFactor / 3;
    338 
    339   for (int i = 0; i < kSamples; ++i)
    340     feedback.WithReceivedPacket(i, i * kTooSmallDelta);
    341 
    342   feedback.Build();
    343   std::vector<int64_t> deltas = feedback.GetReceiveDeltasUs();
    344 
    345   int64_t accumulated_delta = 0;
    346   int num_samples = 0;
    347   for (int64_t delta : deltas) {
    348     accumulated_delta += delta;
    349     int64_t expected_time = num_samples * kTooSmallDelta;
    350     ++num_samples;
    351 
    352     EXPECT_NEAR(expected_time, accumulated_delta,
    353                 TransportFeedback::kDeltaScaleFactor / 2);
    354   }
    355 }
    356 
    357 TEST(RtcpPacketTest, TransportFeedback_Limits) {
    358   // Sequence number wrap above 0x8000.
    359   rtc::scoped_ptr<TransportFeedback> packet(new TransportFeedback());
    360   packet->WithBase(0, 0);
    361   EXPECT_TRUE(packet->WithReceivedPacket(0x8000, 1000));
    362 
    363   packet.reset(new TransportFeedback());
    364   packet->WithBase(0, 0);
    365   EXPECT_FALSE(packet->WithReceivedPacket(0x8000 + 1, 1000));
    366 
    367   // Packet status count max 0xFFFF.
    368   packet.reset(new TransportFeedback());
    369   packet->WithBase(0, 0);
    370   EXPECT_TRUE(packet->WithReceivedPacket(0x8000, 1000));
    371   EXPECT_TRUE(packet->WithReceivedPacket(0xFFFF, 2000));
    372   EXPECT_FALSE(packet->WithReceivedPacket(0, 3000));
    373 
    374   // Too large delta.
    375   packet.reset(new TransportFeedback());
    376   packet->WithBase(0, 0);
    377   int64_t kMaxPositiveTimeDelta = std::numeric_limits<int16_t>::max() *
    378                                   TransportFeedback::kDeltaScaleFactor;
    379   EXPECT_FALSE(packet->WithReceivedPacket(
    380       1, kMaxPositiveTimeDelta + TransportFeedback::kDeltaScaleFactor));
    381   EXPECT_TRUE(packet->WithReceivedPacket(1, kMaxPositiveTimeDelta));
    382 
    383   // Too large negative delta.
    384   packet.reset(new TransportFeedback());
    385   packet->WithBase(0, 0);
    386   int64_t kMaxNegativeTimeDelta = std::numeric_limits<int16_t>::min() *
    387                                   TransportFeedback::kDeltaScaleFactor;
    388   EXPECT_FALSE(packet->WithReceivedPacket(
    389       1, kMaxNegativeTimeDelta - TransportFeedback::kDeltaScaleFactor));
    390   EXPECT_TRUE(packet->WithReceivedPacket(1, kMaxNegativeTimeDelta));
    391 
    392   // Base time at maximum value.
    393   int64_t kMaxBaseTime =
    394       static_cast<int64_t>(TransportFeedback::kDeltaScaleFactor) * (1L << 8) *
    395       ((1L << 23) - 1);
    396   packet.reset(new TransportFeedback());
    397   packet->WithBase(0, kMaxBaseTime);
    398   packet->WithReceivedPacket(0, kMaxBaseTime);
    399   // Serialize and de-serialize (verify 24bit parsing).
    400   rtc::scoped_ptr<rtcp::RawPacket> raw_packet = packet->Build();
    401   packet =
    402       TransportFeedback::ParseFrom(raw_packet->Buffer(), raw_packet->Length());
    403   EXPECT_EQ(kMaxBaseTime, packet->GetBaseTimeUs());
    404 
    405   // Base time above maximum value.
    406   int64_t kTooLargeBaseTime =
    407       kMaxBaseTime + (TransportFeedback::kDeltaScaleFactor * (1L << 8));
    408   packet.reset(new TransportFeedback());
    409   packet->WithBase(0, kTooLargeBaseTime);
    410   packet->WithReceivedPacket(0, kTooLargeBaseTime);
    411   raw_packet = packet->Build();
    412   packet =
    413       TransportFeedback::ParseFrom(raw_packet->Buffer(), raw_packet->Length());
    414   EXPECT_NE(kTooLargeBaseTime, packet->GetBaseTimeUs());
    415 
    416   // TODO(sprang): Once we support max length lower than RTCP length limit,
    417   // add back test for max size in bytes.
    418 }
    419 
    420 TEST(RtcpPacketTest, TransportFeedback_Padding) {
    421   const size_t kExpectedSizeBytes =
    422       kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
    423   const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
    424 
    425   TransportFeedback feedback;
    426   feedback.WithBase(0, 0);
    427   EXPECT_TRUE(feedback.WithReceivedPacket(0, 0));
    428 
    429   rtc::scoped_ptr<rtcp::RawPacket> packet(feedback.Build());
    430   EXPECT_EQ(kExpectedSizeWords * 4, packet->Length());
    431   ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
    432   for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i)
    433     EXPECT_EQ(0u, packet->Buffer()[i]);
    434 
    435   // Modify packet by adding 4 bytes of padding at the end. Not currently used
    436   // when we're sending, but need to be able to handle it when receiving.
    437 
    438   const int kPaddingBytes = 4;
    439   const size_t kExpectedSizeWithPadding =
    440       (kExpectedSizeWords * 4) + kPaddingBytes;
    441   uint8_t mod_buffer[kExpectedSizeWithPadding];
    442   memcpy(mod_buffer, packet->Buffer(), kExpectedSizeWords * 4);
    443   memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1);
    444   mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes;
    445   const uint8_t padding_flag = 1 << 5;
    446   mod_buffer[0] |= padding_flag;
    447   ByteWriter<uint16_t>::WriteBigEndian(
    448       &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) +
    449                           ((kPaddingBytes + 3) / 4));
    450 
    451   rtc::scoped_ptr<TransportFeedback> parsed_packet(
    452       TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding));
    453   ASSERT_TRUE(parsed_packet.get() != nullptr);
    454   EXPECT_EQ(kExpectedSizeWords * 4, packet->Length());  // Padding not included.
    455 }
    456 
    457 TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) {
    458   const int kOneBitVectorCapacity = 14;
    459   const int64_t kLargeTimeDelta =
    460       TransportFeedback::kDeltaScaleFactor * (1 << 8);
    461 
    462   // Test that a number of small deltas followed by a large delta results in a
    463   // correct split into multiple chunks, as needed.
    464 
    465   for (int deltas = 0; deltas <= kOneBitVectorCapacity + 1; ++deltas) {
    466     TransportFeedback feedback;
    467     feedback.WithBase(0, 0);
    468     for (int i = 0; i < deltas; ++i)
    469       feedback.WithReceivedPacket(i, i * 1000);
    470     feedback.WithReceivedPacket(deltas, deltas * 1000 + kLargeTimeDelta);
    471 
    472     rtc::scoped_ptr<rtcp::RawPacket> serialized_packet = feedback.Build();
    473     EXPECT_TRUE(serialized_packet.get() != nullptr);
    474     rtc::scoped_ptr<TransportFeedback> deserialized_packet =
    475         TransportFeedback::ParseFrom(serialized_packet->Buffer(),
    476                                      serialized_packet->Length());
    477     EXPECT_TRUE(deserialized_packet.get() != nullptr);
    478   }
    479 }
    480 
    481 }  // namespace
    482 }  // namespace webrtc
    483