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 "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
12
13 #include <limits>
14 #include <memory>
15 #include <utility>
16
17 #include "api/array_view.h"
18 #include "api/units/time_delta.h"
19 #include "api/units/timestamp.h"
20 #include "modules/rtp_rtcp/source/byte_io.h"
21 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
22 #include "test/gmock.h"
23 #include "test/gtest.h"
24
25 namespace webrtc {
26 namespace {
27
28 using rtcp::TransportFeedback;
29 using ::testing::AllOf;
30 using ::testing::Each;
31 using ::testing::ElementsAreArray;
32 using ::testing::Eq;
33 using ::testing::Property;
34 using ::testing::SizeIs;
35
36 constexpr int kHeaderSize = 20;
37 constexpr int kStatusChunkSize = 2;
38 constexpr int kSmallDeltaSize = 1;
39 constexpr int kLargeDeltaSize = 2;
40
41 constexpr TimeDelta kDeltaLimit = 0xFF * TransportFeedback::kDeltaTick;
42 constexpr TimeDelta kBaseTimeTick = TransportFeedback::kDeltaTick * (1 << 8);
43 constexpr TimeDelta kBaseTimeWrapPeriod = kBaseTimeTick * (1 << 24);
44
45 MATCHER_P2(Near, value, max_abs_error, "") {
46 return value - max_abs_error <= arg && arg <= value + max_abs_error;
47 }
48
49 MATCHER(IsValidFeedback, "") {
50 rtcp::CommonHeader rtcp_header;
51 TransportFeedback feedback;
52 return rtcp_header.Parse(std::data(arg), std::size(arg)) &&
53 rtcp_header.type() == TransportFeedback::kPacketType &&
54 rtcp_header.fmt() == TransportFeedback::kFeedbackMessageType &&
55 feedback.Parse(rtcp_header);
56 }
57
Parse(rtc::ArrayView<const uint8_t> buffer)58 TransportFeedback Parse(rtc::ArrayView<const uint8_t> buffer) {
59 rtcp::CommonHeader header;
60 RTC_DCHECK(header.Parse(buffer.data(), buffer.size()));
61 RTC_DCHECK_EQ(header.type(), TransportFeedback::kPacketType);
62 RTC_DCHECK_EQ(header.fmt(), TransportFeedback::kFeedbackMessageType);
63 TransportFeedback feedback;
64 RTC_DCHECK(feedback.Parse(header));
65 return feedback;
66 }
67
68 class FeedbackTester {
69 public:
FeedbackTester()70 FeedbackTester() : FeedbackTester(true) {}
FeedbackTester(bool include_timestamps)71 explicit FeedbackTester(bool include_timestamps)
72 : expected_size_(kAnySize),
73 default_delta_(TransportFeedback::kDeltaTick * 4),
74 include_timestamps_(include_timestamps) {}
75
WithExpectedSize(size_t expected_size)76 void WithExpectedSize(size_t expected_size) {
77 expected_size_ = expected_size;
78 }
79
WithDefaultDelta(TimeDelta delta)80 void WithDefaultDelta(TimeDelta delta) { default_delta_ = delta; }
81
WithInput(rtc::ArrayView<const uint16_t> received_seq,rtc::ArrayView<const Timestamp> received_ts={})82 void WithInput(rtc::ArrayView<const uint16_t> received_seq,
83 rtc::ArrayView<const Timestamp> received_ts = {}) {
84 std::vector<Timestamp> temp_timestamps;
85 if (received_ts.empty()) {
86 temp_timestamps = GenerateReceiveTimestamps(received_seq);
87 received_ts = temp_timestamps;
88 }
89 RTC_DCHECK_EQ(received_seq.size(), received_ts.size());
90
91 expected_deltas_.clear();
92 feedback_.emplace(include_timestamps_);
93 feedback_->SetBase(received_seq[0], received_ts[0]);
94 ASSERT_TRUE(feedback_->IsConsistent());
95 // First delta is special: it doesn't represent the delta between two times,
96 // but a compensation for the reduced precision of the base time.
97 EXPECT_TRUE(feedback_->AddReceivedPacket(received_seq[0], received_ts[0]));
98 // GetBaseDelta suppose to return balanced diff between base time of the new
99 // feedback message (stored internally) and base time of the old feedback
100 // message (passed as parameter), but first delta is the difference between
101 // 1st timestamp (passed as parameter) and base time (stored internally),
102 // thus to get the first delta need to negate whatever GetBaseDelta returns.
103 expected_deltas_.push_back(-feedback_->GetBaseDelta(received_ts[0]));
104
105 for (size_t i = 1; i < received_ts.size(); ++i) {
106 EXPECT_TRUE(
107 feedback_->AddReceivedPacket(received_seq[i], received_ts[i]));
108 expected_deltas_.push_back(received_ts[i] - received_ts[i - 1]);
109 }
110 ASSERT_TRUE(feedback_->IsConsistent());
111 expected_seq_.assign(received_seq.begin(), received_seq.end());
112 }
113
VerifyPacket()114 void VerifyPacket() {
115 ASSERT_TRUE(feedback_->IsConsistent());
116 serialized_ = feedback_->Build();
117 VerifyInternal();
118
119 feedback_.emplace(Parse(serialized_));
120 ASSERT_TRUE(feedback_->IsConsistent());
121 EXPECT_EQ(include_timestamps_, feedback_->IncludeTimestamps());
122 VerifyInternal();
123 }
124
125 static constexpr size_t kAnySize = static_cast<size_t>(0) - 1;
126
127 private:
VerifyInternal()128 void VerifyInternal() {
129 if (expected_size_ != kAnySize) {
130 // Round up to whole 32-bit words.
131 size_t expected_size_words = (expected_size_ + 3) / 4;
132 size_t expected_size_bytes = expected_size_words * 4;
133 EXPECT_EQ(expected_size_bytes, serialized_.size());
134 }
135
136 std::vector<uint16_t> actual_seq_nos;
137 std::vector<TimeDelta> actual_deltas;
138 for (const auto& packet : feedback_->GetReceivedPackets()) {
139 actual_seq_nos.push_back(packet.sequence_number());
140 actual_deltas.push_back(packet.delta());
141 }
142 EXPECT_THAT(actual_seq_nos, ElementsAreArray(expected_seq_));
143 if (include_timestamps_) {
144 EXPECT_THAT(actual_deltas, ElementsAreArray(expected_deltas_));
145 }
146 }
147
GenerateReceiveTimestamps(rtc::ArrayView<const uint16_t> seq_nums)148 std::vector<Timestamp> GenerateReceiveTimestamps(
149 rtc::ArrayView<const uint16_t> seq_nums) {
150 RTC_DCHECK(!seq_nums.empty());
151 uint16_t last_seq = seq_nums[0];
152 Timestamp time = Timestamp::Zero();
153 std::vector<Timestamp> result;
154
155 for (uint16_t seq : seq_nums) {
156 if (seq < last_seq)
157 time += 0x10000 * default_delta_;
158 last_seq = seq;
159
160 result.push_back(time + last_seq * default_delta_);
161 }
162 return result;
163 }
164
165 std::vector<uint16_t> expected_seq_;
166 std::vector<TimeDelta> expected_deltas_;
167 size_t expected_size_;
168 TimeDelta default_delta_;
169 absl::optional<TransportFeedback> feedback_;
170 rtc::Buffer serialized_;
171 bool include_timestamps_;
172 };
173
174 // The following tests use FeedbackTester that simulates received packets as
175 // specified by the parameters `received_seq[]` and `received_ts[]` (optional).
176 // The following is verified in these tests:
177 // - Expected size of serialized packet.
178 // - Expected sequence numbers and receive deltas.
179 // - Sequence numbers and receive deltas are persistent after serialization
180 // followed by parsing.
181 // - The internal state of a feedback packet is consistent.
TEST(RtcpPacketTest,TransportFeedbackOneBitVector)182 TEST(RtcpPacketTest, TransportFeedbackOneBitVector) {
183 const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
184 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
185 const size_t kExpectedSizeBytes =
186 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
187
188 FeedbackTester test;
189 test.WithExpectedSize(kExpectedSizeBytes);
190 test.WithInput(kReceived);
191 test.VerifyPacket();
192 }
193
TEST(RtcpPacketTest,TransportFeedbackOneBitVectorNoRecvDelta)194 TEST(RtcpPacketTest, TransportFeedbackOneBitVectorNoRecvDelta) {
195 const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
196 const size_t kExpectedSizeBytes = kHeaderSize + kStatusChunkSize;
197
198 FeedbackTester test(/*include_timestamps=*/false);
199 test.WithExpectedSize(kExpectedSizeBytes);
200 test.WithInput(kReceived);
201 test.VerifyPacket();
202 }
203
TEST(RtcpPacketTest,TransportFeedbackFullOneBitVector)204 TEST(RtcpPacketTest, TransportFeedbackFullOneBitVector) {
205 const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14};
206 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
207 const size_t kExpectedSizeBytes =
208 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
209
210 FeedbackTester test;
211 test.WithExpectedSize(kExpectedSizeBytes);
212 test.WithInput(kReceived);
213 test.VerifyPacket();
214 }
215
TEST(RtcpPacketTest,TransportFeedbackOneBitVectorWrapReceived)216 TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapReceived) {
217 const uint16_t kMax = 0xFFFF;
218 const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2};
219 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
220 const size_t kExpectedSizeBytes =
221 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
222
223 FeedbackTester test;
224 test.WithExpectedSize(kExpectedSizeBytes);
225 test.WithInput(kReceived);
226 test.VerifyPacket();
227 }
228
TEST(RtcpPacketTest,TransportFeedbackOneBitVectorWrapMissing)229 TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapMissing) {
230 const uint16_t kMax = 0xFFFF;
231 const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2};
232 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
233 const size_t kExpectedSizeBytes =
234 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
235
236 FeedbackTester test;
237 test.WithExpectedSize(kExpectedSizeBytes);
238 test.WithInput(kReceived);
239 test.VerifyPacket();
240 }
241
TEST(RtcpPacketTest,TransportFeedbackTwoBitVector)242 TEST(RtcpPacketTest, TransportFeedbackTwoBitVector) {
243 const uint16_t kReceived[] = {1, 2, 6, 7};
244 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
245 const size_t kExpectedSizeBytes =
246 kHeaderSize + kStatusChunkSize + (kLength * kLargeDeltaSize);
247
248 FeedbackTester test;
249 test.WithExpectedSize(kExpectedSizeBytes);
250 test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaTick);
251 test.WithInput(kReceived);
252 test.VerifyPacket();
253 }
254
TEST(RtcpPacketTest,TransportFeedbackTwoBitVectorFull)255 TEST(RtcpPacketTest, TransportFeedbackTwoBitVectorFull) {
256 const uint16_t kReceived[] = {1, 2, 6, 7, 8};
257 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
258 const size_t kExpectedSizeBytes =
259 kHeaderSize + (2 * kStatusChunkSize) + (kLength * kLargeDeltaSize);
260
261 FeedbackTester test;
262 test.WithExpectedSize(kExpectedSizeBytes);
263 test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaTick);
264 test.WithInput(kReceived);
265 test.VerifyPacket();
266 }
267
TEST(RtcpPacketTest,TransportFeedbackWithLargeBaseTimeIsConsistent)268 TEST(RtcpPacketTest, TransportFeedbackWithLargeBaseTimeIsConsistent) {
269 TransportFeedback tb;
270 constexpr Timestamp kTimestamp =
271 Timestamp::Zero() + int64_t{0x7fff'ffff} * TransportFeedback::kDeltaTick;
272 tb.SetBase(/*base_sequence=*/0, /*ref_timestamp=*/kTimestamp);
273 tb.AddReceivedPacket(/*base_sequence=*/0, /*ref_timestamp=*/kTimestamp);
274 EXPECT_TRUE(tb.IsConsistent());
275 }
276
TEST(RtcpPacketTest,TransportFeedbackLargeAndNegativeDeltas)277 TEST(RtcpPacketTest, TransportFeedbackLargeAndNegativeDeltas) {
278 const uint16_t kReceived[] = {1, 2, 6, 7, 8};
279 const Timestamp kReceiveTimes[] = {
280 Timestamp::Millis(2), Timestamp::Millis(1), Timestamp::Millis(4),
281 Timestamp::Millis(3),
282 Timestamp::Millis(3) + TransportFeedback::kDeltaTick * (1 << 8)};
283 const size_t kExpectedSizeBytes =
284 kHeaderSize + kStatusChunkSize + (3 * kLargeDeltaSize) + kSmallDeltaSize;
285
286 FeedbackTester test;
287 test.WithExpectedSize(kExpectedSizeBytes);
288 test.WithInput(kReceived, kReceiveTimes);
289 test.VerifyPacket();
290 }
291
TEST(RtcpPacketTest,TransportFeedbackMaxRle)292 TEST(RtcpPacketTest, TransportFeedbackMaxRle) {
293 // Expected chunks created:
294 // * 1-bit vector chunk (1xreceived + 13xdropped)
295 // * RLE chunk of max length for dropped symbol
296 // * 1-bit vector chunk (1xreceived + 13xdropped)
297
298 const size_t kPacketCount = (1 << 13) - 1 + 14;
299 const uint16_t kReceived[] = {0, kPacketCount};
300 const Timestamp kReceiveTimes[] = {Timestamp::Millis(1),
301 Timestamp::Millis(2)};
302 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
303 const size_t kExpectedSizeBytes =
304 kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
305
306 FeedbackTester test;
307 test.WithExpectedSize(kExpectedSizeBytes);
308 test.WithInput(kReceived, kReceiveTimes);
309 test.VerifyPacket();
310 }
311
TEST(RtcpPacketTest,TransportFeedbackMinRle)312 TEST(RtcpPacketTest, TransportFeedbackMinRle) {
313 // Expected chunks created:
314 // * 1-bit vector chunk (1xreceived + 13xdropped)
315 // * RLE chunk of length 15 for dropped symbol
316 // * 1-bit vector chunk (1xreceived + 13xdropped)
317
318 const uint16_t kReceived[] = {0, (14 * 2) + 1};
319 const Timestamp kReceiveTimes[] = {Timestamp::Millis(1),
320 Timestamp::Millis(2)};
321 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
322 const size_t kExpectedSizeBytes =
323 kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
324
325 FeedbackTester test;
326 test.WithExpectedSize(kExpectedSizeBytes);
327 test.WithInput(kReceived, kReceiveTimes);
328 test.VerifyPacket();
329 }
330
TEST(RtcpPacketTest,TransportFeedbackOneToTwoBitVector)331 TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVector) {
332 const size_t kTwoBitVectorCapacity = 7;
333 const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1};
334 const Timestamp kReceiveTimes[] = {
335 Timestamp::Zero(),
336 Timestamp::Zero() + kDeltaLimit + TransportFeedback::kDeltaTick};
337 const size_t kExpectedSizeBytes =
338 kHeaderSize + kStatusChunkSize + kSmallDeltaSize + kLargeDeltaSize;
339
340 FeedbackTester test;
341 test.WithExpectedSize(kExpectedSizeBytes);
342 test.WithInput(kReceived, kReceiveTimes);
343 test.VerifyPacket();
344 }
345
TEST(RtcpPacketTest,TransportFeedbackOneToTwoBitVectorSimpleSplit)346 TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSimpleSplit) {
347 const size_t kTwoBitVectorCapacity = 7;
348 const uint16_t kReceived[] = {0, kTwoBitVectorCapacity};
349 const Timestamp kReceiveTimes[] = {
350 Timestamp::Zero(),
351 Timestamp::Zero() + kDeltaLimit + TransportFeedback::kDeltaTick};
352 const size_t kExpectedSizeBytes =
353 kHeaderSize + (kStatusChunkSize * 2) + kSmallDeltaSize + kLargeDeltaSize;
354
355 FeedbackTester test;
356 test.WithExpectedSize(kExpectedSizeBytes);
357 test.WithInput(kReceived, kReceiveTimes);
358 test.VerifyPacket();
359 }
360
TEST(RtcpPacketTest,TransportFeedbackOneToTwoBitVectorSplit)361 TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSplit) {
362 // With received small delta = S, received large delta = L, use input
363 // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L.
364 // After split there will be two symbols in symbol_vec: SL.
365
366 const TimeDelta kLargeDelta = TransportFeedback::kDeltaTick * (1 << 8);
367 const size_t kNumPackets = (3 * 7) + 1;
368 const size_t kExpectedSizeBytes = kHeaderSize + (kStatusChunkSize * 3) +
369 (kSmallDeltaSize * (kNumPackets - 1)) +
370 (kLargeDeltaSize * 1);
371
372 uint16_t kReceived[kNumPackets];
373 for (size_t i = 0; i < kNumPackets; ++i)
374 kReceived[i] = i;
375
376 std::vector<Timestamp> receive_times;
377 receive_times.reserve(kNumPackets);
378 receive_times.push_back(Timestamp::Millis(1));
379 for (size_t i = 1; i < kNumPackets; ++i) {
380 TimeDelta delta = (i == 8) ? kLargeDelta : TimeDelta::Millis(1);
381 receive_times.push_back(receive_times.back() + delta);
382 }
383
384 FeedbackTester test;
385 test.WithExpectedSize(kExpectedSizeBytes);
386 test.WithInput(kReceived, receive_times);
387 test.VerifyPacket();
388 }
389
TEST(RtcpPacketTest,TransportFeedbackAliasing)390 TEST(RtcpPacketTest, TransportFeedbackAliasing) {
391 TransportFeedback feedback;
392 feedback.SetBase(0, Timestamp::Zero());
393
394 const int kSamples = 100;
395 const TimeDelta kTooSmallDelta = TransportFeedback::kDeltaTick / 3;
396
397 for (int i = 0; i < kSamples; ++i)
398 feedback.AddReceivedPacket(i, Timestamp::Zero() + i * kTooSmallDelta);
399
400 feedback.Build();
401
402 TimeDelta accumulated_delta = TimeDelta::Zero();
403 int num_samples = 0;
404 for (const auto& packet : feedback.GetReceivedPackets()) {
405 accumulated_delta += packet.delta();
406 TimeDelta expected_time = num_samples * kTooSmallDelta;
407 ++num_samples;
408
409 EXPECT_THAT(accumulated_delta,
410 Near(expected_time, TransportFeedback::kDeltaTick / 2));
411 }
412 }
413
TEST(RtcpPacketTest,TransportFeedbackLimits)414 TEST(RtcpPacketTest, TransportFeedbackLimits) {
415 // Sequence number wrap above 0x8000.
416 std::unique_ptr<TransportFeedback> packet(new TransportFeedback());
417 packet->SetBase(0, Timestamp::Zero());
418 EXPECT_TRUE(packet->AddReceivedPacket(0x0, Timestamp::Zero()));
419 EXPECT_TRUE(packet->AddReceivedPacket(0x8000, Timestamp::Millis(1)));
420
421 packet.reset(new TransportFeedback());
422 packet->SetBase(0, Timestamp::Zero());
423 EXPECT_TRUE(packet->AddReceivedPacket(0x0, Timestamp::Zero()));
424 EXPECT_FALSE(packet->AddReceivedPacket(0x8000 + 1, Timestamp::Millis(1)));
425
426 // Packet status count max 0xFFFF.
427 packet.reset(new TransportFeedback());
428 packet->SetBase(0, Timestamp::Zero());
429 EXPECT_TRUE(packet->AddReceivedPacket(0x0, Timestamp::Zero()));
430 EXPECT_TRUE(packet->AddReceivedPacket(0x8000, Timestamp::Millis(1)));
431 EXPECT_TRUE(packet->AddReceivedPacket(0xFFFE, Timestamp::Millis(2)));
432 EXPECT_FALSE(packet->AddReceivedPacket(0xFFFF, Timestamp::Millis(3)));
433
434 // Too large delta.
435 packet.reset(new TransportFeedback());
436 packet->SetBase(0, Timestamp::Zero());
437 TimeDelta kMaxPositiveTimeDelta =
438 std::numeric_limits<int16_t>::max() * TransportFeedback::kDeltaTick;
439 EXPECT_FALSE(packet->AddReceivedPacket(1, Timestamp::Zero() +
440 kMaxPositiveTimeDelta +
441 TransportFeedback::kDeltaTick));
442 EXPECT_TRUE(
443 packet->AddReceivedPacket(1, Timestamp::Zero() + kMaxPositiveTimeDelta));
444
445 // Too large negative delta.
446 packet.reset(new TransportFeedback());
447 TimeDelta kMaxNegativeTimeDelta =
448 std::numeric_limits<int16_t>::min() * TransportFeedback::kDeltaTick;
449 // Use larger base time to avoid kBaseTime + kNegativeDelta to be negative.
450 Timestamp kBaseTime = Timestamp::Seconds(1'000'000);
451 packet->SetBase(0, kBaseTime);
452 EXPECT_FALSE(packet->AddReceivedPacket(
453 1, kBaseTime + kMaxNegativeTimeDelta - TransportFeedback::kDeltaTick));
454 EXPECT_TRUE(packet->AddReceivedPacket(1, kBaseTime + kMaxNegativeTimeDelta));
455
456 // TODO(sprang): Once we support max length lower than RTCP length limit,
457 // add back test for max size in bytes.
458 }
459
TEST(RtcpPacketTest,BaseTimeIsConsistentAcrossMultiplePackets)460 TEST(RtcpPacketTest, BaseTimeIsConsistentAcrossMultiplePackets) {
461 constexpr Timestamp kMaxBaseTime =
462 Timestamp::Zero() + kBaseTimeWrapPeriod - kBaseTimeTick;
463
464 TransportFeedback packet1;
465 packet1.SetBase(0, kMaxBaseTime);
466 packet1.AddReceivedPacket(0, kMaxBaseTime);
467 // Build and parse packet to simulate sending it over the wire.
468 TransportFeedback parsed_packet1 = Parse(packet1.Build());
469
470 TransportFeedback packet2;
471 packet2.SetBase(1, kMaxBaseTime + kBaseTimeTick);
472 packet2.AddReceivedPacket(1, kMaxBaseTime + kBaseTimeTick);
473 TransportFeedback parsed_packet2 = Parse(packet2.Build());
474
475 EXPECT_EQ(parsed_packet2.GetBaseDelta(parsed_packet1.BaseTime()),
476 kBaseTimeTick);
477 }
478
TEST(RtcpPacketTest,SupportsMaximumNumberOfNegativeDeltas)479 TEST(RtcpPacketTest, SupportsMaximumNumberOfNegativeDeltas) {
480 TransportFeedback feedback;
481 // Use large base time to avoid hitting zero limit while filling the feedback,
482 // but use multiple of kBaseTimeWrapPeriod to hit edge case where base time
483 // is recorded as zero in the raw rtcp packet.
484 Timestamp time = Timestamp::Zero() + 1'000 * kBaseTimeWrapPeriod;
485 feedback.SetBase(0, time);
486 static constexpr TimeDelta kMinDelta =
487 TransportFeedback::kDeltaTick * std::numeric_limits<int16_t>::min();
488 uint16_t num_received_rtp_packets = 0;
489 time += kMinDelta;
490 while (feedback.AddReceivedPacket(++num_received_rtp_packets, time)) {
491 ASSERT_GE(time, Timestamp::Zero() - kMinDelta);
492 time += kMinDelta;
493 }
494 // Subtract one last packet that failed to add.
495 --num_received_rtp_packets;
496 EXPECT_TRUE(feedback.IsConsistent());
497
498 TransportFeedback parsed = Parse(feedback.Build());
499 EXPECT_EQ(parsed.GetReceivedPackets().size(), num_received_rtp_packets);
500 EXPECT_THAT(parsed.GetReceivedPackets(),
501 AllOf(SizeIs(num_received_rtp_packets),
502 Each(Property(&TransportFeedback::ReceivedPacket::delta,
503 Eq(kMinDelta)))));
504 EXPECT_GE(parsed.BaseTime(),
505 Timestamp::Zero() - kMinDelta * num_received_rtp_packets);
506 }
507
TEST(RtcpPacketTest,TransportFeedbackPadding)508 TEST(RtcpPacketTest, TransportFeedbackPadding) {
509 const size_t kExpectedSizeBytes =
510 kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
511 const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
512 const size_t kExpectedPaddingSizeBytes =
513 4 * kExpectedSizeWords - kExpectedSizeBytes;
514
515 TransportFeedback feedback;
516 feedback.SetBase(0, Timestamp::Zero());
517 EXPECT_TRUE(feedback.AddReceivedPacket(0, Timestamp::Zero()));
518
519 rtc::Buffer packet = feedback.Build();
520 EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
521 ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
522 for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
523 EXPECT_EQ(0u, packet[i]);
524
525 EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
526
527 // Modify packet by adding 4 bytes of padding at the end. Not currently used
528 // when we're sending, but need to be able to handle it when receiving.
529
530 const int kPaddingBytes = 4;
531 const size_t kExpectedSizeWithPadding =
532 (kExpectedSizeWords * 4) + kPaddingBytes;
533 uint8_t mod_buffer[kExpectedSizeWithPadding];
534 memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
535 memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1);
536 mod_buffer[kExpectedSizeWithPadding - 1] =
537 kPaddingBytes + kExpectedPaddingSizeBytes;
538 const uint8_t padding_flag = 1 << 5;
539 mod_buffer[0] |= padding_flag;
540 ByteWriter<uint16_t>::WriteBigEndian(
541 &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) +
542 ((kPaddingBytes + 3) / 4));
543
544 EXPECT_THAT(mod_buffer, IsValidFeedback());
545 }
546
TEST(RtcpPacketTest,TransportFeedbackPaddingBackwardsCompatibility)547 TEST(RtcpPacketTest, TransportFeedbackPaddingBackwardsCompatibility) {
548 const size_t kExpectedSizeBytes =
549 kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
550 const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
551 const size_t kExpectedPaddingSizeBytes =
552 4 * kExpectedSizeWords - kExpectedSizeBytes;
553
554 TransportFeedback feedback;
555 feedback.SetBase(0, Timestamp::Zero());
556 EXPECT_TRUE(feedback.AddReceivedPacket(0, Timestamp::Zero()));
557
558 rtc::Buffer packet = feedback.Build();
559 EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
560 ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
561 for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
562 EXPECT_EQ(0u, packet[i]);
563
564 EXPECT_GT(kExpectedPaddingSizeBytes, 0u);
565 EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
566
567 // Modify packet by removing padding bit and writing zero at the last padding
568 // byte to verify that we can parse packets from old clients, where zero
569 // padding of up to three bytes was used without the padding bit being set.
570 uint8_t mod_buffer[kExpectedSizeWords * 4];
571 memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
572 mod_buffer[kExpectedSizeWords * 4 - 1] = 0;
573 const uint8_t padding_flag = 1 << 5;
574 mod_buffer[0] &= ~padding_flag; // Unset padding flag.
575
576 EXPECT_THAT(mod_buffer, IsValidFeedback());
577 }
578
TEST(RtcpPacketTest,TransportFeedbackCorrectlySplitsVectorChunks)579 TEST(RtcpPacketTest, TransportFeedbackCorrectlySplitsVectorChunks) {
580 const int kOneBitVectorCapacity = 14;
581 const TimeDelta kLargeTimeDelta = TransportFeedback::kDeltaTick * (1 << 8);
582
583 // Test that a number of small deltas followed by a large delta results in a
584 // correct split into multiple chunks, as needed.
585
586 for (int deltas = 0; deltas <= kOneBitVectorCapacity + 1; ++deltas) {
587 TransportFeedback feedback;
588 feedback.SetBase(0, Timestamp::Zero());
589 for (int i = 0; i < deltas; ++i)
590 feedback.AddReceivedPacket(i, Timestamp::Millis(i));
591 feedback.AddReceivedPacket(deltas,
592 Timestamp::Millis(deltas) + kLargeTimeDelta);
593
594 EXPECT_THAT(feedback.Build(), IsValidFeedback());
595 }
596 }
597
TEST(RtcpPacketTest,TransportFeedbackMoveConstructor)598 TEST(RtcpPacketTest, TransportFeedbackMoveConstructor) {
599 const int kSamples = 100;
600 const uint16_t kBaseSeqNo = 7531;
601 const Timestamp kBaseTimestamp = Timestamp::Micros(123'456'789);
602 const uint8_t kFeedbackSeqNo = 90;
603
604 TransportFeedback feedback;
605 feedback.SetBase(kBaseSeqNo, kBaseTimestamp);
606 feedback.SetFeedbackSequenceNumber(kFeedbackSeqNo);
607 for (int i = 0; i < kSamples; ++i) {
608 feedback.AddReceivedPacket(
609 kBaseSeqNo + i, kBaseTimestamp + i * TransportFeedback::kDeltaTick);
610 }
611 EXPECT_TRUE(feedback.IsConsistent());
612
613 TransportFeedback feedback_copy(feedback);
614 EXPECT_TRUE(feedback_copy.IsConsistent());
615 EXPECT_TRUE(feedback.IsConsistent());
616 EXPECT_EQ(feedback_copy.Build(), feedback.Build());
617
618 TransportFeedback moved(std::move(feedback));
619 EXPECT_TRUE(moved.IsConsistent());
620 EXPECT_TRUE(feedback.IsConsistent());
621 EXPECT_EQ(moved.Build(), feedback_copy.Build());
622 }
623
TEST(TransportFeedbackTest,ReportsMissingPackets)624 TEST(TransportFeedbackTest, ReportsMissingPackets) {
625 const uint16_t kBaseSeqNo = 1000;
626 const Timestamp kBaseTimestamp = Timestamp::Millis(10);
627 const uint8_t kFeedbackSeqNo = 90;
628 TransportFeedback feedback_builder(/*include_timestamps*/ true);
629 feedback_builder.SetBase(kBaseSeqNo, kBaseTimestamp);
630 feedback_builder.SetFeedbackSequenceNumber(kFeedbackSeqNo);
631 feedback_builder.AddReceivedPacket(kBaseSeqNo + 0, kBaseTimestamp);
632 // Packet losses indicated by jump in sequence number.
633 feedback_builder.AddReceivedPacket(kBaseSeqNo + 3,
634 kBaseTimestamp + TimeDelta::Millis(2));
635
636 EXPECT_THAT(
637 Parse(feedback_builder.Build()).GetAllPackets(),
638 ElementsAre(
639 Property(&TransportFeedback::ReceivedPacket::received, true),
640 Property(&TransportFeedback::ReceivedPacket::received, false),
641 Property(&TransportFeedback::ReceivedPacket::received, false),
642 Property(&TransportFeedback::ReceivedPacket::received, true)));
643 }
644
TEST(TransportFeedbackTest,ReportsMissingPacketsWithoutTimestamps)645 TEST(TransportFeedbackTest, ReportsMissingPacketsWithoutTimestamps) {
646 const uint16_t kBaseSeqNo = 1000;
647 const uint8_t kFeedbackSeqNo = 90;
648 TransportFeedback feedback_builder(/*include_timestamps*/ false);
649 feedback_builder.SetBase(kBaseSeqNo, Timestamp::Millis(10));
650 feedback_builder.SetFeedbackSequenceNumber(kFeedbackSeqNo);
651 feedback_builder.AddReceivedPacket(kBaseSeqNo + 0, Timestamp::Zero());
652 // Packet losses indicated by jump in sequence number.
653 feedback_builder.AddReceivedPacket(kBaseSeqNo + 3, Timestamp::Zero());
654
655 EXPECT_THAT(
656 Parse(feedback_builder.Build()).GetAllPackets(),
657 ElementsAre(
658 Property(&TransportFeedback::ReceivedPacket::received, true),
659 Property(&TransportFeedback::ReceivedPacket::received, false),
660 Property(&TransportFeedback::ReceivedPacket::received, false),
661 Property(&TransportFeedback::ReceivedPacket::received, true)));
662 }
663 } // namespace
664 } // namespace webrtc
665