1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_packetizer.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <chrono>
8*3f982cf4SFabien Sanglard #include <memory>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "absl/types/optional.h"
11*3f982cf4SFabien Sanglard #include "cast/streaming/frame_crypto.h"
12*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_defines.h"
13*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_packet_parser.h"
14*3f982cf4SFabien Sanglard #include "cast/streaming/ssrc.h"
15*3f982cf4SFabien Sanglard #include "gtest/gtest.h"
16*3f982cf4SFabien Sanglard #include "util/chrono_helpers.h"
17*3f982cf4SFabien Sanglard #include "util/crypto/random_bytes.h"
18*3f982cf4SFabien Sanglard
19*3f982cf4SFabien Sanglard namespace openscreen {
20*3f982cf4SFabien Sanglard namespace cast {
21*3f982cf4SFabien Sanglard namespace {
22*3f982cf4SFabien Sanglard
23*3f982cf4SFabien Sanglard constexpr RtpPayloadType kPayloadType = RtpPayloadType::kAudioOpus;
24*3f982cf4SFabien Sanglard
25*3f982cf4SFabien Sanglard // Returns true if |needle| is fully within |haystack|.
IsSubspan(absl::Span<const uint8_t> needle,absl::Span<const uint8_t> haystack)26*3f982cf4SFabien Sanglard bool IsSubspan(absl::Span<const uint8_t> needle,
27*3f982cf4SFabien Sanglard absl::Span<const uint8_t> haystack) {
28*3f982cf4SFabien Sanglard return (needle.data() >= haystack.data()) &&
29*3f982cf4SFabien Sanglard ((needle.data() + needle.size()) <=
30*3f982cf4SFabien Sanglard (haystack.data() + haystack.size()));
31*3f982cf4SFabien Sanglard }
32*3f982cf4SFabien Sanglard
33*3f982cf4SFabien Sanglard class RtpPacketizerTest : public testing::Test {
34*3f982cf4SFabien Sanglard public:
35*3f982cf4SFabien Sanglard RtpPacketizerTest() = default;
36*3f982cf4SFabien Sanglard ~RtpPacketizerTest() = default;
37*3f982cf4SFabien Sanglard
packetizer()38*3f982cf4SFabien Sanglard RtpPacketizer* packetizer() { return &packetizer_; }
39*3f982cf4SFabien Sanglard
CreateFrame(FrameId frame_id,bool is_key_frame,milliseconds new_playout_delay,int payload_size) const40*3f982cf4SFabien Sanglard EncryptedFrame CreateFrame(FrameId frame_id,
41*3f982cf4SFabien Sanglard bool is_key_frame,
42*3f982cf4SFabien Sanglard milliseconds new_playout_delay,
43*3f982cf4SFabien Sanglard int payload_size) const {
44*3f982cf4SFabien Sanglard EncodedFrame frame;
45*3f982cf4SFabien Sanglard frame.dependency = is_key_frame ? EncodedFrame::KEY_FRAME
46*3f982cf4SFabien Sanglard : EncodedFrame::DEPENDS_ON_ANOTHER;
47*3f982cf4SFabien Sanglard frame.frame_id = frame_id;
48*3f982cf4SFabien Sanglard frame.referenced_frame_id = is_key_frame ? frame_id : (frame_id - 1);
49*3f982cf4SFabien Sanglard frame.rtp_timestamp = RtpTimeTicks() + RtpTimeDelta::FromTicks(987);
50*3f982cf4SFabien Sanglard frame.reference_time = Clock::now();
51*3f982cf4SFabien Sanglard frame.new_playout_delay = new_playout_delay;
52*3f982cf4SFabien Sanglard
53*3f982cf4SFabien Sanglard std::unique_ptr<uint8_t[]> buffer(new uint8_t[payload_size]);
54*3f982cf4SFabien Sanglard for (int i = 0; i < payload_size; ++i) {
55*3f982cf4SFabien Sanglard buffer[i] = static_cast<uint8_t>(i);
56*3f982cf4SFabien Sanglard }
57*3f982cf4SFabien Sanglard frame.data = absl::Span<uint8_t>(buffer.get(), payload_size);
58*3f982cf4SFabien Sanglard
59*3f982cf4SFabien Sanglard return crypto_.Encrypt(frame);
60*3f982cf4SFabien Sanglard }
61*3f982cf4SFabien Sanglard
62*3f982cf4SFabien Sanglard // Generates one of the frame's packets, then parses it and checks for the
63*3f982cf4SFabien Sanglard // expected values. Thus, this test assumes PacketParser is already working
64*3f982cf4SFabien Sanglard // (i.e., all RtpPacketParser unit tests are passing).
TestGeneratePacket(const EncryptedFrame & frame,FramePacketId packet_id)65*3f982cf4SFabien Sanglard void TestGeneratePacket(const EncryptedFrame& frame,
66*3f982cf4SFabien Sanglard FramePacketId packet_id) {
67*3f982cf4SFabien Sanglard SCOPED_TRACE(testing::Message() << "packet_id=" << packet_id);
68*3f982cf4SFabien Sanglard
69*3f982cf4SFabien Sanglard const int frame_payload_size = frame.data.size();
70*3f982cf4SFabien Sanglard constexpr int kExpectedRtpHeaderSize = 23;
71*3f982cf4SFabien Sanglard const int packet_payload_size =
72*3f982cf4SFabien Sanglard kMaxRtpPacketSizeForIpv4UdpOnEthernet - kExpectedRtpHeaderSize;
73*3f982cf4SFabien Sanglard const int final_packet_payload_size =
74*3f982cf4SFabien Sanglard frame_payload_size % packet_payload_size;
75*3f982cf4SFabien Sanglard const int num_packets = 1 + frame_payload_size / packet_payload_size;
76*3f982cf4SFabien Sanglard
77*3f982cf4SFabien Sanglard // Generate a RTP packet and parse it.
78*3f982cf4SFabien Sanglard uint8_t scratch[kMaxRtpPacketSizeForIpv4UdpOnEthernet];
79*3f982cf4SFabien Sanglard memset(scratch, 0, sizeof(scratch));
80*3f982cf4SFabien Sanglard const auto packet = packetizer_.GeneratePacket(frame, packet_id, scratch);
81*3f982cf4SFabien Sanglard ASSERT_TRUE(IsSubspan(packet, scratch));
82*3f982cf4SFabien Sanglard
83*3f982cf4SFabien Sanglard const auto result = parser_.Parse(packet);
84*3f982cf4SFabien Sanglard ASSERT_TRUE(result);
85*3f982cf4SFabien Sanglard
86*3f982cf4SFabien Sanglard // Check that RTP header fields match expected values.
87*3f982cf4SFabien Sanglard EXPECT_EQ(kPayloadType, result->payload_type);
88*3f982cf4SFabien Sanglard EXPECT_EQ(frame.rtp_timestamp, result->rtp_timestamp);
89*3f982cf4SFabien Sanglard EXPECT_EQ(frame.dependency == EncodedFrame::KEY_FRAME,
90*3f982cf4SFabien Sanglard result->is_key_frame);
91*3f982cf4SFabien Sanglard EXPECT_EQ(frame.frame_id, result->frame_id);
92*3f982cf4SFabien Sanglard EXPECT_EQ(packet_id, result->packet_id);
93*3f982cf4SFabien Sanglard EXPECT_EQ(static_cast<FramePacketId>(num_packets - 1),
94*3f982cf4SFabien Sanglard result->max_packet_id);
95*3f982cf4SFabien Sanglard EXPECT_EQ(frame.referenced_frame_id, result->referenced_frame_id);
96*3f982cf4SFabien Sanglard
97*3f982cf4SFabien Sanglard // The sequence number field MUST be different for each packet, regardless
98*3f982cf4SFabien Sanglard // of whether the exact same packet is being re-generated.
99*3f982cf4SFabien Sanglard if (last_sequence_number_) {
100*3f982cf4SFabien Sanglard EXPECT_EQ(static_cast<uint16_t>(*last_sequence_number_ + 1),
101*3f982cf4SFabien Sanglard result->sequence_number);
102*3f982cf4SFabien Sanglard }
103*3f982cf4SFabien Sanglard last_sequence_number_ = result->sequence_number;
104*3f982cf4SFabien Sanglard
105*3f982cf4SFabien Sanglard // If there is a playout delay change starting with this |frame|, it must
106*3f982cf4SFabien Sanglard // only be mentioned in the first packet.
107*3f982cf4SFabien Sanglard if (packet_id == FramePacketId{0}) {
108*3f982cf4SFabien Sanglard EXPECT_EQ(frame.new_playout_delay, result->new_playout_delay);
109*3f982cf4SFabien Sanglard } else {
110*3f982cf4SFabien Sanglard EXPECT_EQ(milliseconds(0), result->new_playout_delay);
111*3f982cf4SFabien Sanglard }
112*3f982cf4SFabien Sanglard
113*3f982cf4SFabien Sanglard // Check that the RTP payload is correct for this packet.
114*3f982cf4SFabien Sanglard ASSERT_TRUE(IsSubspan(result->payload, packet));
115*3f982cf4SFabien Sanglard // Last packet is smaller, as its payload is just the remaining bytes.
116*3f982cf4SFabien Sanglard const int expected_payload_size = (int{packet_id} == (num_packets - 1))
117*3f982cf4SFabien Sanglard ? final_packet_payload_size
118*3f982cf4SFabien Sanglard : packet_payload_size;
119*3f982cf4SFabien Sanglard EXPECT_EQ(expected_payload_size, static_cast<int>(result->payload.size()));
120*3f982cf4SFabien Sanglard const absl::Span<const uint8_t> expected_bytes(
121*3f982cf4SFabien Sanglard frame.data.data() + (packet_id * packet_payload_size),
122*3f982cf4SFabien Sanglard expected_payload_size);
123*3f982cf4SFabien Sanglard EXPECT_EQ(expected_bytes, result->payload);
124*3f982cf4SFabien Sanglard }
125*3f982cf4SFabien Sanglard
126*3f982cf4SFabien Sanglard private:
127*3f982cf4SFabien Sanglard // The RtpPacketizer instance under test, plus some surrounding dependencies
128*3f982cf4SFabien Sanglard // to generate its input and examine its output.
129*3f982cf4SFabien Sanglard const Ssrc ssrc_{GenerateSsrc(true)};
130*3f982cf4SFabien Sanglard const FrameCrypto crypto_{GenerateRandomBytes16(), GenerateRandomBytes16()};
131*3f982cf4SFabien Sanglard RtpPacketizer packetizer_{kPayloadType, ssrc_,
132*3f982cf4SFabien Sanglard kMaxRtpPacketSizeForIpv4UdpOnEthernet};
133*3f982cf4SFabien Sanglard RtpPacketParser parser_{ssrc_};
134*3f982cf4SFabien Sanglard
135*3f982cf4SFabien Sanglard // absl::nullopt until the random starting sequence number, from the first
136*3f982cf4SFabien Sanglard // packet generated by TestGeneratePacket(), is known.
137*3f982cf4SFabien Sanglard absl::optional<uint16_t> last_sequence_number_;
138*3f982cf4SFabien Sanglard };
139*3f982cf4SFabien Sanglard
140*3f982cf4SFabien Sanglard // Tests that all packets are generated for one key frame, followed by 9 "delta"
141*3f982cf4SFabien Sanglard // frames. The key frame is larger than the other frames, as is typical in a
142*3f982cf4SFabien Sanglard // real-world usage scenario.
TEST_F(RtpPacketizerTest,GeneratesPacketsForSequenceOfFrames)143*3f982cf4SFabien Sanglard TEST_F(RtpPacketizerTest, GeneratesPacketsForSequenceOfFrames) {
144*3f982cf4SFabien Sanglard for (int i = 0; i < 10; ++i) {
145*3f982cf4SFabien Sanglard const bool is_key_frame = (i == 0);
146*3f982cf4SFabien Sanglard const int frame_payload_size = is_key_frame ? 48269 : 10000;
147*3f982cf4SFabien Sanglard const EncryptedFrame frame =
148*3f982cf4SFabien Sanglard CreateFrame(FrameId::first() + i, is_key_frame, milliseconds(0),
149*3f982cf4SFabien Sanglard frame_payload_size);
150*3f982cf4SFabien Sanglard SCOPED_TRACE(testing::Message() << "frame_id=" << frame.frame_id);
151*3f982cf4SFabien Sanglard const int num_packets = packetizer()->ComputeNumberOfPackets(frame);
152*3f982cf4SFabien Sanglard ASSERT_EQ(is_key_frame ? 34 : 7, num_packets);
153*3f982cf4SFabien Sanglard
154*3f982cf4SFabien Sanglard for (int j = 0; j < num_packets; ++j) {
155*3f982cf4SFabien Sanglard TestGeneratePacket(frame, static_cast<FramePacketId>(j));
156*3f982cf4SFabien Sanglard if (testing::Test::HasFailure()) {
157*3f982cf4SFabien Sanglard return;
158*3f982cf4SFabien Sanglard }
159*3f982cf4SFabien Sanglard }
160*3f982cf4SFabien Sanglard }
161*3f982cf4SFabien Sanglard }
162*3f982cf4SFabien Sanglard
163*3f982cf4SFabien Sanglard // Tests that all packets are generated for a key frame that includes a playout
164*3f982cf4SFabien Sanglard // delay change. Only the first packet should mention the playout delay change.
TEST_F(RtpPacketizerTest,GeneratesPacketsForFrameWithLatencyChange)165*3f982cf4SFabien Sanglard TEST_F(RtpPacketizerTest, GeneratesPacketsForFrameWithLatencyChange) {
166*3f982cf4SFabien Sanglard const int frame_payload_size = 38383;
167*3f982cf4SFabien Sanglard const EncryptedFrame frame = CreateFrame(
168*3f982cf4SFabien Sanglard FrameId::first() + 42, true, milliseconds(543), frame_payload_size);
169*3f982cf4SFabien Sanglard const int num_packets = packetizer()->ComputeNumberOfPackets(frame);
170*3f982cf4SFabien Sanglard ASSERT_EQ(27, num_packets);
171*3f982cf4SFabien Sanglard
172*3f982cf4SFabien Sanglard for (int i = 0; i < num_packets; ++i) {
173*3f982cf4SFabien Sanglard TestGeneratePacket(frame, static_cast<FramePacketId>(i));
174*3f982cf4SFabien Sanglard if (testing::Test::HasFailure()) {
175*3f982cf4SFabien Sanglard return;
176*3f982cf4SFabien Sanglard }
177*3f982cf4SFabien Sanglard }
178*3f982cf4SFabien Sanglard }
179*3f982cf4SFabien Sanglard
180*3f982cf4SFabien Sanglard // Tests that a single, valid RTP packet is generated for a frame with no data
181*3f982cf4SFabien Sanglard // payload. Having no payload is valid with some codecs (e.g., complete audio
182*3f982cf4SFabien Sanglard // silence can be represented by an empty payload).
TEST_F(RtpPacketizerTest,GeneratesOnePacketForFrameWithNoPayload)183*3f982cf4SFabien Sanglard TEST_F(RtpPacketizerTest, GeneratesOnePacketForFrameWithNoPayload) {
184*3f982cf4SFabien Sanglard const int frame_payload_size = 0;
185*3f982cf4SFabien Sanglard const EncryptedFrame frame = CreateFrame(FrameId::first() + 99, false,
186*3f982cf4SFabien Sanglard milliseconds(0), frame_payload_size);
187*3f982cf4SFabien Sanglard ASSERT_EQ(1, packetizer()->ComputeNumberOfPackets(frame));
188*3f982cf4SFabien Sanglard TestGeneratePacket(frame, FramePacketId{0});
189*3f982cf4SFabien Sanglard }
190*3f982cf4SFabien Sanglard
191*3f982cf4SFabien Sanglard // Tests that re-generating the same packet for re-transmission works, including
192*3f982cf4SFabien Sanglard // a different sequence counter value in the packet each time.
TEST_F(RtpPacketizerTest,GeneratesPacketForRetransmission)193*3f982cf4SFabien Sanglard TEST_F(RtpPacketizerTest, GeneratesPacketForRetransmission) {
194*3f982cf4SFabien Sanglard const int frame_payload_size = 16384;
195*3f982cf4SFabien Sanglard const EncryptedFrame frame =
196*3f982cf4SFabien Sanglard CreateFrame(FrameId::first(), true, milliseconds(0), frame_payload_size);
197*3f982cf4SFabien Sanglard const int num_packets = packetizer()->ComputeNumberOfPackets(frame);
198*3f982cf4SFabien Sanglard ASSERT_EQ(12, num_packets);
199*3f982cf4SFabien Sanglard
200*3f982cf4SFabien Sanglard for (int i = 0; i < 10; ++i) {
201*3f982cf4SFabien Sanglard // Keep generating the same packet. TestGeneratePacket() will check that a
202*3f982cf4SFabien Sanglard // different sequence number is used each time.
203*3f982cf4SFabien Sanglard TestGeneratePacket(frame, FramePacketId{3});
204*3f982cf4SFabien Sanglard }
205*3f982cf4SFabien Sanglard }
206*3f982cf4SFabien Sanglard
207*3f982cf4SFabien Sanglard } // namespace
208*3f982cf4SFabien Sanglard } // namespace cast
209*3f982cf4SFabien Sanglard } // namespace openscreen
210