blob: 21f290f9a49ac60011fc30e87286b3b9c36b6012 [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.
#ifndef MEDIA_REMOTING_COURIER_RENDERER_H_
#define MEDIA_REMOTING_COURIER_RENDERER_H_
#include <memory>
#include <tuple>
#include <utility>
#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
#include "media/base/pipeline_status.h"
#include "media/base/renderer.h"
#include "media/mojo/mojom/remoting.mojom.h"
#include "media/remoting/metrics.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/openscreen/src/cast/streaming/remoting.pb.h"
#include "third_party/openscreen/src/cast/streaming/rpc_messenger.h"
#include "third_party/openscreen/src/util/weak_ptr.h"
namespace media {
class RendererClient;
class VideoRendererSink;
namespace remoting {
class DemuxerStreamAdapter;
class RendererController;
// A media::Renderer implementation that proxies all operations to a remote
// renderer via RPCs. The CourierRenderer is instantiated by
// AdaptiveRendererFactory when media remoting is meant to take place.
class CourierRenderer final : public Renderer {
public:
// The whole class except for constructor and GetMediaTime() runs on
// |media_task_runner|. The constructor and GetMediaTime() run on render main
// thread.
CourierRenderer(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
const base::WeakPtr<RendererController>& controller,
VideoRendererSink* video_renderer_sink);
CourierRenderer(const CourierRenderer&) = delete;
CourierRenderer& operator=(const CourierRenderer&) = delete;
~CourierRenderer() final;
private:
// Callback when attempting to establish data pipe. The function is set to
// static in order to post task to media thread in order to avoid threading
// race condition.
static void OnDataPipeCreatedOnMainThread(
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
base::WeakPtr<CourierRenderer> self,
openscreen::WeakPtr<openscreen::cast::RpcMessenger> rpc_messenger,
mojo::PendingRemote<mojom::RemotingDataStreamSender> audio,
mojo::PendingRemote<mojom::RemotingDataStreamSender> video,
mojo::ScopedDataPipeProducerHandle audio_handle,
mojo::ScopedDataPipeProducerHandle video_handle);
// Callback function when RPC message is received. The function is set to
// static in order to post task to media thread in order to avoid threading
// race condition.
static void OnMessageReceivedOnMainThread(
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
base::WeakPtr<CourierRenderer> self,
std::unique_ptr<openscreen::cast::RpcMessage> message);
public:
// media::Renderer implementation.
void Initialize(MediaResource* media_resource,
RendererClient* client,
PipelineStatusCallback init_cb) final;
void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) final;
void Flush(base::OnceClosure flush_cb) final;
void StartPlayingFrom(base::TimeDelta time) final;
void SetPlaybackRate(double playback_rate) final;
void SetVolume(float volume) final;
base::TimeDelta GetMediaTime() final;
private:
friend class CourierRendererTest;
enum State {
STATE_UNINITIALIZED,
STATE_CREATE_PIPE,
STATE_ACQUIRING,
STATE_INITIALIZING,
STATE_FLUSHING,
STATE_PLAYING,
STATE_ERROR
};
// Callback when attempting to establish data pipe. Runs on media thread only.
void OnDataPipeCreated(
mojo::PendingRemote<mojom::RemotingDataStreamSender> audio,
mojo::PendingRemote<mojom::RemotingDataStreamSender> video,
mojo::ScopedDataPipeProducerHandle audio_handle,
mojo::ScopedDataPipeProducerHandle video_handle,
int audio_rpc_handle,
int video_rpc_handle);
// Callback function when RPC message is received. Runs on media thread only.
void OnReceivedRpc(std::unique_ptr<openscreen::cast::RpcMessage> message);
// Function to post task to main thread in order to send RPC message.
void SendRpcToRemote(std::unique_ptr<openscreen::cast::RpcMessage> message);
// Functions when RPC message is received.
void AcquireRendererDone(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void InitializeCallback(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void FlushUntilCallback();
void OnTimeUpdate(std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnBufferingStateChange(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnAudioConfigChange(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnVideoConfigChange(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnVideoNaturalSizeChange(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnVideoOpacityChange(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnStatisticsUpdate(
std::unique_ptr<openscreen::cast::RpcMessage> message);
// Called when |current_media_time_| is updated.
void OnMediaTimeUpdated();
// Called to update the |video_stats_queue_|.
void UpdateVideoStatsQueue(int video_frames_decoded,
int video_frames_dropped);
// Called to clear all recent measurements history and schedule resuming after
// a stabilization period elapses.
void ResetMeasurements();
// Called when a fatal runtime error occurs. |stop_trigger| is the error code
// handed to the RendererController.
void OnFatalError(StopTrigger stop_trigger);
// Called periodically to measure the data flows from the
// DemuxerStreamAdapters and record this information in the metrics.
void MeasureAndRecordDataRates();
// Helper to check whether is waiting for data from the Demuxers while
// receiver is waiting for buffering. If yes, remoting will be continued even
// though the playback might be delayed or paused.
bool IsWaitingForDataFromDemuxers() const;
// Helper to deregister the renderer from the RPC messenger.
void DeregisterFromRpcMessaging();
State state_;
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
// Current renderer playback time information.
base::TimeDelta current_media_time_;
base::TimeDelta current_max_time_;
// Both |current_media_time_| and |current_max_time_| should be protected by
// lock because it can be accessed from both media and render main thread.
base::Lock time_lock_;
MediaResource* media_resource_;
RendererClient* client_;
std::unique_ptr<DemuxerStreamAdapter> audio_demuxer_stream_adapter_;
std::unique_ptr<DemuxerStreamAdapter> video_demuxer_stream_adapter_;
// Component to establish mojo remoting service on browser process.
const base::WeakPtr<RendererController> controller_;
// Broker class to process incoming and outgoing RPC messages.
// Only accessed on |main_task_runner_|. NOTE: the messenger is wrapped
// in an |openscreen::WeakPtr| instead of |base|'s implementation due to
// it being defined in the third_party/openscreen repository.
const openscreen::WeakPtr<openscreen::cast::RpcMessenger> rpc_messenger_;
// RPC handle value for CourierRenderer component.
const int rpc_handle_;
// RPC handle value for render on receiver endpoint.
int remote_renderer_handle_;
// Callbacks.
PipelineStatusCallback init_workflow_done_callback_;
base::OnceClosure flush_cb_;
VideoRendererSink* const video_renderer_sink_; // Outlives this class.
// Current playback rate.
double playback_rate_ = 0;
// Current volume.
float volume_ = 1.0f;
// Ignores updates until this time.
base::TimeTicks ignore_updates_until_time_;
// Indicates whether stats has been updated.
bool stats_updated_ = false;
// Stores all |current_media_time_| and the local time when updated in the
// moving time window. This is used to check whether the playback duration
// matches the update duration in the window.
base::circular_deque<std::pair<base::TimeTicks, base::TimeDelta>>
media_time_queue_;
// Stores all updates on the number of video frames decoded/dropped, and the
// local time when updated in the moving time window. This is used to check
// whether too many video frames were dropped.
base::circular_deque<std::tuple<base::TimeTicks, int, int>>
video_stats_queue_;
// The total number of frames decoded/dropped in the time window.
int sum_video_frames_decoded_ = 0;
int sum_video_frames_dropped_ = 0;
// Records the number of consecutive times that remoting playback was delayed.
int times_playback_delayed_ = 0;
// Records events and measurements of interest.
RendererMetricsRecorder metrics_recorder_;
const base::TickClock* clock_;
// A timer that polls the DemuxerStreamAdapters periodically to measure
// the data flow rates for metrics.
base::RepeatingTimer data_flow_poll_timer_;
// Indicates whether is waiting for data from the Demuxers while receiver
// reported buffer underflow.
bool receiver_is_blocked_on_local_demuxers_ = true;
base::WeakPtrFactory<CourierRenderer> weak_factory_{this};
};
} // namespace remoting
} // namespace media
#endif // MEDIA_REMOTING_COURIER_RENDERER_H_