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