1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved. 2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be 3*3f982cf4SFabien Sanglard // found in the LICENSE file. 4*3f982cf4SFabien Sanglard 5*3f982cf4SFabien Sanglard #ifndef CAST_STREAMING_SENDER_H_ 6*3f982cf4SFabien Sanglard #define CAST_STREAMING_SENDER_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <stdint.h> 9*3f982cf4SFabien Sanglard 10*3f982cf4SFabien Sanglard #include <array> 11*3f982cf4SFabien Sanglard #include <chrono> 12*3f982cf4SFabien Sanglard #include <vector> 13*3f982cf4SFabien Sanglard 14*3f982cf4SFabien Sanglard #include "absl/types/span.h" 15*3f982cf4SFabien Sanglard #include "cast/streaming/compound_rtcp_parser.h" 16*3f982cf4SFabien Sanglard #include "cast/streaming/constants.h" 17*3f982cf4SFabien Sanglard #include "cast/streaming/frame_crypto.h" 18*3f982cf4SFabien Sanglard #include "cast/streaming/frame_id.h" 19*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_defines.h" 20*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_packetizer.h" 21*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_time.h" 22*3f982cf4SFabien Sanglard #include "cast/streaming/sender_packet_router.h" 23*3f982cf4SFabien Sanglard #include "cast/streaming/sender_report_builder.h" 24*3f982cf4SFabien Sanglard #include "cast/streaming/session_config.h" 25*3f982cf4SFabien Sanglard #include "platform/api/time.h" 26*3f982cf4SFabien Sanglard #include "util/yet_another_bit_vector.h" 27*3f982cf4SFabien Sanglard 28*3f982cf4SFabien Sanglard namespace openscreen { 29*3f982cf4SFabien Sanglard namespace cast { 30*3f982cf4SFabien Sanglard 31*3f982cf4SFabien Sanglard class Environment; 32*3f982cf4SFabien Sanglard 33*3f982cf4SFabien Sanglard // The Cast Streaming Sender, a peer corresponding to some Cast Streaming 34*3f982cf4SFabien Sanglard // Receiver at the other end of a network link. See class level comments for 35*3f982cf4SFabien Sanglard // Receiver for a high-level overview. 36*3f982cf4SFabien Sanglard // 37*3f982cf4SFabien Sanglard // The Sender is the peer responsible for enqueuing EncodedFrames for streaming, 38*3f982cf4SFabien Sanglard // guaranteeing their delivery to a Receiver, and handling feedback events from 39*3f982cf4SFabien Sanglard // a Receiver. Some feedback events are used for managing the Sender's internal 40*3f982cf4SFabien Sanglard // queue of in-flight frames, requesting network packet re-transmits, etc.; 41*3f982cf4SFabien Sanglard // while others are exposed via the Sender's public interface. For example, 42*3f982cf4SFabien Sanglard // sometimes the Receiver signals that it needs a a key frame to resolve a 43*3f982cf4SFabien Sanglard // picture loss condition, and the modules upstream of the Sender (e.g., where 44*3f982cf4SFabien Sanglard // encoding happens) should call NeedsKeyFrame() to check for, and handle that. 45*3f982cf4SFabien Sanglard // 46*3f982cf4SFabien Sanglard // There are usually one or two Senders in a streaming session, one for audio 47*3f982cf4SFabien Sanglard // and one for video. Both senders work with the same SenderPacketRouter 48*3f982cf4SFabien Sanglard // instance to schedule their transmission of packets, and provide the necessary 49*3f982cf4SFabien Sanglard // metrics for estimating bandwidth utilization and availability. 50*3f982cf4SFabien Sanglard // 51*3f982cf4SFabien Sanglard // It is the responsibility of upstream code modules to handle congestion 52*3f982cf4SFabien Sanglard // control. With respect to this Sender, that means the media encoding bit rate 53*3f982cf4SFabien Sanglard // should be throttled based on network bandwidth availability. This Sender does 54*3f982cf4SFabien Sanglard // not do any throttling, only flow-control. In other words, this Sender can 55*3f982cf4SFabien Sanglard // only manage its in-flight queue of frames, and if that queue grows too large, 56*3f982cf4SFabien Sanglard // it will eventually reject further enqueuing. 57*3f982cf4SFabien Sanglard // 58*3f982cf4SFabien Sanglard // General usage: A client should check the in-flight media duration frequently 59*3f982cf4SFabien Sanglard // to decide when to pause encoding, to avoid wasting system resources on 60*3f982cf4SFabien Sanglard // encoding frames that will likely be rejected by the Sender. The client should 61*3f982cf4SFabien Sanglard // also frequently call NeedsKeyFrame() and, when this returns true, direct its 62*3f982cf4SFabien Sanglard // encoder to produce a key frame soon. Finally, when using EnqueueFrame(), an 63*3f982cf4SFabien Sanglard // EncodedFrame struct should be prepared with its frame_id field set to 64*3f982cf4SFabien Sanglard // whatever GetNextFrameId() returns. Please see method comments for 65*3f982cf4SFabien Sanglard // more-detailed usage info. 66*3f982cf4SFabien Sanglard class Sender final : public SenderPacketRouter::Sender, 67*3f982cf4SFabien Sanglard public CompoundRtcpParser::Client { 68*3f982cf4SFabien Sanglard public: 69*3f982cf4SFabien Sanglard // Interface for receiving notifications about events of possible interest. 70*3f982cf4SFabien Sanglard // Handling each of these is optional, but some may be mandatory for certain 71*3f982cf4SFabien Sanglard // applications (see method comments below). 72*3f982cf4SFabien Sanglard class Observer { 73*3f982cf4SFabien Sanglard public: 74*3f982cf4SFabien Sanglard // Called when a frame was canceled. "Canceled" means that the Receiver has 75*3f982cf4SFabien Sanglard // either acknowledged successful receipt of the frame or has decided to 76*3f982cf4SFabien Sanglard // skip over it. Note: Frame cancellations may occur out-of-order. 77*3f982cf4SFabien Sanglard virtual void OnFrameCanceled(FrameId frame_id); 78*3f982cf4SFabien Sanglard 79*3f982cf4SFabien Sanglard // Called when a Receiver begins reporting picture loss, and there is no key 80*3f982cf4SFabien Sanglard // frame currently enqueued in the Sender. The application should enqueue a 81*3f982cf4SFabien Sanglard // key frame as soon as possible. Note: An application that pauses frame 82*3f982cf4SFabien Sanglard // sending (e.g., screen mirroring when the screen is not changing) should 83*3f982cf4SFabien Sanglard // use this notification to send an out-of-band "refresh frame," encoded as 84*3f982cf4SFabien Sanglard // a key frame. 85*3f982cf4SFabien Sanglard virtual void OnPictureLost(); 86*3f982cf4SFabien Sanglard 87*3f982cf4SFabien Sanglard protected: 88*3f982cf4SFabien Sanglard virtual ~Observer(); 89*3f982cf4SFabien Sanglard }; 90*3f982cf4SFabien Sanglard 91*3f982cf4SFabien Sanglard // Result codes for EnqueueFrame(). 92*3f982cf4SFabien Sanglard enum EnqueueFrameResult { 93*3f982cf4SFabien Sanglard // The frame has been queued for sending. 94*3f982cf4SFabien Sanglard OK, 95*3f982cf4SFabien Sanglard 96*3f982cf4SFabien Sanglard // The frame's payload was too large. This is typically triggered when 97*3f982cf4SFabien Sanglard // submitting a payload of several dozen megabytes or more. This result code 98*3f982cf4SFabien Sanglard // likely indicates some kind of upstream bug. 99*3f982cf4SFabien Sanglard PAYLOAD_TOO_LARGE, 100*3f982cf4SFabien Sanglard 101*3f982cf4SFabien Sanglard // The span of FrameIds is too large. Cast Streaming's protocol design 102*3f982cf4SFabien Sanglard // imposes a limit in the maximum difference between the highest-valued 103*3f982cf4SFabien Sanglard // in-flight FrameId and the least-valued one. 104*3f982cf4SFabien Sanglard REACHED_ID_SPAN_LIMIT, 105*3f982cf4SFabien Sanglard 106*3f982cf4SFabien Sanglard // Too-large a media duration is in-flight. Enqueuing another frame would 107*3f982cf4SFabien Sanglard // automatically cause late play-out at the Receiver. 108*3f982cf4SFabien Sanglard MAX_DURATION_IN_FLIGHT, 109*3f982cf4SFabien Sanglard }; 110*3f982cf4SFabien Sanglard 111*3f982cf4SFabien Sanglard // Constructs a Sender that attaches to the given |environment|-provided 112*3f982cf4SFabien Sanglard // resources and |packet_router|. The |config| contains the settings that were 113*3f982cf4SFabien Sanglard // agreed-upon by both sides from the OFFER/ANSWER exchange (i.e., the part of 114*3f982cf4SFabien Sanglard // the overall end-to-end connection process that occurs before Cast Streaming 115*3f982cf4SFabien Sanglard // is started). The |rtp_payload_type| does not affect the behavior of this 116*3f982cf4SFabien Sanglard // Sender. It is simply passed along to a Receiver in the RTP packet stream. 117*3f982cf4SFabien Sanglard Sender(Environment* environment, 118*3f982cf4SFabien Sanglard SenderPacketRouter* packet_router, 119*3f982cf4SFabien Sanglard SessionConfig config, 120*3f982cf4SFabien Sanglard RtpPayloadType rtp_payload_type); 121*3f982cf4SFabien Sanglard 122*3f982cf4SFabien Sanglard ~Sender() final; 123*3f982cf4SFabien Sanglard config()124*3f982cf4SFabien Sanglard const SessionConfig& config() const { return config_; } ssrc()125*3f982cf4SFabien Sanglard Ssrc ssrc() const { return rtcp_session_.sender_ssrc(); } rtp_timebase()126*3f982cf4SFabien Sanglard int rtp_timebase() const { return rtp_timebase_; } 127*3f982cf4SFabien Sanglard 128*3f982cf4SFabien Sanglard // Sets an observer for receiving notifications. Call with nullptr to stop 129*3f982cf4SFabien Sanglard // observing. 130*3f982cf4SFabien Sanglard void SetObserver(Observer* observer); 131*3f982cf4SFabien Sanglard 132*3f982cf4SFabien Sanglard // Returns the number of frames currently in-flight. This is only meant to be 133*3f982cf4SFabien Sanglard // informative. Clients should use GetInFlightMediaDuration() to make 134*3f982cf4SFabien Sanglard // throttling decisions. 135*3f982cf4SFabien Sanglard int GetInFlightFrameCount() const; 136*3f982cf4SFabien Sanglard 137*3f982cf4SFabien Sanglard // Returns the total media duration of the frames currently in-flight, 138*3f982cf4SFabien Sanglard // assuming the next not-yet-enqueued frame will have the given RTP timestamp. 139*3f982cf4SFabien Sanglard // For a better user experience, the result should be compared to 140*3f982cf4SFabien Sanglard // GetMaxInFlightMediaDuration(), and media encoding should be throttled down 141*3f982cf4SFabien Sanglard // before additional EnqueueFrame() calls would cause this to reach the 142*3f982cf4SFabien Sanglard // current maximum limit. 143*3f982cf4SFabien Sanglard Clock::duration GetInFlightMediaDuration( 144*3f982cf4SFabien Sanglard RtpTimeTicks next_frame_rtp_timestamp) const; 145*3f982cf4SFabien Sanglard 146*3f982cf4SFabien Sanglard // Return the maximum acceptable in-flight media duration, given the current 147*3f982cf4SFabien Sanglard // target playout delay setting and end-to-end network/system conditions. 148*3f982cf4SFabien Sanglard Clock::duration GetMaxInFlightMediaDuration() const; 149*3f982cf4SFabien Sanglard 150*3f982cf4SFabien Sanglard // Returns true if the Receiver requires a key frame. Note that this will 151*3f982cf4SFabien Sanglard // return true until a key frame is accepted by EnqueueFrame(). Thus, when 152*3f982cf4SFabien Sanglard // encoding is pipelined, care should be taken to instruct the encoder to 153*3f982cf4SFabien Sanglard // produce just ONE forced key frame. 154*3f982cf4SFabien Sanglard bool NeedsKeyFrame() const; 155*3f982cf4SFabien Sanglard 156*3f982cf4SFabien Sanglard // Returns the next FrameId, the one after the frame enqueued by the last call 157*3f982cf4SFabien Sanglard // to EnqueueFrame(). Note that the next call to EnqueueFrame() assumes this 158*3f982cf4SFabien Sanglard // frame ID be used. 159*3f982cf4SFabien Sanglard FrameId GetNextFrameId() const; 160*3f982cf4SFabien Sanglard 161*3f982cf4SFabien Sanglard // Enqueues the given |frame| for sending as soon as possible. Returns OK if 162*3f982cf4SFabien Sanglard // the frame is accepted, and some time later Observer::OnFrameCanceled() will 163*3f982cf4SFabien Sanglard // be called once it is no longer in-flight. 164*3f982cf4SFabien Sanglard // 165*3f982cf4SFabien Sanglard // All fields of the |frame| must be set to valid values: the |frame_id| must 166*3f982cf4SFabien Sanglard // be the same as GetNextFrameId(); both the |rtp_timestamp| and 167*3f982cf4SFabien Sanglard // |reference_time| fields must be monotonically increasing relative to the 168*3f982cf4SFabien Sanglard // prior frame; and the frame's |data| pointer must be set. 169*3f982cf4SFabien Sanglard [[nodiscard]] EnqueueFrameResult EnqueueFrame(const EncodedFrame& frame); 170*3f982cf4SFabien Sanglard 171*3f982cf4SFabien Sanglard // Causes all pending operations to discard data when they are processed 172*3f982cf4SFabien Sanglard // later. 173*3f982cf4SFabien Sanglard void CancelInFlightData(); 174*3f982cf4SFabien Sanglard 175*3f982cf4SFabien Sanglard private: 176*3f982cf4SFabien Sanglard // Tracking/Storage for frames that are ready-to-send, and until they are 177*3f982cf4SFabien Sanglard // fully received at the other end. 178*3f982cf4SFabien Sanglard struct PendingFrameSlot { 179*3f982cf4SFabien Sanglard // The frame to send, or nullopt if this slot is not in use. 180*3f982cf4SFabien Sanglard absl::optional<EncryptedFrame> frame; 181*3f982cf4SFabien Sanglard 182*3f982cf4SFabien Sanglard // Represents which packets need to be sent. Elements are indexed by 183*3f982cf4SFabien Sanglard // FramePacketId. A set bit means a packet needs to be sent (or re-sent). 184*3f982cf4SFabien Sanglard YetAnotherBitVector send_flags; 185*3f982cf4SFabien Sanglard 186*3f982cf4SFabien Sanglard // The time when each of the packets was last sent, or 187*3f982cf4SFabien Sanglard // |SenderPacketRouter::kNever| if the packet has not been sent yet. 188*3f982cf4SFabien Sanglard // Elements are indexed by FramePacketId. This is used to avoid 189*3f982cf4SFabien Sanglard // re-transmitting any given packet too frequently. 190*3f982cf4SFabien Sanglard std::vector<Clock::time_point> packet_sent_times; 191*3f982cf4SFabien Sanglard 192*3f982cf4SFabien Sanglard PendingFrameSlot(); 193*3f982cf4SFabien Sanglard ~PendingFrameSlot(); 194*3f982cf4SFabien Sanglard is_active_for_framePendingFrameSlot195*3f982cf4SFabien Sanglard bool is_active_for_frame(FrameId frame_id) const { 196*3f982cf4SFabien Sanglard return frame && frame->frame_id == frame_id; 197*3f982cf4SFabien Sanglard } 198*3f982cf4SFabien Sanglard }; 199*3f982cf4SFabien Sanglard 200*3f982cf4SFabien Sanglard // Return value from the ChooseXYZ() helper methods. 201*3f982cf4SFabien Sanglard struct ChosenPacket { 202*3f982cf4SFabien Sanglard PendingFrameSlot* slot = nullptr; 203*3f982cf4SFabien Sanglard FramePacketId packet_id{}; 204*3f982cf4SFabien Sanglard 205*3f982cf4SFabien Sanglard explicit operator bool() const { return !!slot; } 206*3f982cf4SFabien Sanglard }; 207*3f982cf4SFabien Sanglard 208*3f982cf4SFabien Sanglard // An extension of ChosenPacket that also includes the point-in-time when the 209*3f982cf4SFabien Sanglard // packet should be sent. 210*3f982cf4SFabien Sanglard struct ChosenPacketAndWhen : public ChosenPacket { 211*3f982cf4SFabien Sanglard Clock::time_point when = SenderPacketRouter::kNever; 212*3f982cf4SFabien Sanglard }; 213*3f982cf4SFabien Sanglard 214*3f982cf4SFabien Sanglard // SenderPacketRouter::Sender implementation. 215*3f982cf4SFabien Sanglard void OnReceivedRtcpPacket(Clock::time_point arrival_time, 216*3f982cf4SFabien Sanglard absl::Span<const uint8_t> packet) final; 217*3f982cf4SFabien Sanglard absl::Span<uint8_t> GetRtcpPacketForImmediateSend( 218*3f982cf4SFabien Sanglard Clock::time_point send_time, 219*3f982cf4SFabien Sanglard absl::Span<uint8_t> buffer) final; 220*3f982cf4SFabien Sanglard absl::Span<uint8_t> GetRtpPacketForImmediateSend( 221*3f982cf4SFabien Sanglard Clock::time_point send_time, 222*3f982cf4SFabien Sanglard absl::Span<uint8_t> buffer) final; 223*3f982cf4SFabien Sanglard Clock::time_point GetRtpResumeTime() final; 224*3f982cf4SFabien Sanglard 225*3f982cf4SFabien Sanglard // CompoundRtcpParser::Client implementation. 226*3f982cf4SFabien Sanglard void OnReceiverReferenceTimeAdvanced(Clock::time_point reference_time) final; 227*3f982cf4SFabien Sanglard void OnReceiverReport(const RtcpReportBlock& receiver_report) final; 228*3f982cf4SFabien Sanglard void OnReceiverIndicatesPictureLoss() final; 229*3f982cf4SFabien Sanglard void OnReceiverCheckpoint(FrameId frame_id, 230*3f982cf4SFabien Sanglard std::chrono::milliseconds playout_delay) final; 231*3f982cf4SFabien Sanglard void OnReceiverHasFrames(std::vector<FrameId> acks) final; 232*3f982cf4SFabien Sanglard void OnReceiverIsMissingPackets(std::vector<PacketNack> nacks) final; 233*3f982cf4SFabien Sanglard 234*3f982cf4SFabien Sanglard // Helper to choose which packet to send, from those that have been flagged as 235*3f982cf4SFabien Sanglard // "need to send." Returns a "false" result if nothing needs to be sent. 236*3f982cf4SFabien Sanglard ChosenPacket ChooseNextRtpPacketNeedingSend(); 237*3f982cf4SFabien Sanglard 238*3f982cf4SFabien Sanglard // Helper that returns the packet that should be used to kick-start the 239*3f982cf4SFabien Sanglard // Receiver, and the time at which the packet should be sent. Returns a kNever 240*3f982cf4SFabien Sanglard // result if kick-starting is not needed. 241*3f982cf4SFabien Sanglard ChosenPacketAndWhen ChooseKickstartPacket(); 242*3f982cf4SFabien Sanglard 243*3f982cf4SFabien Sanglard // Cancels the given frame once it is known to have been fully received (i.e., 244*3f982cf4SFabien Sanglard // based on the ACK feedback from the Receiver in a RTCP packet). This clears 245*3f982cf4SFabien Sanglard // the corresponding entry in |pending_frames_| and notifies the Observer. 246*3f982cf4SFabien Sanglard void CancelPendingFrame(FrameId frame_id); 247*3f982cf4SFabien Sanglard 248*3f982cf4SFabien Sanglard // Inline helper to return the slot that would contain the tracking info for 249*3f982cf4SFabien Sanglard // the given |frame_id|. get_slot_for(FrameId frame_id)250*3f982cf4SFabien Sanglard const PendingFrameSlot* get_slot_for(FrameId frame_id) const { 251*3f982cf4SFabien Sanglard return &pending_frames_[(frame_id - FrameId::first()) % 252*3f982cf4SFabien Sanglard pending_frames_.size()]; 253*3f982cf4SFabien Sanglard } get_slot_for(FrameId frame_id)254*3f982cf4SFabien Sanglard PendingFrameSlot* get_slot_for(FrameId frame_id) { 255*3f982cf4SFabien Sanglard return &pending_frames_[(frame_id - FrameId::first()) % 256*3f982cf4SFabien Sanglard pending_frames_.size()]; 257*3f982cf4SFabien Sanglard } 258*3f982cf4SFabien Sanglard 259*3f982cf4SFabien Sanglard const SessionConfig config_; 260*3f982cf4SFabien Sanglard SenderPacketRouter* const packet_router_; 261*3f982cf4SFabien Sanglard RtcpSession rtcp_session_; 262*3f982cf4SFabien Sanglard CompoundRtcpParser rtcp_parser_; 263*3f982cf4SFabien Sanglard SenderReportBuilder sender_report_builder_; 264*3f982cf4SFabien Sanglard RtpPacketizer rtp_packetizer_; 265*3f982cf4SFabien Sanglard const int rtp_timebase_; 266*3f982cf4SFabien Sanglard FrameCrypto crypto_; 267*3f982cf4SFabien Sanglard 268*3f982cf4SFabien Sanglard // Ring buffer of PendingFrameSlots. The frame having FrameId x will always 269*3f982cf4SFabien Sanglard // be slotted at position x % pending_frames_.size(). Use get_slot_for() to 270*3f982cf4SFabien Sanglard // access the correct slot for a given FrameId. 271*3f982cf4SFabien Sanglard std::array<PendingFrameSlot, kMaxUnackedFrames> pending_frames_{}; 272*3f982cf4SFabien Sanglard 273*3f982cf4SFabien Sanglard // A count of the number of frames in-flight (i.e., the number of active 274*3f982cf4SFabien Sanglard // entries in |pending_frames_|). 275*3f982cf4SFabien Sanglard int num_frames_in_flight_ = 0; 276*3f982cf4SFabien Sanglard 277*3f982cf4SFabien Sanglard // The ID of the last frame enqueued. 278*3f982cf4SFabien Sanglard FrameId last_enqueued_frame_id_ = FrameId::leader(); 279*3f982cf4SFabien Sanglard 280*3f982cf4SFabien Sanglard // Indicates that all of the packets for all frames up to and including this 281*3f982cf4SFabien Sanglard // FrameId have been successfully received (or otherwise do not need to be 282*3f982cf4SFabien Sanglard // re-transmitted). 283*3f982cf4SFabien Sanglard FrameId checkpoint_frame_id_ = FrameId::leader(); 284*3f982cf4SFabien Sanglard 285*3f982cf4SFabien Sanglard // The ID of the latest frame the Receiver seems to be aware of. 286*3f982cf4SFabien Sanglard FrameId latest_expected_frame_id_ = FrameId::leader(); 287*3f982cf4SFabien Sanglard 288*3f982cf4SFabien Sanglard // The target playout delay for the last-enqueued frame. This is auto-updated 289*3f982cf4SFabien Sanglard // when a frame is enqueued that changes the delay. 290*3f982cf4SFabien Sanglard std::chrono::milliseconds target_playout_delay_; 291*3f982cf4SFabien Sanglard FrameId playout_delay_change_at_frame_id_ = FrameId::first(); 292*3f982cf4SFabien Sanglard 293*3f982cf4SFabien Sanglard // The exact arrival time of the last RTCP packet. 294*3f982cf4SFabien Sanglard Clock::time_point rtcp_packet_arrival_time_ = SenderPacketRouter::kNever; 295*3f982cf4SFabien Sanglard 296*3f982cf4SFabien Sanglard // The near-term average round trip time. This is updated with each Sender 297*3f982cf4SFabien Sanglard // Report → Receiver Report round trip. This is initially zero, indicating the 298*3f982cf4SFabien Sanglard // round trip time has not been measured yet. 299*3f982cf4SFabien Sanglard Clock::duration round_trip_time_{0}; 300*3f982cf4SFabien Sanglard 301*3f982cf4SFabien Sanglard // Maintain current stats in a Sender Report that is ready for sending at any 302*3f982cf4SFabien Sanglard // time. This includes up-to-date lip-sync information, and packet and byte 303*3f982cf4SFabien Sanglard // count stats. 304*3f982cf4SFabien Sanglard RtcpSenderReport pending_sender_report_; 305*3f982cf4SFabien Sanglard 306*3f982cf4SFabien Sanglard // These are used to determine whether a key frame needs to be sent to the 307*3f982cf4SFabien Sanglard // Receiver. When the Receiver provides a picture loss notification, the 308*3f982cf4SFabien Sanglard // current checkpoint frame ID is stored in |picture_lost_at_frame_id_|. Then, 309*3f982cf4SFabien Sanglard // while |last_enqueued_key_frame_id_| is less than or equal to 310*3f982cf4SFabien Sanglard // |picture_lost_at_frame_id_|, the Sender knows it still needs to send a key 311*3f982cf4SFabien Sanglard // frame to resolve the picture loss condition. In all other cases, the 312*3f982cf4SFabien Sanglard // Receiver is either in a good state or is in the process of receiving the 313*3f982cf4SFabien Sanglard // key frame that will make that happen. 314*3f982cf4SFabien Sanglard FrameId picture_lost_at_frame_id_ = FrameId::leader(); 315*3f982cf4SFabien Sanglard FrameId last_enqueued_key_frame_id_ = FrameId::leader(); 316*3f982cf4SFabien Sanglard 317*3f982cf4SFabien Sanglard // The current observer (optional). 318*3f982cf4SFabien Sanglard Observer* observer_ = nullptr; 319*3f982cf4SFabien Sanglard }; 320*3f982cf4SFabien Sanglard 321*3f982cf4SFabien Sanglard } // namespace cast 322*3f982cf4SFabien Sanglard } // namespace openscreen 323*3f982cf4SFabien Sanglard 324*3f982cf4SFabien Sanglard #endif // CAST_STREAMING_SENDER_H_ 325