1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/mojo_renderer_impl.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "media/base/bind_to_current_loop.h"
12 #include "media/base/demuxer_stream_provider.h"
13 #include "media/mojo/services/mojo_demuxer_stream_impl.h"
14 #include "mojo/application/public/cpp/connect.h"
15 #include "mojo/application/public/interfaces/service_provider.mojom.h"
19 MojoRendererImpl::MojoRendererImpl(
20 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
21 interfaces::RendererPtr remote_renderer
)
22 : task_runner_(task_runner
),
23 remote_renderer_(remote_renderer
.Pass()),
26 DVLOG(1) << __FUNCTION__
;
29 MojoRendererImpl::~MojoRendererImpl() {
30 DVLOG(1) << __FUNCTION__
;
31 DCHECK(task_runner_
->BelongsToCurrentThread());
32 // Connection to |remote_renderer_| will error-out here.
35 // TODO(xhwang): Support |waiting_for_decryption_key_cb| if needed.
36 void MojoRendererImpl::Initialize(
37 DemuxerStreamProvider
* demuxer_stream_provider
,
38 const PipelineStatusCB
& init_cb
,
39 const StatisticsCB
& statistics_cb
,
40 const BufferingStateCB
& buffering_state_cb
,
41 const base::Closure
& ended_cb
,
42 const PipelineStatusCB
& error_cb
,
43 const base::Closure
& /* waiting_for_decryption_key_cb */) {
44 DVLOG(1) << __FUNCTION__
;
45 DCHECK(task_runner_
->BelongsToCurrentThread());
46 DCHECK(demuxer_stream_provider
);
48 demuxer_stream_provider_
= demuxer_stream_provider
;
52 buffering_state_cb_
= buffering_state_cb
;
54 // Create audio and video interfaces::DemuxerStream and bind its lifetime to
56 DemuxerStream
* const audio
=
57 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
58 DemuxerStream
* const video
=
59 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
61 interfaces::DemuxerStreamPtr audio_stream
;
63 new MojoDemuxerStreamImpl(audio
, GetProxy(&audio_stream
));
65 interfaces::DemuxerStreamPtr video_stream
;
67 new MojoDemuxerStreamImpl(video
, GetProxy(&video_stream
));
69 interfaces::RendererClientPtr client_ptr
;
70 binding_
.Bind(GetProxy(&client_ptr
));
71 remote_renderer_
->Initialize(
72 client_ptr
.Pass(), audio_stream
.Pass(), video_stream
.Pass(),
73 BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized
,
74 weak_factory_
.GetWeakPtr())));
77 void MojoRendererImpl::SetCdm(CdmContext
* cdm_context
,
78 const CdmAttachedCB
& cdm_attached_cb
) {
79 DVLOG(1) << __FUNCTION__
;
80 DCHECK(task_runner_
->BelongsToCurrentThread());
82 int32_t cdm_id
= cdm_context
->GetCdmId();
83 if (cdm_id
== CdmContext::kInvalidCdmId
) {
84 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID "
86 cdm_attached_cb
.Run(false);
90 remote_renderer_
->SetCdm(cdm_id
, cdm_attached_cb
);
93 void MojoRendererImpl::Flush(const base::Closure
& flush_cb
) {
94 DVLOG(2) << __FUNCTION__
;
95 DCHECK(task_runner_
->BelongsToCurrentThread());
96 remote_renderer_
->Flush(flush_cb
);
99 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time
) {
100 DVLOG(2) << __FUNCTION__
;
101 DCHECK(task_runner_
->BelongsToCurrentThread());
104 base::AutoLock
auto_lock(lock_
);
108 remote_renderer_
->StartPlayingFrom(time
.InMicroseconds());
111 void MojoRendererImpl::SetPlaybackRate(double playback_rate
) {
112 DVLOG(2) << __FUNCTION__
;
113 DCHECK(task_runner_
->BelongsToCurrentThread());
114 remote_renderer_
->SetPlaybackRate(playback_rate
);
117 void MojoRendererImpl::SetVolume(float volume
) {
118 DVLOG(2) << __FUNCTION__
;
119 DCHECK(task_runner_
->BelongsToCurrentThread());
120 remote_renderer_
->SetVolume(volume
);
123 base::TimeDelta
MojoRendererImpl::GetMediaTime() {
124 base::AutoLock
auto_lock(lock_
);
125 DVLOG(3) << __FUNCTION__
<< ": " << time_
.InMilliseconds() << " ms";
129 bool MojoRendererImpl::HasAudio() {
130 DVLOG(1) << __FUNCTION__
;
131 DCHECK(task_runner_
->BelongsToCurrentThread());
132 DCHECK(remote_renderer_
.get()); // We always bind the renderer.
133 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
136 bool MojoRendererImpl::HasVideo() {
137 DVLOG(1) << __FUNCTION__
;
138 DCHECK(task_runner_
->BelongsToCurrentThread());
139 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
142 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec
, int64_t max_time_usec
) {
143 DVLOG(3) << __FUNCTION__
<< ": " << time_usec
<< ", " << max_time_usec
;
145 if (!task_runner_
->BelongsToCurrentThread()) {
146 task_runner_
->PostTask(FROM_HERE
,
147 base::Bind(&MojoRendererImpl::OnTimeUpdate
,
148 weak_factory_
.GetWeakPtr(),
154 base::AutoLock
auto_lock(lock_
);
155 time_
= base::TimeDelta::FromMicroseconds(time_usec
);
156 max_time_
= base::TimeDelta::FromMicroseconds(max_time_usec
);
159 void MojoRendererImpl::OnBufferingStateChange(
160 interfaces::BufferingState state
) {
161 DVLOG(2) << __FUNCTION__
;
163 if (!task_runner_
->BelongsToCurrentThread()) {
164 task_runner_
->PostTask(FROM_HERE
,
165 base::Bind(&MojoRendererImpl::OnBufferingStateChange
,
166 weak_factory_
.GetWeakPtr(),
171 buffering_state_cb_
.Run(static_cast<media::BufferingState
>(state
));
174 void MojoRendererImpl::OnEnded() {
175 DVLOG(1) << __FUNCTION__
;
177 if (!task_runner_
->BelongsToCurrentThread()) {
178 task_runner_
->PostTask(
180 base::Bind(&MojoRendererImpl::OnEnded
, weak_factory_
.GetWeakPtr()));
187 void MojoRendererImpl::OnError() {
188 DVLOG(1) << __FUNCTION__
;
189 DCHECK(init_cb_
.is_null());
191 if (!task_runner_
->BelongsToCurrentThread()) {
192 task_runner_
->PostTask(
194 base::Bind(&MojoRendererImpl::OnError
, weak_factory_
.GetWeakPtr()));
198 // TODO(tim): Should we plumb error code from remote renderer?
199 // http://crbug.com/410451.
200 error_cb_
.Run(PIPELINE_ERROR_DECODE
);
203 void MojoRendererImpl::OnInitialized(bool success
) {
204 DVLOG(1) << __FUNCTION__
;
205 DCHECK(task_runner_
->BelongsToCurrentThread());
206 DCHECK(!init_cb_
.is_null());
208 base::ResetAndReturn(&init_cb_
)
209 .Run(success
? PIPELINE_OK
: PIPELINE_ERROR_INITIALIZATION_FAILED
);