xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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