transport_feedback_unittest.cc revision c8a1cccd0a80b35a5b6846f6efe6082f96c29083
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
19using webrtc::rtcp::TransportFeedback;
20
21namespace webrtc {
22namespace {
23
24static const int kHeaderSize = 20;
25static const int kStatusChunkSize = 2;
26static const int kSmallDeltaSize = 1;
27static const int kLargeDeltaSize = 2;
28
29static const int64_t kDeltaLimit = 0xFF * TransportFeedback::kDeltaScaleFactor;
30
31class 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
143TEST(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
155TEST(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
167TEST(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
180TEST(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
193TEST(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
206TEST(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
219TEST(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
237TEST(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
256TEST(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
274TEST(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
289TEST(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
304TEST(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
332TEST(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
357TEST(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
420TEST(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}  // namespace
458}  // namespace webrtc
459