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 if (!init_cb_
.is_null())
54 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_ERROR_ABORT
);
55 else if (!flush_cb_
.is_null())
56 base::ResetAndReturn(&flush_cb_
).Run();
59 void RendererImpl::Initialize(DemuxerStreamProvider
* demuxer_stream_provider
,
60 const PipelineStatusCB
& init_cb
,
61 const StatisticsCB
& statistics_cb
,
62 const BufferingStateCB
& buffering_state_cb
,
63 const PaintCB
& paint_cb
,
64 const base::Closure
& ended_cb
,
65 const PipelineStatusCB
& error_cb
) {
66 DVLOG(1) << __FUNCTION__
;
67 DCHECK(task_runner_
->BelongsToCurrentThread());
68 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
69 DCHECK(!init_cb
.is_null());
70 DCHECK(!statistics_cb
.is_null());
71 DCHECK(!buffering_state_cb
.is_null());
72 DCHECK(!paint_cb
.is_null());
73 DCHECK(!ended_cb
.is_null());
74 DCHECK(!error_cb
.is_null());
75 DCHECK(demuxer_stream_provider
->GetStream(DemuxerStream::AUDIO
) ||
76 demuxer_stream_provider
->GetStream(DemuxerStream::VIDEO
));
78 demuxer_stream_provider_
= demuxer_stream_provider
;
79 statistics_cb_
= statistics_cb
;
80 buffering_state_cb_
= buffering_state_cb
;
86 state_
= STATE_INITIALIZING
;
87 InitializeAudioRenderer();
90 void RendererImpl::SetCdm(CdmContext
* cdm_context
,
91 const CdmAttachedCB
& cdm_attached_cb
) {
92 DVLOG(1) << __FUNCTION__
;
93 DCHECK(task_runner_
->BelongsToCurrentThread());
97 DVLOG(1) << "Switching CDM not supported.";
98 cdm_attached_cb
.Run(false);
102 cdm_context_
= cdm_context
;
104 if (decryptor_ready_cb_
.is_null()) {
105 cdm_attached_cb
.Run(true);
109 base::ResetAndReturn(&decryptor_ready_cb_
)
110 .Run(cdm_context
->GetDecryptor(), cdm_attached_cb
);
113 void RendererImpl::Flush(const base::Closure
& flush_cb
) {
114 DVLOG(1) << __FUNCTION__
;
115 DCHECK(task_runner_
->BelongsToCurrentThread());
116 DCHECK(flush_cb_
.is_null());
118 if (state_
!= STATE_PLAYING
) {
119 DCHECK_EQ(state_
, STATE_ERROR
);
123 flush_cb_
= flush_cb
;
124 state_
= STATE_FLUSHING
;
129 FlushAudioRenderer();
132 void RendererImpl::StartPlayingFrom(base::TimeDelta time
) {
133 DVLOG(1) << __FUNCTION__
;
134 DCHECK(task_runner_
->BelongsToCurrentThread());
136 if (state_
!= STATE_PLAYING
) {
137 DCHECK_EQ(state_
, STATE_ERROR
);
141 time_source_
->SetMediaTime(time
);
144 audio_renderer_
->StartPlaying();
146 video_renderer_
->StartPlayingFrom(time
);
149 void RendererImpl::SetPlaybackRate(float playback_rate
) {
150 DVLOG(1) << __FUNCTION__
<< "(" << playback_rate
<< ")";
151 DCHECK(task_runner_
->BelongsToCurrentThread());
153 // Playback rate changes are only carried out while playing.
154 if (state_
!= STATE_PLAYING
)
157 time_source_
->SetPlaybackRate(playback_rate
);
160 void RendererImpl::SetVolume(float volume
) {
161 DVLOG(1) << __FUNCTION__
;
162 DCHECK(task_runner_
->BelongsToCurrentThread());
165 audio_renderer_
->SetVolume(volume
);
168 base::TimeDelta
RendererImpl::GetMediaTime() {
169 // No BelongsToCurrentThread() checking because this can be called from other
171 return time_source_
->CurrentMediaTime();
174 bool RendererImpl::HasAudio() {
175 DCHECK(task_runner_
->BelongsToCurrentThread());
176 return audio_renderer_
!= NULL
;
179 bool RendererImpl::HasVideo() {
180 DCHECK(task_runner_
->BelongsToCurrentThread());
181 return video_renderer_
!= NULL
;
184 void RendererImpl::DisableUnderflowForTesting() {
185 DVLOG(1) << __FUNCTION__
;
186 DCHECK(task_runner_
->BelongsToCurrentThread());
187 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
189 underflow_disabled_for_testing_
= true;
192 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
193 DVLOG(1) << __FUNCTION__
;
194 DCHECK(task_runner_
->BelongsToCurrentThread());
195 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
196 DCHECK(underflow_disabled_for_testing_
)
197 << "Underflow must be disabled for clockless video playback";
199 clockless_video_playback_enabled_for_testing_
= true;
202 base::TimeDelta
RendererImpl::GetMediaTimeForSyncingVideo() {
203 // No BelongsToCurrentThread() checking because this can be called from other
206 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
207 // which should go away at some point http://crbug.com/110814
208 if (clockless_video_playback_enabled_for_testing_
)
209 return base::TimeDelta::Max();
211 return time_source_
->CurrentMediaTimeForSyncingVideo();
214 void RendererImpl::SetDecryptorReadyCallback(
215 const DecryptorReadyCB
& decryptor_ready_cb
) {
216 // Cancels the previous decryptor request.
217 if (decryptor_ready_cb
.is_null()) {
218 if (!decryptor_ready_cb_
.is_null()) {
219 base::ResetAndReturn(&decryptor_ready_cb_
)
220 .Run(nullptr, base::Bind(IgnoreCdmAttached
));
225 // We initialize audio and video decoders in sequence.
226 DCHECK(decryptor_ready_cb_
.is_null());
229 decryptor_ready_cb
.Run(cdm_context_
->GetDecryptor(),
230 base::Bind(IgnoreCdmAttached
));
234 decryptor_ready_cb_
= decryptor_ready_cb
;
237 void RendererImpl::InitializeAudioRenderer() {
238 DVLOG(1) << __FUNCTION__
;
239 DCHECK(task_runner_
->BelongsToCurrentThread());
240 DCHECK_EQ(state_
, STATE_INITIALIZING
);
241 DCHECK(!init_cb_
.is_null());
243 PipelineStatusCB done_cb
=
244 base::Bind(&RendererImpl::OnAudioRendererInitializeDone
, weak_this_
);
246 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
)) {
247 audio_renderer_
.reset();
248 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
252 // Note: After the initialization of a renderer, error events from it may
253 // happen at any time and all future calls must guard against STATE_ERROR.
254 audio_renderer_
->Initialize(
255 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
), done_cb
,
256 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
257 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
258 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
259 &audio_buffering_state_
),
260 base::Bind(&RendererImpl::OnAudioRendererEnded
, weak_this_
),
261 base::Bind(&RendererImpl::OnError
, weak_this_
));
264 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status
) {
265 DVLOG(1) << __FUNCTION__
<< ": " << status
;
266 DCHECK(task_runner_
->BelongsToCurrentThread());
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 DCHECK(init_cb_
.is_null());
272 audio_renderer_
.reset();
276 if (status
!= PIPELINE_OK
) {
277 base::ResetAndReturn(&init_cb_
).Run(status
);
281 DCHECK(!init_cb_
.is_null());
282 InitializeVideoRenderer();
285 void RendererImpl::InitializeVideoRenderer() {
286 DVLOG(1) << __FUNCTION__
;
287 DCHECK(task_runner_
->BelongsToCurrentThread());
288 DCHECK_EQ(state_
, STATE_INITIALIZING
);
289 DCHECK(!init_cb_
.is_null());
291 PipelineStatusCB done_cb
=
292 base::Bind(&RendererImpl::OnVideoRendererInitializeDone
, weak_this_
);
294 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
)) {
295 video_renderer_
.reset();
296 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
300 video_renderer_
->Initialize(
301 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
), done_cb
,
302 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
303 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
304 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
305 &video_buffering_state_
),
306 base::ResetAndReturn(&paint_cb_
),
307 base::Bind(&RendererImpl::OnVideoRendererEnded
, weak_this_
),
308 base::Bind(&RendererImpl::OnError
, weak_this_
),
309 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo
,
310 base::Unretained(this)));
313 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status
) {
314 DVLOG(1) << __FUNCTION__
<< ": " << status
;
315 DCHECK(task_runner_
->BelongsToCurrentThread());
317 // OnError() may be fired at any time by the renderers, even if they thought
318 // they initialized successfully (due to delayed output device setup).
319 if (state_
!= STATE_INITIALIZING
) {
320 DCHECK(init_cb_
.is_null());
321 audio_renderer_
.reset();
322 video_renderer_
.reset();
326 DCHECK(!init_cb_
.is_null());
328 if (status
!= PIPELINE_OK
) {
329 base::ResetAndReturn(&init_cb_
).Run(status
);
333 if (audio_renderer_
) {
334 time_source_
= audio_renderer_
->GetTimeSource();
336 wall_clock_time_source_
.reset(new WallClockTimeSource());
337 time_source_
= wall_clock_time_source_
.get();
340 state_
= STATE_PLAYING
;
341 DCHECK(time_source_
);
342 DCHECK(audio_renderer_
|| video_renderer_
);
343 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_OK
);
346 void RendererImpl::FlushAudioRenderer() {
347 DVLOG(1) << __FUNCTION__
;
348 DCHECK(task_runner_
->BelongsToCurrentThread());
349 DCHECK_EQ(state_
, STATE_FLUSHING
);
350 DCHECK(!flush_cb_
.is_null());
352 if (!audio_renderer_
) {
353 OnAudioRendererFlushDone();
357 audio_renderer_
->Flush(
358 base::Bind(&RendererImpl::OnAudioRendererFlushDone
, weak_this_
));
361 void RendererImpl::OnAudioRendererFlushDone() {
362 DVLOG(1) << __FUNCTION__
;
363 DCHECK(task_runner_
->BelongsToCurrentThread());
365 if (state_
== STATE_ERROR
) {
366 DCHECK(flush_cb_
.is_null());
370 DCHECK_EQ(state_
, STATE_FLUSHING
);
371 DCHECK(!flush_cb_
.is_null());
373 DCHECK_EQ(audio_buffering_state_
, BUFFERING_HAVE_NOTHING
);
374 audio_ended_
= false;
375 FlushVideoRenderer();
378 void RendererImpl::FlushVideoRenderer() {
379 DVLOG(1) << __FUNCTION__
;
380 DCHECK(task_runner_
->BelongsToCurrentThread());
381 DCHECK_EQ(state_
, STATE_FLUSHING
);
382 DCHECK(!flush_cb_
.is_null());
384 if (!video_renderer_
) {
385 OnVideoRendererFlushDone();
389 video_renderer_
->Flush(
390 base::Bind(&RendererImpl::OnVideoRendererFlushDone
, weak_this_
));
393 void RendererImpl::OnVideoRendererFlushDone() {
394 DVLOG(1) << __FUNCTION__
;
395 DCHECK(task_runner_
->BelongsToCurrentThread());
397 if (state_
== STATE_ERROR
) {
398 DCHECK(flush_cb_
.is_null());
402 DCHECK_EQ(state_
, STATE_FLUSHING
);
403 DCHECK(!flush_cb_
.is_null());
405 DCHECK_EQ(video_buffering_state_
, BUFFERING_HAVE_NOTHING
);
406 video_ended_
= false;
407 state_
= STATE_PLAYING
;
408 base::ResetAndReturn(&flush_cb_
).Run();
411 void RendererImpl::OnUpdateStatistics(const PipelineStatistics
& stats
) {
412 DCHECK(task_runner_
->BelongsToCurrentThread());
413 statistics_cb_
.Run(stats
);
416 void RendererImpl::OnBufferingStateChanged(BufferingState
* buffering_state
,
417 BufferingState new_buffering_state
) {
418 DVLOG(1) << __FUNCTION__
<< "(" << *buffering_state
<< ", "
419 << new_buffering_state
<< ") "
420 << (buffering_state
== &audio_buffering_state_
? "audio" : "video");
421 DCHECK(task_runner_
->BelongsToCurrentThread());
422 bool was_waiting_for_enough_data
= WaitingForEnoughData();
424 *buffering_state
= new_buffering_state
;
426 // Disable underflow by ignoring updates that renderers have ran out of data.
427 if (state_
== STATE_PLAYING
&& underflow_disabled_for_testing_
&&
429 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
433 // Renderer underflowed.
434 if (!was_waiting_for_enough_data
&& WaitingForEnoughData()) {
437 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
438 // underflow state http://crbug.com/144683
442 // Renderer prerolled.
443 if (was_waiting_for_enough_data
&& !WaitingForEnoughData()) {
445 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
450 bool RendererImpl::WaitingForEnoughData() const {
451 DCHECK(task_runner_
->BelongsToCurrentThread());
452 if (state_
!= STATE_PLAYING
)
454 if (audio_renderer_
&& audio_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
456 if (video_renderer_
&& video_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
461 void RendererImpl::PausePlayback() {
462 DVLOG(1) << __FUNCTION__
;
463 DCHECK(task_runner_
->BelongsToCurrentThread());
464 DCHECK(time_ticking_
);
467 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
468 << "Playback should only pause due to ending or underflowing";
472 // It's OK to pause playback when flushing.
475 case STATE_UNINITIALIZED
:
476 case STATE_INITIALIZING
:
477 NOTREACHED() << "Invalid state: " << state_
;
481 // An error state may occur at any time.
485 time_ticking_
= false;
486 time_source_
->StopTicking();
489 void RendererImpl::StartPlayback() {
490 DVLOG(1) << __FUNCTION__
;
491 DCHECK(task_runner_
->BelongsToCurrentThread());
492 DCHECK_EQ(state_
, STATE_PLAYING
);
493 DCHECK(!time_ticking_
);
494 DCHECK(!WaitingForEnoughData());
496 time_ticking_
= true;
497 time_source_
->StartTicking();
500 void RendererImpl::OnAudioRendererEnded() {
501 DVLOG(1) << __FUNCTION__
;
502 DCHECK(task_runner_
->BelongsToCurrentThread());
504 if (state_
!= STATE_PLAYING
)
507 DCHECK(!audio_ended_
);
510 RunEndedCallbackIfNeeded();
513 void RendererImpl::OnVideoRendererEnded() {
514 DVLOG(1) << __FUNCTION__
;
515 DCHECK(task_runner_
->BelongsToCurrentThread());
517 if (state_
!= STATE_PLAYING
)
520 DCHECK(!video_ended_
);
523 RunEndedCallbackIfNeeded();
526 bool RendererImpl::PlaybackHasEnded() const {
527 DVLOG(1) << __FUNCTION__
;
528 DCHECK(task_runner_
->BelongsToCurrentThread());
530 if (audio_renderer_
&& !audio_ended_
)
533 if (video_renderer_
&& !video_ended_
)
539 void RendererImpl::RunEndedCallbackIfNeeded() {
540 DVLOG(1) << __FUNCTION__
;
541 DCHECK(task_runner_
->BelongsToCurrentThread());
543 if (!PlaybackHasEnded())
552 void RendererImpl::OnError(PipelineStatus error
) {
553 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
554 DCHECK(task_runner_
->BelongsToCurrentThread());
555 DCHECK_NE(PIPELINE_OK
, error
) << "PIPELINE_OK isn't an error!";
557 // An error has already been delivered.
558 if (state_
== STATE_ERROR
)
561 const State old_state
= state_
;
562 state_
= STATE_ERROR
;
564 if (old_state
== STATE_INITIALIZING
) {
565 base::ResetAndReturn(&init_cb_
).Run(error
);
569 // After OnError() returns, the pipeline may destroy |this|.
570 base::ResetAndReturn(&error_cb_
).Run(error
);
572 if (!flush_cb_
.is_null())
573 base::ResetAndReturn(&flush_cb_
).Run();