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/memory/scoped_vector.h"
10 #include "base/message_loop/message_loop.h"
11 #include "media/base/audio_decoder.h"
12 #include "media/base/audio_renderer.h"
13 #include "media/base/audio_renderer_sink.h"
14 #include "media/base/cdm_context.h"
15 #include "media/base/decryptor.h"
16 #include "media/base/media_log.h"
17 #include "media/base/renderer_factory.h"
18 #include "media/base/video_renderer.h"
19 #include "media/base/video_renderer_sink.h"
20 #include "media/mojo/services/demuxer_stream_provider_shim.h"
21 #include "media/mojo/services/mojo_media_client.h"
22 #include "media/renderers/audio_renderer_impl.h"
23 #include "media/renderers/renderer_impl.h"
24 #include "media/renderers/video_renderer_impl.h"
28 // Time interval to update media time.
29 const int kTimeUpdateIntervalMs
= 50;
31 MojoRendererService::MojoRendererService(
32 base::WeakPtr
<CdmContextProvider
> cdm_context_provider
,
33 RendererFactory
* renderer_factory
,
34 const scoped_refptr
<MediaLog
>& media_log
,
35 mojo::InterfaceRequest
<interfaces::Renderer
> request
)
36 : binding_(this, request
.Pass()),
37 cdm_context_provider_(cdm_context_provider
),
38 state_(STATE_UNINITIALIZED
),
39 last_media_time_usec_(0),
41 weak_this_
= weak_factory_
.GetWeakPtr();
42 DVLOG(1) << __FUNCTION__
;
44 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner(
45 base::MessageLoop::current()->task_runner());
46 MojoMediaClient
* mojo_media_client
= MojoMediaClient::Get();
47 audio_renderer_sink_
= mojo_media_client
->CreateAudioRendererSink();
48 video_renderer_sink_
=
49 mojo_media_client
->CreateVideoRendererSink(task_runner
);
52 if (renderer_factory
) {
53 renderer_
= renderer_factory
->CreateRenderer(task_runner
, task_runner
,
54 audio_renderer_sink_
.get(),
55 video_renderer_sink_
.get());
57 scoped_ptr
<AudioRenderer
> audio_renderer(new AudioRendererImpl(
58 task_runner
, audio_renderer_sink_
.get(),
59 mojo_media_client
->CreateAudioDecoders(task_runner
, media_log
).Pass(),
60 mojo_media_client
->GetAudioHardwareConfig(), media_log
));
61 scoped_ptr
<VideoRenderer
> video_renderer(new VideoRendererImpl(
62 task_runner
, task_runner
, video_renderer_sink_
.get(),
63 mojo_media_client
->CreateVideoDecoders(task_runner
, media_log
).Pass(),
64 true, nullptr, media_log
));
65 renderer_
.reset(new RendererImpl(task_runner
, audio_renderer
.Pass(),
66 video_renderer
.Pass()));
70 MojoRendererService::~MojoRendererService() {
73 void MojoRendererService::Initialize(
74 interfaces::RendererClientPtr client
,
75 interfaces::DemuxerStreamPtr audio
,
76 interfaces::DemuxerStreamPtr video
,
77 const mojo::Callback
<void(bool)>& callback
) {
78 DVLOG(1) << __FUNCTION__
;
79 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
80 client_
= client
.Pass();
81 state_
= STATE_INITIALIZING
;
82 stream_provider_
.reset(new DemuxerStreamProviderShim(
85 base::Bind(&MojoRendererService::OnStreamReady
, weak_this_
, callback
)));
88 void MojoRendererService::Flush(const mojo::Closure
& callback
) {
89 DVLOG(2) << __FUNCTION__
;
90 DCHECK_EQ(state_
, STATE_PLAYING
);
92 state_
= STATE_FLUSHING
;
93 CancelPeriodicMediaTimeUpdates();
95 base::Bind(&MojoRendererService::OnFlushCompleted
, weak_this_
, callback
));
98 void MojoRendererService::StartPlayingFrom(int64_t time_delta_usec
) {
99 DVLOG(2) << __FUNCTION__
<< ": " << time_delta_usec
;
100 renderer_
->StartPlayingFrom(
101 base::TimeDelta::FromMicroseconds(time_delta_usec
));
102 SchedulePeriodicMediaTimeUpdates();
105 void MojoRendererService::SetPlaybackRate(double playback_rate
) {
106 DVLOG(2) << __FUNCTION__
<< ": " << playback_rate
;
107 DCHECK_EQ(state_
, STATE_PLAYING
);
108 renderer_
->SetPlaybackRate(playback_rate
);
111 void MojoRendererService::SetVolume(float volume
) {
112 renderer_
->SetVolume(volume
);
115 void MojoRendererService::SetCdm(int32_t cdm_id
,
116 const mojo::Callback
<void(bool)>& callback
) {
117 if (!cdm_context_provider_
) {
118 LOG(ERROR
) << "CDM context provider not available.";
123 CdmContext
* cdm_context
= cdm_context_provider_
->GetCdmContext(cdm_id
);
125 LOG(ERROR
) << "CDM context not found: " << cdm_id
;
130 renderer_
->SetCdm(cdm_context
, base::Bind(&MojoRendererService::OnCdmAttached
,
131 weak_this_
, callback
));
134 void MojoRendererService::OnStreamReady(
135 const mojo::Callback
<void(bool)>& callback
) {
136 DCHECK_EQ(state_
, STATE_INITIALIZING
);
138 renderer_
->Initialize(
139 stream_provider_
.get(),
141 &MojoRendererService::OnRendererInitializeDone
, weak_this_
, callback
),
142 base::Bind(&MojoRendererService::OnUpdateStatistics
, weak_this_
),
143 base::Bind(&MojoRendererService::OnBufferingStateChanged
, weak_this_
),
144 base::Bind(&MojoRendererService::OnRendererEnded
, weak_this_
),
145 base::Bind(&MojoRendererService::OnError
, weak_this_
),
146 base::Bind(base::DoNothing
));
149 void MojoRendererService::OnRendererInitializeDone(
150 const mojo::Callback
<void(bool)>& callback
,
151 PipelineStatus status
) {
152 DVLOG(1) << __FUNCTION__
;
153 DCHECK_EQ(state_
, STATE_INITIALIZING
);
155 if (status
!= PIPELINE_OK
) {
156 state_
= STATE_ERROR
;
161 state_
= STATE_PLAYING
;
165 void MojoRendererService::OnUpdateStatistics(const PipelineStatistics
& stats
) {
168 void MojoRendererService::UpdateMediaTime(bool force
) {
169 const uint64_t media_time
= renderer_
->GetMediaTime().InMicroseconds();
170 if (!force
&& media_time
== last_media_time_usec_
)
173 client_
->OnTimeUpdate(media_time
, media_time
);
174 last_media_time_usec_
= media_time
;
177 void MojoRendererService::CancelPeriodicMediaTimeUpdates() {
178 DVLOG(2) << __FUNCTION__
;
179 UpdateMediaTime(false);
180 time_update_timer_
.Stop();
183 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() {
184 DVLOG(2) << __FUNCTION__
;
185 UpdateMediaTime(true);
186 time_update_timer_
.Start(
188 base::TimeDelta::FromMilliseconds(kTimeUpdateIntervalMs
),
189 base::Bind(&MojoRendererService::UpdateMediaTime
, weak_this_
, false));
192 void MojoRendererService::OnBufferingStateChanged(
193 BufferingState new_buffering_state
) {
194 DVLOG(2) << __FUNCTION__
<< "(" << new_buffering_state
<< ")";
195 client_
->OnBufferingStateChange(
196 static_cast<interfaces::BufferingState
>(new_buffering_state
));
199 void MojoRendererService::OnRendererEnded() {
200 DVLOG(1) << __FUNCTION__
;
201 CancelPeriodicMediaTimeUpdates();
205 void MojoRendererService::OnError(PipelineStatus error
) {
206 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
207 state_
= STATE_ERROR
;
211 void MojoRendererService::OnFlushCompleted(const mojo::Closure
& callback
) {
212 DVLOG(1) << __FUNCTION__
;
213 DCHECK_EQ(state_
, STATE_FLUSHING
);
214 state_
= STATE_PLAYING
;
218 void MojoRendererService::OnCdmAttached(
219 const mojo::Callback
<void(bool)>& callback
,
221 DVLOG(1) << __FUNCTION__
<< "(" << success
<< ")";
222 callback
.Run(success
);