Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / media / filters / renderer_impl.cc
blobb8005d409d8218f725cced19056b8d8c4b696b04
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"
7 #include "base/bind.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"
20 namespace media {
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()),
30 time_source_(NULL),
31 time_ticking_(false),
32 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
33 video_buffering_state_(BUFFERING_HAVE_NOTHING),
34 audio_ended_(false),
35 video_ended_(false),
36 cdm_context_(nullptr),
37 underflow_disabled_for_testing_(false),
38 clockless_video_playback_enabled_for_testing_(false),
39 weak_factory_(this) {
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(DemuxerStreamProvider* demuxer_stream_provider,
60 const PipelineStatusCB& init_cb,
61 const StatisticsCB& statistics_cb,
62 const BufferingStateCB& buffering_state_cb,
63 const PaintCB& paint_cb,
64 const base::Closure& ended_cb,
65 const PipelineStatusCB& error_cb) {
66 DVLOG(1) << __FUNCTION__;
67 DCHECK(task_runner_->BelongsToCurrentThread());
68 DCHECK_EQ(state_, STATE_UNINITIALIZED);
69 DCHECK(!init_cb.is_null());
70 DCHECK(!statistics_cb.is_null());
71 DCHECK(!buffering_state_cb.is_null());
72 DCHECK(!paint_cb.is_null());
73 DCHECK(!ended_cb.is_null());
74 DCHECK(!error_cb.is_null());
75 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) ||
76 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO));
78 demuxer_stream_provider_ = demuxer_stream_provider;
79 statistics_cb_ = statistics_cb;
80 buffering_state_cb_ = buffering_state_cb;
81 paint_cb_ = paint_cb;
82 ended_cb_ = ended_cb;
83 error_cb_ = error_cb;
84 init_cb_ = init_cb;
86 state_ = STATE_INITIALIZING;
87 InitializeAudioRenderer();
90 void RendererImpl::SetCdm(CdmContext* cdm_context,
91 const CdmAttachedCB& cdm_attached_cb) {
92 DVLOG(1) << __FUNCTION__;
93 DCHECK(task_runner_->BelongsToCurrentThread());
94 DCHECK(cdm_context);
96 if (cdm_context_) {
97 DVLOG(1) << "Switching CDM not supported.";
98 cdm_attached_cb.Run(false);
99 return;
102 cdm_context_ = cdm_context;
104 if (decryptor_ready_cb_.is_null()) {
105 cdm_attached_cb.Run(true);
106 return;
109 base::ResetAndReturn(&decryptor_ready_cb_)
110 .Run(cdm_context->GetDecryptor(), cdm_attached_cb);
113 void RendererImpl::Flush(const base::Closure& flush_cb) {
114 DVLOG(1) << __FUNCTION__;
115 DCHECK(task_runner_->BelongsToCurrentThread());
116 DCHECK(flush_cb_.is_null());
118 if (state_ != STATE_PLAYING) {
119 DCHECK_EQ(state_, STATE_ERROR);
120 return;
123 flush_cb_ = flush_cb;
124 state_ = STATE_FLUSHING;
126 if (time_ticking_)
127 PausePlayback();
129 FlushAudioRenderer();
132 void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
133 DVLOG(1) << __FUNCTION__;
134 DCHECK(task_runner_->BelongsToCurrentThread());
136 if (state_ != STATE_PLAYING) {
137 DCHECK_EQ(state_, STATE_ERROR);
138 return;
141 time_source_->SetMediaTime(time);
143 if (audio_renderer_)
144 audio_renderer_->StartPlaying();
145 if (video_renderer_)
146 video_renderer_->StartPlayingFrom(time);
149 void RendererImpl::SetPlaybackRate(float playback_rate) {
150 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
151 DCHECK(task_runner_->BelongsToCurrentThread());
153 // Playback rate changes are only carried out while playing.
154 if (state_ != STATE_PLAYING)
155 return;
157 time_source_->SetPlaybackRate(playback_rate);
160 void RendererImpl::SetVolume(float volume) {
161 DVLOG(1) << __FUNCTION__;
162 DCHECK(task_runner_->BelongsToCurrentThread());
164 if (audio_renderer_)
165 audio_renderer_->SetVolume(volume);
168 base::TimeDelta RendererImpl::GetMediaTime() {
169 // No BelongsToCurrentThread() checking because this can be called from other
170 // threads.
171 return time_source_->CurrentMediaTime();
174 bool RendererImpl::HasAudio() {
175 DCHECK(task_runner_->BelongsToCurrentThread());
176 return audio_renderer_ != NULL;
179 bool RendererImpl::HasVideo() {
180 DCHECK(task_runner_->BelongsToCurrentThread());
181 return video_renderer_ != NULL;
184 void RendererImpl::DisableUnderflowForTesting() {
185 DVLOG(1) << __FUNCTION__;
186 DCHECK(task_runner_->BelongsToCurrentThread());
187 DCHECK_EQ(state_, STATE_UNINITIALIZED);
189 underflow_disabled_for_testing_ = true;
192 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
193 DVLOG(1) << __FUNCTION__;
194 DCHECK(task_runner_->BelongsToCurrentThread());
195 DCHECK_EQ(state_, STATE_UNINITIALIZED);
196 DCHECK(underflow_disabled_for_testing_)
197 << "Underflow must be disabled for clockless video playback";
199 clockless_video_playback_enabled_for_testing_ = true;
202 base::TimeDelta RendererImpl::GetMediaTimeForSyncingVideo() {
203 // No BelongsToCurrentThread() checking because this can be called from other
204 // threads.
206 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
207 // which should go away at some point http://crbug.com/110814
208 if (clockless_video_playback_enabled_for_testing_)
209 return base::TimeDelta::Max();
211 return time_source_->CurrentMediaTimeForSyncingVideo();
214 void RendererImpl::SetDecryptorReadyCallback(
215 const DecryptorReadyCB& decryptor_ready_cb) {
216 // Cancels the previous decryptor request.
217 if (decryptor_ready_cb.is_null()) {
218 if (!decryptor_ready_cb_.is_null()) {
219 base::ResetAndReturn(&decryptor_ready_cb_)
220 .Run(nullptr, base::Bind(IgnoreCdmAttached));
222 return;
225 // We initialize audio and video decoders in sequence.
226 DCHECK(decryptor_ready_cb_.is_null());
228 if (cdm_context_) {
229 decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
230 base::Bind(IgnoreCdmAttached));
231 return;
234 decryptor_ready_cb_ = decryptor_ready_cb;
237 void RendererImpl::InitializeAudioRenderer() {
238 DVLOG(1) << __FUNCTION__;
239 DCHECK(task_runner_->BelongsToCurrentThread());
240 DCHECK_EQ(state_, STATE_INITIALIZING);
241 DCHECK(!init_cb_.is_null());
243 PipelineStatusCB done_cb =
244 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_);
246 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) {
247 audio_renderer_.reset();
248 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
249 return;
252 // Note: After the initialization of a renderer, error events from it may
253 // happen at any time and all future calls must guard against STATE_ERROR.
254 audio_renderer_->Initialize(
255 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb,
256 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
257 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
258 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
259 &audio_buffering_state_),
260 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
261 base::Bind(&RendererImpl::OnError, weak_this_));
264 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
265 DVLOG(1) << __FUNCTION__ << ": " << status;
266 DCHECK(task_runner_->BelongsToCurrentThread());
268 // OnError() may be fired at any time by the renderers, even if they thought
269 // they initialized successfully (due to delayed output device setup).
270 if (state_ != STATE_INITIALIZING) {
271 DCHECK(init_cb_.is_null());
272 audio_renderer_.reset();
273 return;
276 if (status != PIPELINE_OK) {
277 base::ResetAndReturn(&init_cb_).Run(status);
278 return;
281 DCHECK(!init_cb_.is_null());
282 InitializeVideoRenderer();
285 void RendererImpl::InitializeVideoRenderer() {
286 DVLOG(1) << __FUNCTION__;
287 DCHECK(task_runner_->BelongsToCurrentThread());
288 DCHECK_EQ(state_, STATE_INITIALIZING);
289 DCHECK(!init_cb_.is_null());
291 PipelineStatusCB done_cb =
292 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_);
294 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) {
295 video_renderer_.reset();
296 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
297 return;
300 video_renderer_->Initialize(
301 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb,
302 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
303 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
304 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
305 &video_buffering_state_),
306 base::ResetAndReturn(&paint_cb_),
307 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
308 base::Bind(&RendererImpl::OnError, weak_this_),
309 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo,
310 base::Unretained(this)));
313 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
314 DVLOG(1) << __FUNCTION__ << ": " << status;
315 DCHECK(task_runner_->BelongsToCurrentThread());
317 // OnError() may be fired at any time by the renderers, even if they thought
318 // they initialized successfully (due to delayed output device setup).
319 if (state_ != STATE_INITIALIZING) {
320 DCHECK(init_cb_.is_null());
321 audio_renderer_.reset();
322 video_renderer_.reset();
323 return;
326 DCHECK(!init_cb_.is_null());
328 if (status != PIPELINE_OK) {
329 base::ResetAndReturn(&init_cb_).Run(status);
330 return;
333 if (audio_renderer_) {
334 time_source_ = audio_renderer_->GetTimeSource();
335 } else {
336 wall_clock_time_source_.reset(new WallClockTimeSource());
337 time_source_ = wall_clock_time_source_.get();
340 state_ = STATE_PLAYING;
341 DCHECK(time_source_);
342 DCHECK(audio_renderer_ || video_renderer_);
343 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
346 void RendererImpl::FlushAudioRenderer() {
347 DVLOG(1) << __FUNCTION__;
348 DCHECK(task_runner_->BelongsToCurrentThread());
349 DCHECK_EQ(state_, STATE_FLUSHING);
350 DCHECK(!flush_cb_.is_null());
352 if (!audio_renderer_) {
353 OnAudioRendererFlushDone();
354 return;
357 audio_renderer_->Flush(
358 base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
361 void RendererImpl::OnAudioRendererFlushDone() {
362 DVLOG(1) << __FUNCTION__;
363 DCHECK(task_runner_->BelongsToCurrentThread());
365 if (state_ == STATE_ERROR) {
366 DCHECK(flush_cb_.is_null());
367 return;
370 DCHECK_EQ(state_, STATE_FLUSHING);
371 DCHECK(!flush_cb_.is_null());
373 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
374 audio_ended_ = false;
375 FlushVideoRenderer();
378 void RendererImpl::FlushVideoRenderer() {
379 DVLOG(1) << __FUNCTION__;
380 DCHECK(task_runner_->BelongsToCurrentThread());
381 DCHECK_EQ(state_, STATE_FLUSHING);
382 DCHECK(!flush_cb_.is_null());
384 if (!video_renderer_) {
385 OnVideoRendererFlushDone();
386 return;
389 video_renderer_->Flush(
390 base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
393 void RendererImpl::OnVideoRendererFlushDone() {
394 DVLOG(1) << __FUNCTION__;
395 DCHECK(task_runner_->BelongsToCurrentThread());
397 if (state_ == STATE_ERROR) {
398 DCHECK(flush_cb_.is_null());
399 return;
402 DCHECK_EQ(state_, STATE_FLUSHING);
403 DCHECK(!flush_cb_.is_null());
405 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
406 video_ended_ = false;
407 state_ = STATE_PLAYING;
408 base::ResetAndReturn(&flush_cb_).Run();
411 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) {
412 DCHECK(task_runner_->BelongsToCurrentThread());
413 statistics_cb_.Run(stats);
416 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state,
417 BufferingState new_buffering_state) {
418 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
419 << new_buffering_state << ") "
420 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
421 DCHECK(task_runner_->BelongsToCurrentThread());
422 bool was_waiting_for_enough_data = WaitingForEnoughData();
424 *buffering_state = new_buffering_state;
426 // Disable underflow by ignoring updates that renderers have ran out of data.
427 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
428 time_ticking_) {
429 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
430 return;
433 // Renderer underflowed.
434 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
435 PausePlayback();
437 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
438 // underflow state http://crbug.com/144683
439 return;
442 // Renderer prerolled.
443 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
444 StartPlayback();
445 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
446 return;
450 bool RendererImpl::WaitingForEnoughData() const {
451 DCHECK(task_runner_->BelongsToCurrentThread());
452 if (state_ != STATE_PLAYING)
453 return false;
454 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
455 return true;
456 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
457 return true;
458 return false;
461 void RendererImpl::PausePlayback() {
462 DVLOG(1) << __FUNCTION__;
463 DCHECK(task_runner_->BelongsToCurrentThread());
464 DCHECK(time_ticking_);
465 switch (state_) {
466 case STATE_PLAYING:
467 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
468 << "Playback should only pause due to ending or underflowing";
469 break;
471 case STATE_FLUSHING:
472 // It's OK to pause playback when flushing.
473 break;
475 case STATE_UNINITIALIZED:
476 case STATE_INITIALIZING:
477 NOTREACHED() << "Invalid state: " << state_;
478 break;
480 case STATE_ERROR:
481 // An error state may occur at any time.
482 break;
485 time_ticking_ = false;
486 time_source_->StopTicking();
489 void RendererImpl::StartPlayback() {
490 DVLOG(1) << __FUNCTION__;
491 DCHECK(task_runner_->BelongsToCurrentThread());
492 DCHECK_EQ(state_, STATE_PLAYING);
493 DCHECK(!time_ticking_);
494 DCHECK(!WaitingForEnoughData());
496 time_ticking_ = true;
497 time_source_->StartTicking();
500 void RendererImpl::OnAudioRendererEnded() {
501 DVLOG(1) << __FUNCTION__;
502 DCHECK(task_runner_->BelongsToCurrentThread());
504 if (state_ != STATE_PLAYING)
505 return;
507 DCHECK(!audio_ended_);
508 audio_ended_ = true;
510 RunEndedCallbackIfNeeded();
513 void RendererImpl::OnVideoRendererEnded() {
514 DVLOG(1) << __FUNCTION__;
515 DCHECK(task_runner_->BelongsToCurrentThread());
517 if (state_ != STATE_PLAYING)
518 return;
520 DCHECK(!video_ended_);
521 video_ended_ = true;
523 RunEndedCallbackIfNeeded();
526 bool RendererImpl::PlaybackHasEnded() const {
527 DVLOG(1) << __FUNCTION__;
528 DCHECK(task_runner_->BelongsToCurrentThread());
530 if (audio_renderer_ && !audio_ended_)
531 return false;
533 if (video_renderer_ && !video_ended_)
534 return false;
536 return true;
539 void RendererImpl::RunEndedCallbackIfNeeded() {
540 DVLOG(1) << __FUNCTION__;
541 DCHECK(task_runner_->BelongsToCurrentThread());
543 if (!PlaybackHasEnded())
544 return;
546 if (time_ticking_)
547 PausePlayback();
549 ended_cb_.Run();
552 void RendererImpl::OnError(PipelineStatus error) {
553 DVLOG(1) << __FUNCTION__ << "(" << error << ")";
554 DCHECK(task_runner_->BelongsToCurrentThread());
555 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
557 // An error has already been delivered.
558 if (state_ == STATE_ERROR)
559 return;
561 const State old_state = state_;
562 state_ = STATE_ERROR;
564 if (old_state == STATE_INITIALIZING) {
565 base::ResetAndReturn(&init_cb_).Run(error);
566 return;
569 // After OnError() returns, the pipeline may destroy |this|.
570 base::ResetAndReturn(&error_cb_).Run(error);
572 if (!flush_cb_.is_null())
573 base::ResetAndReturn(&flush_cb_).Run();
576 } // namespace media