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/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/location.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "media/base/audio_renderer.h"
16 #include "media/base/bind_to_current_loop.h"
17 #include "media/base/demuxer_stream_provider.h"
18 #include "media/base/media_switches.h"
19 #include "media/base/time_source.h"
20 #include "media/base/video_renderer.h"
21 #include "media/base/wall_clock_time_source.h"
25 // See |video_underflow_threshold_|.
26 static const int kDefaultVideoUnderflowThresholdMs
= 3000;
28 RendererImpl::RendererImpl(
29 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
30 scoped_ptr
<AudioRenderer
> audio_renderer
,
31 scoped_ptr
<VideoRenderer
> video_renderer
)
32 : state_(STATE_UNINITIALIZED
),
33 task_runner_(task_runner
),
34 audio_renderer_(audio_renderer
.Pass()),
35 video_renderer_(video_renderer
.Pass()),
39 audio_buffering_state_(BUFFERING_HAVE_NOTHING
),
40 video_buffering_state_(BUFFERING_HAVE_NOTHING
),
43 cdm_context_(nullptr),
44 underflow_disabled_for_testing_(false),
45 clockless_video_playback_enabled_for_testing_(false),
46 video_underflow_threshold_(
47 base::TimeDelta::FromMilliseconds(kDefaultVideoUnderflowThresholdMs
)),
49 weak_this_
= weak_factory_
.GetWeakPtr();
50 DVLOG(1) << __FUNCTION__
;
52 // TODO(dalecurtis): Remove once experiments for http://crbug.com/470940 are
55 std::string
threshold_ms_str(
56 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
57 switches::kVideoUnderflowThresholdMs
));
58 if (base::StringToInt(threshold_ms_str
, &threshold_ms
) && threshold_ms
> 0) {
59 video_underflow_threshold_
=
60 base::TimeDelta::FromMilliseconds(threshold_ms
);
64 RendererImpl::~RendererImpl() {
65 DVLOG(1) << __FUNCTION__
;
66 DCHECK(task_runner_
->BelongsToCurrentThread());
68 // Tear down in opposite order of construction as |video_renderer_| can still
69 // need |time_source_| (which can be |audio_renderer_|) to be alive.
70 video_renderer_
.reset();
71 audio_renderer_
.reset();
73 if (!init_cb_
.is_null())
74 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_ERROR_ABORT
);
75 else if (!flush_cb_
.is_null())
76 base::ResetAndReturn(&flush_cb_
).Run();
79 void RendererImpl::Initialize(
80 DemuxerStreamProvider
* demuxer_stream_provider
,
81 const PipelineStatusCB
& init_cb
,
82 const StatisticsCB
& statistics_cb
,
83 const BufferingStateCB
& buffering_state_cb
,
84 const base::Closure
& ended_cb
,
85 const PipelineStatusCB
& error_cb
,
86 const base::Closure
& waiting_for_decryption_key_cb
) {
87 DVLOG(1) << __FUNCTION__
;
88 DCHECK(task_runner_
->BelongsToCurrentThread());
89 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
90 DCHECK(!init_cb
.is_null());
91 DCHECK(!statistics_cb
.is_null());
92 DCHECK(!buffering_state_cb
.is_null());
93 DCHECK(!ended_cb
.is_null());
94 DCHECK(!error_cb
.is_null());
95 DCHECK(demuxer_stream_provider
->GetStream(DemuxerStream::AUDIO
) ||
96 demuxer_stream_provider
->GetStream(DemuxerStream::VIDEO
));
98 demuxer_stream_provider_
= demuxer_stream_provider
;
99 statistics_cb_
= statistics_cb
;
100 buffering_state_cb_
= buffering_state_cb
;
101 ended_cb_
= ended_cb
;
102 error_cb_
= error_cb
;
104 waiting_for_decryption_key_cb_
= waiting_for_decryption_key_cb
;
106 state_
= STATE_INITIALIZING
;
107 InitializeAudioRenderer();
110 void RendererImpl::SetCdm(CdmContext
* cdm_context
,
111 const CdmAttachedCB
& cdm_attached_cb
) {
112 DVLOG(1) << __FUNCTION__
;
113 DCHECK(task_runner_
->BelongsToCurrentThread());
117 DVLOG(1) << "Switching CDM not supported.";
118 cdm_attached_cb
.Run(false);
122 cdm_context_
= cdm_context
;
124 if (decryptor_ready_cb_
.is_null()) {
125 cdm_attached_cb
.Run(true);
129 base::ResetAndReturn(&decryptor_ready_cb_
)
130 .Run(cdm_context
->GetDecryptor(), cdm_attached_cb
);
133 void RendererImpl::Flush(const base::Closure
& flush_cb
) {
134 DVLOG(1) << __FUNCTION__
;
135 DCHECK(task_runner_
->BelongsToCurrentThread());
136 DCHECK(flush_cb_
.is_null());
138 if (state_
!= STATE_PLAYING
) {
139 DCHECK_EQ(state_
, STATE_ERROR
);
143 flush_cb_
= flush_cb
;
144 state_
= STATE_FLUSHING
;
149 FlushAudioRenderer();
152 void RendererImpl::StartPlayingFrom(base::TimeDelta time
) {
153 DVLOG(1) << __FUNCTION__
;
154 DCHECK(task_runner_
->BelongsToCurrentThread());
156 if (state_
!= STATE_PLAYING
) {
157 DCHECK_EQ(state_
, STATE_ERROR
);
161 time_source_
->SetMediaTime(time
);
164 audio_renderer_
->StartPlaying();
166 video_renderer_
->StartPlayingFrom(time
);
169 void RendererImpl::SetPlaybackRate(double playback_rate
) {
170 DVLOG(1) << __FUNCTION__
<< "(" << playback_rate
<< ")";
171 DCHECK(task_runner_
->BelongsToCurrentThread());
173 // Playback rate changes are only carried out while playing.
174 if (state_
!= STATE_PLAYING
)
177 time_source_
->SetPlaybackRate(playback_rate
);
179 const double old_rate
= playback_rate_
;
180 playback_rate_
= playback_rate
;
181 if (!time_ticking_
|| !video_renderer_
)
184 if (old_rate
== 0 && playback_rate
> 0)
185 video_renderer_
->OnTimeStateChanged(true);
186 else if (old_rate
> 0 && playback_rate
== 0)
187 video_renderer_
->OnTimeStateChanged(false);
190 void RendererImpl::SetVolume(float volume
) {
191 DVLOG(1) << __FUNCTION__
;
192 DCHECK(task_runner_
->BelongsToCurrentThread());
195 audio_renderer_
->SetVolume(volume
);
198 base::TimeDelta
RendererImpl::GetMediaTime() {
199 // No BelongsToCurrentThread() checking because this can be called from other
201 return time_source_
->CurrentMediaTime();
204 bool RendererImpl::HasAudio() {
205 DCHECK(task_runner_
->BelongsToCurrentThread());
206 return audio_renderer_
!= NULL
;
209 bool RendererImpl::HasVideo() {
210 DCHECK(task_runner_
->BelongsToCurrentThread());
211 return video_renderer_
!= NULL
;
214 void RendererImpl::DisableUnderflowForTesting() {
215 DVLOG(1) << __FUNCTION__
;
216 DCHECK(task_runner_
->BelongsToCurrentThread());
217 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
219 underflow_disabled_for_testing_
= true;
222 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
223 DVLOG(1) << __FUNCTION__
;
224 DCHECK(task_runner_
->BelongsToCurrentThread());
225 DCHECK_EQ(state_
, STATE_UNINITIALIZED
);
226 DCHECK(underflow_disabled_for_testing_
)
227 << "Underflow must be disabled for clockless video playback";
229 clockless_video_playback_enabled_for_testing_
= true;
232 bool RendererImpl::GetWallClockTimes(
233 const std::vector
<base::TimeDelta
>& media_timestamps
,
234 std::vector
<base::TimeTicks
>* wall_clock_times
) {
235 // No BelongsToCurrentThread() checking because this can be called from other
238 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
239 // which should go away at some point http://crbug.com/110814
240 if (clockless_video_playback_enabled_for_testing_
) {
241 if (media_timestamps
.empty()) {
242 *wall_clock_times
= std::vector
<base::TimeTicks
>(1,
243 base::TimeTicks::Now());
245 *wall_clock_times
= std::vector
<base::TimeTicks
>();
246 for (auto const &media_time
: media_timestamps
) {
247 wall_clock_times
->push_back(base::TimeTicks() + media_time
);
253 return time_source_
->GetWallClockTimes(media_timestamps
, wall_clock_times
);
256 void RendererImpl::SetDecryptorReadyCallback(
257 const DecryptorReadyCB
& decryptor_ready_cb
) {
258 // Cancels the previous decryptor request.
259 if (decryptor_ready_cb
.is_null()) {
260 if (!decryptor_ready_cb_
.is_null()) {
261 base::ResetAndReturn(&decryptor_ready_cb_
)
262 .Run(nullptr, base::Bind(IgnoreCdmAttached
));
267 // We initialize audio and video decoders in sequence.
268 DCHECK(decryptor_ready_cb_
.is_null());
271 decryptor_ready_cb
.Run(cdm_context_
->GetDecryptor(),
272 base::Bind(IgnoreCdmAttached
));
276 decryptor_ready_cb_
= decryptor_ready_cb
;
279 void RendererImpl::InitializeAudioRenderer() {
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::OnAudioRendererInitializeDone
, weak_this_
);
288 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
)) {
289 audio_renderer_
.reset();
290 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
294 // Note: After the initialization of a renderer, error events from it may
295 // happen at any time and all future calls must guard against STATE_ERROR.
296 audio_renderer_
->Initialize(
297 demuxer_stream_provider_
->GetStream(DemuxerStream::AUDIO
), done_cb
,
298 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
299 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
300 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
301 &audio_buffering_state_
),
302 base::Bind(&RendererImpl::OnAudioRendererEnded
, weak_this_
),
303 base::Bind(&RendererImpl::OnError
, weak_this_
),
304 waiting_for_decryption_key_cb_
);
307 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status
) {
308 DVLOG(1) << __FUNCTION__
<< ": " << status
;
309 DCHECK(task_runner_
->BelongsToCurrentThread());
311 // OnError() may be fired at any time by the renderers, even if they thought
312 // they initialized successfully (due to delayed output device setup).
313 if (state_
!= STATE_INITIALIZING
) {
314 DCHECK(init_cb_
.is_null());
315 audio_renderer_
.reset();
319 if (status
!= PIPELINE_OK
) {
320 base::ResetAndReturn(&init_cb_
).Run(status
);
324 DCHECK(!init_cb_
.is_null());
325 InitializeVideoRenderer();
328 void RendererImpl::InitializeVideoRenderer() {
329 DVLOG(1) << __FUNCTION__
;
330 DCHECK(task_runner_
->BelongsToCurrentThread());
331 DCHECK_EQ(state_
, STATE_INITIALIZING
);
332 DCHECK(!init_cb_
.is_null());
334 PipelineStatusCB done_cb
=
335 base::Bind(&RendererImpl::OnVideoRendererInitializeDone
, weak_this_
);
337 if (!demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
)) {
338 video_renderer_
.reset();
339 task_runner_
->PostTask(FROM_HERE
, base::Bind(done_cb
, PIPELINE_OK
));
343 video_renderer_
->Initialize(
344 demuxer_stream_provider_
->GetStream(DemuxerStream::VIDEO
), done_cb
,
345 base::Bind(&RendererImpl::SetDecryptorReadyCallback
, weak_this_
),
346 base::Bind(&RendererImpl::OnUpdateStatistics
, weak_this_
),
347 base::Bind(&RendererImpl::OnBufferingStateChanged
, weak_this_
,
348 &video_buffering_state_
),
349 base::Bind(&RendererImpl::OnVideoRendererEnded
, weak_this_
),
350 base::Bind(&RendererImpl::OnError
, weak_this_
),
351 base::Bind(&RendererImpl::GetWallClockTimes
, base::Unretained(this)),
352 waiting_for_decryption_key_cb_
);
355 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status
) {
356 DVLOG(1) << __FUNCTION__
<< ": " << status
;
357 DCHECK(task_runner_
->BelongsToCurrentThread());
359 // OnError() may be fired at any time by the renderers, even if they thought
360 // they initialized successfully (due to delayed output device setup).
361 if (state_
!= STATE_INITIALIZING
) {
362 DCHECK(init_cb_
.is_null());
363 audio_renderer_
.reset();
364 video_renderer_
.reset();
368 DCHECK(!init_cb_
.is_null());
370 if (status
!= PIPELINE_OK
) {
371 base::ResetAndReturn(&init_cb_
).Run(status
);
375 if (audio_renderer_
) {
376 time_source_
= audio_renderer_
->GetTimeSource();
377 } else if (!time_source_
) {
378 wall_clock_time_source_
.reset(new WallClockTimeSource());
379 time_source_
= wall_clock_time_source_
.get();
382 state_
= STATE_PLAYING
;
383 DCHECK(time_source_
);
384 DCHECK(audio_renderer_
|| video_renderer_
);
385 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_OK
);
388 void RendererImpl::FlushAudioRenderer() {
389 DVLOG(1) << __FUNCTION__
;
390 DCHECK(task_runner_
->BelongsToCurrentThread());
391 DCHECK_EQ(state_
, STATE_FLUSHING
);
392 DCHECK(!flush_cb_
.is_null());
394 if (!audio_renderer_
) {
395 OnAudioRendererFlushDone();
399 audio_renderer_
->Flush(
400 base::Bind(&RendererImpl::OnAudioRendererFlushDone
, weak_this_
));
403 void RendererImpl::OnAudioRendererFlushDone() {
404 DVLOG(1) << __FUNCTION__
;
405 DCHECK(task_runner_
->BelongsToCurrentThread());
407 if (state_
== STATE_ERROR
) {
408 DCHECK(flush_cb_
.is_null());
412 DCHECK_EQ(state_
, STATE_FLUSHING
);
413 DCHECK(!flush_cb_
.is_null());
415 // If we had a deferred video renderer underflow prior to the flush, it should
416 // have been cleared by the audio renderer changing to BUFFERING_HAVE_NOTHING.
417 DCHECK(deferred_underflow_cb_
.IsCancelled());
419 DCHECK_EQ(audio_buffering_state_
, BUFFERING_HAVE_NOTHING
);
420 audio_ended_
= false;
421 FlushVideoRenderer();
424 void RendererImpl::FlushVideoRenderer() {
425 DVLOG(1) << __FUNCTION__
;
426 DCHECK(task_runner_
->BelongsToCurrentThread());
427 DCHECK_EQ(state_
, STATE_FLUSHING
);
428 DCHECK(!flush_cb_
.is_null());
430 if (!video_renderer_
) {
431 OnVideoRendererFlushDone();
435 video_renderer_
->Flush(
436 base::Bind(&RendererImpl::OnVideoRendererFlushDone
, weak_this_
));
439 void RendererImpl::OnVideoRendererFlushDone() {
440 DVLOG(1) << __FUNCTION__
;
441 DCHECK(task_runner_
->BelongsToCurrentThread());
443 if (state_
== STATE_ERROR
) {
444 DCHECK(flush_cb_
.is_null());
448 DCHECK_EQ(state_
, STATE_FLUSHING
);
449 DCHECK(!flush_cb_
.is_null());
451 DCHECK_EQ(video_buffering_state_
, BUFFERING_HAVE_NOTHING
);
452 video_ended_
= false;
453 state_
= STATE_PLAYING
;
454 base::ResetAndReturn(&flush_cb_
).Run();
457 void RendererImpl::OnUpdateStatistics(const PipelineStatistics
& stats
) {
458 DCHECK(task_runner_
->BelongsToCurrentThread());
459 statistics_cb_
.Run(stats
);
462 void RendererImpl::OnBufferingStateChanged(BufferingState
* buffering_state
,
463 BufferingState new_buffering_state
) {
464 const bool is_audio
= buffering_state
== &audio_buffering_state_
;
465 DVLOG(1) << __FUNCTION__
<< "(" << *buffering_state
<< ", "
466 << new_buffering_state
<< ") " << (is_audio
? "audio" : "video");
467 DCHECK(task_runner_
->BelongsToCurrentThread());
469 bool was_waiting_for_enough_data
= WaitingForEnoughData();
471 // When audio is present and has enough data, defer video underflow callbacks
472 // for some time to avoid unnecessary glitches in audio; see
473 // http://crbug.com/144683#c53.
474 if (audio_renderer_
&& !is_audio
&& state_
== STATE_PLAYING
) {
475 if (video_buffering_state_
== BUFFERING_HAVE_ENOUGH
&&
476 audio_buffering_state_
== BUFFERING_HAVE_ENOUGH
&&
477 new_buffering_state
== BUFFERING_HAVE_NOTHING
&&
478 deferred_underflow_cb_
.IsCancelled()) {
479 deferred_underflow_cb_
.Reset(base::Bind(
480 &RendererImpl::OnBufferingStateChanged
, weak_factory_
.GetWeakPtr(),
481 buffering_state
, new_buffering_state
));
482 task_runner_
->PostDelayedTask(FROM_HERE
,
483 deferred_underflow_cb_
.callback(),
484 video_underflow_threshold_
);
488 deferred_underflow_cb_
.Cancel();
489 } else if (!deferred_underflow_cb_
.IsCancelled() && is_audio
&&
490 new_buffering_state
== BUFFERING_HAVE_NOTHING
) {
491 // If audio underflows while we have a deferred video underflow in progress
492 // we want to mark video as underflowed immediately and cancel the deferral.
493 deferred_underflow_cb_
.Cancel();
494 video_buffering_state_
= BUFFERING_HAVE_NOTHING
;
497 *buffering_state
= new_buffering_state
;
499 // Disable underflow by ignoring updates that renderers have ran out of data.
500 if (state_
== STATE_PLAYING
&& underflow_disabled_for_testing_
&&
502 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
506 // Renderer underflowed.
507 if (!was_waiting_for_enough_data
&& WaitingForEnoughData()) {
510 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
511 // underflow state http://crbug.com/144683
515 // Renderer prerolled.
516 if (was_waiting_for_enough_data
&& !WaitingForEnoughData()) {
518 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
523 bool RendererImpl::WaitingForEnoughData() const {
524 DCHECK(task_runner_
->BelongsToCurrentThread());
525 if (state_
!= STATE_PLAYING
)
527 if (audio_renderer_
&& audio_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
529 if (video_renderer_
&& video_buffering_state_
!= BUFFERING_HAVE_ENOUGH
)
534 void RendererImpl::PausePlayback() {
535 DVLOG(1) << __FUNCTION__
;
536 DCHECK(task_runner_
->BelongsToCurrentThread());
537 DCHECK(time_ticking_
);
540 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
541 << "Playback should only pause due to ending or underflowing";
545 // It's OK to pause playback when flushing.
548 case STATE_UNINITIALIZED
:
549 case STATE_INITIALIZING
:
550 NOTREACHED() << "Invalid state: " << state_
;
554 // An error state may occur at any time.
558 time_ticking_
= false;
559 time_source_
->StopTicking();
560 if (playback_rate_
> 0 && video_renderer_
)
561 video_renderer_
->OnTimeStateChanged(false);
564 void RendererImpl::StartPlayback() {
565 DVLOG(1) << __FUNCTION__
;
566 DCHECK(task_runner_
->BelongsToCurrentThread());
567 DCHECK_EQ(state_
, STATE_PLAYING
);
568 DCHECK(!time_ticking_
);
569 DCHECK(!WaitingForEnoughData());
571 time_ticking_
= true;
572 time_source_
->StartTicking();
573 if (playback_rate_
> 0 && video_renderer_
)
574 video_renderer_
->OnTimeStateChanged(true);
577 void RendererImpl::OnAudioRendererEnded() {
578 DVLOG(1) << __FUNCTION__
;
579 DCHECK(task_runner_
->BelongsToCurrentThread());
581 if (state_
!= STATE_PLAYING
)
584 DCHECK(!audio_ended_
);
587 RunEndedCallbackIfNeeded();
590 void RendererImpl::OnVideoRendererEnded() {
591 DVLOG(1) << __FUNCTION__
;
592 DCHECK(task_runner_
->BelongsToCurrentThread());
594 if (state_
!= STATE_PLAYING
)
597 DCHECK(!video_ended_
);
600 RunEndedCallbackIfNeeded();
603 bool RendererImpl::PlaybackHasEnded() const {
604 DVLOG(1) << __FUNCTION__
;
605 DCHECK(task_runner_
->BelongsToCurrentThread());
607 if (audio_renderer_
&& !audio_ended_
)
610 if (video_renderer_
&& !video_ended_
)
616 void RendererImpl::RunEndedCallbackIfNeeded() {
617 DVLOG(1) << __FUNCTION__
;
618 DCHECK(task_runner_
->BelongsToCurrentThread());
620 if (!PlaybackHasEnded())
629 void RendererImpl::OnError(PipelineStatus error
) {
630 DVLOG(1) << __FUNCTION__
<< "(" << error
<< ")";
631 DCHECK(task_runner_
->BelongsToCurrentThread());
632 DCHECK_NE(PIPELINE_OK
, error
) << "PIPELINE_OK isn't an error!";
634 // An error has already been delivered.
635 if (state_
== STATE_ERROR
)
638 const State old_state
= state_
;
639 state_
= STATE_ERROR
;
641 if (old_state
== STATE_INITIALIZING
) {
642 base::ResetAndReturn(&init_cb_
).Run(error
);
646 // After OnError() returns, the pipeline may destroy |this|.
647 base::ResetAndReturn(&error_cb_
).Run(error
);
649 if (!flush_cb_
.is_null())
650 base::ResetAndReturn(&flush_cb_
).Run();