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 #ifndef CAST_STREAMING_FRAME_COLLECTOR_H_
6 #define CAST_STREAMING_FRAME_COLLECTOR_H_
7 
8 #include <vector>
9 
10 #include "absl/types/span.h"
11 #include "cast/streaming/frame_crypto.h"
12 #include "cast/streaming/frame_id.h"
13 #include "cast/streaming/rtcp_common.h"
14 #include "cast/streaming/rtp_packet_parser.h"
15 
16 namespace openscreen {
17 namespace cast {
18 
19 // Used by a Receiver to collect the parts of a frame, track what is
20 // missing/complete, and assemble a complete frame.
21 class FrameCollector {
22  public:
23   FrameCollector();
24   ~FrameCollector();
25 
26   // Sets the ID of the current frame being collected. This must be called after
27   // each Reset(), and before any of the other methods.
set_frame_id(FrameId frame_id)28   void set_frame_id(FrameId frame_id) { frame_.frame_id = frame_id; }
29 
30   // Examine the parsed packet, representing part of the whole frame, and
31   // collect any data/metadata from it that helps complete the frame. Returns
32   // false if the |part| contained invalid data. On success, this method takes
33   // the data contained within the |buffer|, into which |part.payload| is
34   // pointing, in lieu of copying the data.
35   [[nodiscard]] bool CollectRtpPacket(const RtpPacketParser::ParseResult& part,
36                                       std::vector<uint8_t>* buffer);
37 
38   // Returns true if the frame data collection is complete and the frame can be
39   // assembled.
is_complete()40   bool is_complete() const { return num_missing_packets_ == 0; }
41 
42   // Appends zero or more elements to |nacks| representing which packets are not
43   // yet collected. If all packets for the frame are missing, this appends a
44   // single element containing the special kAllPacketsLost packet ID. Otherwise,
45   // one element is appended for each missing packet, in increasing order of
46   // packet ID.
47   void GetMissingPackets(std::vector<PacketNack>* nacks) const;
48 
49   // Returns a read-only reference to the completely-collected frame, assembling
50   // it if necessary. The caller should reset the FrameCollector (see Reset()
51   // below) to free-up memory once it has finished reading from the returned
52   // frame.
53   //
54   // Precondition: is_complete() must return true before this method can be
55   // called.
56   const EncryptedFrame& PeekAtAssembledFrame();
57 
58   // Resets the FrameCollector back to its initial state, freeing-up memory.
59   void Reset();
60 
61  private:
62   struct PayloadChunk {
63     std::vector<uint8_t> buffer;
64     absl::Span<const uint8_t> payload;  // Once set, is within |buffer.data()|.
65 
66     PayloadChunk();
67     ~PayloadChunk();
68 
has_dataPayloadChunk69     bool has_data() const { return !!payload.data(); }
70   };
71 
72   // Storage for frame metadata and data. Once the frame has been completely
73   // collected and assembled, |frame_.data| is set to non-null, and this is
74   // exposed externally (read-only).
75   EncryptedFrame frame_;
76 
77   // The number of packets needed to complete the frame, or the maximum int if
78   // this is not yet known.
79   int num_missing_packets_;
80 
81   // The chunks of payload data being collected, where element indices
82   // correspond 1:1 with packet IDs. When the first part is collected, this is
83   // resized to match the total number of packets being expected.
84   std::vector<PayloadChunk> chunks_;
85 };
86 
87 }  // namespace cast
88 }  // namespace openscreen
89 
90 #endif  // CAST_STREAMING_FRAME_COLLECTOR_H_
91