1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/cast_streaming/renderer/control/playback_command_forwarding_renderer.h"
7 #include "base/memory/raw_ptr.h"
8 #include "base/notreached.h"
9 #include "base/task/bind_post_task.h"
10 #include "base/task/sequenced_task_runner.h"
12 namespace cast_streaming {
15 constexpr base::TimeDelta kTimeUpdateInterval = base::Milliseconds(250);
19 // Class responsible for receiving Renderer commands from a remote source and
20 // forwarding them to |owning_renderer| unchanged. This class exists only to
21 // avoid intersection of media::Renderer and media::mojom::Renderer methods in
22 // PlaybackCommandForwardingRenderer.
24 // NOTE: This class CANNOT be declared in an unnamed namespace or the friend
25 // declaration in PlaybackCommandForwardingRenderer will no longer function.
26 class RendererCommandForwarder : public media::mojom::Renderer {
28 // |owning_renderer| is expected to outlive this class.
29 RendererCommandForwarder(
30 PlaybackCommandForwardingRenderer* owning_renderer,
31 mojo::PendingReceiver<media::mojom::Renderer> playback_controller,
32 scoped_refptr<base::SequencedTaskRunner> task_runner)
33 : owning_renderer_(owning_renderer),
34 playback_controller_(this, std::move(playback_controller)) {
35 DCHECK(owning_renderer_);
37 playback_controller_.set_disconnect_handler(base::BindPostTask(
38 std::move(task_runner),
39 base::BindOnce(&PlaybackCommandForwardingRenderer::OnMojoDisconnect,
40 owning_renderer_->weak_factory_.GetWeakPtr())));
43 ~RendererCommandForwarder() override = default;
45 // media::mojom::Renderer overrides.
46 #if defined(TIZEN_MULTIMEDIA)
47 void EnableLowLatencyMode() override {}
48 void SetHardwareResource(
49 media::mojom::HardwareResourceConfig config,
50 media::mojom::Renderer::SetHardwareResourceCallback) override {}
51 void RequestVideoDecodedBuffer(
52 media::mojom::Renderer::RequestVideoDecodedBufferCallback cb) override {}
55 ::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
57 std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
59 media::mojom::MediaUrlParamsPtr media_url_params,
60 InitializeCallback callback) override {
61 owning_renderer_->MojoRendererInitialize(
62 std::move(client), std::move(streams), std::move(media_url_params),
66 void StartPlayingFrom(::base::TimeDelta time) override {
67 owning_renderer_->MojoRendererStartPlayingFrom(std::move(time));
70 void SetPlaybackRate(double playback_rate) override {
71 owning_renderer_->MojoRendererSetPlaybackRate(playback_rate);
74 void Flush(FlushCallback callback) override {
75 owning_renderer_->MojoRendererFlush(std::move(callback));
78 void SetVolume(float volume) override {
79 owning_renderer_->MojoRendererSetVolume(volume);
82 void SetCdm(const absl::optional<::base::UnguessableToken>& cdm_id,
83 SetCdmCallback callback) override {
84 owning_renderer_->MojoRendererSetCdm(cdm_id, std::move(callback));
87 #if BUILDFLAG(IS_TIZEN_TV)
88 void SetActiveTextTrack(int, bool) override {}
89 void SetActiveAudioTrack(int) override {}
90 void SetActiveVideoTrack(int) override {}
91 void SetPreferTextLanguage(const std::string&) override {}
95 const raw_ptr<PlaybackCommandForwardingRenderer, ExperimentalRenderer>
97 mojo::Receiver<media::mojom::Renderer> playback_controller_;
100 PlaybackCommandForwardingRenderer::PlaybackCommandForwardingRenderer(
101 std::unique_ptr<media::Renderer> renderer,
102 scoped_refptr<base::SequencedTaskRunner> task_runner,
103 mojo::PendingReceiver<media::mojom::Renderer> pending_renderer_controls)
104 : real_renderer_(std::move(renderer)),
105 pending_renderer_controls_(std::move(pending_renderer_controls)),
106 task_runner_(std::move(task_runner)),
107 weak_factory_(this) {
108 DCHECK(real_renderer_);
109 DCHECK(pending_renderer_controls_);
110 InitializeSendTimestampUpdateCaller();
113 PlaybackCommandForwardingRenderer::~PlaybackCommandForwardingRenderer() =
116 void PlaybackCommandForwardingRenderer::Initialize(
117 media::MediaResource* media_resource,
118 media::RendererClient* client,
119 media::PipelineStatusCallback init_cb) {
122 upstream_renderer_client_ = client;
123 init_cb_ = std::move(init_cb);
124 real_renderer_->Initialize(
125 media_resource, this,
127 task_runner_, base::BindOnce(&PlaybackCommandForwardingRenderer::
128 OnRealRendererInitializationComplete,
129 weak_factory_.GetWeakPtr())));
132 void PlaybackCommandForwardingRenderer::SetCdm(media::CdmContext* cdm_context,
133 CdmAttachedCB cdm_attached_cb) {
134 // CDM should not be set for current mirroring use cases.
138 void PlaybackCommandForwardingRenderer::SetLatencyHint(
139 absl::optional<base::TimeDelta> latency_hint) {
140 // Not relevant for current mirroring use cases.
143 void PlaybackCommandForwardingRenderer::Flush(base::OnceClosure flush_cb) {}
145 void PlaybackCommandForwardingRenderer::StartPlayingFrom(base::TimeDelta time) {
146 DCHECK(task_runner_->RunsTasksInCurrentSequence());
149 void PlaybackCommandForwardingRenderer::SetPlaybackRate(double playback_rate) {
150 DCHECK(task_runner_->RunsTasksInCurrentSequence());
153 void PlaybackCommandForwardingRenderer::SetVolume(float volume) {}
155 base::TimeDelta PlaybackCommandForwardingRenderer::GetMediaTime() {
156 return real_renderer_ ? real_renderer_->GetMediaTime() : base::TimeDelta();
159 media::RendererType PlaybackCommandForwardingRenderer::GetRendererType() {
160 return media::RendererType::kCastStreaming;
163 void PlaybackCommandForwardingRenderer::OnRealRendererInitializationComplete(
164 media::PipelineStatus status) {
166 DCHECK(!playback_controller_);
168 playback_controller_ = std::make_unique<RendererCommandForwarder>(
169 this, std::move(pending_renderer_controls_), task_runner_);
171 std::move(init_cb_).Run(status);
174 // NOTE: The mojo pipe CANNOT be bound to task runner |task_runner_| - this will
175 // result in runtime errors on the release branch due to an outdated mojo
176 // implementation. Calls must instead be bounced to the correct task runner in
177 // each receiver method.
178 // TODO(b/205307190): Bind the mojo pipe to the task runner directly.
179 void PlaybackCommandForwardingRenderer::MojoRendererInitialize(
180 ::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
182 std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
184 media::mojom::MediaUrlParamsPtr media_url_params,
185 media::mojom::Renderer::InitializeCallback callback) {
186 DCHECK(!media_url_params);
189 // NOTE: To maintain existing functionality, and ensure mirroring continues
190 // working as currently written with or without this Renderer, the mirroring
191 // data stream is provided through the standard Initialize() call, not passed
192 // over the mojo pipe here
193 DCHECK(!streams || streams.value().empty());
195 if (!task_runner_->RunsTasksInCurrentSequence()) {
196 task_runner_->PostTask(
199 &PlaybackCommandForwardingRenderer::MojoRendererInitialize,
200 weak_factory_.GetWeakPtr(), std::move(client), std::move(streams),
201 std::move(media_url_params), std::move(callback)));
205 remote_renderer_client_.Bind(std::move(client));
207 // |playback_controller_| which forwards the call here is only set following
208 // the completion of real_renderer_->Initialize().
209 std::move(callback).Run(true);
212 void PlaybackCommandForwardingRenderer::MojoRendererFlush(
213 media::mojom::Renderer::FlushCallback callback) {
214 if (!task_runner_->RunsTasksInCurrentSequence()) {
215 task_runner_->PostTask(
217 base::BindOnce(&PlaybackCommandForwardingRenderer::MojoRendererFlush,
218 weak_factory_.GetWeakPtr(), std::move(callback)));
222 real_renderer_->Flush(std::move(callback));
225 void PlaybackCommandForwardingRenderer::MojoRendererStartPlayingFrom(
226 ::base::TimeDelta time) {
227 if (!task_runner_->RunsTasksInCurrentSequence()) {
228 task_runner_->PostTask(
231 &PlaybackCommandForwardingRenderer::MojoRendererStartPlayingFrom,
232 weak_factory_.GetWeakPtr(), time));
236 real_renderer_->StartPlayingFrom(time);
239 void PlaybackCommandForwardingRenderer::MojoRendererSetPlaybackRate(
240 double playback_rate) {
241 if (!task_runner_->RunsTasksInCurrentSequence()) {
242 task_runner_->PostTask(
245 &PlaybackCommandForwardingRenderer::MojoRendererSetPlaybackRate,
246 weak_factory_.GetWeakPtr(), playback_rate));
250 real_renderer_->SetPlaybackRate(playback_rate);
253 void PlaybackCommandForwardingRenderer::MojoRendererSetVolume(float volume) {
254 if (!task_runner_->RunsTasksInCurrentSequence()) {
255 task_runner_->PostTask(
258 &PlaybackCommandForwardingRenderer::MojoRendererSetVolume,
259 weak_factory_.GetWeakPtr(), volume));
263 real_renderer_->SetVolume(volume);
266 void PlaybackCommandForwardingRenderer::MojoRendererSetCdm(
267 const absl::optional<::base::UnguessableToken>& cdm_id,
268 media::mojom::Renderer::SetCdmCallback callback) {
269 NOTREACHED() << "Use of a CDM is not supported by the remoting protocol.";
272 void PlaybackCommandForwardingRenderer::OnError(media::PipelineStatus status) {
273 if (remote_renderer_client_) {
274 remote_renderer_client_->OnError(status);
276 if (upstream_renderer_client_) {
277 upstream_renderer_client_->OnError(status);
281 void PlaybackCommandForwardingRenderer::OnFallback(
282 media::PipelineStatus status) {}
284 void PlaybackCommandForwardingRenderer::OnEnded() {
285 DCHECK(task_runner_->RunsTasksInCurrentSequence());
287 if (remote_renderer_client_) {
288 remote_renderer_client_->OnEnded();
290 if (upstream_renderer_client_) {
291 upstream_renderer_client_->OnEnded();
295 void PlaybackCommandForwardingRenderer::OnStatisticsUpdate(
296 const media::PipelineStatistics& stats) {
297 DCHECK(task_runner_->RunsTasksInCurrentSequence());
299 if (remote_renderer_client_) {
300 remote_renderer_client_->OnStatisticsUpdate(stats);
302 if (upstream_renderer_client_) {
303 upstream_renderer_client_->OnStatisticsUpdate(stats);
307 void PlaybackCommandForwardingRenderer::OnBufferingStateChange(
308 media::BufferingState state,
309 media::BufferingStateChangeReason reason) {
310 DCHECK(task_runner_->RunsTasksInCurrentSequence());
312 if (remote_renderer_client_) {
313 remote_renderer_client_->OnBufferingStateChange(state, reason);
315 if (upstream_renderer_client_) {
316 upstream_renderer_client_->OnBufferingStateChange(state, reason);
320 void PlaybackCommandForwardingRenderer::OnWaiting(media::WaitingReason reason) {
321 DCHECK(task_runner_->RunsTasksInCurrentSequence());
323 if (remote_renderer_client_) {
324 remote_renderer_client_->OnWaiting(reason);
326 if (upstream_renderer_client_) {
327 upstream_renderer_client_->OnWaiting(reason);
331 void PlaybackCommandForwardingRenderer::OnAudioConfigChange(
332 const media::AudioDecoderConfig& config) {
333 DCHECK(task_runner_->RunsTasksInCurrentSequence());
335 if (remote_renderer_client_) {
336 remote_renderer_client_->OnAudioConfigChange(config);
338 if (upstream_renderer_client_) {
339 upstream_renderer_client_->OnAudioConfigChange(config);
343 void PlaybackCommandForwardingRenderer::OnVideoConfigChange(
344 const media::VideoDecoderConfig& config) {
345 DCHECK(task_runner_->RunsTasksInCurrentSequence());
347 if (remote_renderer_client_) {
348 remote_renderer_client_->OnVideoConfigChange(config);
350 if (upstream_renderer_client_) {
351 upstream_renderer_client_->OnVideoConfigChange(config);
355 void PlaybackCommandForwardingRenderer::OnVideoNaturalSizeChange(
356 const gfx::Size& size) {
357 DCHECK(task_runner_->RunsTasksInCurrentSequence());
359 if (remote_renderer_client_) {
360 remote_renderer_client_->OnVideoNaturalSizeChange(size);
362 if (upstream_renderer_client_) {
363 upstream_renderer_client_->OnVideoNaturalSizeChange(size);
367 void PlaybackCommandForwardingRenderer::OnVideoOpacityChange(bool opaque) {
368 DCHECK(task_runner_->RunsTasksInCurrentSequence());
370 if (remote_renderer_client_) {
371 remote_renderer_client_->OnVideoOpacityChange(opaque);
373 if (upstream_renderer_client_) {
374 upstream_renderer_client_->OnVideoOpacityChange(opaque);
378 void PlaybackCommandForwardingRenderer::OnVideoFrameRateChange(
379 absl::optional<int> fps) {
380 DCHECK(task_runner_->RunsTasksInCurrentSequence());
382 // media::mojom::RendererClient does not support this call.
383 if (upstream_renderer_client_) {
384 upstream_renderer_client_->OnVideoFrameRateChange(std::move(fps));
388 void PlaybackCommandForwardingRenderer::SendTimestampUpdate() {
389 DCHECK(task_runner_->RunsTasksInCurrentSequence());
391 if (!remote_renderer_client_) {
395 // Because |remote_renderer_client_| isn't set until |real_renderer_| is
396 // initialized, this call is well defined.
397 base::TimeDelta media_time = real_renderer_->GetMediaTime();
398 remote_renderer_client_->OnTimeUpdate(media_time, media_time,
399 base::TimeTicks::Now());
402 void PlaybackCommandForwardingRenderer::InitializeSendTimestampUpdateCaller() {
403 if (!task_runner_->RunsTasksInCurrentSequence()) {
404 task_runner_->PostTask(
405 FROM_HERE, base::BindOnce(&PlaybackCommandForwardingRenderer::
406 InitializeSendTimestampUpdateCaller,
407 weak_factory_.GetWeakPtr()));
411 send_timestamp_update_caller_.Start(
412 FROM_HERE, kTimeUpdateInterval,
416 &PlaybackCommandForwardingRenderer::SendTimestampUpdate,
417 weak_factory_.GetWeakPtr())));
420 void PlaybackCommandForwardingRenderer::OnMojoDisconnect() {
421 DCHECK(task_runner_->RunsTasksInCurrentSequence());
423 OnError(media::PIPELINE_ERROR_DISCONNECTED);
424 real_renderer_.reset();
427 } // namespace cast_streaming