Switch TestFrameNavigationObserver to DidCommitProvisionalLoadForFrame.
[chromium-blink-merge.git] / media / renderers / renderer_impl.cc
blob8efe432a7ccd64f8fb5dc982ff2a17b415fbe05d
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"
7 #include "base/bind.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"
23 namespace media {
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()),
36 time_source_(NULL),
37 time_ticking_(false),
38 playback_rate_(0.0),
39 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
40 video_buffering_state_(BUFFERING_HAVE_NOTHING),
41 audio_ended_(false),
42 video_ended_(false),
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)),
48 weak_factory_(this) {
49 weak_this_ = weak_factory_.GetWeakPtr();
50 DVLOG(1) << __FUNCTION__;
52 // TODO(dalecurtis): Remove once experiments for http://crbug.com/470940 are
53 // complete.
54 int threshold_ms = 0;
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;
103 init_cb_ = init_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());
114 DCHECK(cdm_context);
116 if (cdm_context_) {
117 DVLOG(1) << "Switching CDM not supported.";
118 cdm_attached_cb.Run(false);
119 return;
122 cdm_context_ = cdm_context;
124 if (decryptor_ready_cb_.is_null()) {
125 cdm_attached_cb.Run(true);
126 return;
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);
140 return;
143 flush_cb_ = flush_cb;
144 state_ = STATE_FLUSHING;
146 if (time_ticking_)
147 PausePlayback();
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);
158 return;
161 time_source_->SetMediaTime(time);
163 if (audio_renderer_)
164 audio_renderer_->StartPlaying();
165 if (video_renderer_)
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)
175 return;
177 time_source_->SetPlaybackRate(playback_rate);
179 const double old_rate = playback_rate_;
180 playback_rate_ = playback_rate;
181 if (!time_ticking_ || !video_renderer_)
182 return;
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());
194 if (audio_renderer_)
195 audio_renderer_->SetVolume(volume);
198 base::TimeDelta RendererImpl::GetMediaTime() {
199 // No BelongsToCurrentThread() checking because this can be called from other
200 // threads.
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
236 // threads.
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 *wall_clock_times = std::vector<base::TimeTicks>(media_timestamps.size(),
242 base::TimeTicks::Now());
243 return true;
246 return time_source_->GetWallClockTimes(media_timestamps, wall_clock_times);
249 void RendererImpl::SetDecryptorReadyCallback(
250 const DecryptorReadyCB& decryptor_ready_cb) {
251 // Cancels the previous decryptor request.
252 if (decryptor_ready_cb.is_null()) {
253 if (!decryptor_ready_cb_.is_null()) {
254 base::ResetAndReturn(&decryptor_ready_cb_)
255 .Run(nullptr, base::Bind(IgnoreCdmAttached));
257 return;
260 // We initialize audio and video decoders in sequence.
261 DCHECK(decryptor_ready_cb_.is_null());
263 if (cdm_context_) {
264 decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
265 base::Bind(IgnoreCdmAttached));
266 return;
269 decryptor_ready_cb_ = decryptor_ready_cb;
272 void RendererImpl::InitializeAudioRenderer() {
273 DVLOG(1) << __FUNCTION__;
274 DCHECK(task_runner_->BelongsToCurrentThread());
275 DCHECK_EQ(state_, STATE_INITIALIZING);
276 DCHECK(!init_cb_.is_null());
278 PipelineStatusCB done_cb =
279 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_);
281 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) {
282 audio_renderer_.reset();
283 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
284 return;
287 // Note: After the initialization of a renderer, error events from it may
288 // happen at any time and all future calls must guard against STATE_ERROR.
289 audio_renderer_->Initialize(
290 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb,
291 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
292 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
293 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
294 &audio_buffering_state_),
295 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
296 base::Bind(&RendererImpl::OnError, weak_this_),
297 waiting_for_decryption_key_cb_);
300 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
301 DVLOG(1) << __FUNCTION__ << ": " << status;
302 DCHECK(task_runner_->BelongsToCurrentThread());
304 // OnError() may be fired at any time by the renderers, even if they thought
305 // they initialized successfully (due to delayed output device setup).
306 if (state_ != STATE_INITIALIZING) {
307 DCHECK(init_cb_.is_null());
308 audio_renderer_.reset();
309 return;
312 if (status != PIPELINE_OK) {
313 base::ResetAndReturn(&init_cb_).Run(status);
314 return;
317 DCHECK(!init_cb_.is_null());
318 InitializeVideoRenderer();
321 void RendererImpl::InitializeVideoRenderer() {
322 DVLOG(1) << __FUNCTION__;
323 DCHECK(task_runner_->BelongsToCurrentThread());
324 DCHECK_EQ(state_, STATE_INITIALIZING);
325 DCHECK(!init_cb_.is_null());
327 PipelineStatusCB done_cb =
328 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_);
330 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) {
331 video_renderer_.reset();
332 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
333 return;
336 video_renderer_->Initialize(
337 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb,
338 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
339 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
340 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
341 &video_buffering_state_),
342 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
343 base::Bind(&RendererImpl::OnError, weak_this_),
344 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)),
345 waiting_for_decryption_key_cb_);
348 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
349 DVLOG(1) << __FUNCTION__ << ": " << status;
350 DCHECK(task_runner_->BelongsToCurrentThread());
352 // OnError() may be fired at any time by the renderers, even if they thought
353 // they initialized successfully (due to delayed output device setup).
354 if (state_ != STATE_INITIALIZING) {
355 DCHECK(init_cb_.is_null());
356 audio_renderer_.reset();
357 video_renderer_.reset();
358 return;
361 DCHECK(!init_cb_.is_null());
363 if (status != PIPELINE_OK) {
364 base::ResetAndReturn(&init_cb_).Run(status);
365 return;
368 if (audio_renderer_) {
369 time_source_ = audio_renderer_->GetTimeSource();
370 } else if (!time_source_) {
371 wall_clock_time_source_.reset(new WallClockTimeSource());
372 time_source_ = wall_clock_time_source_.get();
375 state_ = STATE_PLAYING;
376 DCHECK(time_source_);
377 DCHECK(audio_renderer_ || video_renderer_);
378 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
381 void RendererImpl::FlushAudioRenderer() {
382 DVLOG(1) << __FUNCTION__;
383 DCHECK(task_runner_->BelongsToCurrentThread());
384 DCHECK_EQ(state_, STATE_FLUSHING);
385 DCHECK(!flush_cb_.is_null());
387 if (!audio_renderer_) {
388 OnAudioRendererFlushDone();
389 return;
392 audio_renderer_->Flush(
393 base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
396 void RendererImpl::OnAudioRendererFlushDone() {
397 DVLOG(1) << __FUNCTION__;
398 DCHECK(task_runner_->BelongsToCurrentThread());
400 if (state_ == STATE_ERROR) {
401 DCHECK(flush_cb_.is_null());
402 return;
405 DCHECK_EQ(state_, STATE_FLUSHING);
406 DCHECK(!flush_cb_.is_null());
408 // If we had a deferred video renderer underflow prior to the flush, it should
409 // have been cleared by the audio renderer changing to BUFFERING_HAVE_NOTHING.
410 DCHECK(deferred_underflow_cb_.IsCancelled());
412 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
413 audio_ended_ = false;
414 FlushVideoRenderer();
417 void RendererImpl::FlushVideoRenderer() {
418 DVLOG(1) << __FUNCTION__;
419 DCHECK(task_runner_->BelongsToCurrentThread());
420 DCHECK_EQ(state_, STATE_FLUSHING);
421 DCHECK(!flush_cb_.is_null());
423 if (!video_renderer_) {
424 OnVideoRendererFlushDone();
425 return;
428 video_renderer_->Flush(
429 base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
432 void RendererImpl::OnVideoRendererFlushDone() {
433 DVLOG(1) << __FUNCTION__;
434 DCHECK(task_runner_->BelongsToCurrentThread());
436 if (state_ == STATE_ERROR) {
437 DCHECK(flush_cb_.is_null());
438 return;
441 DCHECK_EQ(state_, STATE_FLUSHING);
442 DCHECK(!flush_cb_.is_null());
444 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
445 video_ended_ = false;
446 state_ = STATE_PLAYING;
447 base::ResetAndReturn(&flush_cb_).Run();
450 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) {
451 DCHECK(task_runner_->BelongsToCurrentThread());
452 statistics_cb_.Run(stats);
455 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state,
456 BufferingState new_buffering_state) {
457 const bool is_audio = buffering_state == &audio_buffering_state_;
458 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
459 << new_buffering_state << ") " << (is_audio ? "audio" : "video");
460 DCHECK(task_runner_->BelongsToCurrentThread());
462 bool was_waiting_for_enough_data = WaitingForEnoughData();
464 // When audio is present and has enough data, defer video underflow callbacks
465 // for some time to avoid unnecessary glitches in audio; see
466 // http://crbug.com/144683#c53.
467 if (audio_renderer_ && !is_audio && state_ == STATE_PLAYING) {
468 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH &&
469 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH &&
470 new_buffering_state == BUFFERING_HAVE_NOTHING &&
471 deferred_underflow_cb_.IsCancelled()) {
472 deferred_underflow_cb_.Reset(base::Bind(
473 &RendererImpl::OnBufferingStateChanged, weak_factory_.GetWeakPtr(),
474 buffering_state, new_buffering_state));
475 task_runner_->PostDelayedTask(FROM_HERE,
476 deferred_underflow_cb_.callback(),
477 video_underflow_threshold_);
478 return;
481 deferred_underflow_cb_.Cancel();
482 } else if (!deferred_underflow_cb_.IsCancelled() && is_audio &&
483 new_buffering_state == BUFFERING_HAVE_NOTHING) {
484 // If audio underflows while we have a deferred video underflow in progress
485 // we want to mark video as underflowed immediately and cancel the deferral.
486 deferred_underflow_cb_.Cancel();
487 video_buffering_state_ = BUFFERING_HAVE_NOTHING;
490 *buffering_state = new_buffering_state;
492 // Disable underflow by ignoring updates that renderers have ran out of data.
493 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
494 time_ticking_) {
495 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
496 return;
499 // Renderer underflowed.
500 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
501 PausePlayback();
503 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
504 // underflow state http://crbug.com/144683
505 return;
508 // Renderer prerolled.
509 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
510 StartPlayback();
511 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
512 return;
516 bool RendererImpl::WaitingForEnoughData() const {
517 DCHECK(task_runner_->BelongsToCurrentThread());
518 if (state_ != STATE_PLAYING)
519 return false;
520 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
521 return true;
522 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
523 return true;
524 return false;
527 void RendererImpl::PausePlayback() {
528 DVLOG(1) << __FUNCTION__;
529 DCHECK(task_runner_->BelongsToCurrentThread());
530 DCHECK(time_ticking_);
531 switch (state_) {
532 case STATE_PLAYING:
533 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
534 << "Playback should only pause due to ending or underflowing";
535 break;
537 case STATE_FLUSHING:
538 // It's OK to pause playback when flushing.
539 break;
541 case STATE_UNINITIALIZED:
542 case STATE_INITIALIZING:
543 NOTREACHED() << "Invalid state: " << state_;
544 break;
546 case STATE_ERROR:
547 // An error state may occur at any time.
548 break;
551 time_ticking_ = false;
552 time_source_->StopTicking();
553 if (playback_rate_ > 0 && video_renderer_)
554 video_renderer_->OnTimeStateChanged(false);
557 void RendererImpl::StartPlayback() {
558 DVLOG(1) << __FUNCTION__;
559 DCHECK(task_runner_->BelongsToCurrentThread());
560 DCHECK_EQ(state_, STATE_PLAYING);
561 DCHECK(!time_ticking_);
562 DCHECK(!WaitingForEnoughData());
564 time_ticking_ = true;
565 time_source_->StartTicking();
566 if (playback_rate_ > 0 && video_renderer_)
567 video_renderer_->OnTimeStateChanged(true);
570 void RendererImpl::OnAudioRendererEnded() {
571 DVLOG(1) << __FUNCTION__;
572 DCHECK(task_runner_->BelongsToCurrentThread());
574 if (state_ != STATE_PLAYING)
575 return;
577 DCHECK(!audio_ended_);
578 audio_ended_ = true;
580 RunEndedCallbackIfNeeded();
583 void RendererImpl::OnVideoRendererEnded() {
584 DVLOG(1) << __FUNCTION__;
585 DCHECK(task_runner_->BelongsToCurrentThread());
587 if (state_ != STATE_PLAYING)
588 return;
590 DCHECK(!video_ended_);
591 video_ended_ = true;
593 RunEndedCallbackIfNeeded();
596 bool RendererImpl::PlaybackHasEnded() const {
597 DVLOG(1) << __FUNCTION__;
598 DCHECK(task_runner_->BelongsToCurrentThread());
600 if (audio_renderer_ && !audio_ended_)
601 return false;
603 if (video_renderer_ && !video_ended_)
604 return false;
606 return true;
609 void RendererImpl::RunEndedCallbackIfNeeded() {
610 DVLOG(1) << __FUNCTION__;
611 DCHECK(task_runner_->BelongsToCurrentThread());
613 if (!PlaybackHasEnded())
614 return;
616 if (time_ticking_)
617 PausePlayback();
619 ended_cb_.Run();
622 void RendererImpl::OnError(PipelineStatus error) {
623 DVLOG(1) << __FUNCTION__ << "(" << error << ")";
624 DCHECK(task_runner_->BelongsToCurrentThread());
625 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
627 // An error has already been delivered.
628 if (state_ == STATE_ERROR)
629 return;
631 const State old_state = state_;
632 state_ = STATE_ERROR;
634 if (old_state == STATE_INITIALIZING) {
635 base::ResetAndReturn(&init_cb_).Run(error);
636 return;
639 // After OnError() returns, the pipeline may destroy |this|.
640 base::ResetAndReturn(&error_cb_).Run(error);
642 if (!flush_cb_.is_null())
643 base::ResetAndReturn(&flush_cb_).Run();
646 } // namespace media