Roll src/breakpad/src 3ea146d:57c3d7c (svn 1405:1407)
[chromium-blink-merge.git] / media / filters / renderer_impl.cc
blobf9237da4eb0ff7b76a5aee3f70a3cfeb3d3eac15
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/demuxer_stream_provider.h"
15 #include "media/base/time_source.h"
16 #include "media/base/video_renderer.h"
17 #include "media/base/wall_clock_time_source.h"
19 namespace media {
21 RendererImpl::RendererImpl(
22 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
23 scoped_ptr<AudioRenderer> audio_renderer,
24 scoped_ptr<VideoRenderer> video_renderer)
25 : state_(STATE_UNINITIALIZED),
26 task_runner_(task_runner),
27 audio_renderer_(audio_renderer.Pass()),
28 video_renderer_(video_renderer.Pass()),
29 time_source_(NULL),
30 time_ticking_(false),
31 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
32 video_buffering_state_(BUFFERING_HAVE_NOTHING),
33 audio_ended_(false),
34 video_ended_(false),
35 cdm_context_(nullptr),
36 underflow_disabled_for_testing_(false),
37 clockless_video_playback_enabled_for_testing_(false),
38 weak_factory_(this),
39 weak_this_(weak_factory_.GetWeakPtr()) {
40 DVLOG(1) << __FUNCTION__;
43 RendererImpl::~RendererImpl() {
44 DVLOG(1) << __FUNCTION__;
45 DCHECK(task_runner_->BelongsToCurrentThread());
47 // Tear down in opposite order of construction as |video_renderer_| can still
48 // need |time_source_| (which can be |audio_renderer_|) to be alive.
49 video_renderer_.reset();
50 audio_renderer_.reset();
52 FireAllPendingCallbacks();
55 void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider,
56 const base::Closure& init_cb,
57 const StatisticsCB& statistics_cb,
58 const BufferingStateCB& buffering_state_cb,
59 const PaintCB& paint_cb,
60 const base::Closure& ended_cb,
61 const PipelineStatusCB& error_cb) {
62 DVLOG(1) << __FUNCTION__;
63 DCHECK(task_runner_->BelongsToCurrentThread());
64 DCHECK_EQ(state_, STATE_UNINITIALIZED);
65 DCHECK(!init_cb.is_null());
66 DCHECK(!statistics_cb.is_null());
67 DCHECK(!buffering_state_cb.is_null());
68 DCHECK(!paint_cb.is_null());
69 DCHECK(!ended_cb.is_null());
70 DCHECK(!error_cb.is_null());
71 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) ||
72 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO));
74 demuxer_stream_provider_ = demuxer_stream_provider;
75 statistics_cb_ = statistics_cb;
76 buffering_state_cb_ = buffering_state_cb;
77 paint_cb_ = paint_cb;
78 ended_cb_ = ended_cb;
79 error_cb_ = error_cb;
81 init_cb_ = init_cb;
82 state_ = STATE_INITIALIZING;
83 InitializeAudioRenderer();
86 void RendererImpl::SetCdm(CdmContext* cdm_context,
87 const CdmAttachedCB& cdm_attached_cb) {
88 DVLOG(1) << __FUNCTION__;
89 DCHECK(task_runner_->BelongsToCurrentThread());
90 DCHECK(cdm_context);
92 if (cdm_context_) {
93 DVLOG(1) << "Switching CDM not supported.";
94 cdm_attached_cb.Run(false);
95 return;
98 cdm_context_ = cdm_context;
100 if (decryptor_ready_cb_.is_null()) {
101 cdm_attached_cb.Run(true);
102 return;
105 base::ResetAndReturn(&decryptor_ready_cb_)
106 .Run(cdm_context->GetDecryptor(), cdm_attached_cb);
109 void RendererImpl::Flush(const base::Closure& flush_cb) {
110 DVLOG(1) << __FUNCTION__;
111 DCHECK(task_runner_->BelongsToCurrentThread());
112 DCHECK(flush_cb_.is_null());
114 if (state_ != STATE_PLAYING) {
115 DCHECK_EQ(state_, STATE_ERROR);
116 return;
119 flush_cb_ = flush_cb;
120 state_ = STATE_FLUSHING;
122 if (time_ticking_)
123 PausePlayback();
125 FlushAudioRenderer();
128 void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
129 DVLOG(1) << __FUNCTION__;
130 DCHECK(task_runner_->BelongsToCurrentThread());
132 if (state_ != STATE_PLAYING) {
133 DCHECK_EQ(state_, STATE_ERROR);
134 return;
137 time_source_->SetMediaTime(time);
139 if (audio_renderer_)
140 audio_renderer_->StartPlaying();
141 if (video_renderer_)
142 video_renderer_->StartPlayingFrom(time);
145 void RendererImpl::SetPlaybackRate(float playback_rate) {
146 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
147 DCHECK(task_runner_->BelongsToCurrentThread());
149 // Playback rate changes are only carried out while playing.
150 if (state_ != STATE_PLAYING)
151 return;
153 time_source_->SetPlaybackRate(playback_rate);
156 void RendererImpl::SetVolume(float volume) {
157 DVLOG(1) << __FUNCTION__;
158 DCHECK(task_runner_->BelongsToCurrentThread());
160 if (audio_renderer_)
161 audio_renderer_->SetVolume(volume);
164 base::TimeDelta RendererImpl::GetMediaTime() {
165 // No BelongsToCurrentThread() checking because this can be called from other
166 // threads.
167 return time_source_->CurrentMediaTime();
170 bool RendererImpl::HasAudio() {
171 DCHECK(task_runner_->BelongsToCurrentThread());
172 return audio_renderer_ != NULL;
175 bool RendererImpl::HasVideo() {
176 DCHECK(task_runner_->BelongsToCurrentThread());
177 return video_renderer_ != NULL;
180 void RendererImpl::DisableUnderflowForTesting() {
181 DVLOG(1) << __FUNCTION__;
182 DCHECK(task_runner_->BelongsToCurrentThread());
183 DCHECK_EQ(state_, STATE_UNINITIALIZED);
185 underflow_disabled_for_testing_ = true;
188 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
189 DVLOG(1) << __FUNCTION__;
190 DCHECK(task_runner_->BelongsToCurrentThread());
191 DCHECK_EQ(state_, STATE_UNINITIALIZED);
192 DCHECK(underflow_disabled_for_testing_)
193 << "Underflow must be disabled for clockless video playback";
195 clockless_video_playback_enabled_for_testing_ = true;
198 base::TimeDelta RendererImpl::GetMediaTimeForSyncingVideo() {
199 // No BelongsToCurrentThread() checking because this can be called from other
200 // threads.
202 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
203 // which should go away at some point http://crbug.com/110814
204 if (clockless_video_playback_enabled_for_testing_)
205 return base::TimeDelta::Max();
207 return time_source_->CurrentMediaTimeForSyncingVideo();
210 void RendererImpl::SetDecryptorReadyCallback(
211 const DecryptorReadyCB& decryptor_ready_cb) {
212 // Cancels the previous decryptor request.
213 if (decryptor_ready_cb.is_null()) {
214 if (!decryptor_ready_cb_.is_null()) {
215 base::ResetAndReturn(&decryptor_ready_cb_)
216 .Run(nullptr, base::Bind(IgnoreCdmAttached));
218 return;
221 // We initialize audio and video decoders in sequence.
222 DCHECK(decryptor_ready_cb_.is_null());
224 if (cdm_context_) {
225 decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
226 base::Bind(IgnoreCdmAttached));
227 return;
230 decryptor_ready_cb_ = decryptor_ready_cb;
233 void RendererImpl::InitializeAudioRenderer() {
234 DVLOG(1) << __FUNCTION__;
235 DCHECK(task_runner_->BelongsToCurrentThread());
236 DCHECK_EQ(state_, STATE_INITIALIZING);
237 DCHECK(!init_cb_.is_null());
239 PipelineStatusCB done_cb =
240 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_);
242 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) {
243 audio_renderer_.reset();
244 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
245 return;
248 // Note: After the initialization of a renderer, error events from it may
249 // happen at any time and all future calls must guard against STATE_ERROR.
250 audio_renderer_->Initialize(
251 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb,
252 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
253 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
254 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
255 &audio_buffering_state_),
256 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
257 base::Bind(&RendererImpl::OnError, weak_this_));
260 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
261 DVLOG(1) << __FUNCTION__ << ": " << status;
262 DCHECK(task_runner_->BelongsToCurrentThread());
264 if (status != PIPELINE_OK)
265 OnError(status);
267 // OnError() may be fired at any time by the renderers, even if they thought
268 // they initialized successfully (due to delayed output device setup).
269 if (state_ != STATE_INITIALIZING) {
270 audio_renderer_.reset();
271 return;
274 DCHECK(!init_cb_.is_null());
275 InitializeVideoRenderer();
278 void RendererImpl::InitializeVideoRenderer() {
279 DVLOG(1) << __FUNCTION__;
280 DCHECK(task_runner_->BelongsToCurrentThread());
281 DCHECK_EQ(state_, STATE_INITIALIZING);
282 DCHECK(!init_cb_.is_null());
284 PipelineStatusCB done_cb =
285 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_);
287 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) {
288 video_renderer_.reset();
289 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
290 return;
293 video_renderer_->Initialize(
294 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb,
295 base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
296 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
297 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
298 &video_buffering_state_),
299 base::ResetAndReturn(&paint_cb_),
300 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
301 base::Bind(&RendererImpl::OnError, weak_this_),
302 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo,
303 base::Unretained(this)));
306 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
307 DVLOG(1) << __FUNCTION__ << ": " << status;
308 DCHECK(task_runner_->BelongsToCurrentThread());
310 if (status != PIPELINE_OK)
311 OnError(status);
313 // OnError() may be fired at any time by the renderers, even if they thought
314 // they initialized successfully (due to delayed output device setup).
315 if (state_ != STATE_INITIALIZING) {
316 audio_renderer_.reset();
317 video_renderer_.reset();
318 return;
321 DCHECK(!init_cb_.is_null());
323 if (audio_renderer_) {
324 time_source_ = audio_renderer_->GetTimeSource();
325 } else {
326 wall_clock_time_source_.reset(new WallClockTimeSource());
327 time_source_ = wall_clock_time_source_.get();
330 state_ = STATE_PLAYING;
331 DCHECK(time_source_);
332 DCHECK(audio_renderer_ || video_renderer_);
333 base::ResetAndReturn(&init_cb_).Run();
336 void RendererImpl::FlushAudioRenderer() {
337 DVLOG(1) << __FUNCTION__;
338 DCHECK(task_runner_->BelongsToCurrentThread());
339 DCHECK_EQ(state_, STATE_FLUSHING);
340 DCHECK(!flush_cb_.is_null());
342 if (!audio_renderer_) {
343 OnAudioRendererFlushDone();
344 return;
347 audio_renderer_->Flush(
348 base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
351 void RendererImpl::OnAudioRendererFlushDone() {
352 DVLOG(1) << __FUNCTION__;
353 DCHECK(task_runner_->BelongsToCurrentThread());
355 if (state_ == STATE_ERROR) {
356 DCHECK(flush_cb_.is_null());
357 return;
360 DCHECK_EQ(state_, STATE_FLUSHING);
361 DCHECK(!flush_cb_.is_null());
363 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
364 audio_ended_ = false;
365 FlushVideoRenderer();
368 void RendererImpl::FlushVideoRenderer() {
369 DVLOG(1) << __FUNCTION__;
370 DCHECK(task_runner_->BelongsToCurrentThread());
371 DCHECK_EQ(state_, STATE_FLUSHING);
372 DCHECK(!flush_cb_.is_null());
374 if (!video_renderer_) {
375 OnVideoRendererFlushDone();
376 return;
379 video_renderer_->Flush(
380 base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
383 void RendererImpl::OnVideoRendererFlushDone() {
384 DVLOG(1) << __FUNCTION__;
385 DCHECK(task_runner_->BelongsToCurrentThread());
387 if (state_ == STATE_ERROR) {
388 DCHECK(flush_cb_.is_null());
389 return;
392 DCHECK_EQ(state_, STATE_FLUSHING);
393 DCHECK(!flush_cb_.is_null());
395 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
396 video_ended_ = false;
397 state_ = STATE_PLAYING;
398 base::ResetAndReturn(&flush_cb_).Run();
401 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) {
402 DCHECK(task_runner_->BelongsToCurrentThread());
403 statistics_cb_.Run(stats);
406 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state,
407 BufferingState new_buffering_state) {
408 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
409 << new_buffering_state << ") "
410 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
411 DCHECK(task_runner_->BelongsToCurrentThread());
412 bool was_waiting_for_enough_data = WaitingForEnoughData();
414 *buffering_state = new_buffering_state;
416 // Disable underflow by ignoring updates that renderers have ran out of data.
417 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
418 time_ticking_) {
419 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
420 return;
423 // Renderer underflowed.
424 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
425 PausePlayback();
427 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
428 // underflow state http://crbug.com/144683
429 return;
432 // Renderer prerolled.
433 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
434 StartPlayback();
435 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
436 return;
440 bool RendererImpl::WaitingForEnoughData() const {
441 DCHECK(task_runner_->BelongsToCurrentThread());
442 if (state_ != STATE_PLAYING)
443 return false;
444 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
445 return true;
446 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
447 return true;
448 return false;
451 void RendererImpl::PausePlayback() {
452 DVLOG(1) << __FUNCTION__;
453 DCHECK(task_runner_->BelongsToCurrentThread());
454 DCHECK(time_ticking_);
455 switch (state_) {
456 case STATE_PLAYING:
457 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
458 << "Playback should only pause due to ending or underflowing";
459 break;
461 case STATE_FLUSHING:
462 // It's OK to pause playback when flushing.
463 break;
465 case STATE_UNINITIALIZED:
466 case STATE_INITIALIZING:
467 NOTREACHED() << "Invalid state: " << state_;
468 break;
470 case STATE_ERROR:
471 // An error state may occur at any time.
472 break;
475 time_ticking_ = false;
476 time_source_->StopTicking();
479 void RendererImpl::StartPlayback() {
480 DVLOG(1) << __FUNCTION__;
481 DCHECK(task_runner_->BelongsToCurrentThread());
482 DCHECK_EQ(state_, STATE_PLAYING);
483 DCHECK(!time_ticking_);
484 DCHECK(!WaitingForEnoughData());
486 time_ticking_ = true;
487 time_source_->StartTicking();
490 void RendererImpl::OnAudioRendererEnded() {
491 DVLOG(1) << __FUNCTION__;
492 DCHECK(task_runner_->BelongsToCurrentThread());
494 if (state_ != STATE_PLAYING)
495 return;
497 DCHECK(!audio_ended_);
498 audio_ended_ = true;
500 RunEndedCallbackIfNeeded();
503 void RendererImpl::OnVideoRendererEnded() {
504 DVLOG(1) << __FUNCTION__;
505 DCHECK(task_runner_->BelongsToCurrentThread());
507 if (state_ != STATE_PLAYING)
508 return;
510 DCHECK(!video_ended_);
511 video_ended_ = true;
513 RunEndedCallbackIfNeeded();
516 bool RendererImpl::PlaybackHasEnded() const {
517 DVLOG(1) << __FUNCTION__;
518 DCHECK(task_runner_->BelongsToCurrentThread());
520 if (audio_renderer_ && !audio_ended_)
521 return false;
523 if (video_renderer_ && !video_ended_)
524 return false;
526 return true;
529 void RendererImpl::RunEndedCallbackIfNeeded() {
530 DVLOG(1) << __FUNCTION__;
531 DCHECK(task_runner_->BelongsToCurrentThread());
533 if (!PlaybackHasEnded())
534 return;
536 if (time_ticking_)
537 PausePlayback();
539 ended_cb_.Run();
542 void RendererImpl::OnError(PipelineStatus error) {
543 DVLOG(1) << __FUNCTION__ << "(" << error << ")";
544 DCHECK(task_runner_->BelongsToCurrentThread());
545 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
547 // An error has already been delivered.
548 if (state_ == STATE_ERROR)
549 return;
551 state_ = STATE_ERROR;
553 // Pipeline will destroy |this| as the result of error.
554 base::ResetAndReturn(&error_cb_).Run(error);
556 FireAllPendingCallbacks();
559 void RendererImpl::FireAllPendingCallbacks() {
560 DCHECK(task_runner_->BelongsToCurrentThread());
562 if (!init_cb_.is_null())
563 base::ResetAndReturn(&init_cb_).Run();
565 if (!flush_cb_.is_null())
566 base::ResetAndReturn(&flush_cb_).Run();
569 } // namespace media