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/public/cpp/application/connect.h"
15 #include "mojo/public/cpp/bindings/interface_impl.h"
16 #include "mojo/public/interfaces/application/service_provider.mojom.h"
20 MojoRendererImpl::MojoRendererImpl(
21 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
22 mojo::ServiceProvider
* audio_renderer_provider
)
23 : task_runner_(task_runner
),
25 DVLOG(1) << __FUNCTION__
;
26 // For now we only support audio and there must be a provider.
27 DCHECK(audio_renderer_provider
);
28 mojo::ConnectToService(audio_renderer_provider
, &remote_audio_renderer_
);
29 remote_audio_renderer_
.set_client(this);
32 MojoRendererImpl::~MojoRendererImpl() {
33 DVLOG(1) << __FUNCTION__
;
34 DCHECK(task_runner_
->BelongsToCurrentThread());
35 // Connection to |remote_audio_renderer_| will error-out here.
38 void MojoRendererImpl::Initialize(
39 DemuxerStreamProvider
* demuxer_stream_provider
,
40 const base::Closure
& init_cb
,
41 const StatisticsCB
& statistics_cb
,
42 const base::Closure
& ended_cb
,
43 const PipelineStatusCB
& error_cb
,
44 const BufferingStateCB
& buffering_state_cb
) {
45 DVLOG(1) << __FUNCTION__
;
46 DCHECK(task_runner_
->BelongsToCurrentThread());
47 DCHECK(demuxer_stream_provider
);
49 demuxer_stream_provider_
= demuxer_stream_provider
;
50 // |init_cb| can be called on other thread.
54 buffering_state_cb_
= buffering_state_cb
;
56 // Create audio and video mojo::DemuxerStream and bind its lifetime to the
58 DemuxerStream
* const audio
=
59 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
60 DemuxerStream
* const video
=
61 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
63 mojo::DemuxerStreamPtr audio_stream
;
65 mojo::BindToProxy(new MojoDemuxerStreamImpl(audio
), &audio_stream
);
67 mojo::DemuxerStreamPtr video_stream
;
69 mojo::BindToProxy(new MojoDemuxerStreamImpl(video
), &video_stream
);
71 remote_audio_renderer_
->Initialize(
74 BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized
,
75 weak_factory_
.GetWeakPtr())));
78 void MojoRendererImpl::Flush(const base::Closure
& flush_cb
) {
79 DVLOG(2) << __FUNCTION__
;
80 DCHECK(task_runner_
->BelongsToCurrentThread());
81 remote_audio_renderer_
->Flush(flush_cb
);
84 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time
) {
85 DVLOG(2) << __FUNCTION__
;
86 DCHECK(task_runner_
->BelongsToCurrentThread());
89 base::AutoLock
auto_lock(lock_
);
93 remote_audio_renderer_
->StartPlayingFrom(time
.InMicroseconds());
96 void MojoRendererImpl::SetPlaybackRate(float playback_rate
) {
97 DVLOG(2) << __FUNCTION__
;
98 DCHECK(task_runner_
->BelongsToCurrentThread());
99 remote_audio_renderer_
->SetPlaybackRate(playback_rate
);
102 void MojoRendererImpl::SetVolume(float volume
) {
103 DVLOG(2) << __FUNCTION__
;
104 DCHECK(task_runner_
->BelongsToCurrentThread());
105 remote_audio_renderer_
->SetVolume(volume
);
108 base::TimeDelta
MojoRendererImpl::GetMediaTime() {
109 base::AutoLock
auto_lock(lock_
);
110 DVLOG(3) << __FUNCTION__
<< ": " << time_
.InMilliseconds() << " ms";
114 bool MojoRendererImpl::HasAudio() {
115 DVLOG(1) << __FUNCTION__
;
116 DCHECK(task_runner_
->BelongsToCurrentThread());
117 DCHECK(remote_audio_renderer_
.get()); // We always bind the renderer.
118 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
);
121 bool MojoRendererImpl::HasVideo() {
122 DVLOG(1) << __FUNCTION__
;
123 DCHECK(task_runner_
->BelongsToCurrentThread());
124 return !!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
);
127 void MojoRendererImpl::SetCdm(MediaKeys
* cdm
) {
128 DVLOG(1) << __FUNCTION__
;
129 DCHECK(task_runner_
->BelongsToCurrentThread());
133 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec
, int64_t max_time_usec
) {
134 DVLOG(3) << __FUNCTION__
<< ": " << time_usec
<< ", " << max_time_usec
;
136 if (!task_runner_
->BelongsToCurrentThread()) {
137 task_runner_
->PostTask(FROM_HERE
,
138 base::Bind(&MojoRendererImpl::OnTimeUpdate
,
139 weak_factory_
.GetWeakPtr(),
145 base::AutoLock
auto_lock(lock_
);
146 time_
= base::TimeDelta::FromMicroseconds(time_usec
);
147 max_time_
= base::TimeDelta::FromMicroseconds(max_time_usec
);
150 void MojoRendererImpl::OnBufferingStateChange(mojo::BufferingState state
) {
151 DVLOG(2) << __FUNCTION__
;
153 if (!task_runner_
->BelongsToCurrentThread()) {
154 task_runner_
->PostTask(FROM_HERE
,
155 base::Bind(&MojoRendererImpl::OnBufferingStateChange
,
156 weak_factory_
.GetWeakPtr(),
161 buffering_state_cb_
.Run(static_cast<media::BufferingState
>(state
));
164 void MojoRendererImpl::OnEnded() {
165 DVLOG(1) << __FUNCTION__
;
167 if (!task_runner_
->BelongsToCurrentThread()) {
168 task_runner_
->PostTask(
170 base::Bind(&MojoRendererImpl::OnEnded
, weak_factory_
.GetWeakPtr()));
174 base::ResetAndReturn(&ended_cb_
).Run();
177 void MojoRendererImpl::OnError() {
178 DVLOG(1) << __FUNCTION__
;
180 if (!task_runner_
->BelongsToCurrentThread()) {
181 task_runner_
->PostTask(
183 base::Bind(&MojoRendererImpl::OnError
, weak_factory_
.GetWeakPtr()));
187 // TODO(tim): Should we plumb error code from remote renderer?
188 // http://crbug.com/410451.
189 if (init_cb_
.is_null()) // We have initialized already.
190 error_cb_
.Run(PIPELINE_ERROR_DECODE
);
192 error_cb_
.Run(PIPELINE_ERROR_COULD_NOT_RENDER
);
195 void MojoRendererImpl::OnInitialized() {
196 DVLOG(1) << __FUNCTION__
;
197 DCHECK(task_runner_
->BelongsToCurrentThread());
198 DCHECK(!init_cb_
.is_null());
200 base::ResetAndReturn(&init_cb_
).Run();