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_COMPOUND_RTCP_BUILDER_H_ 6 #define CAST_STREAMING_COMPOUND_RTCP_BUILDER_H_ 7 8 #include <chrono> 9 #include <utility> 10 #include <vector> 11 12 #include "absl/types/optional.h" 13 #include "absl/types/span.h" 14 #include "cast/streaming/constants.h" 15 #include "cast/streaming/frame_id.h" 16 #include "cast/streaming/rtcp_common.h" 17 #include "cast/streaming/rtp_defines.h" 18 19 namespace openscreen { 20 namespace cast { 21 22 class RtcpSession; 23 24 // Collects current status and feedback messages from the Receiver in the 25 // current process, and builds compound RTCP packets to be transmitted to a 26 // Sender. 27 // 28 // Usage: 29 // 30 // 1. Call the various SetXYZ/IncludeXYZInNextPacket() methods as the 31 // receiver's state changes. The SetXYZ() methods provide values that will 32 // be included in every RTCP packet until they are changed, while the 33 // IncludeXYZInNextPacket() methods provide values for only the next-built 34 // RTCP packet. The latter case is part of the overall protocol design, to 35 // help prevent the Sender from acting on stale Receiver state. 36 // 37 // 2. At certain times, call BuildPacket() and transmit it to the sender: 38 // a. By default, every 1/2 sec, to provide the sender with a "keep alive" 39 // ping that it can also use to monitor network round-trip times. 40 // b. When there is new feedback, the collected information should be 41 // immediately conveyed to the sender. 42 class CompoundRtcpBuilder { 43 public: 44 explicit CompoundRtcpBuilder(RtcpSession* session); 45 ~CompoundRtcpBuilder(); 46 47 // Gets/Sets the checkpoint |frame_id| that will be included in built RTCP 48 // packets. This value indicates to the sender that all of the packets for all 49 // frames up to and including the given frame have been successfully received. checkpoint_frame()50 FrameId checkpoint_frame() const { return checkpoint_frame_id_; } 51 void SetCheckpointFrame(FrameId frame_id); 52 53 // Gets/Sets the current end-to-end target playout delay setting for the Cast 54 // RTP receiver, to be included in built RTCP packets. This reflect any 55 // changes the sender has made by using the "Cast Adaptive Latency Extension" 56 // in received RTP packets. playout_delay()57 std::chrono::milliseconds playout_delay() const { return playout_delay_; } 58 void SetPlayoutDelay(std::chrono::milliseconds delay); 59 60 // Gets/Sets the picture loss indicator flag. While this is set, built RTCP 61 // packets will include a PLI message that indicates to the sender that there 62 // has been an unrecoverable decoding error. This asks the sender to provide a 63 // key frame as soon as possible. The client must explicitly clear this flag 64 // when decoding will recover. is_picture_loss_indicator_set()65 bool is_picture_loss_indicator_set() const { return picture_loss_indicator_; } 66 void SetPictureLossIndicator(bool picture_is_lost); 67 68 // Include a receiver report about recent packet receive activity in ONLY the 69 // next built RTCP packet. This replaces a prior receiver report if 70 // BuildPacket() was not called in the meantime (since only the most 71 // up-to-date version of the Receiver's state is relevant to the Sender). 72 void IncludeReceiverReportInNextPacket( 73 const RtcpReportBlock& receiver_report); 74 75 // Include detailed feedback about wholly-received frames, whole missing 76 // frames, and partially-received frames (specific missing packets) in ONLY 77 // the next built RTCP packet. The data will be included in a best-effort 78 // fashion, depending on the size of the |buffer| passed to the next call to 79 // BuildPacket(). This replaces prior feedback data if BuildPacket() was not 80 // called in the meantime (since only the most up-to-date version of the 81 // Receiver's state is relevant to the Sender). 82 // 83 // The elements in the lists are assumed to be monotonically increasing: 84 // |packet_nacks| indicates specific packets that have not yet been received, 85 // or may use kAllPacketsLost to indicate that no packets have been received 86 // for a frame. |frame_acks| indicates which frames after the checkpoint frame 87 // have been fully received. 88 void IncludeFeedbackInNextPacket(std::vector<PacketNack> packet_nacks, 89 std::vector<FrameId> frame_acks); 90 91 // Builds a compound RTCP packet and returns the portion of the |buffer| that 92 // was used. The buffer's size must be at least kRequiredBufferSize, but 93 // should generally be the maximum packet size (see discussion in 94 // rtp_defines.h), to avoid dropping any ACK/NACK feedback. 95 // 96 // |send_time| specifies the when the resulting packet will be sent. This 97 // should be monotonically increasing so the consuming side (the Sender) can 98 // determine the chronological ordering of RTCP packets. The Sender might also 99 // use this to estimate round-trip times over the network. 100 absl::Span<uint8_t> BuildPacket(Clock::time_point send_time, 101 absl::Span<uint8_t> buffer); 102 103 // The required buffer size to be provided to BuildPacket(). This accounts for 104 // all the possible headers and report structures that might be included, 105 // along with a reasonable amount of space for the feedback's ACK/NACKs bit 106 // vectors. 107 static constexpr int kRequiredBufferSize = 256; 108 109 private: 110 // Helper methods called by BuildPacket() to append one RTCP packet to the 111 // |buffer| that will ultimately contain a "compound RTCP packet." 112 void AppendReceiverReportPacket(absl::Span<uint8_t>* buffer); 113 void AppendReceiverReferenceTimeReportPacket(Clock::time_point send_time, 114 absl::Span<uint8_t>* buffer); 115 void AppendPictureLossIndicatorPacket(absl::Span<uint8_t>* buffer); 116 void AppendCastFeedbackPacket(absl::Span<uint8_t>* buffer); 117 int AppendCastFeedbackLossFields(absl::Span<uint8_t>* buffer); 118 void AppendCastFeedbackAckFields(absl::Span<uint8_t>* buffer); 119 120 RtcpSession* const session_; 121 122 // Data to include in the next built RTCP packet. 123 FrameId checkpoint_frame_id_ = FrameId::leader(); 124 std::chrono::milliseconds playout_delay_ = kDefaultTargetPlayoutDelay; 125 absl::optional<RtcpReportBlock> receiver_report_for_next_packet_; 126 std::vector<PacketNack> nacks_for_next_packet_; 127 std::vector<FrameId> acks_for_next_packet_; 128 bool picture_loss_indicator_ = false; 129 130 // An 8-bit wrap-around counter that tracks how many times Cast Feedback has 131 // been included in the built RTCP packets. 132 uint8_t feedback_count_ = 0; 133 }; 134 135 } // namespace cast 136 } // namespace openscreen 137 138 #endif // CAST_STREAMING_COMPOUND_RTCP_BUILDER_H_ 139