blob: 4e2ae1af491e60404b265c922d6129cc91b688e8 [file] [log] [blame]
// 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.
#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 cast {
// The callback that is used to send frame events to renderer process for
// logging purpose.
using FrameEventCallback =
base::Callback<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 {
// |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,
const base::Closure& error_callback);
// 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_;
base::TickClock* clock_;
// Callback that is run to notify when a fatal error occurs.
base::Closure 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_;
} // namespace cast