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/filters/renderer_impl.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/compiler_specific.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "media/base/audio_renderer.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/demuxer_stream_provider.h"
16 #include "media/base/time_source.h"
17 #include "media/base/video_renderer.h"
18 #include "media/base/wall_clock_time_source.h"
22 RendererImpl::RendererImpl(
23 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
24 scoped_ptr
<AudioRenderer
> audio_renderer
,
25 scoped_ptr
<VideoRenderer
> video_renderer
)
26 : state_(STATE_UNINITIALIZED
),
27 task_runner_(task_runner
),
28 audio_renderer_(audio_renderer
.Pass()),
29 video_renderer_(video_renderer
.Pass()),
32 audio_buffering_state_(BUFFERING_HAVE_NOTHING
),
33 video_buffering_state_(BUFFERING_HAVE_NOTHING
),
36 cdm_context_(nullptr),
37 underflow_disabled_for_testing_(false),
38 clockless_video_playback_enabled_for_testing_(false),
40 weak_this_
= weak_factory_
.GetWeakPtr();
41 DVLOG(1) << __FUNCTION__
;
44 RendererImpl::~RendererImpl() {
45 DVLOG(1) << __FUNCTION__
;
46 DCHECK(task_runner_
->BelongsToCurrentThread());
48 // Tear down in opposite order of construction as |video_renderer_| can still
49 // need |time_source_| (which can be |audio_renderer_|) to be alive.
50 video_renderer_
.reset();
51 audio_renderer_
.reset();
53 FireAllPendingCallbacks();
56 void RendererImpl::Initialize(DemuxerStreamProvider
* demuxer_stream_provider
,
57 const base::Closure
& init_cb
,
58 const StatisticsCB
& statistics_cb
,
59 const BufferingStateCB
& buffering_state_cb
,
60 const PaintCB
& paint_cb
,
61 const base::Closure
& ended_cb
,
62 const PipelineStatusCB
& error_cb
) {
63 DVLOG(1) << __FUNCTION__
;
64 DCHECK(task_runner_
->BelongsToCurrentThread());
65 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
66 DCHECK(!init_cb
.is_null());
67 DCHECK(!statistics_cb
.is_null());
68 DCHECK(!buffering_state_cb
.is_null());
69 DCHECK(!paint_cb
.is_null());
70 DCHECK(!ended_cb
.is_null());
71 DCHECK(!error_cb
.is_null());
72 DCHECK(demuxer_stream_provider
->GetStream(DemuxerStream::AUDIO
) ||
73 demuxer_stream_provider
->GetStream(DemuxerStream::VIDEO
));
75 demuxer_stream_provider_
= demuxer_stream_provider
;
76 statistics_cb_
= statistics_cb
;
77 buffering_state_cb_
= buffering_state_cb
;
83 state_
= STATE_INITIALIZING
;
84 InitializeAudioRenderer();
87 void RendererImpl::SetCdm(CdmContext
* cdm_context
,
88 const CdmAttachedCB
& cdm_attached_cb
) {
89 DVLOG(1) << __FUNCTION__
;
90 DCHECK(task_runner_
->BelongsToCurrentThread());
94 DVLOG(1) << "Switching CDM not supported.";
95 cdm_attached_cb
.Run(false);
99 cdm_context_
= cdm_context
;
101 if (decryptor_ready_cb_
.is_null()) {
102 cdm_attached_cb
.Run(true);
106 base::ResetAndReturn(&decryptor_ready_cb_
)
107 .Run(cdm_context
->GetDecryptor(), cdm_attached_cb
);
110 void RendererImpl::Flush(const base::Closure
& flush_cb
) {
111 DVLOG(1) << __FUNCTION__
;
112 DCHECK(task_runner_
->BelongsToCurrentThread());
113 DCHECK(flush_cb_
.is_null());
115 if (state_
!= STATE_PLAYING
) {
116 DCHECK_EQ(state_
, STATE_ERROR
);
120 flush_cb_
= flush_cb
;
121 state_
= STATE_FLUSHING
;
126 FlushAudioRenderer();
129 void RendererImpl::StartPlayingFrom(base::TimeDelta time
) {
130 DVLOG(1) << __FUNCTION__
;
131 DCHECK(task_runner_
->BelongsToCurrentThread());
133 if (state_
!= STATE_PLAYING
) {
134 DCHECK_EQ(state_
, STATE_ERROR
);
138 time_source_
->SetMediaTime(time
);
141 audio_renderer_
->StartPlaying();
143 video_renderer_
->StartPlayingFrom(time
);
146 void RendererImpl::SetPlaybackRate(float playback_rate
) {
147 DVLOG(1) << __FUNCTION__
<< "(" << playback_rate
<< ")";
148 DCHECK(task_runner_
->BelongsToCurrentThread());
150 // Playback rate changes are only carried out while playing.
151 if (state_
!= STATE_PLAYING
)
154 time_source_
->SetPlaybackRate(playback_rate
);
157 void RendererImpl::SetVolume(float volume
) {
158 DVLOG(1) << __FUNCTION__
;
159 DCHECK(task_runner_
->BelongsToCurrentThread());
162 audio_renderer_
->SetVolume(volume
);
165 base::TimeDelta
RendererImpl::GetMediaTime() {
166 // No BelongsToCurrentThread() checking because this can be called from other
168 return time_source_
->CurrentMediaTime();
171 bool RendererImpl::HasAudio() {
172 DCHECK(task_runner_
->BelongsToCurrentThread());
173 return audio_renderer_
!= NULL
;
176 bool RendererImpl::HasVideo() {
177 DCHECK(task_runner_
->BelongsToCurrentThread());
178 return video_renderer_
!= NULL
;
181 void RendererImpl::DisableUnderflowForTesting() {
182 DVLOG(1) << __FUNCTION__
;
183 DCHECK(task_runner_
->BelongsToCurrentThread());
184 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
186 underflow_disabled_for_testing_
= true;
189 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
190 DVLOG(1) << __FUNCTION__
;
191 DCHECK(task_runner_
->BelongsToCurrentThread());
192 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
193 DCHECK(underflow_disabled_for_testing_
)
194 << "Underflow must be disabled for clockless video playback";
196 clockless_video_playback_enabled_for_testing_
= true;
199 base::TimeDelta
RendererImpl::GetMediaTimeForSyncingVideo() {
200 // No BelongsToCurrentThread() checking because this can be called from other
203 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
204 // which should go away at some point http://crbug.com/110814
205 if (clockless_video_playback_enabled_for_testing_
)
206 return base::TimeDelta::Max();
208 return time_source_
->CurrentMediaTimeForSyncingVideo();
211 void RendererImpl::SetDecryptorReadyCallback(
212 const DecryptorReadyCB
& decryptor_ready_cb
) {
213 // Cancels the previous decryptor request.
214 if (decryptor_ready_cb
.is_null()) {
215 if (!decryptor_ready_cb_
.is_null()) {
216 base::ResetAndReturn(&decryptor_ready_cb_
)
217 .Run(nullptr, base::Bind(IgnoreCdmAttached
));
222 // We initialize audio and video decoders in sequence.
223 DCHECK(decryptor_ready_cb_
.is_null());
226 decryptor_ready_cb
.Run(cdm_context_
->GetDecryptor(),
227 base::Bind(IgnoreCdmAttached
));
231 decryptor_ready_cb_
= decryptor_ready_cb
;
234 void RendererImpl::InitializeAudioRenderer() {
235 DVLOG(1) << __FUNCTION__
;
236 DCHECK(task_runner_
->BelongsToCurrentThread());
237 DCHECK_EQ(state_
, STATE_INITIALIZING
);
238 DCHECK(!init_cb_
.is_null());
240 PipelineStatusCB done_cb
=
241 base::Bind(&RendererImpl::OnAudioRendererInitializeDone
, weak_this_
);
243 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
)) {
244 audio_renderer_
.reset();
245 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
249 // Note: After the initialization of a renderer, error events from it may
250 // happen at any time and all future calls must guard against STATE_ERROR.
251 audio_renderer_
->Initialize(
252 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
), done_cb
,
253 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
254 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
255 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
256 &audio_buffering_state_
),
257 base::Bind(&RendererImpl::OnAudioRendererEnded
, weak_this_
),
258 base::Bind(&RendererImpl::OnError
, weak_this_
));
261 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status
) {
262 DVLOG(1) << __FUNCTION__
<< ": " << status
;
263 DCHECK(task_runner_
->BelongsToCurrentThread());
265 if (status
!= PIPELINE_OK
)
268 // OnError() may be fired at any time by the renderers, even if they thought
269 // they initialized successfully (due to delayed output device setup).
270 if (state_
!= STATE_INITIALIZING
) {
271 audio_renderer_
.reset();
275 DCHECK(!init_cb_
.is_null());
276 InitializeVideoRenderer();
279 void RendererImpl::InitializeVideoRenderer() {
280 DVLOG(1) << __FUNCTION__
;
281 DCHECK(task_runner_
->BelongsToCurrentThread());
282 DCHECK_EQ(state_
, STATE_INITIALIZING
);
283 DCHECK(!init_cb_
.is_null());
285 PipelineStatusCB done_cb
=
286 base::Bind(&RendererImpl::OnVideoRendererInitializeDone
, weak_this_
);
288 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
)) {
289 video_renderer_
.reset();
290 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
294 video_renderer_
->Initialize(
295 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
), done_cb
,
296 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
297 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
298 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
299 &video_buffering_state_
),
300 base::ResetAndReturn(&paint_cb_
),
301 base::Bind(&RendererImpl::OnVideoRendererEnded
, weak_this_
),
302 base::Bind(&RendererImpl::OnError
, weak_this_
),
303 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo
,
304 base::Unretained(this)));
307 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status
) {
308 DVLOG(1) << __FUNCTION__
<< ": " << status
;
309 DCHECK(task_runner_
->BelongsToCurrentThread());
311 if (status
!= PIPELINE_OK
)
314 // OnError() may be fired at any time by the renderers, even if they thought
315 // they initialized successfully (due to delayed output device setup).
316 if (state_
!= STATE_INITIALIZING
) {
317 audio_renderer_
.reset();
318 video_renderer_
.reset();
322 DCHECK(!init_cb_
.is_null());
324 if (audio_renderer_
) {
325 time_source_
= audio_renderer_
->GetTimeSource();
327 wall_clock_time_source_
.reset(new WallClockTimeSource());
328 time_source_
= wall_clock_time_source_
.get();
331 state_
= STATE_PLAYING
;
332 DCHECK(time_source_
);
333 DCHECK(audio_renderer_
|| video_renderer_
);
334 base::ResetAndReturn(&init_cb_
).Run();
337 void RendererImpl::FlushAudioRenderer() {
338 DVLOG(1) << __FUNCTION__
;
339 DCHECK(task_runner_
->BelongsToCurrentThread());
340 DCHECK_EQ(state_
, STATE_FLUSHING
);
341 DCHECK(!flush_cb_
.is_null());
343 if (!audio_renderer_
) {
344 OnAudioRendererFlushDone();
348 audio_renderer_
->Flush(
349 base::Bind(&RendererImpl::OnAudioRendererFlushDone
, weak_this_
));
352 void RendererImpl::OnAudioRendererFlushDone() {
353 DVLOG(1) << __FUNCTION__
;
354 DCHECK(task_runner_
->BelongsToCurrentThread());
356 if (state_
== STATE_ERROR
) {
357 DCHECK(flush_cb_
.is_null());
361 DCHECK_EQ(state_
, STATE_FLUSHING
);
362 DCHECK(!flush_cb_
.is_null());
364 DCHECK_EQ(audio_buffering_state_
, BUFFERING_HAVE_NOTHING
);
365 audio_ended_
= false;
366 FlushVideoRenderer();
369 void RendererImpl::FlushVideoRenderer() {
370 DVLOG(1) << __FUNCTION__
;
371 DCHECK(task_runner_
->BelongsToCurrentThread());
372 DCHECK_EQ(state_
, STATE_FLUSHING
);
373 DCHECK(!flush_cb_
.is_null());
375 if (!video_renderer_
) {
376 OnVideoRendererFlushDone();
380 video_renderer_
->Flush(
381 base::Bind(&RendererImpl::OnVideoRendererFlushDone
, weak_this_
));
384 void RendererImpl::OnVideoRendererFlushDone() {
385 DVLOG(1) << __FUNCTION__
;
386 DCHECK(task_runner_
->BelongsToCurrentThread());
388 if (state_
== STATE_ERROR
) {
389 DCHECK(flush_cb_
.is_null());
393 DCHECK_EQ(state_
, STATE_FLUSHING
);
394 DCHECK(!flush_cb_
.is_null());
396 DCHECK_EQ(video_buffering_state_
, BUFFERING_HAVE_NOTHING
);
397 video_ended_
= false;
398 state_
= STATE_PLAYING
;
399 base::ResetAndReturn(&flush_cb_
).Run();
402 void RendererImpl::OnUpdateStatistics(const PipelineStatistics
& stats
) {
403 DCHECK(task_runner_
->BelongsToCurrentThread());
404 statistics_cb_
.Run(stats
);
407 void RendererImpl::OnBufferingStateChanged(BufferingState
* buffering_state
,
408 BufferingState new_buffering_state
) {
409 DVLOG(1) << __FUNCTION__
<< "(" << *buffering_state
<< ", "
410 << new_buffering_state
<< ") "
411 << (buffering_state
== &audio_buffering_state_
? "audio" : "video");
412 DCHECK(task_runner_
->BelongsToCurrentThread());
413 bool was_waiting_for_enough_data
= WaitingForEnoughData();
415 *buffering_state
= new_buffering_state
;
417 // Disable underflow by ignoring updates that renderers have ran out of data.
418 if (state_
== STATE_PLAYING
&& underflow_disabled_for_testing_
&&
420 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
424 // Renderer underflowed.
425 if (!was_waiting_for_enough_data
&& WaitingForEnoughData()) {
428 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
429 // underflow state http://crbug.com/144683
433 // Renderer prerolled.
434 if (was_waiting_for_enough_data
&& !WaitingForEnoughData()) {
436 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
441 bool RendererImpl::WaitingForEnoughData() const {
442 DCHECK(task_runner_
->BelongsToCurrentThread());
443 if (state_
!= STATE_PLAYING
)
445 if (audio_renderer_
&& audio_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
447 if (video_renderer_
&& video_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
452 void RendererImpl::PausePlayback() {
453 DVLOG(1) << __FUNCTION__
;
454 DCHECK(task_runner_
->BelongsToCurrentThread());
455 DCHECK(time_ticking_
);
458 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
459 << "Playback should only pause due to ending or underflowing";
463 // It's OK to pause playback when flushing.
466 case STATE_UNINITIALIZED
:
467 case STATE_INITIALIZING
:
468 NOTREACHED() << "Invalid state: " << state_
;
472 // An error state may occur at any time.
476 time_ticking_
= false;
477 time_source_
->StopTicking();
480 void RendererImpl::StartPlayback() {
481 DVLOG(1) << __FUNCTION__
;
482 DCHECK(task_runner_
->BelongsToCurrentThread());
483 DCHECK_EQ(state_
, STATE_PLAYING
);
484 DCHECK(!time_ticking_
);
485 DCHECK(!WaitingForEnoughData());
487 time_ticking_
= true;
488 time_source_
->StartTicking();
491 void RendererImpl::OnAudioRendererEnded() {
492 DVLOG(1) << __FUNCTION__
;
493 DCHECK(task_runner_
->BelongsToCurrentThread());
495 if (state_
!= STATE_PLAYING
)
498 DCHECK(!audio_ended_
);
501 RunEndedCallbackIfNeeded();
504 void RendererImpl::OnVideoRendererEnded() {
505 DVLOG(1) << __FUNCTION__
;
506 DCHECK(task_runner_
->BelongsToCurrentThread());
508 if (state_
!= STATE_PLAYING
)
511 DCHECK(!video_ended_
);
514 RunEndedCallbackIfNeeded();
517 bool RendererImpl::PlaybackHasEnded() const {
518 DVLOG(1) << __FUNCTION__
;
519 DCHECK(task_runner_
->BelongsToCurrentThread());
521 if (audio_renderer_
&& !audio_ended_
)
524 if (video_renderer_
&& !video_ended_
)
530 void RendererImpl::RunEndedCallbackIfNeeded() {
531 DVLOG(1) << __FUNCTION__
;
532 DCHECK(task_runner_
->BelongsToCurrentThread());
534 if (!PlaybackHasEnded())
543 void RendererImpl::OnError(PipelineStatus error
) {
544 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
545 DCHECK(task_runner_
->BelongsToCurrentThread());
546 DCHECK_NE(PIPELINE_OK
, error
) << "PIPELINE_OK isn't an error!";
548 // An error has already been delivered.
549 if (state_
== STATE_ERROR
)
552 state_
= STATE_ERROR
;
554 // Pipeline will destroy |this| as the result of error.
555 base::ResetAndReturn(&error_cb_
).Run(error
);
557 FireAllPendingCallbacks();
560 void RendererImpl::FireAllPendingCallbacks() {
561 DCHECK(task_runner_
->BelongsToCurrentThread());
563 if (!init_cb_
.is_null())
564 base::ResetAndReturn(&init_cb_
).Run();
566 if (!flush_cb_
.is_null())
567 base::ResetAndReturn(&flush_cb_
).Run();