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/demuxer_stream_provider.h"
15 #include "media/base/time_source.h"
16 #include "media/base/video_renderer.h"
17 #include "media/base/wall_clock_time_source.h"
21 RendererImpl::RendererImpl(
22 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
23 scoped_ptr
<AudioRenderer
> audio_renderer
,
24 scoped_ptr
<VideoRenderer
> video_renderer
)
25 : state_(STATE_UNINITIALIZED
),
26 task_runner_(task_runner
),
27 audio_renderer_(audio_renderer
.Pass()),
28 video_renderer_(video_renderer
.Pass()),
31 audio_buffering_state_(BUFFERING_HAVE_NOTHING
),
32 video_buffering_state_(BUFFERING_HAVE_NOTHING
),
35 cdm_context_(nullptr),
36 underflow_disabled_for_testing_(false),
37 clockless_video_playback_enabled_for_testing_(false),
39 weak_this_(weak_factory_
.GetWeakPtr()) {
40 DVLOG(1) << __FUNCTION__
;
43 RendererImpl::~RendererImpl() {
44 DVLOG(1) << __FUNCTION__
;
45 DCHECK(task_runner_
->BelongsToCurrentThread());
47 // Tear down in opposite order of construction as |video_renderer_| can still
48 // need |time_source_| (which can be |audio_renderer_|) to be alive.
49 video_renderer_
.reset();
50 audio_renderer_
.reset();
52 FireAllPendingCallbacks();
55 void RendererImpl::Initialize(DemuxerStreamProvider
* demuxer_stream_provider
,
56 const base::Closure
& init_cb
,
57 const StatisticsCB
& statistics_cb
,
58 const BufferingStateCB
& buffering_state_cb
,
59 const PaintCB
& paint_cb
,
60 const base::Closure
& ended_cb
,
61 const PipelineStatusCB
& error_cb
) {
62 DVLOG(1) << __FUNCTION__
;
63 DCHECK(task_runner_
->BelongsToCurrentThread());
64 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
65 DCHECK(!init_cb
.is_null());
66 DCHECK(!statistics_cb
.is_null());
67 DCHECK(!buffering_state_cb
.is_null());
68 DCHECK(!paint_cb
.is_null());
69 DCHECK(!ended_cb
.is_null());
70 DCHECK(!error_cb
.is_null());
71 DCHECK(demuxer_stream_provider
->GetStream(DemuxerStream::AUDIO
) ||
72 demuxer_stream_provider
->GetStream(DemuxerStream::VIDEO
));
74 demuxer_stream_provider_
= demuxer_stream_provider
;
75 statistics_cb_
= statistics_cb
;
76 buffering_state_cb_
= buffering_state_cb
;
82 state_
= STATE_INITIALIZING
;
83 InitializeAudioRenderer();
86 void RendererImpl::SetCdm(CdmContext
* cdm_context
,
87 const CdmAttachedCB
& cdm_attached_cb
) {
88 DVLOG(1) << __FUNCTION__
;
89 DCHECK(task_runner_
->BelongsToCurrentThread());
93 DVLOG(1) << "Switching CDM not supported.";
94 cdm_attached_cb
.Run(false);
98 cdm_context_
= cdm_context
;
100 if (decryptor_ready_cb_
.is_null()) {
101 cdm_attached_cb
.Run(true);
105 base::ResetAndReturn(&decryptor_ready_cb_
)
106 .Run(cdm_context
->GetDecryptor(), cdm_attached_cb
);
109 void RendererImpl::Flush(const base::Closure
& flush_cb
) {
110 DVLOG(1) << __FUNCTION__
;
111 DCHECK(task_runner_
->BelongsToCurrentThread());
112 DCHECK(flush_cb_
.is_null());
114 if (state_
!= STATE_PLAYING
) {
115 DCHECK_EQ(state_
, STATE_ERROR
);
119 flush_cb_
= flush_cb
;
120 state_
= STATE_FLUSHING
;
125 FlushAudioRenderer();
128 void RendererImpl::StartPlayingFrom(base::TimeDelta time
) {
129 DVLOG(1) << __FUNCTION__
;
130 DCHECK(task_runner_
->BelongsToCurrentThread());
132 if (state_
!= STATE_PLAYING
) {
133 DCHECK_EQ(state_
, STATE_ERROR
);
137 time_source_
->SetMediaTime(time
);
140 audio_renderer_
->StartPlaying();
142 video_renderer_
->StartPlayingFrom(time
);
145 void RendererImpl::SetPlaybackRate(float playback_rate
) {
146 DVLOG(1) << __FUNCTION__
<< "(" << playback_rate
<< ")";
147 DCHECK(task_runner_
->BelongsToCurrentThread());
149 // Playback rate changes are only carried out while playing.
150 if (state_
!= STATE_PLAYING
)
153 time_source_
->SetPlaybackRate(playback_rate
);
156 void RendererImpl::SetVolume(float volume
) {
157 DVLOG(1) << __FUNCTION__
;
158 DCHECK(task_runner_
->BelongsToCurrentThread());
161 audio_renderer_
->SetVolume(volume
);
164 base::TimeDelta
RendererImpl::GetMediaTime() {
165 // No BelongsToCurrentThread() checking because this can be called from other
167 return time_source_
->CurrentMediaTime();
170 bool RendererImpl::HasAudio() {
171 DCHECK(task_runner_
->BelongsToCurrentThread());
172 return audio_renderer_
!= NULL
;
175 bool RendererImpl::HasVideo() {
176 DCHECK(task_runner_
->BelongsToCurrentThread());
177 return video_renderer_
!= NULL
;
180 void RendererImpl::DisableUnderflowForTesting() {
181 DVLOG(1) << __FUNCTION__
;
182 DCHECK(task_runner_
->BelongsToCurrentThread());
183 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
185 underflow_disabled_for_testing_
= true;
188 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
189 DVLOG(1) << __FUNCTION__
;
190 DCHECK(task_runner_
->BelongsToCurrentThread());
191 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
192 DCHECK(underflow_disabled_for_testing_
)
193 << "Underflow must be disabled for clockless video playback";
195 clockless_video_playback_enabled_for_testing_
= true;
198 base::TimeDelta
RendererImpl::GetMediaTimeForSyncingVideo() {
199 // No BelongsToCurrentThread() checking because this can be called from other
202 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
203 // which should go away at some point http://crbug.com/110814
204 if (clockless_video_playback_enabled_for_testing_
)
205 return base::TimeDelta::Max();
207 return time_source_
->CurrentMediaTimeForSyncingVideo();
210 void RendererImpl::SetDecryptorReadyCallback(
211 const DecryptorReadyCB
& decryptor_ready_cb
) {
212 // Cancels the previous decryptor request.
213 if (decryptor_ready_cb
.is_null()) {
214 if (!decryptor_ready_cb_
.is_null()) {
215 base::ResetAndReturn(&decryptor_ready_cb_
)
216 .Run(nullptr, base::Bind(IgnoreCdmAttached
));
221 // We initialize audio and video decoders in sequence.
222 DCHECK(decryptor_ready_cb_
.is_null());
225 decryptor_ready_cb
.Run(cdm_context_
->GetDecryptor(),
226 base::Bind(IgnoreCdmAttached
));
230 decryptor_ready_cb_
= decryptor_ready_cb
;
233 void RendererImpl::InitializeAudioRenderer() {
234 DVLOG(1) << __FUNCTION__
;
235 DCHECK(task_runner_
->BelongsToCurrentThread());
236 DCHECK_EQ(state_
, STATE_INITIALIZING
);
237 DCHECK(!init_cb_
.is_null());
239 PipelineStatusCB done_cb
=
240 base::Bind(&RendererImpl::OnAudioRendererInitializeDone
, weak_this_
);
242 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
)) {
243 audio_renderer_
.reset();
244 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
248 // Note: After the initialization of a renderer, error events from it may
249 // happen at any time and all future calls must guard against STATE_ERROR.
250 audio_renderer_
->Initialize(
251 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
), done_cb
,
252 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
253 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
254 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
255 &audio_buffering_state_
),
256 base::Bind(&RendererImpl::OnAudioRendererEnded
, weak_this_
),
257 base::Bind(&RendererImpl::OnError
, weak_this_
));
260 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status
) {
261 DVLOG(1) << __FUNCTION__
<< ": " << status
;
262 DCHECK(task_runner_
->BelongsToCurrentThread());
264 if (status
!= PIPELINE_OK
)
267 // OnError() may be fired at any time by the renderers, even if they thought
268 // they initialized successfully (due to delayed output device setup).
269 if (state_
!= STATE_INITIALIZING
) {
270 audio_renderer_
.reset();
274 DCHECK(!init_cb_
.is_null());
275 InitializeVideoRenderer();
278 void RendererImpl::InitializeVideoRenderer() {
279 DVLOG(1) << __FUNCTION__
;
280 DCHECK(task_runner_
->BelongsToCurrentThread());
281 DCHECK_EQ(state_
, STATE_INITIALIZING
);
282 DCHECK(!init_cb_
.is_null());
284 PipelineStatusCB done_cb
=
285 base::Bind(&RendererImpl::OnVideoRendererInitializeDone
, weak_this_
);
287 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
)) {
288 video_renderer_
.reset();
289 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
293 video_renderer_
->Initialize(
294 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
), done_cb
,
295 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
296 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
297 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
298 &video_buffering_state_
),
299 base::ResetAndReturn(&paint_cb_
),
300 base::Bind(&RendererImpl::OnVideoRendererEnded
, weak_this_
),
301 base::Bind(&RendererImpl::OnError
, weak_this_
),
302 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo
,
303 base::Unretained(this)));
306 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status
) {
307 DVLOG(1) << __FUNCTION__
<< ": " << status
;
308 DCHECK(task_runner_
->BelongsToCurrentThread());
310 if (status
!= PIPELINE_OK
)
313 // OnError() may be fired at any time by the renderers, even if they thought
314 // they initialized successfully (due to delayed output device setup).
315 if (state_
!= STATE_INITIALIZING
) {
316 audio_renderer_
.reset();
317 video_renderer_
.reset();
321 DCHECK(!init_cb_
.is_null());
323 if (audio_renderer_
) {
324 time_source_
= audio_renderer_
->GetTimeSource();
326 wall_clock_time_source_
.reset(new WallClockTimeSource());
327 time_source_
= wall_clock_time_source_
.get();
330 state_
= STATE_PLAYING
;
331 DCHECK(time_source_
);
332 DCHECK(audio_renderer_
|| video_renderer_
);
333 base::ResetAndReturn(&init_cb_
).Run();
336 void RendererImpl::FlushAudioRenderer() {
337 DVLOG(1) << __FUNCTION__
;
338 DCHECK(task_runner_
->BelongsToCurrentThread());
339 DCHECK_EQ(state_
, STATE_FLUSHING
);
340 DCHECK(!flush_cb_
.is_null());
342 if (!audio_renderer_
) {
343 OnAudioRendererFlushDone();
347 audio_renderer_
->Flush(
348 base::Bind(&RendererImpl::OnAudioRendererFlushDone
, weak_this_
));
351 void RendererImpl::OnAudioRendererFlushDone() {
352 DVLOG(1) << __FUNCTION__
;
353 DCHECK(task_runner_
->BelongsToCurrentThread());
355 if (state_
== STATE_ERROR
) {
356 DCHECK(flush_cb_
.is_null());
360 DCHECK_EQ(state_
, STATE_FLUSHING
);
361 DCHECK(!flush_cb_
.is_null());
363 DCHECK_EQ(audio_buffering_state_
, BUFFERING_HAVE_NOTHING
);
364 audio_ended_
= false;
365 FlushVideoRenderer();
368 void RendererImpl::FlushVideoRenderer() {
369 DVLOG(1) << __FUNCTION__
;
370 DCHECK(task_runner_
->BelongsToCurrentThread());
371 DCHECK_EQ(state_
, STATE_FLUSHING
);
372 DCHECK(!flush_cb_
.is_null());
374 if (!video_renderer_
) {
375 OnVideoRendererFlushDone();
379 video_renderer_
->Flush(
380 base::Bind(&RendererImpl::OnVideoRendererFlushDone
, weak_this_
));
383 void RendererImpl::OnVideoRendererFlushDone() {
384 DVLOG(1) << __FUNCTION__
;
385 DCHECK(task_runner_
->BelongsToCurrentThread());
387 if (state_
== STATE_ERROR
) {
388 DCHECK(flush_cb_
.is_null());
392 DCHECK_EQ(state_
, STATE_FLUSHING
);
393 DCHECK(!flush_cb_
.is_null());
395 DCHECK_EQ(video_buffering_state_
, BUFFERING_HAVE_NOTHING
);
396 video_ended_
= false;
397 state_
= STATE_PLAYING
;
398 base::ResetAndReturn(&flush_cb_
).Run();
401 void RendererImpl::OnUpdateStatistics(const PipelineStatistics
& stats
) {
402 DCHECK(task_runner_
->BelongsToCurrentThread());
403 statistics_cb_
.Run(stats
);
406 void RendererImpl::OnBufferingStateChanged(BufferingState
* buffering_state
,
407 BufferingState new_buffering_state
) {
408 DVLOG(1) << __FUNCTION__
<< "(" << *buffering_state
<< ", "
409 << new_buffering_state
<< ") "
410 << (buffering_state
== &audio_buffering_state_
? "audio" : "video");
411 DCHECK(task_runner_
->BelongsToCurrentThread());
412 bool was_waiting_for_enough_data
= WaitingForEnoughData();
414 *buffering_state
= new_buffering_state
;
416 // Disable underflow by ignoring updates that renderers have ran out of data.
417 if (state_
== STATE_PLAYING
&& underflow_disabled_for_testing_
&&
419 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
423 // Renderer underflowed.
424 if (!was_waiting_for_enough_data
&& WaitingForEnoughData()) {
427 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
428 // underflow state http://crbug.com/144683
432 // Renderer prerolled.
433 if (was_waiting_for_enough_data
&& !WaitingForEnoughData()) {
435 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
440 bool RendererImpl::WaitingForEnoughData() const {
441 DCHECK(task_runner_
->BelongsToCurrentThread());
442 if (state_
!= STATE_PLAYING
)
444 if (audio_renderer_
&& audio_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
446 if (video_renderer_
&& video_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
451 void RendererImpl::PausePlayback() {
452 DVLOG(1) << __FUNCTION__
;
453 DCHECK(task_runner_
->BelongsToCurrentThread());
454 DCHECK(time_ticking_
);
457 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
458 << "Playback should only pause due to ending or underflowing";
462 // It's OK to pause playback when flushing.
465 case STATE_UNINITIALIZED
:
466 case STATE_INITIALIZING
:
467 NOTREACHED() << "Invalid state: " << state_
;
471 // An error state may occur at any time.
475 time_ticking_
= false;
476 time_source_
->StopTicking();
479 void RendererImpl::StartPlayback() {
480 DVLOG(1) << __FUNCTION__
;
481 DCHECK(task_runner_
->BelongsToCurrentThread());
482 DCHECK_EQ(state_
, STATE_PLAYING
);
483 DCHECK(!time_ticking_
);
484 DCHECK(!WaitingForEnoughData());
486 time_ticking_
= true;
487 time_source_
->StartTicking();
490 void RendererImpl::OnAudioRendererEnded() {
491 DVLOG(1) << __FUNCTION__
;
492 DCHECK(task_runner_
->BelongsToCurrentThread());
494 if (state_
!= STATE_PLAYING
)
497 DCHECK(!audio_ended_
);
500 RunEndedCallbackIfNeeded();
503 void RendererImpl::OnVideoRendererEnded() {
504 DVLOG(1) << __FUNCTION__
;
505 DCHECK(task_runner_
->BelongsToCurrentThread());
507 if (state_
!= STATE_PLAYING
)
510 DCHECK(!video_ended_
);
513 RunEndedCallbackIfNeeded();
516 bool RendererImpl::PlaybackHasEnded() const {
517 DVLOG(1) << __FUNCTION__
;
518 DCHECK(task_runner_
->BelongsToCurrentThread());
520 if (audio_renderer_
&& !audio_ended_
)
523 if (video_renderer_
&& !video_ended_
)
529 void RendererImpl::RunEndedCallbackIfNeeded() {
530 DVLOG(1) << __FUNCTION__
;
531 DCHECK(task_runner_
->BelongsToCurrentThread());
533 if (!PlaybackHasEnded())
542 void RendererImpl::OnError(PipelineStatus error
) {
543 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
544 DCHECK(task_runner_
->BelongsToCurrentThread());
545 DCHECK_NE(PIPELINE_OK
, error
) << "PIPELINE_OK isn't an error!";
547 // An error has already been delivered.
548 if (state_
== STATE_ERROR
)
551 state_
= STATE_ERROR
;
553 // Pipeline will destroy |this| as the result of error.
554 base::ResetAndReturn(&error_cb_
).Run(error
);
556 FireAllPendingCallbacks();
559 void RendererImpl::FireAllPendingCallbacks() {
560 DCHECK(task_runner_
->BelongsToCurrentThread());
562 if (!init_cb_
.is_null())
563 base::ResetAndReturn(&init_cb_
).Run();
565 if (!flush_cb_
.is_null())
566 base::ResetAndReturn(&flush_cb_
).Run();