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/renderers/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(
60 DemuxerStreamProvider
* demuxer_stream_provider
,
61 const PipelineStatusCB
& init_cb
,
62 const StatisticsCB
& statistics_cb
,
63 const BufferingStateCB
& buffering_state_cb
,
64 const PaintCB
& paint_cb
,
65 const base::Closure
& ended_cb
,
66 const PipelineStatusCB
& error_cb
,
67 const base::Closure
& waiting_for_decryption_key_cb
) {
68 DVLOG(1) << __FUNCTION__
;
69 DCHECK(task_runner_
->BelongsToCurrentThread());
70 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
71 DCHECK(!init_cb
.is_null());
72 DCHECK(!statistics_cb
.is_null());
73 DCHECK(!buffering_state_cb
.is_null());
74 DCHECK(!paint_cb
.is_null());
75 DCHECK(!ended_cb
.is_null());
76 DCHECK(!error_cb
.is_null());
77 DCHECK(demuxer_stream_provider
->GetStream(DemuxerStream::AUDIO
) ||
78 demuxer_stream_provider
->GetStream(DemuxerStream::VIDEO
));
80 demuxer_stream_provider_
= demuxer_stream_provider
;
81 statistics_cb_
= statistics_cb
;
82 buffering_state_cb_
= buffering_state_cb
;
87 waiting_for_decryption_key_cb_
= waiting_for_decryption_key_cb
;
89 state_
= STATE_INITIALIZING
;
90 InitializeAudioRenderer();
93 void RendererImpl::SetCdm(CdmContext
* cdm_context
,
94 const CdmAttachedCB
& cdm_attached_cb
) {
95 DVLOG(1) << __FUNCTION__
;
96 DCHECK(task_runner_
->BelongsToCurrentThread());
100 DVLOG(1) << "Switching CDM not supported.";
101 cdm_attached_cb
.Run(false);
105 cdm_context_
= cdm_context
;
107 if (decryptor_ready_cb_
.is_null()) {
108 cdm_attached_cb
.Run(true);
112 base::ResetAndReturn(&decryptor_ready_cb_
)
113 .Run(cdm_context
->GetDecryptor(), cdm_attached_cb
);
116 void RendererImpl::Flush(const base::Closure
& flush_cb
) {
117 DVLOG(1) << __FUNCTION__
;
118 DCHECK(task_runner_
->BelongsToCurrentThread());
119 DCHECK(flush_cb_
.is_null());
121 if (state_
!= STATE_PLAYING
) {
122 DCHECK_EQ(state_
, STATE_ERROR
);
126 flush_cb_
= flush_cb
;
127 state_
= STATE_FLUSHING
;
132 FlushAudioRenderer();
135 void RendererImpl::StartPlayingFrom(base::TimeDelta time
) {
136 DVLOG(1) << __FUNCTION__
;
137 DCHECK(task_runner_
->BelongsToCurrentThread());
139 if (state_
!= STATE_PLAYING
) {
140 DCHECK_EQ(state_
, STATE_ERROR
);
144 time_source_
->SetMediaTime(time
);
147 audio_renderer_
->StartPlaying();
149 video_renderer_
->StartPlayingFrom(time
);
152 void RendererImpl::SetPlaybackRate(float playback_rate
) {
153 DVLOG(1) << __FUNCTION__
<< "(" << playback_rate
<< ")";
154 DCHECK(task_runner_
->BelongsToCurrentThread());
156 // Playback rate changes are only carried out while playing.
157 if (state_
!= STATE_PLAYING
)
160 time_source_
->SetPlaybackRate(playback_rate
);
163 void RendererImpl::SetVolume(float volume
) {
164 DVLOG(1) << __FUNCTION__
;
165 DCHECK(task_runner_
->BelongsToCurrentThread());
168 audio_renderer_
->SetVolume(volume
);
171 base::TimeDelta
RendererImpl::GetMediaTime() {
172 // No BelongsToCurrentThread() checking because this can be called from other
174 return time_source_
->CurrentMediaTime();
177 bool RendererImpl::HasAudio() {
178 DCHECK(task_runner_
->BelongsToCurrentThread());
179 return audio_renderer_
!= NULL
;
182 bool RendererImpl::HasVideo() {
183 DCHECK(task_runner_
->BelongsToCurrentThread());
184 return video_renderer_
!= NULL
;
187 void RendererImpl::DisableUnderflowForTesting() {
188 DVLOG(1) << __FUNCTION__
;
189 DCHECK(task_runner_
->BelongsToCurrentThread());
190 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
192 underflow_disabled_for_testing_
= true;
195 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
196 DVLOG(1) << __FUNCTION__
;
197 DCHECK(task_runner_
->BelongsToCurrentThread());
198 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
199 DCHECK(underflow_disabled_for_testing_
)
200 << "Underflow must be disabled for clockless video playback";
202 clockless_video_playback_enabled_for_testing_
= true;
205 base::TimeDelta
RendererImpl::GetMediaTimeForSyncingVideo() {
206 // No BelongsToCurrentThread() checking because this can be called from other
209 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
210 // which should go away at some point http://crbug.com/110814
211 if (clockless_video_playback_enabled_for_testing_
)
212 return base::TimeDelta::Max();
214 return time_source_
->CurrentMediaTimeForSyncingVideo();
217 void RendererImpl::SetDecryptorReadyCallback(
218 const DecryptorReadyCB
& decryptor_ready_cb
) {
219 // Cancels the previous decryptor request.
220 if (decryptor_ready_cb
.is_null()) {
221 if (!decryptor_ready_cb_
.is_null()) {
222 base::ResetAndReturn(&decryptor_ready_cb_
)
223 .Run(nullptr, base::Bind(IgnoreCdmAttached
));
228 // We initialize audio and video decoders in sequence.
229 DCHECK(decryptor_ready_cb_
.is_null());
232 decryptor_ready_cb
.Run(cdm_context_
->GetDecryptor(),
233 base::Bind(IgnoreCdmAttached
));
237 decryptor_ready_cb_
= decryptor_ready_cb
;
240 void RendererImpl::InitializeAudioRenderer() {
241 DVLOG(1) << __FUNCTION__
;
242 DCHECK(task_runner_
->BelongsToCurrentThread());
243 DCHECK_EQ(state_
, STATE_INITIALIZING
);
244 DCHECK(!init_cb_
.is_null());
246 PipelineStatusCB done_cb
=
247 base::Bind(&RendererImpl::OnAudioRendererInitializeDone
, weak_this_
);
249 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
)) {
250 audio_renderer_
.reset();
251 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
255 // Note: After the initialization of a renderer, error events from it may
256 // happen at any time and all future calls must guard against STATE_ERROR.
257 audio_renderer_
->Initialize(
258 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
), done_cb
,
259 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
260 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
261 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
262 &audio_buffering_state_
),
263 base::Bind(&RendererImpl::OnAudioRendererEnded
, weak_this_
),
264 base::Bind(&RendererImpl::OnError
, weak_this_
),
265 waiting_for_decryption_key_cb_
);
268 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status
) {
269 DVLOG(1) << __FUNCTION__
<< ": " << status
;
270 DCHECK(task_runner_
->BelongsToCurrentThread());
272 // OnError() may be fired at any time by the renderers, even if they thought
273 // they initialized successfully (due to delayed output device setup).
274 if (state_
!= STATE_INITIALIZING
) {
275 DCHECK(init_cb_
.is_null());
276 audio_renderer_
.reset();
280 if (status
!= PIPELINE_OK
) {
281 base::ResetAndReturn(&init_cb_
).Run(status
);
285 DCHECK(!init_cb_
.is_null());
286 InitializeVideoRenderer();
289 void RendererImpl::InitializeVideoRenderer() {
290 DVLOG(1) << __FUNCTION__
;
291 DCHECK(task_runner_
->BelongsToCurrentThread());
292 DCHECK_EQ(state_
, STATE_INITIALIZING
);
293 DCHECK(!init_cb_
.is_null());
295 PipelineStatusCB done_cb
=
296 base::Bind(&RendererImpl::OnVideoRendererInitializeDone
, weak_this_
);
298 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
)) {
299 video_renderer_
.reset();
300 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
304 video_renderer_
->Initialize(
305 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
), done_cb
,
306 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
307 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
308 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
309 &video_buffering_state_
),
310 base::ResetAndReturn(&paint_cb_
),
311 base::Bind(&RendererImpl::OnVideoRendererEnded
, weak_this_
),
312 base::Bind(&RendererImpl::OnError
, weak_this_
),
313 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo
,
314 base::Unretained(this)),
315 waiting_for_decryption_key_cb_
);
318 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status
) {
319 DVLOG(1) << __FUNCTION__
<< ": " << status
;
320 DCHECK(task_runner_
->BelongsToCurrentThread());
322 // OnError() may be fired at any time by the renderers, even if they thought
323 // they initialized successfully (due to delayed output device setup).
324 if (state_
!= STATE_INITIALIZING
) {
325 DCHECK(init_cb_
.is_null());
326 audio_renderer_
.reset();
327 video_renderer_
.reset();
331 DCHECK(!init_cb_
.is_null());
333 if (status
!= PIPELINE_OK
) {
334 base::ResetAndReturn(&init_cb_
).Run(status
);
338 if (audio_renderer_
) {
339 time_source_
= audio_renderer_
->GetTimeSource();
341 wall_clock_time_source_
.reset(new WallClockTimeSource());
342 time_source_
= wall_clock_time_source_
.get();
345 state_
= STATE_PLAYING
;
346 DCHECK(time_source_
);
347 DCHECK(audio_renderer_
|| video_renderer_
);
348 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_OK
);
351 void RendererImpl::FlushAudioRenderer() {
352 DVLOG(1) << __FUNCTION__
;
353 DCHECK(task_runner_
->BelongsToCurrentThread());
354 DCHECK_EQ(state_
, STATE_FLUSHING
);
355 DCHECK(!flush_cb_
.is_null());
357 if (!audio_renderer_
) {
358 OnAudioRendererFlushDone();
362 audio_renderer_
->Flush(
363 base::Bind(&RendererImpl::OnAudioRendererFlushDone
, weak_this_
));
366 void RendererImpl::OnAudioRendererFlushDone() {
367 DVLOG(1) << __FUNCTION__
;
368 DCHECK(task_runner_
->BelongsToCurrentThread());
370 if (state_
== STATE_ERROR
) {
371 DCHECK(flush_cb_
.is_null());
375 DCHECK_EQ(state_
, STATE_FLUSHING
);
376 DCHECK(!flush_cb_
.is_null());
378 DCHECK_EQ(audio_buffering_state_
, BUFFERING_HAVE_NOTHING
);
379 audio_ended_
= false;
380 FlushVideoRenderer();
383 void RendererImpl::FlushVideoRenderer() {
384 DVLOG(1) << __FUNCTION__
;
385 DCHECK(task_runner_
->BelongsToCurrentThread());
386 DCHECK_EQ(state_
, STATE_FLUSHING
);
387 DCHECK(!flush_cb_
.is_null());
389 if (!video_renderer_
) {
390 OnVideoRendererFlushDone();
394 video_renderer_
->Flush(
395 base::Bind(&RendererImpl::OnVideoRendererFlushDone
, weak_this_
));
398 void RendererImpl::OnVideoRendererFlushDone() {
399 DVLOG(1) << __FUNCTION__
;
400 DCHECK(task_runner_
->BelongsToCurrentThread());
402 if (state_
== STATE_ERROR
) {
403 DCHECK(flush_cb_
.is_null());
407 DCHECK_EQ(state_
, STATE_FLUSHING
);
408 DCHECK(!flush_cb_
.is_null());
410 DCHECK_EQ(video_buffering_state_
, BUFFERING_HAVE_NOTHING
);
411 video_ended_
= false;
412 state_
= STATE_PLAYING
;
413 base::ResetAndReturn(&flush_cb_
).Run();
416 void RendererImpl::OnUpdateStatistics(const PipelineStatistics
& stats
) {
417 DCHECK(task_runner_
->BelongsToCurrentThread());
418 statistics_cb_
.Run(stats
);
421 void RendererImpl::OnBufferingStateChanged(BufferingState
* buffering_state
,
422 BufferingState new_buffering_state
) {
423 DVLOG(1) << __FUNCTION__
<< "(" << *buffering_state
<< ", "
424 << new_buffering_state
<< ") "
425 << (buffering_state
== &audio_buffering_state_
? "audio" : "video");
426 DCHECK(task_runner_
->BelongsToCurrentThread());
427 bool was_waiting_for_enough_data
= WaitingForEnoughData();
429 *buffering_state
= new_buffering_state
;
431 // Disable underflow by ignoring updates that renderers have ran out of data.
432 if (state_
== STATE_PLAYING
&& underflow_disabled_for_testing_
&&
434 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
438 // Renderer underflowed.
439 if (!was_waiting_for_enough_data
&& WaitingForEnoughData()) {
442 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
443 // underflow state http://crbug.com/144683
447 // Renderer prerolled.
448 if (was_waiting_for_enough_data
&& !WaitingForEnoughData()) {
450 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
455 bool RendererImpl::WaitingForEnoughData() const {
456 DCHECK(task_runner_
->BelongsToCurrentThread());
457 if (state_
!= STATE_PLAYING
)
459 if (audio_renderer_
&& audio_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
461 if (video_renderer_
&& video_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
466 void RendererImpl::PausePlayback() {
467 DVLOG(1) << __FUNCTION__
;
468 DCHECK(task_runner_
->BelongsToCurrentThread());
469 DCHECK(time_ticking_
);
472 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
473 << "Playback should only pause due to ending or underflowing";
477 // It's OK to pause playback when flushing.
480 case STATE_UNINITIALIZED
:
481 case STATE_INITIALIZING
:
482 NOTREACHED() << "Invalid state: " << state_
;
486 // An error state may occur at any time.
490 time_ticking_
= false;
491 time_source_
->StopTicking();
494 void RendererImpl::StartPlayback() {
495 DVLOG(1) << __FUNCTION__
;
496 DCHECK(task_runner_
->BelongsToCurrentThread());
497 DCHECK_EQ(state_
, STATE_PLAYING
);
498 DCHECK(!time_ticking_
);
499 DCHECK(!WaitingForEnoughData());
501 time_ticking_
= true;
502 time_source_
->StartTicking();
505 void RendererImpl::OnAudioRendererEnded() {
506 DVLOG(1) << __FUNCTION__
;
507 DCHECK(task_runner_
->BelongsToCurrentThread());
509 if (state_
!= STATE_PLAYING
)
512 DCHECK(!audio_ended_
);
515 RunEndedCallbackIfNeeded();
518 void RendererImpl::OnVideoRendererEnded() {
519 DVLOG(1) << __FUNCTION__
;
520 DCHECK(task_runner_
->BelongsToCurrentThread());
522 if (state_
!= STATE_PLAYING
)
525 DCHECK(!video_ended_
);
528 RunEndedCallbackIfNeeded();
531 bool RendererImpl::PlaybackHasEnded() const {
532 DVLOG(1) << __FUNCTION__
;
533 DCHECK(task_runner_
->BelongsToCurrentThread());
535 if (audio_renderer_
&& !audio_ended_
)
538 if (video_renderer_
&& !video_ended_
)
544 void RendererImpl::RunEndedCallbackIfNeeded() {
545 DVLOG(1) << __FUNCTION__
;
546 DCHECK(task_runner_
->BelongsToCurrentThread());
548 if (!PlaybackHasEnded())
557 void RendererImpl::OnError(PipelineStatus error
) {
558 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
559 DCHECK(task_runner_
->BelongsToCurrentThread());
560 DCHECK_NE(PIPELINE_OK
, error
) << "PIPELINE_OK isn't an error!";
562 // An error has already been delivered.
563 if (state_
== STATE_ERROR
)
566 const State old_state
= state_
;
567 state_
= STATE_ERROR
;
569 if (old_state
== STATE_INITIALIZING
) {
570 base::ResetAndReturn(&init_cb_
).Run(error
);
574 // After OnError() returns, the pipeline may destroy |this|.
575 base::ResetAndReturn(&error_cb_
).Run(error
);
577 if (!flush_cb_
.is_null())
578 base::ResetAndReturn(&flush_cb_
).Run();