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/frame_collector.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <vector>
11
12 #include "cast/streaming/encoded_frame.h"
13 #include "cast/streaming/frame_id.h"
14 #include "cast/streaming/rtcp_common.h"
15 #include "cast/streaming/rtp_time.h"
16 #include "gtest/gtest.h"
17
18 namespace openscreen {
19 namespace cast {
20 namespace {
21
22 const FrameId kSomeFrameId = FrameId::first() + 39;
23 constexpr RtpTimeTicks kSomeRtpTimestamp =
24 RtpTimeTicks() + RtpTimeDelta::FromTicks(90000);
25
26 // Convenience macro to check that the |collector| generates an expected set of
27 // NACKs.
28 #define EXPECT_HAS_NACKS(expected_nacks, collector) \
29 do { \
30 std::vector<PacketNack> nacks; \
31 (collector).GetMissingPackets(&nacks); \
32 EXPECT_EQ((expected_nacks), nacks); \
33 } while (false);
34
TEST(FrameCollectorTest,CollectsFrameWithOnlyOnePart)35 TEST(FrameCollectorTest, CollectsFrameWithOnlyOnePart) {
36 FrameCollector collector;
37
38 // Run for two frames to test that the collector can be re-used.
39 for (int i = 0; i < 2; ++i) {
40 const FrameId frame_id = kSomeFrameId + i;
41 collector.set_frame_id(frame_id);
42 EXPECT_FALSE(collector.is_complete());
43
44 // With no packets seen yet, the collector should provide the "all packets
45 // lost" NACK.
46 EXPECT_HAS_NACKS((std::vector<PacketNack>{{frame_id, kAllPacketsLost}}),
47 collector);
48
49 // Collect the single packet of the frame.
50 RtpPacketParser::ParseResult part;
51 part.rtp_timestamp = kSomeRtpTimestamp + (RtpTimeDelta::FromTicks(200) * i);
52 part.frame_id = frame_id;
53 part.packet_id = 0;
54 part.max_packet_id = 0;
55 if (i == 0) {
56 part.is_key_frame = true;
57 // Do not set |part.new_playout_delay|.
58 } else {
59 part.is_key_frame = false;
60 part.new_playout_delay = std::chrono::milliseconds(800);
61 }
62 part.referenced_frame_id = kSomeFrameId;
63 std::vector<uint8_t> buffer(255);
64 for (int j = 0; j < 255; ++j) {
65 buffer[j] = static_cast<uint8_t>(j);
66 }
67 part.payload = absl::Span<uint8_t>(buffer);
68 EXPECT_TRUE(collector.CollectRtpPacket(part, &buffer));
69
70 // At this point, the collector should feel complete.
71 EXPECT_TRUE(collector.is_complete());
72 EXPECT_HAS_NACKS(std::vector<PacketNack>(), collector);
73
74 // Examine the assembled frame, and confirm its metadata and payload match
75 // what was put into the collector via the packet above.
76 const auto& frame = collector.PeekAtAssembledFrame();
77 if (i == 0) {
78 EXPECT_EQ(EncodedFrame::KEY_FRAME, frame.dependency);
79 EXPECT_EQ(std::chrono::milliseconds(), frame.new_playout_delay);
80 } else {
81 EXPECT_EQ(EncodedFrame::DEPENDS_ON_ANOTHER, frame.dependency);
82 EXPECT_EQ(std::chrono::milliseconds(800), frame.new_playout_delay);
83 }
84 EXPECT_EQ(part.frame_id, frame.frame_id);
85 EXPECT_EQ(kSomeFrameId, frame.referenced_frame_id);
86 EXPECT_EQ(part.rtp_timestamp, frame.rtp_timestamp);
87 for (int j = 0; j < 255; ++j) {
88 EXPECT_EQ(static_cast<uint8_t>(j), frame.data[j]);
89 }
90
91 collector.Reset();
92 }
93 }
94
TEST(FrameCollectorTest,CollectsFrameWithMultiplePartsArrivingOutOfOrder)95 TEST(FrameCollectorTest, CollectsFrameWithMultiplePartsArrivingOutOfOrder) {
96 FrameCollector collector;
97 collector.set_frame_id(kSomeFrameId);
98
99 // With no packets seen yet, the collector should provide the "all packets
100 // lost" NACK.
101 EXPECT_HAS_NACKS((std::vector<PacketNack>{{kSomeFrameId, kAllPacketsLost}}),
102 collector);
103
104 // Prepare the six packet payloads, and the list of remaining NACKs (checked
105 // after each part is collected).
106 const int kPayloadSizes[] = {999, 998, 998, 998, 42, 0};
107 std::vector<uint8_t> payloads[6];
108 std::vector<PacketNack> remaining_nacks;
109 for (int i = 0; i < 6; ++i) {
110 payloads[i].resize(kPayloadSizes[i], static_cast<uint8_t>(i));
111 remaining_nacks.push_back(
112 PacketNack{kSomeFrameId, static_cast<FramePacketId>(i)});
113 }
114
115 // Collect all six packets, out-of-order, and with some duplicates.
116 constexpr FramePacketId kPacketIds[] = {2, 0, 1, 2, 4, 3, 5, 5, 5, 0};
117 for (FramePacketId packet_id : kPacketIds) {
118 RtpPacketParser::ParseResult part{};
119 part.rtp_timestamp = kSomeRtpTimestamp;
120 part.is_key_frame = true;
121 part.frame_id = kSomeFrameId;
122 part.packet_id = packet_id;
123 part.max_packet_id = 5;
124 part.referenced_frame_id = kSomeFrameId;
125 // Prepare a copy of the payload to pass into the FrameCollector. Place 24
126 // bytes of bogus data at the start of the buffer to simulate the
127 // non-payload part of the RTP packet.
128 std::vector<uint8_t> buffer(24, uint8_t{0xab});
129 buffer.insert(buffer.end(), payloads[packet_id].begin(),
130 payloads[packet_id].end());
131 part.payload = absl::Span<uint8_t>(buffer.data() + 24, buffer.size() - 24);
132 EXPECT_TRUE(collector.CollectRtpPacket(part, &buffer));
133
134 // Remove the packet from the list of expected remaining NACKs, and then
135 // check that the collector agrees.
136 remaining_nacks.erase(
137 std::remove_if(remaining_nacks.begin(), remaining_nacks.end(),
138 [packet_id](const PacketNack& nack) {
139 return nack.packet_id == packet_id;
140 }),
141 remaining_nacks.end());
142 EXPECT_HAS_NACKS(remaining_nacks, collector);
143 }
144
145 // Confirm there are no missing packets and no NACKs generated.
146 EXPECT_TRUE(collector.is_complete());
147 EXPECT_HAS_NACKS(std::vector<PacketNack>(), collector);
148
149 // Examine the assembled frame, and confirm its metadata and payload match
150 // what was put into the collector via the packets above, and that the payload
151 // bytes are in-order.
152 const auto& frame = collector.PeekAtAssembledFrame();
153 EXPECT_EQ(EncodedFrame::KEY_FRAME, frame.dependency);
154 EXPECT_EQ(kSomeFrameId, frame.frame_id);
155 EXPECT_EQ(kSomeFrameId, frame.referenced_frame_id);
156 EXPECT_EQ(kSomeRtpTimestamp, frame.rtp_timestamp);
157 absl::Span<const uint8_t> remaining_data = frame.data;
158 for (int i = 0; i < 6; ++i) {
159 ASSERT_LE(kPayloadSizes[i], static_cast<int>(remaining_data.size()));
160 EXPECT_EQ(absl::Span<const uint8_t>(payloads[i]),
161 remaining_data.subspan(0, kPayloadSizes[i]))
162 << "i=" << i;
163 remaining_data.remove_prefix(kPayloadSizes[i]);
164 }
165 ASSERT_TRUE(remaining_data.empty());
166 }
167
TEST(FrameCollectorTest,RejectsInvalidParts)168 TEST(FrameCollectorTest, RejectsInvalidParts) {
169 FrameCollector collector;
170
171 // Expect the collector rejects a part not having the correct FrameId.
172 collector.set_frame_id(kSomeFrameId + 256);
173 RtpPacketParser::ParseResult part{};
174 part.rtp_timestamp = kSomeRtpTimestamp;
175 part.is_key_frame = false;
176 part.frame_id = kSomeFrameId;
177 part.packet_id = 0;
178 part.max_packet_id = 3;
179 std::vector<uint8_t> buffer(1, 'A');
180 part.payload = absl::Span<uint8_t>(buffer);
181 EXPECT_FALSE(collector.CollectRtpPacket(part, &buffer));
182 // Note: When CollectRtpPacket() returns false, it does not take ownership of
183 // the buffer memory.
184 ASSERT_TRUE(buffer.size() == 1 && buffer[0] == 'A');
185
186 // The collector should accept a part having the correct FrameId.
187 collector.set_frame_id(kSomeFrameId);
188 part.frame_id = kSomeFrameId;
189 EXPECT_TRUE(collector.CollectRtpPacket(part, &buffer));
190 // Note: Re-assign the buffer and payload pointer since the buffer was just
191 // consumed.
192 buffer.assign(1, 'A');
193 part.payload = absl::Span<uint8_t>(buffer);
194
195 // The collector should reject a part where the packet_id is greater than the
196 // previously-established max_packet_id.
197 part.packet_id = 5; // BAD, since max_packet_id is 3 (see above).
198 EXPECT_FALSE(collector.CollectRtpPacket(part, &buffer));
199 ASSERT_TRUE(buffer.size() == 1 && buffer[0] == 'A');
200
201 // The collector should reject a part where the max_packet_id disagrees with
202 // previously-established max_packet_id.
203 part.packet_id = 2;
204 part.max_packet_id = 5; // BAD, since max_packet_id is 3 (see above).
205 EXPECT_FALSE(collector.CollectRtpPacket(part, &buffer));
206 ASSERT_TRUE(buffer.size() == 1 && buffer[0] == 'A');
207 }
208
209 } // namespace
210 } // namespace cast
211 } // namespace openscreen
212