OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/blink/webmediaplayer_impl.h" | 5 #include "media/blink/webmediaplayer_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <limits> | 9 #include <limits> |
10 #include <string> | 10 #include <string> |
11 #include <utility> | 11 #include <utility> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" |
14 #include "base/callback.h" | 15 #include "base/callback.h" |
15 #include "base/callback_helpers.h" | 16 #include "base/callback_helpers.h" |
16 #include "base/command_line.h" | 17 #include "base/command_line.h" |
17 #include "base/debug/alias.h" | 18 #include "base/debug/alias.h" |
18 #include "base/debug/crash_logging.h" | 19 #include "base/debug/crash_logging.h" |
19 #include "base/metrics/histogram.h" | 20 #include "base/metrics/histogram.h" |
20 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
21 #include "base/synchronization/waitable_event.h" | 22 #include "base/synchronization/waitable_event.h" |
22 #include "base/task_runner_util.h" | 23 #include "base/task_runner_util.h" |
23 #include "base/thread_task_runner_handle.h" | 24 #include "base/thread_task_runner_handle.h" |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 network_state_(WebMediaPlayer::NetworkStateEmpty), | 137 network_state_(WebMediaPlayer::NetworkStateEmpty), |
137 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 138 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
138 preload_(BufferedDataSource::AUTO), | 139 preload_(BufferedDataSource::AUTO), |
139 buffering_strategy_( | 140 buffering_strategy_( |
140 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), | 141 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), |
141 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 142 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
142 media_task_runner_(params.media_task_runner()), | 143 media_task_runner_(params.media_task_runner()), |
143 worker_task_runner_(params.worker_task_runner()), | 144 worker_task_runner_(params.worker_task_runner()), |
144 media_log_(params.media_log()), | 145 media_log_(params.media_log()), |
145 pipeline_(media_task_runner_, media_log_.get()), | 146 pipeline_(media_task_runner_, media_log_.get()), |
| 147 pipeline_controller_( |
| 148 &pipeline_, |
| 149 base::Bind(&WebMediaPlayerImpl::CreateRenderer, |
| 150 base::Unretained(this)), |
| 151 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), |
| 152 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), |
| 153 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()), |
| 154 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), |
146 load_type_(LoadTypeURL), | 155 load_type_(LoadTypeURL), |
147 opaque_(false), | 156 opaque_(false), |
148 playback_rate_(0.0), | 157 playback_rate_(0.0), |
149 paused_(true), | 158 paused_(true), |
150 seeking_(false), | 159 seeking_(false), |
151 pending_suspend_(false), | |
152 pending_time_change_(false), | |
153 pending_resume_(false), | |
154 suspending_(false), | |
155 suspended_(false), | |
156 resuming_(false), | |
157 pending_suspend_resume_cycle_(false), | 160 pending_suspend_resume_cycle_(false), |
158 ended_(false), | 161 ended_(false), |
159 pending_seek_(false), | |
160 should_notify_time_changed_(false), | 162 should_notify_time_changed_(false), |
161 fullscreen_(false), | 163 fullscreen_(false), |
162 decoder_requires_restart_for_fullscreen_(false), | 164 decoder_requires_restart_for_fullscreen_(false), |
163 client_(client), | 165 client_(client), |
164 encrypted_client_(encrypted_client), | 166 encrypted_client_(encrypted_client), |
165 delegate_(delegate), | 167 delegate_(delegate), |
166 delegate_id_(0), | 168 delegate_id_(0), |
167 defer_load_cb_(params.defer_load_cb()), | 169 defer_load_cb_(params.defer_load_cb()), |
168 context_3d_cb_(params.context_3d_cb()), | 170 context_3d_cb_(params.context_3d_cb()), |
169 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), | 171 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 delegate_->PlayerGone(delegate_id_); | 225 delegate_->PlayerGone(delegate_id_); |
224 delegate_->RemoveObserver(delegate_id_); | 226 delegate_->RemoveObserver(delegate_id_); |
225 } | 227 } |
226 | 228 |
227 // Abort any pending IO so stopping the pipeline doesn't get blocked. | 229 // Abort any pending IO so stopping the pipeline doesn't get blocked. |
228 suppress_destruction_errors_ = true; | 230 suppress_destruction_errors_ = true; |
229 if (data_source_) | 231 if (data_source_) |
230 data_source_->Abort(); | 232 data_source_->Abort(); |
231 if (chunk_demuxer_) { | 233 if (chunk_demuxer_) { |
232 chunk_demuxer_->Shutdown(); | 234 chunk_demuxer_->Shutdown(); |
233 chunk_demuxer_ = NULL; | 235 chunk_demuxer_ = nullptr; |
234 } | 236 } |
235 | 237 |
236 renderer_factory_.reset(); | 238 renderer_factory_.reset(); |
237 | 239 |
238 // Make sure to kill the pipeline so there's no more media threads running. | 240 // Make sure to kill the pipeline so there's no more media threads running. |
239 // Note: stopping the pipeline might block for a long time. | 241 // Note: stopping the pipeline might block for a long time. |
240 base::WaitableEvent waiter(false, false); | 242 base::WaitableEvent waiter(false, false); |
241 pipeline_.Stop( | 243 pipeline_.Stop( |
242 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); | 244 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
243 waiter.Wait(); | 245 waiter.Wait(); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 337 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
336 | 338 |
337 #if defined(OS_ANDROID) // WMPI_CAST | 339 #if defined(OS_ANDROID) // WMPI_CAST |
338 if (isRemote()) { | 340 if (isRemote()) { |
339 cast_impl_.play(); | 341 cast_impl_.play(); |
340 return; | 342 return; |
341 } | 343 } |
342 #endif | 344 #endif |
343 | 345 |
344 paused_ = false; | 346 paused_ = false; |
| 347 pipeline_.SetPlaybackRate(playback_rate_); |
345 | 348 |
346 pipeline_.SetPlaybackRate(playback_rate_); | |
347 if (data_source_) | 349 if (data_source_) |
348 data_source_->MediaIsPlaying(); | 350 data_source_->MediaIsPlaying(); |
349 | 351 |
350 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 352 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
351 | 353 |
352 if (playback_rate_ > 0) { | 354 if (playback_rate_ > 0) { |
353 // Resume the player if playback was initiated in the foreground. | 355 NotifyPlaybackStarted(); |
354 if (suspended_ && !resuming_ && delegate_ && !delegate_->IsHidden()) { | |
355 ScheduleResume(); | |
356 return; | |
357 } | |
358 | 356 |
359 NotifyPlaybackStarted(); | 357 // Resume the player if playback was initiated in the foreground. Resume() |
| 358 // will do nothing if the pipeline is not suspended state, but will clear |
| 359 // some internal pending state, so it should always be called. |
| 360 if (delegate_ && !delegate_->IsHidden()) |
| 361 pipeline_controller_.Resume(); |
360 } | 362 } |
361 } | 363 } |
362 | 364 |
363 void WebMediaPlayerImpl::pause() { | 365 void WebMediaPlayerImpl::pause() { |
364 DVLOG(1) << __FUNCTION__; | 366 DVLOG(1) << __FUNCTION__; |
365 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 367 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
366 | 368 |
367 const bool was_already_paused = paused_ || playback_rate_ == 0; | 369 const bool was_already_paused = paused_ || playback_rate_ == 0; |
368 paused_ = true; | 370 paused_ = true; |
369 | 371 |
370 #if defined(OS_ANDROID) // WMPI_CAST | 372 #if defined(OS_ANDROID) // WMPI_CAST |
371 if (isRemote()) { | 373 if (isRemote()) { |
372 cast_impl_.pause(); | 374 cast_impl_.pause(); |
373 return; | 375 return; |
374 } | 376 } |
375 #endif | 377 #endif |
376 | 378 |
377 pipeline_.SetPlaybackRate(0.0); | 379 pipeline_.SetPlaybackRate(0.0); |
378 UpdatePausedTime(); | 380 |
| 381 // pause() may be called after playback has ended and the HTMLMediaElement |
| 382 // requires that currentTime() == duration() after ending. We want to ensure |
| 383 // |paused_time_| matches currentTime() in this case or a future seek() may |
| 384 // incorrectly discard what it thinks is a seek to the existing time. |
| 385 paused_time_ = |
| 386 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); |
379 | 387 |
380 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 388 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
381 | 389 |
382 if (!was_already_paused) | 390 if (!was_already_paused) |
383 NotifyPlaybackPaused(); | 391 NotifyPlaybackPaused(); |
384 } | 392 } |
385 | 393 |
386 bool WebMediaPlayerImpl::supportsSave() const { | 394 bool WebMediaPlayerImpl::supportsSave() const { |
387 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 395 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
388 return supports_save_; | 396 return supports_save_; |
389 } | 397 } |
390 | 398 |
391 void WebMediaPlayerImpl::seek(double seconds) { | 399 void WebMediaPlayerImpl::seek(double seconds) { |
392 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 400 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
393 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 401 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 402 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); |
| 403 } |
| 404 |
| 405 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { |
| 406 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
394 | 407 |
395 ended_ = false; | 408 ended_ = false; |
396 | 409 |
397 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); | |
398 | |
399 #if defined(OS_ANDROID) // WMPI_CAST | 410 #if defined(OS_ANDROID) // WMPI_CAST |
400 if (isRemote()) { | 411 if (isRemote()) { |
401 cast_impl_.seek(new_seek_time); | 412 cast_impl_.seek(time); |
402 return; | 413 return; |
403 } | 414 } |
404 #endif | 415 #endif |
405 | 416 |
406 ReadyState old_state = ready_state_; | 417 ReadyState old_state = ready_state_; |
407 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 418 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
408 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 419 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
409 | 420 |
410 if (seeking_ || suspended_) { | 421 // When paused, we know exactly what the current time is and can elide seeks |
411 // Once resuming, it's too late to change the resume time and so the | 422 // to it. However, there are two cases that are not elided: |
412 // implementation is a little different. | 423 // 1) When the pipeline state is not stable. |
413 bool is_suspended = suspended_ && !resuming_; | 424 // In this case we just let |pipeline_controller_| decide what to do, as |
414 | 425 // it has complete information. |
415 // If we are currently seeking or resuming to |new_seek_time|, skip the | 426 // 2) For MSE. |
416 // seek (except for MSE, which always seeks). | 427 // Because the buffers may have changed between seeks, MSE seeks are |
417 if (!is_suspended && new_seek_time == seek_time_) { | 428 // never elided. |
418 if (chunk_demuxer_) { | 429 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time && |
419 // Don't suppress any redundant in-progress MSE seek. There could have | 430 !chunk_demuxer_) { |
420 // been changes to the underlying buffers after seeking the demuxer and | 431 // If the ready state was high enough before, we can indicate that the seek |
421 // before receiving OnPipelineSeeked() for the currently in-progress | 432 // completed just by restoring it. Otherwise we will just wait for the real |
422 // seek. | 433 // ready state change to eventually happen. |
423 MEDIA_LOG(DEBUG, media_log_) | 434 if (old_state == ReadyStateHaveEnoughData) { |
424 << "Detected MediaSource seek to same time as in-progress seek to " | |
425 << seek_time_ << "."; | |
426 } else { | |
427 // Suppress all redundant seeks if unrestricted by media source demuxer | |
428 // API. | |
429 pending_seek_ = false; | |
430 pending_seek_time_ = base::TimeDelta(); | |
431 return; | |
432 } | |
433 } | |
434 | |
435 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the | |
436 // new one. | |
437 if (!is_suspended && chunk_demuxer_) | |
438 chunk_demuxer_->CancelPendingSeek(new_seek_time); | |
439 | |
440 // Schedule a seek once the current suspend or seek finishes. | |
441 pending_seek_ = true; | |
442 pending_seek_time_ = new_seek_time; | |
443 | |
444 // In the case of seeking while suspended, the seek is considered to have | |
445 // started immediately (but won't complete until the pipeline is resumed). | |
446 if (is_suspended) { | |
447 seeking_ = true; | |
448 seek_time_ = new_seek_time; | |
449 | |
450 // Resume the pipeline if the seek is initiated in the foreground so that | |
451 // the correct frame is displayed. | |
452 if (delegate_ && !delegate_->IsHidden()) | |
453 ScheduleResume(); | |
454 } | |
455 | |
456 return; | |
457 } | |
458 | |
459 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); | |
460 | |
461 // Update our paused time. | |
462 // For non-MSE playbacks, in paused state ignore the seek operations to | |
463 // current time if the loading is completed and generate | |
464 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked | |
465 // events. We don't short-circuit MSE seeks in this logic because the | |
466 // underlying buffers around the seek time might have changed (or even been | |
467 // removed) since previous seek/preroll/pause action, and the pipeline might | |
468 // need to flush so the new buffers are decoded and rendered instead of the | |
469 // old ones. | |
470 if (paused_) { | |
471 if (paused_time_ != new_seek_time || chunk_demuxer_) { | |
472 paused_time_ = new_seek_time; | |
473 } else if (old_state == ReadyStateHaveEnoughData) { | |
474 main_task_runner_->PostTask( | 435 main_task_runner_->PostTask( |
475 FROM_HERE, | 436 FROM_HERE, |
476 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 437 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
477 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 438 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
478 return; | |
479 } | 439 } |
| 440 return; |
480 } | 441 } |
481 | 442 |
482 seeking_ = true; | 443 seeking_ = true; |
483 seek_time_ = new_seek_time; | 444 seek_time_ = time; |
| 445 if (paused_) |
| 446 paused_time_ = time; |
| 447 pipeline_controller_.Seek(time, time_updated); |
484 | 448 |
485 if (chunk_demuxer_) | 449 // Resume the pipeline if the seek is initiated in the foreground so that |
486 chunk_demuxer_->StartWaitingForSeek(seek_time_); | 450 // the correct frame is displayed. If the pipeline is not suspended, Resume() |
487 | 451 // will do nothing but clear some pending state. |
488 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( | 452 if (delegate_ && !delegate_->IsHidden()) |
489 &WebMediaPlayerImpl::OnPipelineSeeked, true)); | 453 pipeline_controller_.Resume(); |
490 } | 454 } |
491 | 455 |
492 void WebMediaPlayerImpl::setRate(double rate) { | 456 void WebMediaPlayerImpl::setRate(double rate) { |
493 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 457 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
494 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 458 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
495 | 459 |
496 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 460 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
497 // following checks so rewind uses reasonable values also. | 461 // following checks so rewind uses reasonable values also. |
498 if (rate < 0.0) | 462 if (rate < 0.0) |
499 return; | 463 return; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 | 592 |
629 double WebMediaPlayerImpl::currentTime() const { | 593 double WebMediaPlayerImpl::currentTime() const { |
630 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 594 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
631 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 595 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
632 | 596 |
633 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, | 597 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, |
634 // see http://crbug.com/409280 | 598 // see http://crbug.com/409280 |
635 if (ended_) | 599 if (ended_) |
636 return duration(); | 600 return duration(); |
637 | 601 |
638 // We know the current seek time better than pipeline: pipeline may processing | 602 if (seeking()) |
639 // an earlier seek before a pending seek has been started, or it might not yet | 603 return seek_time_.InSecondsF(); |
640 // have the current seek time returnable via GetMediaTime(). | |
641 if (seeking()) { | |
642 return pending_seek_ ? pending_seek_time_.InSecondsF() | |
643 : seek_time_.InSecondsF(); | |
644 } | |
645 | 604 |
646 #if defined(OS_ANDROID) // WMPI_CAST | 605 #if defined(OS_ANDROID) // WMPI_CAST |
647 if (isRemote()) { | 606 if (isRemote()) |
648 return cast_impl_.currentTime(); | 607 return cast_impl_.currentTime(); |
649 } | |
650 #endif | 608 #endif |
651 | 609 |
652 if (paused_) { | 610 if (paused_) |
653 return paused_time_.InSecondsF(); | 611 return paused_time_.InSecondsF(); |
654 } | |
655 | 612 |
656 return pipeline_.GetMediaTime().InSecondsF(); | 613 return pipeline_.GetMediaTime().InSecondsF(); |
657 } | 614 } |
658 | 615 |
659 WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const { | 616 WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const { |
660 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 617 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
661 return network_state_; | 618 return network_state_; |
662 } | 619 } |
663 | 620 |
664 WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const { | 621 WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const { |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 is_cdm_attached_ = true; | 834 is_cdm_attached_ = true; |
878 return; | 835 return; |
879 } | 836 } |
880 | 837 |
881 set_cdm_result_->completeWithError( | 838 set_cdm_result_->completeWithError( |
882 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 839 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
883 "Unable to set MediaKeys object"); | 840 "Unable to set MediaKeys object"); |
884 set_cdm_result_.reset(); | 841 set_cdm_result_.reset(); |
885 } | 842 } |
886 | 843 |
887 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed, | 844 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
888 PipelineStatus status) { | |
889 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")"; | |
890 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
891 | |
892 if (status != PIPELINE_OK) { | |
893 OnPipelineError(status); | |
894 return; | |
895 } | |
896 | |
897 // Whether or not the seek was caused by a resume, we're not suspended now. | |
898 const bool was_resuming = resuming_; | |
899 resuming_ = false; | |
900 suspended_ = false; | |
901 | |
902 // If we we're resuming into the playing state, notify the delegate. | |
903 if (was_resuming && playback_rate_ > 0 && !paused_) | |
904 NotifyPlaybackStarted(); | |
905 | |
906 // If there is a pending suspend, the seek does not complete until after the | |
907 // next resume. | |
908 if (pending_suspend_) { | |
909 pending_suspend_ = false; | |
910 pending_time_change_ = time_changed; | |
911 Suspend(); | |
912 return; | |
913 } | |
914 | |
915 // Clear seek state. Note that if the seek was caused by a resume, then | |
916 // |seek_time_| is always set but |seeking_| is only set if there was a | |
917 // pending seek at the time. | |
918 seeking_ = false; | 845 seeking_ = false; |
919 seek_time_ = base::TimeDelta(); | 846 seek_time_ = base::TimeDelta(); |
920 | |
921 if (pending_seek_) { | |
922 double pending_seek_seconds = pending_seek_time_.InSecondsF(); | |
923 pending_seek_ = false; | |
924 pending_seek_time_ = base::TimeDelta(); | |
925 seek(pending_seek_seconds); | |
926 return; | |
927 } | |
928 | |
929 // Update our paused time. | |
930 if (paused_) | 847 if (paused_) |
931 UpdatePausedTime(); | 848 paused_time_ = pipeline_.GetMediaTime(); |
932 | 849 if (time_updated) |
933 should_notify_time_changed_ = time_changed; | 850 should_notify_time_changed_ = true; |
934 } | 851 } |
935 | 852 |
936 void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) { | 853 void WebMediaPlayerImpl::OnPipelineSuspended() { |
937 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | |
938 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
939 | |
940 if (status != PIPELINE_OK) { | |
941 OnPipelineError(status); | |
942 return; | |
943 } | |
944 | |
945 suspending_ = false; | |
946 if (delegate_) | |
947 delegate_->PlayerGone(delegate_id_); | |
948 | |
949 #if defined(OS_ANDROID) | 854 #if defined(OS_ANDROID) |
950 if (isRemote()) { | 855 if (isRemote()) { |
951 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 856 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
952 if (frame) { | 857 if (frame) { |
953 compositor_->PaintFrameUsingOldRenderingPath(frame); | 858 compositor_->PaintFrameUsingOldRenderingPath(frame); |
954 } | 859 } |
955 } | 860 } |
956 #endif | 861 #endif |
957 | 862 |
958 if (pending_resume_ || pending_suspend_resume_cycle_) { | 863 if (delegate_) |
959 pending_resume_ = false; | 864 delegate_->PlayerGone(delegate_id_); |
| 865 |
| 866 if (pending_suspend_resume_cycle_) { |
960 pending_suspend_resume_cycle_ = false; | 867 pending_suspend_resume_cycle_ = false; |
961 Resume(); | 868 pipeline_controller_.Resume(); |
962 return; | 869 return; |
963 } | 870 } |
964 } | 871 } |
965 | 872 |
| 873 void WebMediaPlayerImpl::OnPipelineResumed() { |
| 874 if (playback_rate_ > 0 && !paused_) |
| 875 NotifyPlaybackStarted(); |
| 876 } |
| 877 |
966 void WebMediaPlayerImpl::OnPipelineEnded() { | 878 void WebMediaPlayerImpl::OnPipelineEnded() { |
967 DVLOG(1) << __FUNCTION__; | 879 DVLOG(1) << __FUNCTION__; |
968 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 880 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
969 | 881 |
970 // Ignore state changes until we've completed all outstanding seeks. | 882 // Ignore state changes until we've completed all outstanding operations. |
971 if (seeking_ || pending_seek_) | 883 if (!pipeline_controller_.IsStable()) |
972 return; | 884 return; |
973 | 885 |
974 ended_ = true; | 886 ended_ = true; |
975 client_->timeChanged(); | 887 client_->timeChanged(); |
976 } | 888 } |
977 | 889 |
978 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 890 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
979 DVLOG(1) << __FUNCTION__; | 891 DVLOG(1) << __FUNCTION__; |
980 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 892 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
981 DCHECK_NE(error, PIPELINE_OK); | 893 DCHECK_NE(error, PIPELINE_OK); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 // playback. | 937 // playback. |
1026 if (delegate_ && delegate_->IsHidden()) | 938 if (delegate_ && delegate_->IsHidden()) |
1027 OnHidden(false); | 939 OnHidden(false); |
1028 } | 940 } |
1029 } | 941 } |
1030 | 942 |
1031 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 943 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
1032 BufferingState buffering_state) { | 944 BufferingState buffering_state) { |
1033 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 945 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
1034 | 946 |
1035 // Ignore buffering state changes until we've completed all outstanding seeks. | 947 // Ignore buffering state changes until we've completed all outstanding |
1036 if (seeking_ || pending_seek_) | 948 // operations. |
| 949 if (!pipeline_controller_.IsStable()) |
1037 return; | 950 return; |
1038 | 951 |
1039 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 952 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
1040 // them and translate them ready state changes http://crbug.com/144683 | 953 // them and translate them ready state changes http://crbug.com/144683 |
1041 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 954 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
1042 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 955 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
1043 | 956 |
1044 // Let the DataSource know we have enough data. It may use this information to | 957 // Let the DataSource know we have enough data. It may use this information to |
1045 // release unused network connections. | 958 // release unused network connections. |
1046 if (data_source_) | 959 if (data_source_) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1100 return; | 1013 return; |
1101 } | 1014 } |
1102 | 1015 |
1103 #if defined(OS_ANDROID) | 1016 #if defined(OS_ANDROID) |
1104 // If we're remote, the pipeline should already be suspended. | 1017 // If we're remote, the pipeline should already be suspended. |
1105 if (isRemote()) | 1018 if (isRemote()) |
1106 return; | 1019 return; |
1107 #endif | 1020 #endif |
1108 | 1021 |
1109 if (must_suspend || (paused_ && ended_) || hasVideo()) | 1022 if (must_suspend || (paused_ && ended_) || hasVideo()) |
1110 ScheduleSuspend(); | 1023 pipeline_controller_.Suspend(); |
1111 } | |
1112 | |
1113 void WebMediaPlayerImpl::ScheduleSuspend() { | |
1114 if (!pipeline_.IsRunning()) | |
1115 return; | |
1116 | |
1117 if (resuming_ || seeking_) { | |
1118 pending_suspend_ = true; | |
1119 return; | |
1120 } | |
1121 | |
1122 if (pending_resume_) { | |
1123 pending_resume_ = false; | |
1124 return; | |
1125 } | |
1126 | |
1127 Suspend(); | |
1128 } | |
1129 | |
1130 void WebMediaPlayerImpl::Suspend() { | |
1131 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1132 | |
1133 // Since Pipeline::IsRunning() may be set on the media thread there are cases | |
1134 // where two suspends might be issued concurrently. | |
1135 if (suspended_) | |
1136 return; | |
1137 | |
1138 suspended_ = true; | |
1139 suspending_ = true; | |
1140 pipeline_.Suspend( | |
1141 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended)); | |
1142 } | 1024 } |
1143 | 1025 |
1144 void WebMediaPlayerImpl::OnShown() { | 1026 void WebMediaPlayerImpl::OnShown() { |
1145 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1027 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1146 | 1028 |
1147 #if !defined(OS_ANDROID) | 1029 #if !defined(OS_ANDROID) |
1148 // Suspend/Resume is enabled by default on Android. | 1030 // Suspend/Resume is enabled by default on Android. |
1149 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 1031 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
1150 switches::kEnableMediaSuspend)) { | 1032 switches::kEnableMediaSuspend)) { |
1151 return; | 1033 return; |
1152 } | 1034 } |
1153 #endif // !defined(OS_ANDROID) | 1035 #endif // !defined(OS_ANDROID) |
1154 | 1036 |
1155 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 1037 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
1156 switches::kDisableMediaSuspend)) { | 1038 switches::kDisableMediaSuspend)) { |
1157 return; | 1039 return; |
1158 } | 1040 } |
1159 | 1041 |
1160 #if defined(OS_ANDROID) | 1042 #if defined(OS_ANDROID) |
1161 // If we're remote, the pipeline should stay suspended. | 1043 // If we're remote, the pipeline should stay suspended. |
1162 if (isRemote()) | 1044 if (isRemote()) |
1163 return; | 1045 return; |
1164 #endif | 1046 #endif |
1165 | 1047 |
1166 if (!ended_ && !paused_) | 1048 if (!ended_ && !paused_) |
1167 ScheduleResume(); | 1049 pipeline_controller_.Resume(); |
1168 } | |
1169 | |
1170 void WebMediaPlayerImpl::ScheduleResume() { | |
1171 if (!pipeline_.IsRunning()) | |
1172 return; | |
1173 | |
1174 if (suspending_) { | |
1175 pending_resume_ = true; | |
1176 return; | |
1177 } | |
1178 | |
1179 if (pending_suspend_) { | |
1180 pending_suspend_ = false; | |
1181 return; | |
1182 } | |
1183 | |
1184 // Might already be resuming iff we came back from remote playback recently. | |
1185 if (suspended_ && !resuming_) | |
1186 Resume(); | |
1187 } | 1050 } |
1188 | 1051 |
1189 void WebMediaPlayerImpl::OnPlay() { | 1052 void WebMediaPlayerImpl::OnPlay() { |
1190 play(); | 1053 play(); |
1191 client_->playbackStateChanged(); | 1054 client_->playbackStateChanged(); |
1192 } | 1055 } |
1193 | 1056 |
1194 void WebMediaPlayerImpl::OnPause() { | 1057 void WebMediaPlayerImpl::OnPause() { |
1195 pause(); | 1058 pause(); |
1196 client_->playbackStateChanged(); | 1059 client_->playbackStateChanged(); |
1197 } | 1060 } |
1198 | 1061 |
1199 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { | 1062 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { |
1200 volume_multiplier_ = multiplier; | 1063 volume_multiplier_ = multiplier; |
1201 setVolume(volume_); | 1064 setVolume(volume_); |
1202 } | 1065 } |
1203 | 1066 |
1204 void WebMediaPlayerImpl::Resume() { | |
1205 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1206 CHECK(suspended_); | |
1207 CHECK(!resuming_); | |
1208 | |
1209 // If there was a time change pending when we suspended (which can happen when | |
1210 // we suspend immediately after a seek), surface it after resuming. | |
1211 bool time_changed = pending_time_change_; | |
1212 pending_time_change_ = false; | |
1213 | |
1214 if (seeking_ || pending_seek_) { | |
1215 if (pending_seek_) { | |
1216 seek_time_ = pending_seek_time_; | |
1217 pending_seek_ = false; | |
1218 pending_seek_time_ = base::TimeDelta(); | |
1219 } | |
1220 time_changed = true; | |
1221 } else { | |
1222 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped | |
1223 // during Suspend(). It won't be started again until after Resume() is | |
1224 // called. Use the pipeline time if there's no video. | |
1225 if (!data_source_ || !data_source_->IsStreaming()) { | |
1226 seek_time_ = hasVideo() ? compositor_->GetCurrentFrameTimestamp() | |
1227 : pipeline_.GetMediaTime(); | |
1228 } else { | |
1229 // Resume from zero if a resource does not support range requests; this | |
1230 // avoids a painful "read-the-whole-file" seek penalty. | |
1231 seek_time_ = base::TimeDelta(); | |
1232 } | |
1233 } | |
1234 | |
1235 if (chunk_demuxer_) | |
1236 chunk_demuxer_->StartWaitingForSeek(seek_time_); | |
1237 | |
1238 resuming_ = true; | |
1239 pipeline_.Resume(CreateRenderer(), seek_time_, | |
1240 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, | |
1241 time_changed)); | |
1242 } | |
1243 | |
1244 void WebMediaPlayerImpl::ScheduleRestart() { | 1067 void WebMediaPlayerImpl::ScheduleRestart() { |
1245 // If we're suspended but not resuming there is no need to restart because | 1068 if (!pipeline_controller_.IsSuspended()) { |
1246 // there is no renderer to kill. | |
1247 if (!suspended_ || resuming_) { | |
1248 pending_suspend_resume_cycle_ = true; | 1069 pending_suspend_resume_cycle_ = true; |
1249 ScheduleSuspend(); | 1070 pipeline_controller_.Suspend(); |
1250 } | 1071 } |
1251 } | 1072 } |
1252 | 1073 |
1253 #if defined(OS_ANDROID) // WMPI_CAST | 1074 #if defined(OS_ANDROID) // WMPI_CAST |
1254 | |
1255 bool WebMediaPlayerImpl::isRemote() const { | 1075 bool WebMediaPlayerImpl::isRemote() const { |
1256 return cast_impl_.isRemote(); | 1076 return cast_impl_.isRemote(); |
1257 } | 1077 } |
1258 | 1078 |
1259 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1079 void WebMediaPlayerImpl::SetMediaPlayerManager( |
1260 RendererMediaPlayerManagerInterface* media_player_manager) { | 1080 RendererMediaPlayerManagerInterface* media_player_manager) { |
1261 cast_impl_.SetMediaPlayerManager(media_player_manager); | 1081 cast_impl_.SetMediaPlayerManager(media_player_manager); |
1262 } | 1082 } |
1263 | 1083 |
1264 void WebMediaPlayerImpl::requestRemotePlayback() { | 1084 void WebMediaPlayerImpl::requestRemotePlayback() { |
1265 cast_impl_.requestRemotePlayback(); | 1085 cast_impl_.requestRemotePlayback(); |
1266 } | 1086 } |
1267 | 1087 |
1268 void WebMediaPlayerImpl::requestRemotePlaybackControl() { | 1088 void WebMediaPlayerImpl::requestRemotePlaybackControl() { |
1269 cast_impl_.requestRemotePlaybackControl(); | 1089 cast_impl_.requestRemotePlaybackControl(); |
1270 } | 1090 } |
1271 | 1091 |
1272 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1092 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
1273 DVLOG(1) << __FUNCTION__; | 1093 DVLOG(1) << __FUNCTION__; |
1274 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1094 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1275 | 1095 |
1276 ended_ = true; | 1096 ended_ = true; |
1277 client_->timeChanged(); | 1097 client_->timeChanged(); |
1278 } | 1098 } |
1279 | 1099 |
1280 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1100 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
1281 paused_time_ = base::TimeDelta::FromSecondsD(t); | 1101 DoSeek(base::TimeDelta::FromSecondsD(t), false); |
1282 pending_seek_ = true; | 1102 if (delegate_ && !delegate_->IsHidden()) |
1283 pending_seek_time_ = paused_time_; | 1103 pipeline_controller_.Resume(); |
1284 | 1104 |
1285 ScheduleResume(); | |
1286 | |
1287 if (paused_time_ == pipeline_.GetMediaDuration()) { | |
1288 ended_ = true; | |
1289 } | |
1290 // We already told the delegate we're paused when remoting started. | 1105 // We already told the delegate we're paused when remoting started. |
1291 client_->playbackStateChanged(); | 1106 client_->playbackStateChanged(); |
1292 client_->disconnectedFromRemoteDevice(); | 1107 client_->disconnectedFromRemoteDevice(); |
1293 } | 1108 } |
1294 | 1109 |
1295 void WebMediaPlayerImpl::SuspendForRemote() { | 1110 void WebMediaPlayerImpl::SuspendForRemote() { |
1296 if (suspended_ && !suspending_) { | 1111 if (!pipeline_controller_.IsSuspended()) { |
| 1112 pipeline_controller_.Suspend(); |
| 1113 } else { |
| 1114 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb| |
| 1115 // when already suspended, we wouldn't need this case. |
1297 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1116 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
1298 if (frame) { | 1117 if (frame) { |
1299 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1118 compositor_->PaintFrameUsingOldRenderingPath(frame); |
1300 } | 1119 } |
1301 } | 1120 } |
1302 ScheduleSuspend(); | |
1303 } | 1121 } |
1304 | 1122 |
1305 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1123 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
1306 if (!video_weblayer_) | 1124 if (!video_weblayer_) |
1307 return pipeline_metadata_.natural_size; | 1125 return pipeline_metadata_.natural_size; |
1308 | 1126 |
1309 return video_weblayer_->bounds(); | 1127 return video_weblayer_->bounds(); |
1310 } | 1128 } |
1311 | 1129 |
1312 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1130 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 chunk_demuxer_ = new ChunkDemuxer( | 1221 chunk_demuxer_ = new ChunkDemuxer( |
1404 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), | 1222 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), |
1405 encrypted_media_init_data_cb, media_log_, true); | 1223 encrypted_media_init_data_cb, media_log_, true); |
1406 demuxer_.reset(chunk_demuxer_); | 1224 demuxer_.reset(chunk_demuxer_); |
1407 } | 1225 } |
1408 | 1226 |
1409 // ... and we're ready to go! | 1227 // ... and we're ready to go! |
1410 seeking_ = true; | 1228 seeking_ = true; |
1411 | 1229 |
1412 // TODO(sandersd): On Android, defer Start() if the tab is not visible. | 1230 // TODO(sandersd): On Android, defer Start() if the tab is not visible. |
1413 pipeline_.Start( | 1231 bool is_streaming = (data_source_ && data_source_->IsStreaming()); |
1414 demuxer_.get(), CreateRenderer(), | 1232 pipeline_controller_.Start( |
| 1233 chunk_demuxer_, demuxer_.get(), is_streaming, |
1415 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), | 1234 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
1416 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), | |
1417 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false), | |
1418 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), | 1235 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), |
1419 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), | 1236 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), |
1420 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), | 1237 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), |
1421 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), | 1238 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), |
1422 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); | 1239 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); |
1423 } | 1240 } |
1424 | 1241 |
1425 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { | 1242 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
1426 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1243 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
1427 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1244 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1515 base::WaitableEvent event(false, false); | 1332 base::WaitableEvent event(false, false); |
1516 compositor_task_runner_->PostTask(FROM_HERE, | 1333 compositor_task_runner_->PostTask(FROM_HERE, |
1517 base::Bind(&GetCurrentFrameAndSignal, | 1334 base::Bind(&GetCurrentFrameAndSignal, |
1518 base::Unretained(compositor_), | 1335 base::Unretained(compositor_), |
1519 &video_frame, | 1336 &video_frame, |
1520 &event)); | 1337 &event)); |
1521 event.Wait(); | 1338 event.Wait(); |
1522 return video_frame; | 1339 return video_frame; |
1523 } | 1340 } |
1524 | 1341 |
1525 void WebMediaPlayerImpl::UpdatePausedTime() { | |
1526 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1527 | |
1528 // pause() may be called after playback has ended and the HTMLMediaElement | |
1529 // requires that currentTime() == duration() after ending. We want to ensure | |
1530 // |paused_time_| matches currentTime() in this case or a future seek() may | |
1531 // incorrectly discard what it thinks is a seek to the existing time. | |
1532 paused_time_ = | |
1533 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
1534 } | |
1535 | |
1536 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1342 void WebMediaPlayerImpl::NotifyPlaybackStarted() { |
1537 #if defined(OS_ANDROID) // WMPI_CAST | 1343 #if defined(OS_ANDROID) // WMPI_CAST |
1538 // We do not tell our delegates about remote playback, because that would | 1344 // We do not tell our delegates about remote playback, because that would |
1539 // keep the device awake, which is not what we want. | 1345 // keep the device awake, which is not what we want. |
1540 if (isRemote()) | 1346 if (isRemote()) |
1541 return; | 1347 return; |
1542 #endif | 1348 #endif |
1543 | 1349 |
1544 // Don't send delegate notifications when suspended; upon suspend we send | 1350 // NotifyPlaybackStarted() may be called by interactions while suspended, |
1545 // PlayerGone() to the delegate -- no more notifications should be sent until | 1351 // (play/pause in particular). Those actions won't have any effect until the |
1546 // after resume. | 1352 // pipeline is resumed. |
1547 if (suspended_) | 1353 // TODO(dalecurtis): Should these be dropped at the call sites instead? |
| 1354 // Alternatively, rename this method to include Maybe or Changed, and handle |
| 1355 // multiple calls safely. |
| 1356 if (pipeline_controller_.IsSuspended()) |
1548 return; | 1357 return; |
1549 | 1358 |
1550 if (delegate_) { | 1359 if (delegate_) { |
1551 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1360 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
1552 pipeline_.GetMediaDuration()); | 1361 pipeline_.GetMediaDuration()); |
1553 } | 1362 } |
1554 if (!memory_usage_reporting_timer_.IsRunning()) { | 1363 if (!memory_usage_reporting_timer_.IsRunning()) { |
1555 memory_usage_reporting_timer_.Start(FROM_HERE, | 1364 memory_usage_reporting_timer_.Start(FROM_HERE, |
1556 base::TimeDelta::FromSeconds(2), this, | 1365 base::TimeDelta::FromSeconds(2), this, |
1557 &WebMediaPlayerImpl::ReportMemoryUsage); | 1366 &WebMediaPlayerImpl::ReportMemoryUsage); |
1558 } | 1367 } |
1559 } | 1368 } |
1560 | 1369 |
1561 void WebMediaPlayerImpl::NotifyPlaybackPaused() { | 1370 void WebMediaPlayerImpl::NotifyPlaybackPaused() { |
1562 #if defined(OS_ANDROID) // WMPI_CAST | 1371 #if defined(OS_ANDROID) // WMPI_CAST |
1563 if (isRemote()) | 1372 if (isRemote()) |
1564 return; | 1373 return; |
1565 #endif | 1374 #endif |
1566 // Don't send delegate notifications when suspended; upon suspend we send | 1375 |
1567 // PlayerGone() to the delegate -- no more notifications should be sent until | 1376 // Same as above, NotifyPlaybackPaused() may be called by interactions while |
1568 // after resume. | 1377 // suspended, but those actions won't have any effect until the pipeline is |
1569 if (!suspended_ && delegate_) | 1378 // resumed. |
| 1379 if (pipeline_controller_.IsSuspended()) |
| 1380 return; |
| 1381 |
| 1382 if (delegate_) |
1570 delegate_->DidPause(delegate_id_, ended_); | 1383 delegate_->DidPause(delegate_id_, ended_); |
1571 memory_usage_reporting_timer_.Stop(); | 1384 memory_usage_reporting_timer_.Stop(); |
1572 ReportMemoryUsage(); | 1385 ReportMemoryUsage(); |
1573 } | 1386 } |
1574 | 1387 |
1575 void WebMediaPlayerImpl::ReportMemoryUsage() { | 1388 void WebMediaPlayerImpl::ReportMemoryUsage() { |
1576 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1389 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1577 | 1390 |
1578 // About base::Unretained() usage below: We destroy |demuxer_| on the main | 1391 // About base::Unretained() usage below: We destroy |demuxer_| on the main |
1579 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the | 1392 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the |
(...skipping 23 matching lines...) Expand all Loading... |
1603 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1416 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
1604 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1417 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
1605 << ", Demuxer: " << demuxer_memory_usage; | 1418 << ", Demuxer: " << demuxer_memory_usage; |
1606 | 1419 |
1607 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1420 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
1608 last_reported_memory_usage_ = current_memory_usage; | 1421 last_reported_memory_usage_ = current_memory_usage; |
1609 adjust_allocated_memory_cb_.Run(delta); | 1422 adjust_allocated_memory_cb_.Run(delta); |
1610 } | 1423 } |
1611 | 1424 |
1612 } // namespace media | 1425 } // namespace media |
OLD | NEW |