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