xref: /aosp_15_r20/external/openscreen/cast/streaming/rtcp_common_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/rtcp_common.h"
6 
7 #include <chrono>
8 #include <limits>
9 
10 #include "absl/types/span.h"
11 #include "gtest/gtest.h"
12 #include "platform/api/time.h"
13 #include "util/chrono_helpers.h"
14 
15 namespace openscreen {
16 namespace cast {
17 namespace {
18 
19 template <typename T>
SerializeAndExpectPointerAdvanced(const T & source,int num_bytes,uint8_t * buffer)20 void SerializeAndExpectPointerAdvanced(const T& source,
21                                        int num_bytes,
22                                        uint8_t* buffer) {
23   absl::Span<uint8_t> buffer_span(buffer, num_bytes);
24   source.AppendFields(&buffer_span);
25   EXPECT_EQ(buffer + num_bytes, buffer_span.data());
26 }
27 
28 // Tests that the RTCP Common Header for a packet type that includes an Item
29 // Count is successfully serialized and re-parsed.
TEST(RtcpCommonTest,SerializesAndParsesHeaderForSenderReports)30 TEST(RtcpCommonTest, SerializesAndParsesHeaderForSenderReports) {
31   RtcpCommonHeader original;
32   original.packet_type = RtcpPacketType::kSenderReport;
33   original.with.report_count = 31;
34   original.payload_size = 16;
35 
36   uint8_t buffer[kRtcpCommonHeaderSize];
37   SerializeAndExpectPointerAdvanced(original, kRtcpCommonHeaderSize, buffer);
38 
39   const auto parsed = RtcpCommonHeader::Parse(buffer);
40   ASSERT_TRUE(parsed.has_value());
41   EXPECT_EQ(original.packet_type, parsed->packet_type);
42   EXPECT_EQ(original.with.report_count, parsed->with.report_count);
43   EXPECT_EQ(original.payload_size, parsed->payload_size);
44 }
45 
46 // Tests that the RTCP Common Header for a packet type that includes a RTCP
47 // Subtype is successfully serialized and re-parsed.
TEST(RtcpCommonTest,SerializesAndParsesHeaderForCastFeedback)48 TEST(RtcpCommonTest, SerializesAndParsesHeaderForCastFeedback) {
49   RtcpCommonHeader original;
50   original.packet_type = RtcpPacketType::kPayloadSpecific;
51   original.with.subtype = RtcpSubtype::kFeedback;
52   original.payload_size = 99 * sizeof(uint32_t);
53 
54   uint8_t buffer[kRtcpCommonHeaderSize];
55   SerializeAndExpectPointerAdvanced(original, kRtcpCommonHeaderSize, buffer);
56 
57   const auto parsed = RtcpCommonHeader::Parse(buffer);
58   ASSERT_TRUE(parsed.has_value());
59   EXPECT_EQ(original.packet_type, parsed->packet_type);
60   EXPECT_EQ(original.with.subtype, parsed->with.subtype);
61   EXPECT_EQ(original.payload_size, parsed->payload_size);
62 }
63 
64 // Tests that a RTCP Common Header will not be parsed from an empty buffer.
TEST(RtcpCommonTest,WillNotParseHeaderFromEmptyBuffer)65 TEST(RtcpCommonTest, WillNotParseHeaderFromEmptyBuffer) {
66   const uint8_t kEmptyPacket[] = {};
67   EXPECT_FALSE(
68       RtcpCommonHeader::Parse(absl::Span<const uint8_t>(kEmptyPacket, 0))
69           .has_value());
70 }
71 
72 // Tests that a RTCP Common Header will not be parsed from a buffer containing
73 // garbage data.
TEST(RtcpCommonTest,WillNotParseHeaderFromGarbage)74 TEST(RtcpCommonTest, WillNotParseHeaderFromGarbage) {
75   // clang-format off
76   const uint8_t kGarbage[] = {
77     0x4f, 0x27, 0xeb, 0x22, 0x27, 0xeb, 0x22, 0x4f,
78     0xeb, 0x22, 0x4f, 0x27, 0x22, 0x4f, 0x27, 0xeb,
79   };
80   // clang-format on
81   EXPECT_FALSE(RtcpCommonHeader::Parse(kGarbage).has_value());
82 }
83 
84 // Tests whether RTCP Common Header validation logic is correct.
TEST(RtcpCommonTest,WillNotParseHeaderWithInvalidData)85 TEST(RtcpCommonTest, WillNotParseHeaderWithInvalidData) {
86   // clang-format off
87   const uint8_t kCastFeedbackPacket[] = {
88     0b10000001,  // Version=2, Padding=no, ItemCount=1 byte.
89     206,  // RTCP Packet type byte.
90     0x00, 0x04,  // Length of remainder of packet, in 32-bit words.
91     9, 8, 7, 6,  // SSRC of receiver.
92     1, 2, 3, 4,  // SSRC of sender.
93     'C', 'A', 'S', 'T',
94     0x0a,  // Checkpoint Frame ID (lower 8 bits).
95     0x00,  // Number of "Loss Fields"
96     0x00, 0x28,  // Current Playout Delay in milliseconds.
97   };
98   // clang-format on
99 
100   // Start with a valid packet, and expect the parse to succeed.
101   uint8_t buffer[sizeof(kCastFeedbackPacket)];
102   memcpy(buffer, kCastFeedbackPacket, sizeof(buffer));
103   EXPECT_TRUE(RtcpCommonHeader::Parse(buffer).has_value());
104 
105   // Wrong version in first byte: Expect parse failure.
106   buffer[0] = 0b01000001;
107   EXPECT_FALSE(RtcpCommonHeader::Parse(buffer).has_value());
108   buffer[0] = kCastFeedbackPacket[0];
109 
110   // Wrong packet type (not in RTCP range): Expect parse failure.
111   buffer[1] = 42;
112   EXPECT_FALSE(RtcpCommonHeader::Parse(buffer).has_value());
113   buffer[1] = kCastFeedbackPacket[1];
114 }
115 
116 // Test that the Report Block optionally included in Sender Reports or Receiver
117 // Reports can be serialized and re-parsed correctly.
TEST(RtcpCommonTest,SerializesAndParsesRtcpReportBlocks)118 TEST(RtcpCommonTest, SerializesAndParsesRtcpReportBlocks) {
119   constexpr Ssrc kSsrc{0x04050607};
120 
121   RtcpReportBlock original;
122   original.ssrc = kSsrc;
123   original.packet_fraction_lost_numerator = 0x67;
124   original.cumulative_packets_lost = 74536;
125   original.extended_high_sequence_number = 0x0201fedc;
126   original.jitter = RtpTimeDelta::FromTicks(123);
127   original.last_status_report_id = 0x0908;
128   original.delay_since_last_report = RtcpReportBlock::Delay(99999);
129 
130   uint8_t buffer[kRtcpReportBlockSize];
131   SerializeAndExpectPointerAdvanced(original, kRtcpReportBlockSize, buffer);
132 
133   // If the number of report blocks is zero, or some other SSRC is specified,
134   // ParseOne() should not return a result.
135   EXPECT_FALSE(RtcpReportBlock::ParseOne(buffer, 0, 0).has_value());
136   EXPECT_FALSE(RtcpReportBlock::ParseOne(buffer, 0, kSsrc).has_value());
137   EXPECT_FALSE(RtcpReportBlock::ParseOne(buffer, 1, 0).has_value());
138 
139   // Expect that the report block is parsed correctly.
140   const auto parsed = RtcpReportBlock::ParseOne(buffer, 1, kSsrc);
141   ASSERT_TRUE(parsed.has_value());
142   EXPECT_EQ(original.ssrc, parsed->ssrc);
143   EXPECT_EQ(original.packet_fraction_lost_numerator,
144             parsed->packet_fraction_lost_numerator);
145   EXPECT_EQ(original.cumulative_packets_lost, parsed->cumulative_packets_lost);
146   EXPECT_EQ(original.extended_high_sequence_number,
147             parsed->extended_high_sequence_number);
148   EXPECT_EQ(original.jitter, parsed->jitter);
149   EXPECT_EQ(original.last_status_report_id, parsed->last_status_report_id);
150   EXPECT_EQ(original.delay_since_last_report, parsed->delay_since_last_report);
151 }
152 
153 // Tests that the Report Block parser can, among multiple Report Blocks, find
154 // the one with a matching recipient SSRC.
TEST(RtcpCommonTest,ParsesOneReportBlockFromMultipleBlocks)155 TEST(RtcpCommonTest, ParsesOneReportBlockFromMultipleBlocks) {
156   constexpr Ssrc kSsrc{0x04050607};
157   constexpr int kNumBlocks = 5;
158 
159   RtcpReportBlock expected;
160   expected.ssrc = kSsrc;
161   expected.packet_fraction_lost_numerator = 0x67;
162   expected.cumulative_packets_lost = 74536;
163   expected.extended_high_sequence_number = 0x0201fedc;
164   expected.jitter = RtpTimeDelta::FromTicks(123);
165   expected.last_status_report_id = 0x0908;
166   expected.delay_since_last_report = RtcpReportBlock::Delay(99999);
167 
168   // Generate multiple report blocks with different recipient SSRCs.
169   uint8_t buffer[kRtcpReportBlockSize * kNumBlocks];
170   absl::Span<uint8_t> buffer_span(buffer, kRtcpReportBlockSize * kNumBlocks);
171   for (int i = 0; i < kNumBlocks; ++i) {
172     RtcpReportBlock another;
173     another.ssrc = expected.ssrc + i - 2;
174     another.packet_fraction_lost_numerator =
175         expected.packet_fraction_lost_numerator + i - 2;
176     another.cumulative_packets_lost = expected.cumulative_packets_lost + i - 2;
177     another.extended_high_sequence_number =
178         expected.extended_high_sequence_number + i - 2;
179     another.jitter = expected.jitter + RtpTimeDelta::FromTicks(i - 2);
180     another.last_status_report_id = expected.last_status_report_id + i - 2;
181     another.delay_since_last_report =
182         expected.delay_since_last_report + RtcpReportBlock::Delay(i - 2);
183 
184     another.AppendFields(&buffer_span);
185   }
186 
187   // Expect that the desired report block is found and parsed correctly.
188   const auto parsed = RtcpReportBlock::ParseOne(buffer, kNumBlocks, kSsrc);
189   ASSERT_TRUE(parsed.has_value());
190   EXPECT_EQ(expected.ssrc, parsed->ssrc);
191   EXPECT_EQ(expected.packet_fraction_lost_numerator,
192             parsed->packet_fraction_lost_numerator);
193   EXPECT_EQ(expected.cumulative_packets_lost, parsed->cumulative_packets_lost);
194   EXPECT_EQ(expected.extended_high_sequence_number,
195             parsed->extended_high_sequence_number);
196   EXPECT_EQ(expected.jitter, parsed->jitter);
197   EXPECT_EQ(expected.last_status_report_id, parsed->last_status_report_id);
198   EXPECT_EQ(expected.delay_since_last_report, parsed->delay_since_last_report);
199 }
200 
201 // Tests the helper for computing the packet fraction loss numerator, a value
202 // that should always be between 0 and 255, in terms of absolute packet counts.
TEST(RtcpCommonTest,ComputesPacketLossFractionForReportBlocks)203 TEST(RtcpCommonTest, ComputesPacketLossFractionForReportBlocks) {
204   const auto ComputeFractionLost = [](int64_t num_apparently_sent,
205                                       int64_t num_received) {
206     RtcpReportBlock report;
207     report.SetPacketFractionLostNumerator(num_apparently_sent, num_received);
208     return report.packet_fraction_lost_numerator;
209   };
210 
211   // If no non-duplicate packets were sent to the Receiver, the packet loss
212   // fraction should be zero.
213   EXPECT_EQ(0, ComputeFractionLost(0, 0));
214   EXPECT_EQ(0, ComputeFractionLost(0, 1));
215   EXPECT_EQ(0, ComputeFractionLost(0, 999));
216 
217   // If the same number or more packets were received than those apparently
218   // sent, the packet loss fraction should be zero.
219   EXPECT_EQ(0, ComputeFractionLost(1, 1));
220   EXPECT_EQ(0, ComputeFractionLost(1, 2));
221   EXPECT_EQ(0, ComputeFractionLost(1, 4));
222   EXPECT_EQ(0, ComputeFractionLost(4, 5));
223   EXPECT_EQ(0, ComputeFractionLost(42, 42));
224   EXPECT_EQ(0, ComputeFractionLost(60, 999));
225 
226   // Test various partial loss scenarios.
227   EXPECT_EQ(85, ComputeFractionLost(3, 2));
228   EXPECT_EQ(128, ComputeFractionLost(10, 5));
229   EXPECT_EQ(174, ComputeFractionLost(22, 7));
230 
231   // Test various total-loss/near-total-loss scenarios.
232   EXPECT_EQ(255, ComputeFractionLost(17, 0));
233   EXPECT_EQ(255, ComputeFractionLost(100, 0));
234   EXPECT_EQ(255, ComputeFractionLost(9876, 1));
235 }
236 
237 // Tests the helper for computing the cumulative packet loss total, a value that
238 // should always be between 0 and 2^24 - 1, in terms of absolute packet counts.
TEST(RtcpCommonTest,ComputesCumulativePacketLossForReportBlocks)239 TEST(RtcpCommonTest, ComputesCumulativePacketLossForReportBlocks) {
240   const auto ComputeLoss = [](int64_t num_apparently_sent,
241                               int64_t num_received) {
242     RtcpReportBlock report;
243     report.SetCumulativePacketsLost(num_apparently_sent, num_received);
244     return report.cumulative_packets_lost;
245   };
246 
247   // Test various no-loss scenarios (including duplicate packets).
248   EXPECT_EQ(0, ComputeLoss(0, 0));
249   EXPECT_EQ(0, ComputeLoss(0, 1));
250   EXPECT_EQ(0, ComputeLoss(3, 3));
251   EXPECT_EQ(0, ComputeLoss(56, 56));
252   EXPECT_EQ(0, ComputeLoss(std::numeric_limits<int64_t>::max() - 12,
253                            std::numeric_limits<int64_t>::max()));
254   EXPECT_EQ(0, ComputeLoss(std::numeric_limits<int64_t>::max(),
255                            std::numeric_limits<int64_t>::max()));
256 
257   // Test various partial loss scenarios.
258   EXPECT_EQ(1, ComputeLoss(2, 1));
259   EXPECT_EQ(2, ComputeLoss(42, 40));
260   EXPECT_EQ(1025, ComputeLoss(999999, 999999 - 1025));
261   EXPECT_EQ(1, ComputeLoss(std::numeric_limits<int64_t>::max(),
262                            std::numeric_limits<int64_t>::max() - 1));
263 
264   // Test that a huge cumulative loss saturates to the maximum valid value for
265   // the field.
266   EXPECT_EQ((1 << 24) - 1, ComputeLoss(999999999, 1));
267 }
268 
269 // Tests the helper that converts Clock::durations to the report blocks timebase
270 // (1/65536 sconds), and also that it saturates to to the valid range of values
271 // (0 to 2^32 - 1 ticks).
TEST(RtcpCommonTest,ComputesDelayForReportBlocks)272 TEST(RtcpCommonTest, ComputesDelayForReportBlocks) {
273   RtcpReportBlock report;
274   using Delay = RtcpReportBlock::Delay;
275 
276   const auto ComputeDelay = [](Clock::duration delay_in_wrong_timebase) {
277     RtcpReportBlock report;
278     report.SetDelaySinceLastReport(delay_in_wrong_timebase);
279     return report.delay_since_last_report;
280   };
281 
282   // A duration less than or equal to zero should clamp to zero.
283   EXPECT_EQ(Delay::zero(), ComputeDelay(Clock::duration::min()));
284   EXPECT_EQ(Delay::zero(), ComputeDelay(milliseconds{-1234}));
285   EXPECT_EQ(Delay::zero(), ComputeDelay(Clock::duration::zero()));
286 
287   // Test conversion of various durations that should not clamp.
288   EXPECT_EQ(Delay(32768 /* 1/2 second worth of ticks */),
289             ComputeDelay(milliseconds(500)));
290   EXPECT_EQ(Delay(65536 /* 1 second worth of ticks */),
291             ComputeDelay(seconds(1)));
292   EXPECT_EQ(Delay(655360 /* 10 seconds worth of ticks */),
293             ComputeDelay(seconds(10)));
294   EXPECT_EQ(Delay(4294967294), ComputeDelay(microseconds(65535999983)));
295   EXPECT_EQ(Delay(4294967294), ComputeDelay(microseconds(65535999984)));
296 
297   // A too-large duration should clamp to the maximum-possible Delay value.
298   EXPECT_EQ(Delay(4294967295), ComputeDelay(microseconds(65535999985)));
299   EXPECT_EQ(Delay(4294967295), ComputeDelay(microseconds(65535999986)));
300   EXPECT_EQ(Delay(4294967295), ComputeDelay(microseconds(999999000000)));
301   EXPECT_EQ(Delay(4294967295), ComputeDelay(Clock::duration::max()));
302 }
303 
304 }  // namespace
305 }  // namespace cast
306 }  // namespace openscreen
307