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"
16 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h"
20 MojoRendererImpl::MojoRendererImpl(
21 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
22 interfaces::MediaRendererPtr remote_media_renderer
)
23 : task_runner_(task_runner
),
24 remote_media_renderer_(remote_media_renderer
.Pass()),
27 DVLOG(1) << __FUNCTION__
;
30 MojoRendererImpl::~MojoRendererImpl() {
31 DVLOG(1) << __FUNCTION__
;
32 DCHECK(task_runner_
->BelongsToCurrentThread());
33 // Connection to |remote_media_renderer_| will error-out here.
36 // TODO(xhwang): Support |waiting_for_decryption_key_cb| if needed.
37 void MojoRendererImpl::Initialize(
38 DemuxerStreamProvider
* demuxer_stream_provider
,
39 const PipelineStatusCB
& init_cb
,
40 const StatisticsCB
& statistics_cb
,
41 const BufferingStateCB
& buffering_state_cb
,
42 const base::Closure
& ended_cb
,
43 const PipelineStatusCB
& error_cb
,
44 const base::Closure
& /* waiting_for_decryption_key_cb */) {
45 DVLOG(1) << __FUNCTION__
;
46 DCHECK(task_runner_
->BelongsToCurrentThread());
47 DCHECK(demuxer_stream_provider
);
49 demuxer_stream_provider_
= demuxer_stream_provider
;
53 buffering_state_cb_
= buffering_state_cb
;
55 // Create audio and video interfaces::DemuxerStream and bind its lifetime to
57 DemuxerStream
* const audio
=
58 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
59 DemuxerStream
* const video
=
60 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
62 interfaces::DemuxerStreamPtr audio_stream
;
64 new MojoDemuxerStreamImpl(audio
, GetProxy(&audio_stream
));
66 interfaces::DemuxerStreamPtr video_stream
;
68 new MojoDemuxerStreamImpl(video
, GetProxy(&video_stream
));
70 interfaces::MediaRendererClientPtr client_ptr
;
71 binding_
.Bind(GetProxy(&client_ptr
));
72 remote_media_renderer_
->Initialize(
76 BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized
,
77 weak_factory_
.GetWeakPtr())));
80 void MojoRendererImpl::SetCdm(CdmContext
* cdm_context
,
81 const CdmAttachedCB
& cdm_attached_cb
) {
82 DVLOG(1) << __FUNCTION__
;
83 DCHECK(task_runner_
->BelongsToCurrentThread());
85 int32_t cdm_id
= cdm_context
->GetCdmId();
86 if (cdm_id
== CdmContext::kInvalidCdmId
) {
87 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID "
89 cdm_attached_cb
.Run(false);
93 remote_media_renderer_
->SetCdm(cdm_id
, cdm_attached_cb
);
96 void MojoRendererImpl::Flush(const base::Closure
& flush_cb
) {
97 DVLOG(2) << __FUNCTION__
;
98 DCHECK(task_runner_
->BelongsToCurrentThread());
99 remote_media_renderer_
->Flush(flush_cb
);
102 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time
) {
103 DVLOG(2) << __FUNCTION__
;
104 DCHECK(task_runner_
->BelongsToCurrentThread());
107 base::AutoLock
auto_lock(lock_
);
111 remote_media_renderer_
->StartPlayingFrom(time
.InMicroseconds());
114 void MojoRendererImpl::SetPlaybackRate(double playback_rate
) {
115 DVLOG(2) << __FUNCTION__
;
116 DCHECK(task_runner_
->BelongsToCurrentThread());
117 remote_media_renderer_
->SetPlaybackRate(playback_rate
);
120 void MojoRendererImpl::SetVolume(float volume
) {
121 DVLOG(2) << __FUNCTION__
;
122 DCHECK(task_runner_
->BelongsToCurrentThread());
123 remote_media_renderer_
->SetVolume(volume
);
126 base::TimeDelta
MojoRendererImpl::GetMediaTime() {
127 base::AutoLock
auto_lock(lock_
);
128 DVLOG(3) << __FUNCTION__
<< ": " << time_
.InMilliseconds() << " ms";
132 bool MojoRendererImpl::HasAudio() {
133 DVLOG(1) << __FUNCTION__
;
134 DCHECK(task_runner_
->BelongsToCurrentThread());
135 DCHECK(remote_media_renderer_
.get()); // We always bind the renderer.
136 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
139 bool MojoRendererImpl::HasVideo() {
140 DVLOG(1) << __FUNCTION__
;
141 DCHECK(task_runner_
->BelongsToCurrentThread());
142 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
145 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec
, int64_t max_time_usec
) {
146 DVLOG(3) << __FUNCTION__
<< ": " << time_usec
<< ", " << max_time_usec
;
148 if (!task_runner_
->BelongsToCurrentThread()) {
149 task_runner_
->PostTask(FROM_HERE
,
150 base::Bind(&MojoRendererImpl::OnTimeUpdate
,
151 weak_factory_
.GetWeakPtr(),
157 base::AutoLock
auto_lock(lock_
);
158 time_
= base::TimeDelta::FromMicroseconds(time_usec
);
159 max_time_
= base::TimeDelta::FromMicroseconds(max_time_usec
);
162 void MojoRendererImpl::OnBufferingStateChange(
163 interfaces::BufferingState state
) {
164 DVLOG(2) << __FUNCTION__
;
166 if (!task_runner_
->BelongsToCurrentThread()) {
167 task_runner_
->PostTask(FROM_HERE
,
168 base::Bind(&MojoRendererImpl::OnBufferingStateChange
,
169 weak_factory_
.GetWeakPtr(),
174 buffering_state_cb_
.Run(static_cast<media::BufferingState
>(state
));
177 void MojoRendererImpl::OnEnded() {
178 DVLOG(1) << __FUNCTION__
;
180 if (!task_runner_
->BelongsToCurrentThread()) {
181 task_runner_
->PostTask(
183 base::Bind(&MojoRendererImpl::OnEnded
, weak_factory_
.GetWeakPtr()));
190 void MojoRendererImpl::OnError() {
191 DVLOG(1) << __FUNCTION__
;
192 DCHECK(init_cb_
.is_null());
194 if (!task_runner_
->BelongsToCurrentThread()) {
195 task_runner_
->PostTask(
197 base::Bind(&MojoRendererImpl::OnError
, weak_factory_
.GetWeakPtr()));
201 // TODO(tim): Should we plumb error code from remote renderer?
202 // http://crbug.com/410451.
203 error_cb_
.Run(PIPELINE_ERROR_DECODE
);
206 void MojoRendererImpl::OnInitialized(bool success
) {
207 DVLOG(1) << __FUNCTION__
;
208 DCHECK(task_runner_
->BelongsToCurrentThread());
209 DCHECK(!init_cb_
.is_null());
211 base::ResetAndReturn(&init_cb_
)
212 .Run(success
? PIPELINE_OK
: PIPELINE_ERROR_INITIALIZATION_FAILED
);