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. 4 5 #include "media/filters/renderer_impl.h" 6 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" 18 19 namespace media { 20 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()), 31 time_source_(NULL), 32 time_ticking_(false), 33 audio_buffering_state_(BUFFERING_HAVE_NOTHING), 34 video_buffering_state_(BUFFERING_HAVE_NOTHING), 35 audio_ended_(false), 36 video_ended_(false), 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__; 42 } 43 44 RendererImpl::~RendererImpl() { 45 DVLOG(1) << __FUNCTION__; 46 DCHECK(task_runner_->BelongsToCurrentThread()); 47 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(); 52 53 FireAllPendingCallbacks(); 54 } 55 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)); 71 72 statistics_cb_ = statistics_cb; 73 ended_cb_ = ended_cb; 74 error_cb_ = error_cb; 75 buffering_state_cb_ = buffering_state_cb; 76 77 init_cb_ = init_cb; 78 state_ = STATE_INITIALIZING; 79 InitializeAudioRenderer(); 80 } 81 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()); 87 88 flush_cb_ = flush_cb; 89 state_ = STATE_FLUSHING; 90 91 if (time_ticking_) 92 PausePlayback(); 93 94 FlushAudioRenderer(); 95 } 96 97 void RendererImpl::StartPlayingFrom(base::TimeDelta time) { 98 DVLOG(1) << __FUNCTION__; 99 DCHECK(task_runner_->BelongsToCurrentThread()); 100 DCHECK_EQ(state_, STATE_PLAYING) << state_; 101 102 time_source_->SetMediaTime(time); 103 104 if (audio_renderer_) 105 audio_renderer_->StartPlaying(); 106 if (video_renderer_) 107 video_renderer_->StartPlayingFrom(time); 108 } 109 110 void RendererImpl::SetPlaybackRate(float playback_rate) { 111 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; 112 DCHECK(task_runner_->BelongsToCurrentThread()); 113 114 // Playback rate changes are only carried out while playing. 115 if (state_ != STATE_PLAYING) 116 return; 117 118 time_source_->SetPlaybackRate(playback_rate); 119 } 120 121 void RendererImpl::SetVolume(float volume) { 122 DVLOG(1) << __FUNCTION__; 123 DCHECK(task_runner_->BelongsToCurrentThread()); 124 125 if (audio_renderer_) 126 audio_renderer_->SetVolume(volume); 127 } 128 129 base::TimeDelta RendererImpl::GetMediaTime() { 130 // No BelongsToCurrentThread() checking because this can be called from other 131 // threads. 132 return time_source_->CurrentMediaTime(); 133 } 134 135 bool RendererImpl::HasAudio() { 136 DCHECK(task_runner_->BelongsToCurrentThread()); 137 return audio_renderer_ != NULL; 138 } 139 140 bool RendererImpl::HasVideo() { 141 DCHECK(task_runner_->BelongsToCurrentThread()); 142 return video_renderer_ != NULL; 143 } 144 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 150 NOTREACHED(); 151 } 152 153 void RendererImpl::DisableUnderflowForTesting() { 154 DVLOG(1) << __FUNCTION__; 155 DCHECK(task_runner_->BelongsToCurrentThread()); 156 DCHECK_EQ(state_, STATE_UNINITIALIZED); 157 158 underflow_disabled_for_testing_ = true; 159 } 160 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"; 167 168 clockless_video_playback_enabled_for_testing_ = true; 169 } 170 171 base::TimeDelta RendererImpl::GetMediaTimeForSyncingVideo() { 172 // No BelongsToCurrentThread() checking because this can be called from other 173 // threads. 174 // 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(); 179 180 return time_source_->CurrentMediaTimeForSyncingVideo(); 181 } 182 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()); 188 189 PipelineStatusCB done_cb = 190 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_); 191 192 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) { 193 audio_renderer_.reset(); 194 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 195 return; 196 } 197 198 audio_renderer_->Initialize( 199 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), 200 done_cb, 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_)); 206 } 207 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()); 213 214 if (status != PIPELINE_OK) { 215 audio_renderer_.reset(); 216 OnError(status); 217 return; 218 } 219 220 InitializeVideoRenderer(); 221 } 222 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()); 228 229 PipelineStatusCB done_cb = 230 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_); 231 232 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) { 233 video_renderer_.reset(); 234 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 235 return; 236 } 237 238 video_renderer_->Initialize( 239 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), 240 demuxer_stream_provider_->GetLiveness() == 241 DemuxerStreamProvider::LIVENESS_LIVE, 242 done_cb, 243 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), 244 base::Bind(&RendererImpl::OnBufferingStateChanged, 245 weak_this_, 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))); 251 } 252 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()); 258 259 if (status != PIPELINE_OK) { 260 audio_renderer_.reset(); 261 video_renderer_.reset(); 262 OnError(status); 263 return; 264 } 265 266 if (audio_renderer_) { 267 time_source_ = audio_renderer_->GetTimeSource(); 268 } else { 269 wall_clock_time_source_.reset(new WallClockTimeSource()); 270 time_source_ = wall_clock_time_source_.get(); 271 } 272 273 state_ = STATE_PLAYING; 274 DCHECK(time_source_); 275 DCHECK(audio_renderer_ || video_renderer_); 276 base::ResetAndReturn(&init_cb_).Run(); 277 } 278 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()); 284 285 if (!audio_renderer_) { 286 OnAudioRendererFlushDone(); 287 return; 288 } 289 290 audio_renderer_->Flush( 291 base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_)); 292 } 293 294 void RendererImpl::OnAudioRendererFlushDone() { 295 DVLOG(1) << __FUNCTION__; 296 DCHECK(task_runner_->BelongsToCurrentThread()); 297 298 if (state_ == STATE_ERROR) { 299 DCHECK(flush_cb_.is_null()); 300 return; 301 } 302 303 DCHECK_EQ(state_, STATE_FLUSHING) << state_; 304 DCHECK(!flush_cb_.is_null()); 305 306 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING); 307 audio_ended_ = false; 308 FlushVideoRenderer(); 309 } 310 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()); 316 317 if (!video_renderer_) { 318 OnVideoRendererFlushDone(); 319 return; 320 } 321 322 video_renderer_->Flush( 323 base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_)); 324 } 325 326 void RendererImpl::OnVideoRendererFlushDone() { 327 DVLOG(1) << __FUNCTION__; 328 DCHECK(task_runner_->BelongsToCurrentThread()); 329 330 if (state_ == STATE_ERROR) { 331 DCHECK(flush_cb_.is_null()); 332 return; 333 } 334 335 DCHECK_EQ(state_, STATE_FLUSHING) << state_; 336 DCHECK(!flush_cb_.is_null()); 337 338 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING); 339 video_ended_ = false; 340 state_ = STATE_PLAYING; 341 base::ResetAndReturn(&flush_cb_).Run(); 342 } 343 344 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) { 345 DCHECK(task_runner_->BelongsToCurrentThread()); 346 statistics_cb_.Run(stats); 347 } 348 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(); 356 357 *buffering_state = new_buffering_state; 358 359 // Disable underflow by ignoring updates that renderers have ran out of data. 360 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ && 361 time_ticking_) { 362 DVLOG(1) << "Update ignored because underflow is disabled for testing."; 363 return; 364 } 365 366 // Renderer underflowed. 367 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { 368 PausePlayback(); 369 370 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of 371 // underflow state http://crbug.com/144683 372 return; 373 } 374 375 // Renderer prerolled. 376 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { 377 StartPlayback(); 378 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); 379 return; 380 } 381 } 382 383 bool RendererImpl::WaitingForEnoughData() const { 384 DCHECK(task_runner_->BelongsToCurrentThread()); 385 if (state_ != STATE_PLAYING) 386 return false; 387 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) 388 return true; 389 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) 390 return true; 391 return false; 392 } 393 394 void RendererImpl::PausePlayback() { 395 DVLOG(1) << __FUNCTION__; 396 DCHECK(task_runner_->BelongsToCurrentThread()); 397 DCHECK(time_ticking_); 398 switch (state_) { 399 case STATE_PLAYING: 400 DCHECK(PlaybackHasEnded() || WaitingForEnoughData()) 401 << "Playback should only pause due to ending or underflowing"; 402 break; 403 404 case STATE_FLUSHING: 405 // It's OK to pause playback when flushing. 406 break; 407 408 case STATE_UNINITIALIZED: 409 case STATE_INITIALIZING: 410 case STATE_ERROR: 411 NOTREACHED() << "Invalid state: " << state_; 412 break; 413 } 414 415 time_ticking_ = false; 416 time_source_->StopTicking(); 417 } 418 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()); 425 426 time_ticking_ = true; 427 time_source_->StartTicking(); 428 } 429 430 void RendererImpl::OnAudioRendererEnded() { 431 DVLOG(1) << __FUNCTION__; 432 DCHECK(task_runner_->BelongsToCurrentThread()); 433 434 if (state_ != STATE_PLAYING) 435 return; 436 437 DCHECK(!audio_ended_); 438 audio_ended_ = true; 439 440 RunEndedCallbackIfNeeded(); 441 } 442 443 void RendererImpl::OnVideoRendererEnded() { 444 DVLOG(1) << __FUNCTION__; 445 DCHECK(task_runner_->BelongsToCurrentThread()); 446 447 if (state_ != STATE_PLAYING) 448 return; 449 450 DCHECK(!video_ended_); 451 video_ended_ = true; 452 453 RunEndedCallbackIfNeeded(); 454 } 455 456 bool RendererImpl::PlaybackHasEnded() const { 457 DVLOG(1) << __FUNCTION__; 458 DCHECK(task_runner_->BelongsToCurrentThread()); 459 460 if (audio_renderer_ && !audio_ended_) 461 return false; 462 463 if (video_renderer_ && !video_ended_) 464 return false; 465 466 return true; 467 } 468 469 void RendererImpl::RunEndedCallbackIfNeeded() { 470 DVLOG(1) << __FUNCTION__; 471 DCHECK(task_runner_->BelongsToCurrentThread()); 472 473 if (!PlaybackHasEnded()) 474 return; 475 476 if (time_ticking_) 477 PausePlayback(); 478 479 ended_cb_.Run(); 480 } 481 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!"; 486 487 state_ = STATE_ERROR; 488 489 // Pipeline will destroy |this| as the result of error. 490 base::ResetAndReturn(&error_cb_).Run(error); 491 492 FireAllPendingCallbacks(); 493 } 494 495 void RendererImpl::FireAllPendingCallbacks() { 496 DCHECK(task_runner_->BelongsToCurrentThread()); 497 498 if (!init_cb_.is_null()) 499 base::ResetAndReturn(&init_cb_).Run(); 500 501 if (!flush_cb_.is_null()) 502 base::ResetAndReturn(&flush_cb_).Run(); 503 } 504 505 } // namespace media 506