• 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 "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