| // Copyright 2016 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 COMPONENTS_MIRRORING_BROWSER_CAST_REMOTING_SENDER_H_ |
| #define COMPONENTS_MIRRORING_BROWSER_CAST_REMOTING_SENDER_H_ |
| |
| #include "base/callback_forward.h" |
| #include "base/containers/queue.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/time/time.h" |
| #include "media/cast/cast_config.h" |
| #include "media/cast/net/cast_transport.h" |
| #include "media/cast/net/rtcp/rtcp_defines.h" |
| #include "media/mojo/interfaces/remoting.mojom.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| |
| namespace media { |
| class MojoDataPipeReader; |
| } // namespace media |
| |
| namespace mirroring { |
| |
| // The callback that is used to send frame events to renderer process for |
| // logging purpose. |
| using FrameEventCallback = |
| base::RepeatingCallback<void(const std::vector<media::cast::FrameEvent>&)>; |
| |
| // RTP sender for a single Cast Remoting RTP stream. The client calls Send() to |
| // instruct the sender to read from a Mojo data pipe and transmit the data using |
| // a CastTransport. This entire class executes on the IO BrowserThread. |
| // |
| // This class is instantiated and owned by CastTransportHostFilter in response |
| // to IPC messages from an extension process to create RTP streams for the media |
| // remoting use case. CastTransportHostFilter is also responsible for destroying |
| // the instance in response to later IPCs. |
| // |
| // The Media Router provider extension controls the entire set-up process: |
| // First, it uses the cast.streaming APIs to create remoting API streams (which |
| // instantiates one or more CastRemotingSenders). Then, it sends a message via |
| // Media Router to a CastRemotingConnector to indicate the bitstream transport |
| // is ready. Finally, CastRemotingConnector calls FindAndBind() to look-up the |
| // CastRemotingSender instances and establish the Mojo bindings and data flows. |
| class CastRemotingSender : public media::mojom::RemotingDataStreamSender { |
| public: |
| // |transport| is expected to outlive this class. |
| // |logging_flush_interval| must be greater than |base::TimeDelta()| if |cb| |
| // is not null. |
| CastRemotingSender(media::cast::CastTransport* transport, |
| const media::cast::CastTransportRtpConfig& config, |
| base::TimeDelta logging_flush_interval, |
| const FrameEventCallback& cb); |
| ~CastRemotingSender() final; |
| |
| // Look-up a CastRemotingSender instance by its |rtp_stream_id| and then bind |
| // to the given |request|. The client of the RemotingDataStreamSender will |
| // then instruct this CastRemotingSender when to read from the data |pipe| and |
| // send the data to the Cast Receiver. If the bind fails, or an error occurs |
| // reading from the data pipe during later operation, the |error_callback| is |
| // run. |
| // |
| // Threading note: This function is thread-safe, but its internal |
| // implementation runs on the IO BrowserThread. If |error_callback| is run, it |
| // will execute on the thread that called this function. |
| static void FindAndBind(int32_t rtp_stream_id, |
| mojo::ScopedDataPipeConsumerHandle pipe, |
| media::mojom::RemotingDataStreamSenderRequest request, |
| base::OnceClosure error_callback); |
| |
| private: |
| // Friend class for unit tests. |
| friend class CastRemotingSenderTest; |
| |
| class RemotingRtcpClient; |
| |
| // media::mojom::RemotingDataStreamSender implementation. SendFrame() will |
| // push callbacks onto the back of the input queue, and these may or may not |
| // be processed at a later time. It depends on whether the data pipe has data |
| // available or the CastTransport can accept more frames. CancelInFlightData() |
| // is processed immediately, and will cause all pending operations to discard |
| // data when they are processed later. |
| void SendFrame(uint32_t frame_size) final; |
| void CancelInFlightData() final; |
| |
| // Attempt to run next pending input task, popping the head of the input queue |
| // as each task succeeds. |
| void ProcessNextInputTask(); |
| |
| // These are called via callbacks run from the input queue. |
| // Consumes a frame of |size| from the associated Mojo data pipe. |
| void ReadFrame(uint32_t size); |
| // Sends out the frame to the receiver over network. |
| void TrySendFrame(); |
| |
| // Called when a frame is completely read/discarded from the data pipe. |
| void OnFrameRead(bool success); |
| |
| // Called when an input task completes. |
| void OnInputTaskComplete(); |
| |
| // These are called to deliver RTCP feedback from the receiver. |
| void OnReceivedCastMessage(const media::cast::RtcpCastMessage& cast_feedback); |
| void OnReceivedRtt(base::TimeDelta round_trip_time); |
| |
| // Returns the number of frames that were sent to the CastTransport, but not |
| // yet acknowledged. This is always a high watermark estimate, as frames may |
| // have been acknowledged out-of-order. Also, this does not account for any |
| // frames queued-up in input pipeline (i.e., in the Mojo data pipe, nor in |
| // |next_frame_data_|). |
| int NumberOfFramesInFlight() const; |
| |
| // Schedule and execute periodic checks for re-sending packets. If no |
| // acknowledgements have been received for "too long," CastRemotingSender will |
| // speculatively re-send certain packets of an unacked frame to kick-start |
| // re-transmission. This is a last resort tactic to prevent the session from |
| // getting stuck after a long outage. |
| void ScheduleNextResendCheck(); |
| void ResendCheck(); |
| void ResendForKickstart(); |
| |
| void RecordLatestFrameTimestamps(media::cast::FrameId frame_id, |
| media::cast::RtpTimeTicks rtp_timestamp); |
| media::cast::RtpTimeTicks GetRecordedRtpTimestamp( |
| media::cast::FrameId frame_id) const; |
| |
| // If |frame_event_cb_| is not null, this calls |frame_event_cb_| to |
| // periodically send the frame events to renderer process for logging. |
| void SendFrameEvents(); |
| |
| // Schedule and execute periodic sending of RTCP report to prevent keepalive |
| // timeouts on receiver side during media pause. |
| void ScheduleNextRtcpReport(); |
| void SendRtcpReport(); |
| |
| void OnPipeError(); |
| |
| // Unique identifier for the RTP stream and this CastRemotingSender. |
| const int32_t rtp_stream_id_; |
| |
| // Sends encoded frames over the configured transport (e.g., UDP). It outlives |
| // this class. |
| media::cast::CastTransport* const transport_; |
| |
| const uint32_t ssrc_; |
| |
| const bool is_audio_; |
| |
| // The interval to send frame events to renderer process for logging. When |
| // |frame_event_cb_| is not null, this must be greater than base::TimeDelta(). |
| const base::TimeDelta logging_flush_interval_; |
| |
| // The callback to send frame events to renderer process for logging. |
| const FrameEventCallback frame_event_cb_; |
| |
| const base::TickClock* clock_; |
| |
| // Callback that is run to notify when a fatal error occurs. |
| base::OnceClosure error_callback_; |
| |
| std::unique_ptr<media::MojoDataPipeReader> data_pipe_reader_; |
| |
| // Mojo binding for this instance. Implementation at the other end of the |
| // message pipe uses the RemotingDataStreamSender interface to control when |
| // this CastRemotingSender consumes from |pipe_|. |
| mojo::Binding<RemotingDataStreamSender> binding_; |
| |
| // This is the maximum delay that the sender should get ack from receiver. |
| // Otherwise, sender will call ResendForKickstart(). |
| base::TimeDelta max_ack_delay_; |
| |
| // This is "null" until the first frame is sent. Thereafter, this tracks the |
| // last time any frame was sent or re-sent. |
| base::TimeTicks last_send_time_; |
| |
| // The ID of the last frame sent. This member is invalid until |
| // |!last_send_time_.is_null()|. |
| media::cast::FrameId last_sent_frame_id_; |
| |
| // The ID of the latest (not necessarily the last) frame that has been |
| // acknowledged. This member is invalid until |!last_send_time_.is_null()|. |
| media::cast::FrameId latest_acked_frame_id_; |
| |
| // Counts the number of duplicate ACK that are being received. When this |
| // number reaches a threshold, the sender will take this as a sign that the |
| // receiver hasn't yet received the first packet of the next frame. In this |
| // case, CastRemotingSender will trigger a re-send of the next frame. |
| int duplicate_ack_counter_; |
| |
| // The most recently measured round trip time. |
| base::TimeDelta current_round_trip_time_; |
| |
| // The next frame's payload data. Populated by call to OnFrameRead() when |
| // reading succeeded. |
| std::string next_frame_data_; |
| |
| // Ring buffer to keep track of recent frame RTP timestamps. This should |
| // only be accessed through the Record/GetXX() methods. The index into this |
| // ring buffer is the lower 8 bits of the FrameId. |
| media::cast::RtpTimeTicks frame_rtp_timestamps_[256]; |
| |
| // Queue of pending input operations. |input_queue_discards_remaining_| |
| // indicates the number of operations where data should be discarded (due to |
| // CancelInFlightData()). |
| base::queue<base::RepeatingClosure> input_queue_; |
| size_t input_queue_discards_remaining_; |
| |
| // Indicates whether the |data_pipe_reader_| is processing a reading request. |
| bool is_reading_; |
| |
| // Set to true if the first frame has not yet been sent, or if a |
| // CancelInFlightData() operation just completed. This causes TrySendFrame() |
| // to mark the next frame as the start of a new sequence. |
| bool flow_restart_pending_; |
| |
| // FrameEvents pending delivery via |frame_event_cb_|. No event is added if |
| // |frame_event_cb_| is null. |
| std::vector<media::cast::FrameEvent> recent_frame_events_; |
| |
| // NOTE: Weak pointers must be invalidated before all other member variables. |
| base::WeakPtrFactory<CastRemotingSender> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CastRemotingSender); |
| }; |
| |
| } // namespace mirroring |
| |
| #endif // COMPONENTS_MIRRORING_BROWSER_CAST_REMOTING_SENDER_H_ |