xref: /aosp_15_r20/external/openscreen/cast/streaming/compound_rtcp_parser_unittest.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cast/streaming/compound_rtcp_parser.h"
6 
7 #include <chrono>
8 #include <cmath>
9 
10 #include "cast/streaming/mock_compound_rtcp_parser_client.h"
11 #include "cast/streaming/rtcp_session.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 #include "platform/api/time.h"
15 #include "util/chrono_helpers.h"
16 
17 using testing::_;
18 using testing::Mock;
19 using testing::SaveArg;
20 using testing::StrictMock;
21 
22 namespace openscreen {
23 namespace cast {
24 namespace {
25 
26 constexpr Ssrc kSenderSsrc{1};
27 constexpr Ssrc kReceiverSsrc{2};
28 
29 class CompoundRtcpParserTest : public testing::Test {
30  public:
session()31   RtcpSession* session() { return &session_; }
client()32   StrictMock<MockCompoundRtcpParserClient>* client() { return &client_; }
parser()33   CompoundRtcpParser* parser() { return &parser_; }
34 
35  private:
36   RtcpSession session_{kSenderSsrc, kReceiverSsrc, Clock::now()};
37   StrictMock<MockCompoundRtcpParserClient> client_;
38   CompoundRtcpParser parser_{&session_, &client_};
39 };
40 
TEST_F(CompoundRtcpParserTest,ProcessesEmptyPacket)41 TEST_F(CompoundRtcpParserTest, ProcessesEmptyPacket) {
42   const uint8_t kEmpty[0] = {};
43   // Expect NO calls to mock client.
44   EXPECT_TRUE(
45       parser()->Parse(absl::Span<const uint8_t>(kEmpty, 0), FrameId::first()));
46 }
47 
TEST_F(CompoundRtcpParserTest,ReturnsErrorForGarbage)48 TEST_F(CompoundRtcpParserTest, ReturnsErrorForGarbage) {
49   const uint8_t kGarbage[] = {
50       0x42, 0x61, 0x16, 0x17, 0x26, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69,
51       0x6e, 0x67, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x6d, 0x70,
52       0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, 0x74, 0x63, 0x70, 0x5f};
53   // Expect NO calls to mock client.
54   EXPECT_FALSE(parser()->Parse(kGarbage, FrameId::first()));
55 }
56 
TEST_F(CompoundRtcpParserTest,ParsesReceiverReportWithoutReportBlock)57 TEST_F(CompoundRtcpParserTest, ParsesReceiverReportWithoutReportBlock) {
58   // clang-format off
59   const uint8_t kReceiverReportWithoutReportBlock[] = {
60       0b10000000,  // Version=2, Padding=no, ReportCount=0.
61       201,  // RTCP Packet type byte.
62       0x00, 0x01,  // Length of remainder of packet, in 32-bit words.
63       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
64   };
65   // clang-format on
66 
67   // Expect NO calls to mock client.
68   EXPECT_TRUE(
69       parser()->Parse(kReceiverReportWithoutReportBlock, FrameId::first()));
70 }
71 
TEST_F(CompoundRtcpParserTest,ParsesReceiverReportWithReportBlock)72 TEST_F(CompoundRtcpParserTest, ParsesReceiverReportWithReportBlock) {
73   // clang-format off
74   const uint8_t kReceiverReportWithReportBlock[] = {
75       0b10000001,  // Version=2, Padding=no, ReportCount=1.
76       201,  // RTCP Packet type byte.
77       0x00, 0x07,  // Length of remainder of packet, in 32-bit words.
78       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
79 
80       // Report block:
81       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
82       0x05,  // Fraction Lost.
83       0x01, 0x02, 0x03,  // Cumulative # packets lost.
84       0x09, 0x09, 0x09, 0x02,  // Highest sequence number.
85       0x00, 0x00, 0x00, 0xaa,  // Interarrival Jitter.
86       0x0b, 0x0c, 0x8f, 0xed,  // Sender Report ID.
87       0x00, 0x01, 0x00, 0x00,  // Delay since last sender report.
88   };
89   // clang-format on
90 
91   RtcpReportBlock block;
92   EXPECT_CALL(*(client()), OnReceiverReport(_)).WillOnce(SaveArg<0>(&block));
93   EXPECT_TRUE(
94       parser()->Parse(kReceiverReportWithReportBlock, FrameId::first()));
95   Mock::VerifyAndClearExpectations(client());
96   EXPECT_EQ(kSenderSsrc, block.ssrc);
97   EXPECT_EQ(uint8_t{5}, block.packet_fraction_lost_numerator);
98   EXPECT_EQ(0x010203, block.cumulative_packets_lost);
99   EXPECT_EQ(uint32_t{0x09090902}, block.extended_high_sequence_number);
100   EXPECT_EQ(RtpTimeDelta::FromTicks(170), block.jitter);
101   EXPECT_EQ(StatusReportId{0x0b0c8fed}, block.last_status_report_id);
102   EXPECT_EQ(RtcpReportBlock::Delay(65536), block.delay_since_last_report);
103 }
104 
TEST_F(CompoundRtcpParserTest,ParsesPictureLossIndicatorMessage)105 TEST_F(CompoundRtcpParserTest, ParsesPictureLossIndicatorMessage) {
106   // clang-format off
107   const uint8_t kPictureLossIndicatorPacket[] = {
108       0b10000000 | 1,  // Version=2, Padding=no, Subtype=PLI.
109       206,  // RTCP Packet type byte.
110       0x00, 0x02,  // Length of remainder of packet, in 32-bit words.
111       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
112       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
113   };
114 
115   const uint8_t kPictureLossIndicatorPacketWithWrongReceiverSsrc[] = {
116       0b10000000 | 1,  // Version=2, Padding=no, Subtype=PLI.
117       206,  // RTCP Packet type byte.
118       0x00, 0x02,  // Length of remainder of packet, in 32-bit words.
119       0x00, 0x00, 0x00, 0x03,  // WRONG Receiver SSRC.
120       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
121   };
122 
123   const uint8_t kPictureLossIndicatorPacketWithWrongSenderSsrc[] = {
124       0b10000000 | 1,  // Version=2, Padding=no, Subtype=PLI.
125       206,  // RTCP Packet type byte.
126       0x00, 0x02,  // Length of remainder of packet, in 32-bit words.
127       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
128       0x00, 0x00, 0x00, 0x03,  // WRONG Sender SSRC.
129   };
130   // clang-format on
131 
132   // The mock client should get a PLI notification when the packet is valid and
133   // contains the correct SSRCs.
134   EXPECT_CALL(*(client()), OnReceiverIndicatesPictureLoss());
135   EXPECT_TRUE(parser()->Parse(kPictureLossIndicatorPacket, FrameId::first()));
136   Mock::VerifyAndClearExpectations(client());
137 
138   // The mock client should get no PLI notifications when either of the SSRCs is
139   // incorrect.
140   EXPECT_CALL(*(client()), OnReceiverIndicatesPictureLoss()).Times(0);
141   EXPECT_TRUE(parser()->Parse(kPictureLossIndicatorPacketWithWrongReceiverSsrc,
142                               FrameId::first()));
143   Mock::VerifyAndClearExpectations(client());
144   EXPECT_CALL(*(client()), OnReceiverIndicatesPictureLoss()).Times(0);
145   EXPECT_TRUE(parser()->Parse(kPictureLossIndicatorPacketWithWrongSenderSsrc,
146                               FrameId::first()));
147   Mock::VerifyAndClearExpectations(client());
148 }
149 
150 // Tests that RTCP packets containing chronologically-old data are ignored. This
151 // test's methodology simulates a real-world possibility: A receiver sends a
152 // "Picture Loss Indicator" in one RTCP packet, and then it sends another packet
153 // ~1 second later without the PLI, indicating the problem has been resolved.
154 // However, the packets are delivered out-of-order by the network. In this case,
155 // the CompoundRtcpParser should ignore the stale packet containing the PLI.
TEST_F(CompoundRtcpParserTest,IgnoresStalePackets)156 TEST_F(CompoundRtcpParserTest, IgnoresStalePackets) {
157   // clang-format off
158   const uint8_t kNotStaleCompoundPacket[] = {
159       // Receiver report:
160       0b10000000,  // Version=2, Padding=no, ReportCount=0.
161       201,  // RTCP Packet type byte.
162       0x00, 0x01,  // Length of remainder of packet, in 32-bit words.
163       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
164 
165       // Receiver reference time report:
166       0b10000000,  // Version=2, Padding=no.
167       207,  // RTCP Packet type byte.
168       0x00, 0x04,  // Length of remainder of packet, in 32-bit words.
169       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
170       0x04,  // Block type = Receiver Reference Time Report
171       0x00,  // Reserved byte.
172       0x00, 0x02,  // Block length = 2.
173       0xe0, 0x73, 0x2e, 0x54,  // NTP Timestamp (late evening on 2019-04-30).
174           0x80, 0x00, 0x00, 0x00,
175   };
176 
177   const uint8_t kStaleCompoundPacketWithPli[] = {
178       // Picture loss indicator:
179       0b10000000 | 1,  // Version=2, Padding=no, Subtype=PLI.
180       206,  // RTCP Packet type byte.
181       0x00, 0x02,  // Length of remainder of packet, in 32-bit words.
182       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
183       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
184 
185       // Receiver reference time report:
186       0b10000000,  // Version=2, Padding=no.
187       207,  // RTCP Packet type byte.
188       0x00, 0x04,  // Length of remainder of packet, in 32-bit words.
189       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
190       0x04,  // Block type = Receiver Reference Time Report
191       0x00,  // Reserved byte.
192       0x00, 0x02,  // Block length = 2.
193       0xe0, 0x73, 0x2e, 0x53,  // NTP Timestamp (late evening on 2019-04-30).
194           0x42, 0x31, 0x20, 0x00,
195   };
196   // clang-format on
197 
198   const auto expected_timestamp =
199       session()->ntp_converter().ToLocalTime(NtpTimestamp{0xe0732e5480000000});
200   EXPECT_CALL(*(client()), OnReceiverReferenceTimeAdvanced(expected_timestamp));
201   EXPECT_CALL(*(client()), OnReceiverIndicatesPictureLoss()).Times(0);
202   EXPECT_TRUE(parser()->Parse(kNotStaleCompoundPacket, FrameId::first()));
203   EXPECT_TRUE(parser()->Parse(kStaleCompoundPacketWithPli, FrameId::first()));
204 }
205 
206 // Tests that unknown RTCP extended reports are ignored, but known ones are
207 // still parsed when sent alongside the unknown ones.
TEST_F(CompoundRtcpParserTest,IgnoresUnknownExtendedReports)208 TEST_F(CompoundRtcpParserTest, IgnoresUnknownExtendedReports) {
209   // clang-format off
210   const uint8_t kPacketWithThreeExtendedReports[] = {
211       0b10000000,  // Version=2, Padding=no.
212       207,  // RTCP Packet type byte.
213       0x00, 0x0c,  // Length of remainder of packet, in 32-bit words.
214       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
215 
216       // Unknown extended report:
217       0x02,  // Block type = unknown (2)
218       0x00,  // Reserved byte.
219       0x00, 0x06,  // Block length = 6 words.
220       0x01, 0x01, 0x01, 0x01,
221       0x02, 0x02, 0x02, 0x02,
222       0x03, 0x03, 0x03, 0x03,
223       0x04, 0x04, 0x04, 0x04,
224       0x05, 0x05, 0x05, 0x05,
225       0x06, 0x06, 0x06, 0x06,
226 
227       // Receiver Reference Time Report:
228       0x04,  // Block type = RRTR
229       0x00,  // Reserved byte.
230       0x00, 0x02,  // Block length = 2 words.
231       0xe0, 0x73, 0x2e, 0x55,  // NTP Timestamp (late evening on 2019-04-30).
232           0x00, 0x00, 0x00, 0x00,
233 
234       // Another unknown extended report:
235       0x00,  // Block type = unknown (0)
236       0x00,  // Reserved byte.
237       0x00, 0x00,  // Block length = 0 words.
238   };
239   // clang-format on
240 
241   const auto expected_timestamp =
242       session()->ntp_converter().ToLocalTime(NtpTimestamp{0xe0732e5500000000});
243   EXPECT_CALL(*(client()), OnReceiverReferenceTimeAdvanced(expected_timestamp));
244   EXPECT_TRUE(
245       parser()->Parse(kPacketWithThreeExtendedReports, FrameId::first()));
246 }
247 
248 // Tests that a simple Cast Feedback packet is parsed, and the checkpoint frame
249 // ID is properly bit-extended, based on the current state of the Sender.
TEST_F(CompoundRtcpParserTest,ParsesSimpleFeedback)250 TEST_F(CompoundRtcpParserTest, ParsesSimpleFeedback) {
251   // clang-format off
252   const uint8_t kFeedbackPacket[] = {
253       0b10000000 | 15,  // Version=2, Padding=no, Subtype=Feedback.
254       206,  // RTCP Packet type byte.
255       0x00, 0x04,  // Length of remainder of packet, in 32-bit words.
256       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
257       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
258       'C', 'A', 'S', 'T',
259       0x0a,  // Checkpoint Frame ID = 10.
260       0x00,  // No NACKs.
261       0x02, 0x26,  // Playout delay = 550 ms.
262   };
263   // clang-format on
264 
265   // First scenario: Valid range of FrameIds is [0,42].
266   const auto kMaxFeedbackFrameId0 = FrameId::first() + 42;
267   const auto expected_frame_id0 = FrameId::first() + 10;
268   const auto expected_playout_delay = milliseconds(550);
269   EXPECT_CALL(*(client()),
270               OnReceiverCheckpoint(expected_frame_id0, expected_playout_delay));
271   EXPECT_TRUE(parser()->Parse(kFeedbackPacket, kMaxFeedbackFrameId0));
272   Mock::VerifyAndClearExpectations(client());
273 
274   // Second scenario: Valid range of FrameIds is [299,554]. Note: 544 == 0x22a.
275   const auto kMaxFeedbackFrameId1 = FrameId::first() + 0x22a;
276   const auto expected_frame_id1 = FrameId::first() + 0x20a;
277   EXPECT_CALL(*(client()),
278               OnReceiverCheckpoint(expected_frame_id1, expected_playout_delay));
279   EXPECT_TRUE(parser()->Parse(kFeedbackPacket, kMaxFeedbackFrameId1));
280   Mock::VerifyAndClearExpectations(client());
281 }
282 
283 // Tests NACK feedback parsing, and that redundant NACKs are de-duped, and that
284 // the results are delivered to the client sorted.
TEST_F(CompoundRtcpParserTest,ParsesFeedbackWithNacks)285 TEST_F(CompoundRtcpParserTest, ParsesFeedbackWithNacks) {
286   // clang-format off
287   const uint8_t kFeedbackPacket[] = {
288       0b10000000 | 15,  // Version=2, Padding=no, Subtype=Feedback.
289       206,  // RTCP Packet type byte.
290       0x00, 0x0b,  // Length of remainder of packet, in 32-bit words.
291       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
292       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
293       'C', 'A', 'S', 'T',
294       0x0a,  // Checkpoint Frame ID = 10.
295       0x07,  // Seven NACKs.
296       0x02, 0x28,  // Playout delay = 552 ms.
297       0x0b, 0x00, 0x03, 0b00000000,  // NACK Packet 3 in Frame 11.
298       0x0b, 0x00, 0x07, 0b10001101,  // NACK Packet 7-8, 10-11, 15 in Frame 11.
299       0x0d, 0xff, 0xff, 0b00000000,  // NACK all packets in Frame 13.
300       0x0b, 0x00, 0x0b, 0b00000000,  // Redundant: NACK packet 11 in Frame 11.
301       0x0c, 0xff, 0xff, 0b00000000,  // NACK all packets in Frame 12.
302       0x0d, 0x00, 0x01, 0b00000000,  // Redundant: NACK packet 1 in Frame 13.
303       0x0e, 0x00, 0x00, 0b01000010,  // NACK packets 0, 2, 7 in Frame 14.
304   };
305   // clang-format on
306 
307   // The de-duped and sorted list of the frame/packet NACKs expected when
308   // parsing kFeedbackPacket:
309   const std::vector<PacketNack> kMissingPackets = {
310       {FrameId::first() + 11, 3},
311       {FrameId::first() + 11, 7},
312       {FrameId::first() + 11, 8},
313       {FrameId::first() + 11, 10},
314       {FrameId::first() + 11, 11},
315       {FrameId::first() + 11, 15},
316       {FrameId::first() + 12, kAllPacketsLost},
317       {FrameId::first() + 13, kAllPacketsLost},
318       {FrameId::first() + 14, 0},
319       {FrameId::first() + 14, 2},
320       {FrameId::first() + 14, 7},
321   };
322 
323   const auto kMaxFeedbackFrameId = FrameId::first() + 42;
324   const auto expected_frame_id = FrameId::first() + 10;
325   const auto expected_playout_delay = milliseconds(552);
326   EXPECT_CALL(*(client()),
327               OnReceiverCheckpoint(expected_frame_id, expected_playout_delay));
328   EXPECT_CALL(*(client()), OnReceiverIsMissingPackets(kMissingPackets));
329   EXPECT_TRUE(parser()->Parse(kFeedbackPacket, kMaxFeedbackFrameId));
330 }
331 
332 // Tests the CST2 "later frame ACK" parsing: Both the common "2 bytes of bit
333 // vector" case, and a "multiple words of bit vector" case.
TEST_F(CompoundRtcpParserTest,ParsesFeedbackWithAcks)334 TEST_F(CompoundRtcpParserTest, ParsesFeedbackWithAcks) {
335   // clang-format off
336   const uint8_t kSmallerFeedbackPacket[] = {
337       0b10000000 | 15,  // Version=2, Padding=no, Subtype=Feedback.
338       206,  // RTCP Packet type byte.
339       0x00, 0x07,  // Length of remainder of packet, in 32-bit words.
340       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
341       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
342       'C', 'A', 'S', 'T',
343       0x0a,  // Checkpoint Frame ID = 10.
344       0x01,  // One NACK.
345       0x01, 0x26,  // Playout delay = 294 ms.
346       0x0b, 0x00, 0x03, 0b00000000,  // NACK Packet 3 in Frame 11.
347       'C', 'S', 'T', '2',
348       0x99,  // Feedback counter.
349       0x02,  // 2 bytes of ACK bit vector.
350       0b00000010, 0b00000000,  // ACK only frame 13.
351   };
352 
353   const uint8_t kLargerFeedbackPacket[] = {
354       0b10000000 | 15,  // Version=2, Padding=no, Subtype=Feedback.
355       206,  // RTCP Packet type byte.
356       0x00, 0x08,  // Length of remainder of packet, in 32-bit words.
357       0x00, 0x00, 0x00, 0x02,  // Receiver SSRC.
358       0x00, 0x00, 0x00, 0x01,  // Sender SSRC.
359       'C', 'A', 'S', 'T',
360       0x0a,  // Checkpoint Frame ID = 10.
361       0x00,  // Zero NACKs.
362       0x01, 0x26,  // Playout delay = 294 ms.
363       'C', 'S', 'T', '2',
364       0x99,  // Feedback counter.
365       0x0a,  // 10 bytes of ACK bit vector.
366       0b11111111, 0b11111111,  // ACK frames 12-27.
367       0b00000000, 0b00000001, 0b00000000, 0b00000000,  // ACK frame 36.
368       0b00000000, 0b00000000, 0b00000000, 0b10000000,  // ACK frame 91.
369   };
370   // clang-format on
371 
372   // From the smaller packet: The single frame ACK and single packet NACK.
373   const std::vector<FrameId> kFrame13Only = {FrameId::first() + 13};
374   const std::vector<PacketNack> kFrame11Packet3Only = {
375       {FrameId::first() + 11, 3}};
376 
377   // From the larger packet: Many frame ACKs.
378   const std::vector<FrameId> kManyFrames = {
379       FrameId::first() + 12, FrameId::first() + 13, FrameId::first() + 14,
380       FrameId::first() + 15, FrameId::first() + 16, FrameId::first() + 17,
381       FrameId::first() + 18, FrameId::first() + 19, FrameId::first() + 20,
382       FrameId::first() + 21, FrameId::first() + 22, FrameId::first() + 23,
383       FrameId::first() + 24, FrameId::first() + 25, FrameId::first() + 26,
384       FrameId::first() + 27, FrameId::first() + 36, FrameId::first() + 91,
385   };
386 
387   // Test the smaller packet.
388   const auto kMaxFeedbackFrameId = FrameId::first() + 100;
389   const auto expected_frame_id = FrameId::first() + 10;
390   const auto expected_playout_delay = milliseconds(294);
391   EXPECT_CALL(*(client()),
392               OnReceiverCheckpoint(expected_frame_id, expected_playout_delay));
393   EXPECT_CALL(*(client()), OnReceiverHasFrames(kFrame13Only));
394   EXPECT_CALL(*(client()), OnReceiverIsMissingPackets(kFrame11Packet3Only));
395   EXPECT_TRUE(parser()->Parse(kSmallerFeedbackPacket, kMaxFeedbackFrameId));
396   Mock::VerifyAndClearExpectations(client());
397 
398   // Test the larger ACK packet.
399   EXPECT_CALL(*(client()),
400               OnReceiverCheckpoint(expected_frame_id, expected_playout_delay));
401   EXPECT_CALL(*(client()), OnReceiverHasFrames(kManyFrames));
402   EXPECT_TRUE(parser()->Parse(kLargerFeedbackPacket, kMaxFeedbackFrameId));
403   Mock::VerifyAndClearExpectations(client());
404 }
405 
406 }  // namespace
407 }  // namespace cast
408 }  // namespace openscreen
409