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_service.h"
8 #include "base/callback_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/base/audio_decoder.h"
11 #include "media/base/audio_renderer.h"
12 #include "media/base/audio_renderer_sink.h"
13 #include "media/base/cdm_context.h"
14 #include "media/base/decryptor.h"
15 #include "media/base/media_log.h"
16 #include "media/base/renderer_factory.h"
17 #include "media/base/video_renderer.h"
18 #include "media/base/video_renderer_sink.h"
19 #include "media/mojo/services/demuxer_stream_provider_shim.h"
20 #include "media/mojo/services/mojo_media_client.h"
21 #include "media/renderers/audio_renderer_impl.h"
22 #include "media/renderers/renderer_impl.h"
23 #include "media/renderers/video_renderer_impl.h"
27 // Time interval to update media time.
28 const int kTimeUpdateIntervalMs
= 50;
30 MojoRendererService::MojoRendererService(
31 base::WeakPtr
<CdmContextProvider
> cdm_context_provider
,
32 RendererFactory
* renderer_factory
,
33 const scoped_refptr
<MediaLog
>& media_log
,
34 mojo::InterfaceRequest
<interfaces::Renderer
> request
)
35 : binding_(this, request
.Pass()),
36 cdm_context_provider_(cdm_context_provider
),
37 state_(STATE_UNINITIALIZED
),
38 last_media_time_usec_(0),
40 weak_this_
= weak_factory_
.GetWeakPtr();
41 DVLOG(1) << __FUNCTION__
;
43 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner(
44 base::MessageLoop::current()->task_runner());
45 MojoMediaClient
* mojo_media_client
= MojoMediaClient::Get();
46 audio_renderer_sink_
= mojo_media_client
->CreateAudioRendererSink();
47 video_renderer_sink_
=
48 mojo_media_client
->CreateVideoRendererSink(task_runner
);
51 if (renderer_factory
) {
52 renderer_
= renderer_factory
->CreateRenderer(task_runner
, task_runner
,
53 audio_renderer_sink_
.get(),
54 video_renderer_sink_
.get());
56 scoped_ptr
<AudioRenderer
> audio_renderer(new AudioRendererImpl(
57 task_runner
, audio_renderer_sink_
.get(),
58 mojo_media_client
->CreateAudioDecoders(task_runner
, media_log
).Pass(),
59 mojo_media_client
->GetAudioHardwareConfig(), media_log
));
60 scoped_ptr
<VideoRenderer
> video_renderer(new VideoRendererImpl(
61 task_runner
, task_runner
, video_renderer_sink_
.get(),
62 mojo_media_client
->CreateVideoDecoders(task_runner
, media_log
).Pass(),
63 true, nullptr, media_log
));
64 renderer_
.reset(new RendererImpl(task_runner
, audio_renderer
.Pass(),
65 video_renderer
.Pass()));
69 MojoRendererService::~MojoRendererService() {
72 void MojoRendererService::Initialize(
73 interfaces::RendererClientPtr client
,
74 interfaces::DemuxerStreamPtr audio
,
75 interfaces::DemuxerStreamPtr video
,
76 const mojo::Callback
<void(bool)>& callback
) {
77 DVLOG(1) << __FUNCTION__
;
78 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
79 client_
= client
.Pass();
80 state_
= STATE_INITIALIZING
;
81 stream_provider_
.reset(new DemuxerStreamProviderShim(
84 base::Bind(&MojoRendererService::OnStreamReady
, weak_this_
, callback
)));
87 void MojoRendererService::Flush(const mojo::Closure
& callback
) {
88 DVLOG(2) << __FUNCTION__
;
89 DCHECK_EQ(state_
, STATE_PLAYING
);
91 state_
= STATE_FLUSHING
;
92 CancelPeriodicMediaTimeUpdates();
94 base::Bind(&MojoRendererService::OnFlushCompleted
, weak_this_
, callback
));
97 void MojoRendererService::StartPlayingFrom(int64_t time_delta_usec
) {
98 DVLOG(2) << __FUNCTION__
<< ": " << time_delta_usec
;
99 renderer_
->StartPlayingFrom(
100 base::TimeDelta::FromMicroseconds(time_delta_usec
));
101 SchedulePeriodicMediaTimeUpdates();
104 void MojoRendererService::SetPlaybackRate(double playback_rate
) {
105 DVLOG(2) << __FUNCTION__
<< ": " << playback_rate
;
106 DCHECK_EQ(state_
, STATE_PLAYING
);
107 renderer_
->SetPlaybackRate(playback_rate
);
110 void MojoRendererService::SetVolume(float volume
) {
111 renderer_
->SetVolume(volume
);
114 void MojoRendererService::SetCdm(int32_t cdm_id
,
115 const mojo::Callback
<void(bool)>& callback
) {
116 if (!cdm_context_provider_
) {
117 LOG(ERROR
) << "CDM context provider not available.";
122 CdmContext
* cdm_context
= cdm_context_provider_
->GetCdmContext(cdm_id
);
124 LOG(ERROR
) << "CDM context not found: " << cdm_id
;
129 renderer_
->SetCdm(cdm_context
, base::Bind(&MojoRendererService::OnCdmAttached
,
130 weak_this_
, callback
));
133 void MojoRendererService::OnStreamReady(
134 const mojo::Callback
<void(bool)>& callback
) {
135 DCHECK_EQ(state_
, STATE_INITIALIZING
);
137 renderer_
->Initialize(
138 stream_provider_
.get(),
140 &MojoRendererService::OnRendererInitializeDone
, weak_this_
, callback
),
141 base::Bind(&MojoRendererService::OnUpdateStatistics
, weak_this_
),
142 base::Bind(&MojoRendererService::OnBufferingStateChanged
, weak_this_
),
143 base::Bind(&MojoRendererService::OnRendererEnded
, weak_this_
),
144 base::Bind(&MojoRendererService::OnError
, weak_this_
),
145 base::Bind(base::DoNothing
));
148 void MojoRendererService::OnRendererInitializeDone(
149 const mojo::Callback
<void(bool)>& callback
,
150 PipelineStatus status
) {
151 DVLOG(1) << __FUNCTION__
;
152 DCHECK_EQ(state_
, STATE_INITIALIZING
);
154 if (status
!= PIPELINE_OK
) {
155 state_
= STATE_ERROR
;
160 state_
= STATE_PLAYING
;
164 void MojoRendererService::OnUpdateStatistics(const PipelineStatistics
& stats
) {
167 void MojoRendererService::UpdateMediaTime(bool force
) {
168 const uint64_t media_time
= renderer_
->GetMediaTime().InMicroseconds();
169 if (!force
&& media_time
== last_media_time_usec_
)
172 client_
->OnTimeUpdate(media_time
, media_time
);
173 last_media_time_usec_
= media_time
;
176 void MojoRendererService::CancelPeriodicMediaTimeUpdates() {
177 DVLOG(2) << __FUNCTION__
;
178 UpdateMediaTime(false);
179 time_update_timer_
.Stop();
182 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() {
183 DVLOG(2) << __FUNCTION__
;
184 UpdateMediaTime(true);
185 time_update_timer_
.Start(
187 base::TimeDelta::FromMilliseconds(kTimeUpdateIntervalMs
),
188 base::Bind(&MojoRendererService::UpdateMediaTime
, weak_this_
, false));
191 void MojoRendererService::OnBufferingStateChanged(
192 BufferingState new_buffering_state
) {
193 DVLOG(2) << __FUNCTION__
<< "(" << new_buffering_state
<< ")";
194 client_
->OnBufferingStateChange(
195 static_cast<interfaces::BufferingState
>(new_buffering_state
));
198 void MojoRendererService::OnRendererEnded() {
199 DVLOG(1) << __FUNCTION__
;
200 CancelPeriodicMediaTimeUpdates();
204 void MojoRendererService::OnError(PipelineStatus error
) {
205 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
206 state_
= STATE_ERROR
;
210 void MojoRendererService::OnFlushCompleted(const mojo::Closure
& callback
) {
211 DVLOG(1) << __FUNCTION__
;
212 DCHECK_EQ(state_
, STATE_FLUSHING
);
213 state_
= STATE_PLAYING
;
217 void MojoRendererService::OnCdmAttached(
218 const mojo::Callback
<void(bool)>& callback
,
220 DVLOG(1) << __FUNCTION__
<< "(" << success
<< ")";
221 callback
.Run(success
);