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"
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"
21 RendererImpl::RendererImpl(
22 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
23 DemuxerStreamProvider* demuxer_stream_provider,
24 scoped_ptr<AudioRenderer> audio_renderer,
25 scoped_ptr<VideoRenderer> video_renderer)
26 : state_(STATE_UNINITIALIZED),
27 task_runner_(task_runner),
28 demuxer_stream_provider_(demuxer_stream_provider),
29 audio_renderer_(audio_renderer.Pass()),
30 video_renderer_(video_renderer.Pass()),
33 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
34 video_buffering_state_(BUFFERING_HAVE_NOTHING),
37 underflow_disabled_for_testing_(false),
38 clockless_video_playback_enabled_for_testing_(false),
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 FireAllPendingCallbacks();
56 void RendererImpl::Initialize(const base::Closure& init_cb,
57 const StatisticsCB& statistics_cb,
58 const base::Closure& ended_cb,
59 const PipelineStatusCB& error_cb,
60 const BufferingStateCB& buffering_state_cb) {
61 DVLOG(1) << __FUNCTION__;
62 DCHECK(task_runner_->BelongsToCurrentThread());
63 DCHECK_EQ(state_, STATE_UNINITIALIZED) << state_;
64 DCHECK(!init_cb.is_null());
65 DCHECK(!statistics_cb.is_null());
66 DCHECK(!ended_cb.is_null());
67 DCHECK(!error_cb.is_null());
68 DCHECK(!buffering_state_cb.is_null());
69 DCHECK(demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO) ||
70 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO));
72 statistics_cb_ = statistics_cb;
75 buffering_state_cb_ = buffering_state_cb;
78 state_ = STATE_INITIALIZING;
79 InitializeAudioRenderer();
82 void RendererImpl::Flush(const base::Closure& flush_cb) {
83 DVLOG(1) << __FUNCTION__;
84 DCHECK(task_runner_->BelongsToCurrentThread());
85 DCHECK_EQ(state_, STATE_PLAYING) << state_;
86 DCHECK(flush_cb_.is_null());
89 state_ = STATE_FLUSHING;
97 void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
98 DVLOG(1) << __FUNCTION__;
99 DCHECK(task_runner_->BelongsToCurrentThread());
100 DCHECK_EQ(state_, STATE_PLAYING) << state_;
102 time_source_->SetMediaTime(time);
105 audio_renderer_->StartPlaying();
107 video_renderer_->StartPlayingFrom(time);
110 void RendererImpl::SetPlaybackRate(float playback_rate) {
111 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
112 DCHECK(task_runner_->BelongsToCurrentThread());
114 // Playback rate changes are only carried out while playing.
115 if (state_ != STATE_PLAYING)
118 time_source_->SetPlaybackRate(playback_rate);
121 void RendererImpl::SetVolume(float volume) {
122 DVLOG(1) << __FUNCTION__;
123 DCHECK(task_runner_->BelongsToCurrentThread());
126 audio_renderer_->SetVolume(volume);
129 base::TimeDelta RendererImpl::GetMediaTime() {
130 // No BelongsToCurrentThread() checking because this can be called from other
132 return time_source_->CurrentMediaTime();
135 bool RendererImpl::HasAudio() {
136 DCHECK(task_runner_->BelongsToCurrentThread());
137 return audio_renderer_ != NULL;
140 bool RendererImpl::HasVideo() {
141 DCHECK(task_runner_->BelongsToCurrentThread());
142 return video_renderer_ != NULL;
145 void RendererImpl::SetCdm(MediaKeys* cdm) {
146 DVLOG(1) << __FUNCTION__;
147 DCHECK(task_runner_->BelongsToCurrentThread());
148 // TODO(xhwang): Explore to possibility to move CDM setting from
149 // WebMediaPlayerImpl to this class. See http://crbug.com/401264
153 void RendererImpl::DisableUnderflowForTesting() {
154 DVLOG(1) << __FUNCTION__;
155 DCHECK(task_runner_->BelongsToCurrentThread());
156 DCHECK_EQ(state_, STATE_UNINITIALIZED);
158 underflow_disabled_for_testing_ = true;
161 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
162 DVLOG(1) << __FUNCTION__;
163 DCHECK(task_runner_->BelongsToCurrentThread());
164 DCHECK_EQ(state_, STATE_UNINITIALIZED);
165 DCHECK(underflow_disabled_for_testing_)
166 << "Underflow must be disabled for clockless video playback";
168 clockless_video_playback_enabled_for_testing_ = true;
171 base::TimeDelta RendererImpl::GetMediaTimeForSyncingVideo() {
172 // No BelongsToCurrentThread() checking because this can be called from other
175 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
176 // which should go away at some point http://crbug.com/110814
177 if (clockless_video_playback_enabled_for_testing_)
178 return base::TimeDelta::Max();
180 return time_source_->CurrentMediaTimeForSyncingVideo();
183 void RendererImpl::InitializeAudioRenderer() {
184 DVLOG(1) << __FUNCTION__;
185 DCHECK(task_runner_->BelongsToCurrentThread());
186 DCHECK_EQ(state_, STATE_INITIALIZING) << state_;
187 DCHECK(!init_cb_.is_null());
189 PipelineStatusCB done_cb =
190 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_);
192 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) {
193 audio_renderer_.reset();
194 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
198 audio_renderer_->Initialize(
199 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO),
201 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
202 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
203 &audio_buffering_state_),
204 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
205 base::Bind(&RendererImpl::OnError, weak_this_));
208 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
209 DVLOG(1) << __FUNCTION__ << ": " << status;
210 DCHECK(task_runner_->BelongsToCurrentThread());
211 DCHECK_EQ(state_, STATE_INITIALIZING) << state_;
212 DCHECK(!init_cb_.is_null());
214 if (status != PIPELINE_OK) {
215 audio_renderer_.reset();
220 InitializeVideoRenderer();
223 void RendererImpl::InitializeVideoRenderer() {
224 DVLOG(1) << __FUNCTION__;
225 DCHECK(task_runner_->BelongsToCurrentThread());
226 DCHECK_EQ(state_, STATE_INITIALIZING) << state_;
227 DCHECK(!init_cb_.is_null());
229 PipelineStatusCB done_cb =
230 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_);
232 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) {
233 video_renderer_.reset();
234 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
238 video_renderer_->Initialize(
239 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO),
240 demuxer_stream_provider_->GetLiveness() ==
241 DemuxerStreamProvider::LIVENESS_LIVE,
243 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
244 base::Bind(&RendererImpl::OnBufferingStateChanged,
246 &video_buffering_state_),
247 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
248 base::Bind(&RendererImpl::OnError, weak_this_),
249 base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo,
250 base::Unretained(this)));
253 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
254 DVLOG(1) << __FUNCTION__ << ": " << status;
255 DCHECK(task_runner_->BelongsToCurrentThread());
256 DCHECK_EQ(state_, STATE_INITIALIZING) << state_;
257 DCHECK(!init_cb_.is_null());
259 if (status != PIPELINE_OK) {
260 audio_renderer_.reset();
261 video_renderer_.reset();
266 if (audio_renderer_) {
267 time_source_ = audio_renderer_->GetTimeSource();
269 wall_clock_time_source_.reset(new WallClockTimeSource());
270 time_source_ = wall_clock_time_source_.get();
273 state_ = STATE_PLAYING;
274 DCHECK(time_source_);
275 DCHECK(audio_renderer_ || video_renderer_);
276 base::ResetAndReturn(&init_cb_).Run();
279 void RendererImpl::FlushAudioRenderer() {
280 DVLOG(1) << __FUNCTION__;
281 DCHECK(task_runner_->BelongsToCurrentThread());
282 DCHECK_EQ(state_, STATE_FLUSHING) << state_;
283 DCHECK(!flush_cb_.is_null());
285 if (!audio_renderer_) {
286 OnAudioRendererFlushDone();
290 audio_renderer_->Flush(
291 base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
294 void RendererImpl::OnAudioRendererFlushDone() {
295 DVLOG(1) << __FUNCTION__;
296 DCHECK(task_runner_->BelongsToCurrentThread());
298 if (state_ == STATE_ERROR) {
299 DCHECK(flush_cb_.is_null());
303 DCHECK_EQ(state_, STATE_FLUSHING) << state_;
304 DCHECK(!flush_cb_.is_null());
306 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
307 audio_ended_ = false;
308 FlushVideoRenderer();
311 void RendererImpl::FlushVideoRenderer() {
312 DVLOG(1) << __FUNCTION__;
313 DCHECK(task_runner_->BelongsToCurrentThread());
314 DCHECK_EQ(state_, STATE_FLUSHING) << state_;
315 DCHECK(!flush_cb_.is_null());
317 if (!video_renderer_) {
318 OnVideoRendererFlushDone();
322 video_renderer_->Flush(
323 base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
326 void RendererImpl::OnVideoRendererFlushDone() {
327 DVLOG(1) << __FUNCTION__;
328 DCHECK(task_runner_->BelongsToCurrentThread());
330 if (state_ == STATE_ERROR) {
331 DCHECK(flush_cb_.is_null());
335 DCHECK_EQ(state_, STATE_FLUSHING) << state_;
336 DCHECK(!flush_cb_.is_null());
338 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
339 video_ended_ = false;
340 state_ = STATE_PLAYING;
341 base::ResetAndReturn(&flush_cb_).Run();
344 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) {
345 DCHECK(task_runner_->BelongsToCurrentThread());
346 statistics_cb_.Run(stats);
349 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state,
350 BufferingState new_buffering_state) {
351 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
352 << new_buffering_state << ") "
353 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
354 DCHECK(task_runner_->BelongsToCurrentThread());
355 bool was_waiting_for_enough_data = WaitingForEnoughData();
357 *buffering_state = new_buffering_state;
359 // Disable underflow by ignoring updates that renderers have ran out of data.
360 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
362 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
366 // Renderer underflowed.
367 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
370 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
371 // underflow state http://crbug.com/144683
375 // Renderer prerolled.
376 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
378 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
383 bool RendererImpl::WaitingForEnoughData() const {
384 DCHECK(task_runner_->BelongsToCurrentThread());
385 if (state_ != STATE_PLAYING)
387 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
389 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
394 void RendererImpl::PausePlayback() {
395 DVLOG(1) << __FUNCTION__;
396 DCHECK(task_runner_->BelongsToCurrentThread());
397 DCHECK(time_ticking_);
400 DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
401 << "Playback should only pause due to ending or underflowing";
405 // It's OK to pause playback when flushing.
408 case STATE_UNINITIALIZED:
409 case STATE_INITIALIZING:
411 NOTREACHED() << "Invalid state: " << state_;
415 time_ticking_ = false;
416 time_source_->StopTicking();
419 void RendererImpl::StartPlayback() {
420 DVLOG(1) << __FUNCTION__;
421 DCHECK(task_runner_->BelongsToCurrentThread());
422 DCHECK_EQ(state_, STATE_PLAYING);
423 DCHECK(!time_ticking_);
424 DCHECK(!WaitingForEnoughData());
426 time_ticking_ = true;
427 time_source_->StartTicking();
430 void RendererImpl::OnAudioRendererEnded() {
431 DVLOG(1) << __FUNCTION__;
432 DCHECK(task_runner_->BelongsToCurrentThread());
434 if (state_ != STATE_PLAYING)
437 DCHECK(!audio_ended_);
440 RunEndedCallbackIfNeeded();
443 void RendererImpl::OnVideoRendererEnded() {
444 DVLOG(1) << __FUNCTION__;
445 DCHECK(task_runner_->BelongsToCurrentThread());
447 if (state_ != STATE_PLAYING)
450 DCHECK(!video_ended_);
453 RunEndedCallbackIfNeeded();
456 bool RendererImpl::PlaybackHasEnded() const {
457 DVLOG(1) << __FUNCTION__;
458 DCHECK(task_runner_->BelongsToCurrentThread());
460 if (audio_renderer_ && !audio_ended_)
463 if (video_renderer_ && !video_ended_)
469 void RendererImpl::RunEndedCallbackIfNeeded() {
470 DVLOG(1) << __FUNCTION__;
471 DCHECK(task_runner_->BelongsToCurrentThread());
473 if (!PlaybackHasEnded())
482 void RendererImpl::OnError(PipelineStatus error) {
483 DVLOG(1) << __FUNCTION__ << "(" << error << ")";
484 DCHECK(task_runner_->BelongsToCurrentThread());
485 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
487 state_ = STATE_ERROR;
489 // Pipeline will destroy |this| as the result of error.
490 base::ResetAndReturn(&error_cb_).Run(error);
492 FireAllPendingCallbacks();
495 void RendererImpl::FireAllPendingCallbacks() {
496 DCHECK(task_runner_->BelongsToCurrentThread());
498 if (!init_cb_.is_null())
499 base::ResetAndReturn(&init_cb_).Run();
501 if (!flush_cb_.is_null())
502 base::ResetAndReturn(&flush_cb_).Run();