Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / media / renderers / renderer_impl.cc
blob63c4a5f7a1f9c059bd058fc187c6ef57e3508001
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 if (media_timestamps.empty()) {
242 *wall_clock_times = std::vector<base::TimeTicks>(1,
243 base::TimeTicks::Now());
244 } else {
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);
250 return true;
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));
264 return;
267 // We initialize audio and video decoders in sequence.
268 DCHECK(decryptor_ready_cb_.is_null());
270 if (cdm_context_) {
271 decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
272 base::Bind(IgnoreCdmAttached));
273 return;
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));
291 return;
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();
316 return;
319 if (status != PIPELINE_OK) {
320 base::ResetAndReturn(&init_cb_).Run(status);
321 return;
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));
340 return;
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();
365 return;
368 DCHECK(!init_cb_.is_null());
370 if (status != PIPELINE_OK) {
371 base::ResetAndReturn(&init_cb_).Run(status);
372 return;
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();
396 return;
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());
409 return;
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();
432 return;
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());
445 return;
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_);
485 return;
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_ &&
501 time_ticking_) {
502 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
503 return;
506 // Renderer underflowed.
507 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
508 PausePlayback();
510 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
511 // underflow state http://crbug.com/144683
512 return;
515 // Renderer prerolled.
516 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
517 StartPlayback();
518 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
519 return;
523 bool RendererImpl::WaitingForEnoughData() const {
524 DCHECK(task_runner_->BelongsToCurrentThread());
525 if (state_ != STATE_PLAYING)
526 return false;
527 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
528 return true;
529 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
530 return true;
531 return false;
534 void RendererImpl::PausePlayback() {
535 DVLOG(1) << __FUNCTION__;
536 DCHECK(task_runner_->BelongsToCurrentThread());
537 DCHECK(time_ticking_);
538 switch (state_) {
539 case STATE_PLAYING:
540 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
541 << "Playback should only pause due to ending or underflowing";
542 break;
544 case STATE_FLUSHING:
545 // It's OK to pause playback when flushing.
546 break;
548 case STATE_UNINITIALIZED:
549 case STATE_INITIALIZING:
550 NOTREACHED() << "Invalid state: " << state_;
551 break;
553 case STATE_ERROR:
554 // An error state may occur at any time.
555 break;
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)
582 return;
584 DCHECK(!audio_ended_);
585 audio_ended_ = true;
587 RunEndedCallbackIfNeeded();
590 void RendererImpl::OnVideoRendererEnded() {
591 DVLOG(1) << __FUNCTION__;
592 DCHECK(task_runner_->BelongsToCurrentThread());
594 if (state_ != STATE_PLAYING)
595 return;
597 DCHECK(!video_ended_);
598 video_ended_ = true;
600 RunEndedCallbackIfNeeded();
603 bool RendererImpl::PlaybackHasEnded() const {
604 DVLOG(1) << __FUNCTION__;
605 DCHECK(task_runner_->BelongsToCurrentThread());
607 if (audio_renderer_ && !audio_ended_)
608 return false;
610 if (video_renderer_ && !video_ended_)
611 return false;
613 return true;
616 void RendererImpl::RunEndedCallbackIfNeeded() {
617 DVLOG(1) << __FUNCTION__;
618 DCHECK(task_runner_->BelongsToCurrentThread());
620 if (!PlaybackHasEnded())
621 return;
623 if (time_ticking_)
624 PausePlayback();
626 ended_cb_.Run();
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)
636 return;
638 const State old_state = state_;
639 state_ = STATE_ERROR;
641 if (old_state == STATE_INITIALIZING) {
642 base::ResetAndReturn(&init_cb_).Run(error);
643 return;
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();
653 } // namespace media