• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cmath>
6 
7 #include "absl/types/span.h"
8 #include "cast/streaming/sender_report_builder.h"
9 #include "cast/streaming/sender_report_parser.h"
10 #include "gtest/gtest.h"
11 
12 namespace openscreen {
13 namespace cast {
14 namespace {
15 
16 using openscreen::operator<<;
17 
18 constexpr Ssrc kSenderSsrc{1};
19 constexpr Ssrc kReceiverSsrc{2};
20 
21 class SenderReportTest : public testing::Test {
22  public:
builder()23   SenderReportBuilder* builder() { return &builder_; }
parser()24   SenderReportParser* parser() { return &parser_; }
ntp_converter() const25   const NtpTimeConverter& ntp_converter() const {
26     return session_.ntp_converter();
27   }
28 
29  private:
30   RtcpSession session_{kSenderSsrc, kReceiverSsrc, Clock::now()};
31   SenderReportBuilder builder_{&session_};
32   SenderReportParser parser_{&session_};
33 };
34 
35 // Tests that the compound RTCP packets containing a Sender Report alongside
36 // zero or more other messages can be parsed successfully.
TEST_F(SenderReportTest,Parsing)37 TEST_F(SenderReportTest, Parsing) {
38   // clang-format off
39   const uint8_t kSenderReportPacket[] = {
40     0b10000001,  // Version=2, Padding=no, ItemCount=1 byte.
41     200,  // RTCP Packet type byte.
42     0x00, 0x0c,  // Length of remainder of packet, in 32-bit words.
43     0x00, 0x00, 0x00, 0x01,  // SSRC of sender.
44     0xe0, 0x73, 0x2e, 0x54,  // NTP Timestamp (late evening on 2019-04-30).
45         0x80, 0x00, 0x00, 0x00,
46     0x00, 0x14, 0x99, 0x70,  // RTP Timestamp (15 seconds, 90kHz timebase).
47     0x00, 0x00, 0x01, 0xff,  // Sender's Packet Count.
48     0x00, 0x07, 0x11, 0x0d,  // Sender's Octet Count.
49     0x00, 0x00, 0x00, 0x02,  // SSRC of receiver (to whom this report is for).
50     0x00,  // Fraction lost.
51     0x00, 0x00, 0x02,  // Cumulative Number of Packets Lost.
52     0x00, 0x00, 0x38, 0x40,  // Highest Sequence Number Received.
53     0x00, 0x00, 0x03, 0x84,  // Interarrival Jitter.
54     0xaf, 0xd3, 0xff, 0x00,  // Sender Report ID.
55     0x00, 0x00, 0x83, 0xfa,  // Delay since last Sender Report.
56   };
57 
58   constexpr NtpTimestamp kNtpTimestampInSenderReport{0xe0732e5480000000};
59 
60   const uint8_t kOtherPacket[] = {
61     0b10000000,  // Version=2, Padding=no, ItemCount=0 byte.
62     204,  // RTCP Packet type byte.
63     0x00, 0x01,  // Length of remainder of packet, in 32-bit words.
64     0x00, 0x00, 0x00, 0x02,  // SSRC of receiver.
65   };
66   // clang-format on
67 
68   // A RTCP packet only containing non-sender-reports will not provide a Sender
69   // Report result.
70   EXPECT_FALSE(parser()->Parse(kOtherPacket));
71 
72   // A compound RTCP packet containing a Sender Report alongside other things
73   // should be detected as "well-formed" by the parser and it should also
74   // provide a Sender Report result. Also, it shouldn't matter what the ordering
75   // is.
76   const absl::Span<const uint8_t> kCompoundCombinations[2][2] = {
77       {kSenderReportPacket, kOtherPacket},
78       {kOtherPacket, kSenderReportPacket},
79   };
80   for (const auto& combo : kCompoundCombinations) {
81     uint8_t compound_packet[sizeof(kSenderReportPacket) + sizeof(kOtherPacket)];
82     memcpy(compound_packet, combo[0].data(), combo[0].size());
83     memcpy(compound_packet + combo[0].size(), combo[1].data(), combo[1].size());
84 
85     const auto parsed = parser()->Parse(compound_packet);
86     ASSERT_TRUE(parsed.has_value());
87     EXPECT_EQ(ToStatusReportId(kNtpTimestampInSenderReport), parsed->report_id);
88     EXPECT_EQ(ntp_converter().ToLocalTime(kNtpTimestampInSenderReport),
89               parsed->reference_time);
90     EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(1350000),
91               parsed->rtp_timestamp);
92     EXPECT_EQ(uint32_t{0x1ff}, parsed->send_packet_count);
93     EXPECT_EQ(uint32_t{0x7110d}, parsed->send_octet_count);
94     ASSERT_TRUE(parsed->report_block.has_value());
95     EXPECT_EQ(kReceiverSsrc, parsed->report_block->ssrc);
96     // Note: RtcpReportBlock parsing is unit-tested elsewhere.
97   }
98 }
99 
100 // Tests that the SenderReportParser will not try to parse an empty packet.
TEST_F(SenderReportTest,WillNotParseEmptyPacket)101 TEST_F(SenderReportTest, WillNotParseEmptyPacket) {
102   const uint8_t kEmptyPacket[] = {};
103   EXPECT_FALSE(parser()->Parse(absl::Span<const uint8_t>(kEmptyPacket, 0)));
104 }
105 
106 // Tests that the SenderReportParser will not parse anything from garbage data.
TEST_F(SenderReportTest,WillNotParseGarbage)107 TEST_F(SenderReportTest, WillNotParseGarbage) {
108   // clang-format off
109   const uint8_t kGarbage[] = {
110     0x4f, 0x27, 0xeb, 0x22, 0x27, 0xeb, 0x22, 0x4f,
111     0xeb, 0x22, 0x4f, 0x27, 0x22, 0x4f, 0x27, 0xeb,
112   };
113   // clang-format on
114   EXPECT_FALSE(parser()->Parse(kGarbage));
115 }
116 
117 // Assuming that SenderReportTest.Parsing has been proven the implementation,
118 // this test checks that the builder produces RTCP packets that can be parsed.
TEST_F(SenderReportTest,BuildPackets)119 TEST_F(SenderReportTest, BuildPackets) {
120   for (int i = 0; i <= 1; ++i) {
121     const bool with_report_block = (i == 1);
122 
123     RtcpSenderReport original;
124     original.reference_time = Clock::now();
125     original.rtp_timestamp = RtpTimeTicks() + RtpTimeDelta::FromTicks(5);
126     original.send_packet_count = 55;
127     original.send_octet_count = 20044;
128     if (with_report_block) {
129       RtcpReportBlock& report_block = original.report_block.emplace();
130       report_block.ssrc = kReceiverSsrc;
131     }
132 
133     uint8_t buffer[kRtcpCommonHeaderSize + kRtcpSenderReportSize +
134                    kRtcpReportBlockSize];
135     memset(buffer, 0, sizeof(buffer));
136     const auto result = builder()->BuildPacket(original, buffer);
137     ASSERT_TRUE(result.first.data());
138     const int expected_packet_size =
139         sizeof(buffer) - (with_report_block ? 0 : kRtcpReportBlockSize);
140     EXPECT_EQ(expected_packet_size, static_cast<int>(result.first.size()));
141     const StatusReportId expected_status_report_id = ToStatusReportId(
142         ntp_converter().ToNtpTimestamp(original.reference_time));
143     EXPECT_EQ(expected_status_report_id, result.second);
144 
145     const auto parsed = parser()->Parse(result.first);
146     ASSERT_TRUE(parsed.has_value());
147     EXPECT_EQ(expected_status_report_id, parsed->report_id);
148     // Note: The reference time can be off by one platform clock tick due to
149     // a lossy conversion when going to and from the wire-format NtpTimestamps.
150     // See the unit tests in ntp_time_unittest.cc for further discussion.
151     EXPECT_LE(
152         std::abs((original.reference_time - parsed->reference_time).count()),
153         1);
154     EXPECT_EQ(original.rtp_timestamp, parsed->rtp_timestamp);
155     EXPECT_EQ(original.send_packet_count, parsed->send_packet_count);
156     EXPECT_EQ(original.send_octet_count, parsed->send_octet_count);
157     if (with_report_block) {
158       ASSERT_TRUE(parsed->report_block.has_value());
159       EXPECT_EQ(original.report_block->ssrc, parsed->report_block->ssrc);
160       // Note: RtcpReportBlock serialization/parsing is unit-tested elsewhere.
161     }
162   }
163 }
164 
TEST_F(SenderReportTest,ComputesTimePointsFromReportIds)165 TEST_F(SenderReportTest, ComputesTimePointsFromReportIds) {
166   // Note: The time_points can be off by up to 16 µs because of the loss of
167   // precision caused by truncating the NtpTimestamps into StatusReportIds.
168   constexpr std::chrono::microseconds kEpsilon{16};
169 
170   // Test a sampling of time points over the last 65536 seconds to confirm the
171   // rollover correction logic is working.
172   Clock::time_point on_or_before = Clock::now() + std::chrono::seconds(65536);
173   constexpr int kNumIterations = 16;
174   constexpr int kSecondsPerStep = 4096;
175   for (int i = 0; i < kNumIterations; ++i) {
176     const Clock::time_point expected_time =
177         on_or_before - std::chrono::seconds(i * kSecondsPerStep);
178     const auto report_id =
179         ToStatusReportId(ntp_converter().ToNtpTimestamp(expected_time));
180     const Clock::time_point report_time =
181         builder()->GetRecentReportTime(report_id, on_or_before);
182     EXPECT_GE(on_or_before, report_time);
183     const auto absolute_difference = (expected_time < report_time)
184                                          ? (report_time - expected_time)
185                                          : (expected_time - report_time);
186     EXPECT_LE(absolute_difference, kEpsilon)
187         << expected_time << " vs " << report_time;
188   }
189 }
190 
191 }  // namespace
192 }  // namespace cast
193 }  // namespace openscreen
194