// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CAST_STREAMING_COMPOUND_RTCP_BUILDER_H_ #define CAST_STREAMING_COMPOUND_RTCP_BUILDER_H_ #include #include #include #include "absl/types/optional.h" #include "absl/types/span.h" #include "cast/streaming/constants.h" #include "cast/streaming/frame_id.h" #include "cast/streaming/rtcp_common.h" #include "cast/streaming/rtp_defines.h" namespace openscreen { namespace cast { class RtcpSession; // Collects current status and feedback messages from the Receiver in the // current process, and builds compound RTCP packets to be transmitted to a // Sender. // // Usage: // // 1. Call the various SetXYZ/IncludeXYZInNextPacket() methods as the // receiver's state changes. The SetXYZ() methods provide values that will // be included in every RTCP packet until they are changed, while the // IncludeXYZInNextPacket() methods provide values for only the next-built // RTCP packet. The latter case is part of the overall protocol design, to // help prevent the Sender from acting on stale Receiver state. // // 2. At certain times, call BuildPacket() and transmit it to the sender: // a. By default, every 1/2 sec, to provide the sender with a "keep alive" // ping that it can also use to monitor network round-trip times. // b. When there is new feedback, the collected information should be // immediately conveyed to the sender. class CompoundRtcpBuilder { public: explicit CompoundRtcpBuilder(RtcpSession* session); ~CompoundRtcpBuilder(); // Gets/Sets the checkpoint |frame_id| that will be included in built RTCP // packets. This value indicates to the sender that all of the packets for all // frames up to and including the given frame have been successfully received. FrameId checkpoint_frame() const { return checkpoint_frame_id_; } void SetCheckpointFrame(FrameId frame_id); // Gets/Sets the current end-to-end target playout delay setting for the Cast // RTP receiver, to be included in built RTCP packets. This reflect any // changes the sender has made by using the "Cast Adaptive Latency Extension" // in received RTP packets. std::chrono::milliseconds playout_delay() const { return playout_delay_; } void SetPlayoutDelay(std::chrono::milliseconds delay); // Gets/Sets the picture loss indicator flag. While this is set, built RTCP // packets will include a PLI message that indicates to the sender that there // has been an unrecoverable decoding error. This asks the sender to provide a // key frame as soon as possible. The client must explicitly clear this flag // when decoding will recover. bool is_picture_loss_indicator_set() const { return picture_loss_indicator_; } void SetPictureLossIndicator(bool picture_is_lost); // Include a receiver report about recent packet receive activity in ONLY the // next built RTCP packet. This replaces a prior receiver report if // BuildPacket() was not called in the meantime (since only the most // up-to-date version of the Receiver's state is relevant to the Sender). void IncludeReceiverReportInNextPacket( const RtcpReportBlock& receiver_report); // Include detailed feedback about wholly-received frames, whole missing // frames, and partially-received frames (specific missing packets) in ONLY // the next built RTCP packet. The data will be included in a best-effort // fashion, depending on the size of the |buffer| passed to the next call to // BuildPacket(). This replaces prior feedback data if BuildPacket() was not // called in the meantime (since only the most up-to-date version of the // Receiver's state is relevant to the Sender). // // The elements in the lists are assumed to be monotonically increasing: // |packet_nacks| indicates specific packets that have not yet been received, // or may use kAllPacketsLost to indicate that no packets have been received // for a frame. |frame_acks| indicates which frames after the checkpoint frame // have been fully received. void IncludeFeedbackInNextPacket(std::vector packet_nacks, std::vector frame_acks); // Builds a compound RTCP packet and returns the portion of the |buffer| that // was used. The buffer's size must be at least kRequiredBufferSize, but // should generally be the maximum packet size (see discussion in // rtp_defines.h), to avoid dropping any ACK/NACK feedback. // // |send_time| specifies the when the resulting packet will be sent. This // should be monotonically increasing so the consuming side (the Sender) can // determine the chronological ordering of RTCP packets. The Sender might also // use this to estimate round-trip times over the network. absl::Span BuildPacket(Clock::time_point send_time, absl::Span buffer); // The required buffer size to be provided to BuildPacket(). This accounts for // all the possible headers and report structures that might be included, // along with a reasonable amount of space for the feedback's ACK/NACKs bit // vectors. static constexpr int kRequiredBufferSize = 256; private: // Helper methods called by BuildPacket() to append one RTCP packet to the // |buffer| that will ultimately contain a "compound RTCP packet." void AppendReceiverReportPacket(absl::Span* buffer); void AppendReceiverReferenceTimeReportPacket(Clock::time_point send_time, absl::Span* buffer); void AppendPictureLossIndicatorPacket(absl::Span* buffer); void AppendCastFeedbackPacket(absl::Span* buffer); int AppendCastFeedbackLossFields(absl::Span* buffer); void AppendCastFeedbackAckFields(absl::Span* buffer); RtcpSession* const session_; // Data to include in the next built RTCP packet. FrameId checkpoint_frame_id_ = FrameId::leader(); std::chrono::milliseconds playout_delay_ = kDefaultTargetPlayoutDelay; absl::optional receiver_report_for_next_packet_; std::vector nacks_for_next_packet_; std::vector acks_for_next_packet_; bool picture_loss_indicator_ = false; // An 8-bit wrap-around counter that tracks how many times Cast Feedback has // been included in the built RTCP packets. uint8_t feedback_count_ = 0; }; } // namespace cast } // namespace openscreen #endif // CAST_STREAMING_COMPOUND_RTCP_BUILDER_H_