Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: media/blink/webmediaplayer_impl.cc

Issue 1830913005: Convert WMPI state management to level-triggered. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 const url::Origin& security_origin, 100 const url::Origin& security_origin,
101 const SwitchOutputDeviceCB& callback) { 101 const SwitchOutputDeviceCB& callback) {
102 if (sink->GetOutputDevice()) { 102 if (sink->GetOutputDevice()) {
103 sink->GetOutputDevice()->SwitchOutputDevice(device_id, security_origin, 103 sink->GetOutputDevice()->SwitchOutputDevice(device_id, security_origin,
104 callback); 104 callback);
105 } else { 105 } else {
106 callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); 106 callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
107 } 107 }
108 } 108 }
109 109
110 bool IsSuspendUponHiddenEnabled() { 110 bool IsBackgroundedSuspendEnabled() {
111 #if !defined(OS_ANDROID) 111 #if !defined(OS_ANDROID)
112 // Suspend/Resume is only enabled by default on Android. 112 // Suspend/Resume is only enabled by default on Android.
113 return base::CommandLine::ForCurrentProcess()->HasSwitch( 113 return base::CommandLine::ForCurrentProcess()->HasSwitch(
114 switches::kEnableMediaSuspend); 114 switches::kEnableMediaSuspend);
115 #else 115 #else
116 return !base::CommandLine::ForCurrentProcess()->HasSwitch( 116 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
117 switches::kDisableMediaSuspend); 117 switches::kDisableMediaSuspend);
118 #endif 118 #endif
119 } 119 }
120 120
121 bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
122 bool result = state == blink::WebMediaPlayer::NetworkStateFormatError ||
123 state == blink::WebMediaPlayer::NetworkStateNetworkError ||
124 state == blink::WebMediaPlayer::NetworkStateDecodeError;
125 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result);
126 return result;
127 }
128
121 } // namespace 129 } // namespace
122 130
123 class BufferedDataSourceHostImpl; 131 class BufferedDataSourceHostImpl;
124 132
125 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, 133 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified,
126 UrlData::CORS_UNSPECIFIED); 134 UrlData::CORS_UNSPECIFIED);
127 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); 135 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS);
128 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, 136 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials,
129 UrlData::CORS_USE_CREDENTIALS); 137 UrlData::CORS_USE_CREDENTIALS);
130 138
131 #define BIND_TO_RENDER_LOOP(function) \ 139 #define BIND_TO_RENDER_LOOP(function) \
132 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ 140 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
133 BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) 141 BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
134 142
135 #define BIND_TO_RENDER_LOOP1(function, arg1) \ 143 #define BIND_TO_RENDER_LOOP1(function, arg1) \
136 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ 144 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
137 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) 145 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
138 146
139 WebMediaPlayerImpl::WebMediaPlayerImpl( 147 WebMediaPlayerImpl::WebMediaPlayerImpl(
140 blink::WebLocalFrame* frame, 148 blink::WebLocalFrame* frame,
141 blink::WebMediaPlayerClient* client, 149 blink::WebMediaPlayerClient* client,
142 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, 150 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
143 base::WeakPtr<WebMediaPlayerDelegate> delegate, 151 base::WeakPtr<WebMediaPlayerDelegate> delegate,
144 scoped_ptr<RendererFactory> renderer_factory, 152 scoped_ptr<RendererFactory> renderer_factory,
145 linked_ptr<UrlIndex> url_index, 153 linked_ptr<UrlIndex> url_index,
146 const WebMediaPlayerParams& params) 154 const WebMediaPlayerParams& params)
147 : frame_(frame), 155 : frame_(frame),
156 delegate_state_(DelegateState::GONE),
157 is_idle_(false),
158 must_suspend_(false),
148 network_state_(WebMediaPlayer::NetworkStateEmpty), 159 network_state_(WebMediaPlayer::NetworkStateEmpty),
149 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), 160 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
161 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
150 preload_(BufferedDataSource::AUTO), 162 preload_(BufferedDataSource::AUTO),
151 buffering_strategy_( 163 buffering_strategy_(
152 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), 164 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL),
153 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), 165 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
154 media_task_runner_(params.media_task_runner()), 166 media_task_runner_(params.media_task_runner()),
155 worker_task_runner_(params.worker_task_runner()), 167 worker_task_runner_(params.worker_task_runner()),
156 media_log_(params.media_log()), 168 media_log_(params.media_log()),
157 pipeline_(media_task_runner_, media_log_.get()), 169 pipeline_(media_task_runner_, media_log_.get()),
158 pipeline_controller_( 170 pipeline_controller_(
159 &pipeline_, 171 &pipeline_,
160 base::Bind(&WebMediaPlayerImpl::CreateRenderer, 172 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
161 base::Unretained(this)), 173 base::Unretained(this)),
162 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), 174 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
163 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), 175 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
164 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
165 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), 176 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())),
166 load_type_(LoadTypeURL), 177 load_type_(LoadTypeURL),
167 opaque_(false), 178 opaque_(false),
168 playback_rate_(0.0), 179 playback_rate_(0.0),
169 paused_(true), 180 paused_(true),
170 seeking_(false), 181 seeking_(false),
171 pending_suspend_resume_cycle_(false), 182 pending_suspend_resume_cycle_(false),
172 ended_(false), 183 ended_(false),
173 should_notify_time_changed_(false), 184 should_notify_time_changed_(false),
174 fullscreen_(false), 185 fullscreen_(false),
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 DVLOG(1) << __FUNCTION__; 357 DVLOG(1) << __FUNCTION__;
347 DCHECK(main_task_runner_->BelongsToCurrentThread()); 358 DCHECK(main_task_runner_->BelongsToCurrentThread());
348 359
349 #if defined(OS_ANDROID) // WMPI_CAST 360 #if defined(OS_ANDROID) // WMPI_CAST
350 if (isRemote()) { 361 if (isRemote()) {
351 cast_impl_.play(); 362 cast_impl_.play();
352 return; 363 return;
353 } 364 }
354 #endif 365 #endif
355 366
356 const bool was_paused = paused_;
357 paused_ = false; 367 paused_ = false;
368 is_idle_ = false;
358 pipeline_.SetPlaybackRate(playback_rate_); 369 pipeline_.SetPlaybackRate(playback_rate_);
359 370
360 if (data_source_) 371 if (data_source_)
361 data_source_->MediaIsPlaying(); 372 data_source_->MediaIsPlaying();
362 373
363 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); 374 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
364 375 UpdatePlayState();
365 if (playback_rate_ > 0 && was_paused) {
366 NotifyPlaybackStarted();
367
368 // Resume the player if allowed. We always call Resume() in case there is a
369 // pending suspend that should be aborted. If the pipeline is not suspended,
370 // Resume() will have no effect.
371 if (IsAutomaticResumeAllowed())
372 pipeline_controller_.Resume();
373 }
374 } 376 }
375 377
376 void WebMediaPlayerImpl::pause() { 378 void WebMediaPlayerImpl::pause() {
377 DVLOG(1) << __FUNCTION__; 379 DVLOG(1) << __FUNCTION__;
378 DCHECK(main_task_runner_->BelongsToCurrentThread()); 380 DCHECK(main_task_runner_->BelongsToCurrentThread());
379 381
380 const bool was_already_paused = paused_ || playback_rate_ == 0; 382 // We update the paused state even when casting, since we expect pause() to be
383 // called when casting begins, and when we exit casting we should end up in a
384 // paused state.
381 paused_ = true; 385 paused_ = true;
382 386
383 #if defined(OS_ANDROID) // WMPI_CAST 387 #if defined(OS_ANDROID) // WMPI_CAST
384 if (isRemote()) { 388 if (isRemote()) {
385 cast_impl_.pause(); 389 cast_impl_.pause();
386 return; 390 return;
387 } 391 }
388 #endif 392 #endif
389 393
390 pipeline_.SetPlaybackRate(0.0); 394 pipeline_.SetPlaybackRate(0.0);
391 395
392 // pause() may be called after playback has ended and the HTMLMediaElement 396 // pause() may be called after playback has ended and the HTMLMediaElement
393 // requires that currentTime() == duration() after ending. We want to ensure 397 // requires that currentTime() == duration() after ending. We want to ensure
394 // |paused_time_| matches currentTime() in this case or a future seek() may 398 // |paused_time_| matches currentTime() in this case or a future seek() may
395 // incorrectly discard what it thinks is a seek to the existing time. 399 // incorrectly discard what it thinks is a seek to the existing time.
396 paused_time_ = 400 paused_time_ =
397 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); 401 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
398 402
399 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); 403 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
400 404 UpdatePlayState();
401 if (!was_already_paused)
402 NotifyPlaybackPaused();
403 } 405 }
404 406
405 bool WebMediaPlayerImpl::supportsSave() const { 407 bool WebMediaPlayerImpl::supportsSave() const {
406 DCHECK(main_task_runner_->BelongsToCurrentThread()); 408 DCHECK(main_task_runner_->BelongsToCurrentThread());
407 return supports_save_; 409 return supports_save_;
408 } 410 }
409 411
410 void WebMediaPlayerImpl::seek(double seconds) { 412 void WebMediaPlayerImpl::seek(double seconds) {
411 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; 413 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)";
412 DCHECK(main_task_runner_->BelongsToCurrentThread()); 414 DCHECK(main_task_runner_->BelongsToCurrentThread());
413 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); 415 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
414 } 416 }
415 417
416 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { 418 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
417 DCHECK(main_task_runner_->BelongsToCurrentThread()); 419 DCHECK(main_task_runner_->BelongsToCurrentThread());
418 420
419 ended_ = false;
420
421 #if defined(OS_ANDROID) // WMPI_CAST 421 #if defined(OS_ANDROID) // WMPI_CAST
422 if (isRemote()) { 422 if (isRemote()) {
423 cast_impl_.seek(time); 423 cast_impl_.seek(time);
424 return; 424 return;
425 } 425 }
426 #endif 426 #endif
427 427
428 ReadyState old_state = ready_state_; 428 ReadyState old_state = ready_state_;
429 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) 429 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
430 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); 430 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
(...skipping 13 matching lines...) Expand all
444 // ready state change to eventually happen. 444 // ready state change to eventually happen.
445 if (old_state == ReadyStateHaveEnoughData) { 445 if (old_state == ReadyStateHaveEnoughData) {
446 main_task_runner_->PostTask( 446 main_task_runner_->PostTask(
447 FROM_HERE, 447 FROM_HERE,
448 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, 448 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged,
449 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); 449 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
450 } 450 }
451 return; 451 return;
452 } 452 }
453 453
454 // TODO(sandersd): Ideally we would not clear the idle state if
455 // |pipeline_controller_| can elide the seek.
456 is_idle_ = false;
457 ended_ = false;
458
454 seeking_ = true; 459 seeking_ = true;
455 seek_time_ = time; 460 seek_time_ = time;
456 if (paused_) 461 if (paused_)
457 paused_time_ = time; 462 paused_time_ = time;
458 pipeline_controller_.Seek(time, time_updated); 463 pipeline_controller_.Seek(time, time_updated);
459 464
460 // Resume the pipeline if allowed so that the correct frame is displayed. We 465 // This needs to be called after Seek() so that if a resume is triggered, it
461 // always call Resume() in case there is a pending suspend that should be 466 // is to the correct time.
462 // aborted. If the pipeline is not suspended, Resume() will have no effect. 467 UpdatePlayState();
463 if (IsAutomaticResumeAllowed())
464 pipeline_controller_.Resume();
465 } 468 }
466 469
467 void WebMediaPlayerImpl::setRate(double rate) { 470 void WebMediaPlayerImpl::setRate(double rate) {
468 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; 471 DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
469 DCHECK(main_task_runner_->BelongsToCurrentThread()); 472 DCHECK(main_task_runner_->BelongsToCurrentThread());
470 473
471 // TODO(kylep): Remove when support for negatives is added. Also, modify the 474 // TODO(kylep): Remove when support for negatives is added. Also, modify the
472 // following checks so rewind uses reasonable values also. 475 // following checks so rewind uses reasonable values also.
473 if (rate < 0.0) 476 if (rate < 0.0)
474 return; 477 return;
475 478
476 // Limit rates to reasonable values by clamping. 479 // Limit rates to reasonable values by clamping.
477 if (rate != 0.0) { 480 if (rate != 0.0) {
478 if (rate < kMinRate) 481 if (rate < kMinRate)
479 rate = kMinRate; 482 rate = kMinRate;
480 else if (rate > kMaxRate) 483 else if (rate > kMaxRate)
481 rate = kMaxRate; 484 rate = kMaxRate;
482 if (playback_rate_ == 0 && !paused_)
483 NotifyPlaybackStarted();
484 } else if (playback_rate_ != 0 && !paused_) {
485 NotifyPlaybackPaused();
486 } 485 }
487 486
488 playback_rate_ = rate; 487 playback_rate_ = rate;
489 if (!paused_) { 488 if (!paused_) {
490 pipeline_.SetPlaybackRate(rate); 489 pipeline_.SetPlaybackRate(rate);
491 if (data_source_) 490 if (data_source_)
492 data_source_->MediaPlaybackRateChanged(rate); 491 data_source_->MediaPlaybackRateChanged(rate);
493 } 492 }
494 } 493 }
495 494
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 return blink::WebSize(pipeline_metadata_.natural_size); 572 return blink::WebSize(pipeline_metadata_.natural_size);
574 } 573 }
575 574
576 bool WebMediaPlayerImpl::paused() const { 575 bool WebMediaPlayerImpl::paused() const {
577 DCHECK(main_task_runner_->BelongsToCurrentThread()); 576 DCHECK(main_task_runner_->BelongsToCurrentThread());
578 577
579 #if defined(OS_ANDROID) // WMPI_CAST 578 #if defined(OS_ANDROID) // WMPI_CAST
580 if (isRemote()) 579 if (isRemote())
581 return cast_impl_.paused(); 580 return cast_impl_.paused();
582 #endif 581 #endif
582
583 return pipeline_.GetPlaybackRate() == 0.0f; 583 return pipeline_.GetPlaybackRate() == 0.0f;
584 } 584 }
585 585
586 bool WebMediaPlayerImpl::seeking() const { 586 bool WebMediaPlayerImpl::seeking() const {
587 DCHECK(main_task_runner_->BelongsToCurrentThread()); 587 DCHECK(main_task_runner_->BelongsToCurrentThread());
588 588
589 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) 589 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
590 return false; 590 return false;
591 591
592 return seeking_; 592 return seeking_;
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 paused_time_ = pipeline_.GetMediaTime(); 901 paused_time_ = pipeline_.GetMediaTime();
902 #endif 902 #endif
903 } 903 }
904 if (time_updated) 904 if (time_updated)
905 should_notify_time_changed_ = true; 905 should_notify_time_changed_ = true;
906 } 906 }
907 907
908 void WebMediaPlayerImpl::OnPipelineSuspended() { 908 void WebMediaPlayerImpl::OnPipelineSuspended() {
909 #if defined(OS_ANDROID) 909 #if defined(OS_ANDROID)
910 if (isRemote()) { 910 if (isRemote()) {
911 if (delegate_)
912 delegate_->PlayerGone(delegate_id_);
913 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); 911 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
914 if (frame) { 912 if (frame)
915 compositor_->PaintFrameUsingOldRenderingPath(frame); 913 compositor_->PaintFrameUsingOldRenderingPath(frame);
916 }
917 } 914 }
918 #endif 915 #endif
919 916
920 memory_usage_reporting_timer_.Stop();
921 ReportMemoryUsage();
922
923 // If we're not in an aggressive buffering state, tell the data source we have 917 // If we're not in an aggressive buffering state, tell the data source we have
924 // enough data so that it may release the connection. 918 // enough data so that it may release the connection.
925 if (buffering_strategy_ != 919 if (buffering_strategy_ !=
926 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { 920 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
927 if (data_source_) 921 if (data_source_)
928 data_source_->OnBufferingHaveEnough(true); 922 data_source_->OnBufferingHaveEnough(true);
929 } 923 }
930 924
925 ReportMemoryUsage();
926
931 if (pending_suspend_resume_cycle_) { 927 if (pending_suspend_resume_cycle_) {
932 pending_suspend_resume_cycle_ = false; 928 pending_suspend_resume_cycle_ = false;
933 pipeline_controller_.Resume(); 929 UpdatePlayState();
934 return;
935 } 930 }
936 } 931 }
937 932
938 void WebMediaPlayerImpl::OnPipelineResumed() {
939 if (playback_rate_ > 0 && !paused_) {
940 NotifyPlaybackStarted();
941 } else if (!playback_rate_ || paused_ || ended_) {
942 // Resend our paused notification so the pipeline is considered for idle
943 // resource reclamation; duplicate pause notifications are ignored.
944 NotifyPlaybackPaused();
945 }
946 }
947
948 void WebMediaPlayerImpl::OnPipelineEnded() { 933 void WebMediaPlayerImpl::OnPipelineEnded() {
949 DVLOG(1) << __FUNCTION__; 934 DVLOG(1) << __FUNCTION__;
950 DCHECK(main_task_runner_->BelongsToCurrentThread()); 935 DCHECK(main_task_runner_->BelongsToCurrentThread());
951 936
952 // Ignore state changes until we've completed all outstanding operations. 937 // Ignore state changes until we've completed all outstanding operations.
953 if (!pipeline_controller_.IsStable()) 938 if (!pipeline_controller_.IsStable())
954 return; 939 return;
955 940
956 ended_ = true; 941 ended_ = true;
957 client_->timeChanged(); 942 client_->timeChanged();
943
944 // We don't actually want this to run until |client_| calls seek() or pause(),
945 // but that should have already happened in timeChanged() and so this is
946 // expected to be a no-op.
947 UpdatePlayState();
958 } 948 }
959 949
960 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { 950 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
961 DVLOG(1) << __FUNCTION__; 951 DVLOG(1) << __FUNCTION__;
962 DCHECK(main_task_runner_->BelongsToCurrentThread()); 952 DCHECK(main_task_runner_->BelongsToCurrentThread());
963 DCHECK_NE(error, PIPELINE_OK); 953 DCHECK_NE(error, PIPELINE_OK);
964 954
965 if (suppress_destruction_errors_) 955 if (suppress_destruction_errors_)
966 return; 956 return;
967 957
968 // Release the delegate for player errors; this drops the media session and
969 // avoids idle suspension from ticking.
970 if (delegate_)
971 delegate_->PlayerGone(delegate_id_);
972
973 #if defined(OS_ANDROID) 958 #if defined(OS_ANDROID)
974 // For 10% of pipeline decode failures log the playback URL. The URL is set 959 // For 10% of pipeline decode failures log the playback URL. The URL is set
975 // as the crash-key 'subresource_url' during DoLoad(). 960 // as the crash-key 'subresource_url' during DoLoad().
976 // 961 //
977 // TODO(dalecurtis): This is temporary to track down higher than average 962 // TODO(dalecurtis): This is temporary to track down higher than average
978 // decode failure rates for video-only content. See http://crbug.com/595076. 963 // decode failure rates for video-only content. See http://crbug.com/595076.
979 if (base::RandDouble() <= 0.1 && error == PIPELINE_ERROR_DECODE) 964 if (base::RandDouble() <= 0.1 && error == PIPELINE_ERROR_DECODE)
980 base::debug::DumpWithoutCrashing(); 965 base::debug::DumpWithoutCrashing();
981 #endif 966 #endif
982 967
983 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); 968 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error));
984 969
985 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) { 970 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
986 // Any error that occurs before reaching ReadyStateHaveMetadata should 971 // Any error that occurs before reaching ReadyStateHaveMetadata should
987 // be considered a format error. 972 // be considered a format error.
988 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); 973 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
989 return; 974 } else {
975 SetNetworkState(PipelineErrorToNetworkState(error));
990 } 976 }
991 977
992 SetNetworkState(PipelineErrorToNetworkState(error)); 978 UpdatePlayState();
993 } 979 }
994 980
995 void WebMediaPlayerImpl::OnPipelineMetadata( 981 void WebMediaPlayerImpl::OnPipelineMetadata(
996 PipelineMetadata metadata) { 982 PipelineMetadata metadata) {
997 DVLOG(1) << __FUNCTION__; 983 DVLOG(1) << __FUNCTION__;
998 984
999 pipeline_metadata_ = metadata; 985 pipeline_metadata_ = metadata;
1000 986
1001 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation, 987 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
1002 VIDEO_ROTATION_MAX + 1); 988 VIDEO_ROTATION_MAX + 1);
1003 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); 989 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
1004 990
1005 if (hasVideo()) { 991 if (hasVideo()) {
1006 DCHECK(!video_weblayer_); 992 DCHECK(!video_weblayer_);
1007 scoped_refptr<cc::VideoLayer> layer = 993 scoped_refptr<cc::VideoLayer> layer =
1008 cc::VideoLayer::Create(compositor_, pipeline_metadata_.video_rotation); 994 cc::VideoLayer::Create(compositor_, pipeline_metadata_.video_rotation);
1009 995
1010 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 || 996 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
1011 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) { 997 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
1012 gfx::Size size = pipeline_metadata_.natural_size; 998 gfx::Size size = pipeline_metadata_.natural_size;
1013 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width()); 999 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
1014 } 1000 }
1015 1001
1016 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer)); 1002 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer));
1017 video_weblayer_->layer()->SetContentsOpaque(opaque_); 1003 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1018 video_weblayer_->SetContentsOpaqueIsFixed(true); 1004 video_weblayer_->SetContentsOpaqueIsFixed(true);
1019 client_->setWebLayer(video_weblayer_.get()); 1005 client_->setWebLayer(video_weblayer_.get());
1020 } 1006 }
1021 1007
1022 // Tell the delegate we can now be safely suspended due to inactivity if a 1008 UpdatePlayState();
1023 // subsequent play event does not occur.
1024 if (paused_)
1025 NotifyPlaybackPaused();
1026
1027 // If the frame is hidden, it may be time to suspend playback.
1028 if (delegate_ && delegate_->IsHidden())
1029 OnHidden();
1030 } 1009 }
1031 1010
1032 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( 1011 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged(
1033 BufferingState buffering_state) { 1012 BufferingState buffering_state) {
1034 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; 1013 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")";
1035 1014
1036 // Ignore buffering state changes until we've completed all outstanding 1015 // Ignore buffering state changes until we've completed all outstanding
1037 // operations. 1016 // operations.
1038 if (!pipeline_controller_.IsStable()) 1017 if (!pipeline_controller_.IsStable())
1039 return; 1018 return;
1040 1019
1041 // TODO(scherkus): Handle other buffering states when Pipeline starts using 1020 // TODO(scherkus): Handle other buffering states when Pipeline starts using
1042 // them and translate them ready state changes http://crbug.com/144683 1021 // them and translate them ready state changes http://crbug.com/144683
1043 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); 1022 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH);
1044 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); 1023 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
1045 1024
1046 // Let the DataSource know we have enough data. It may use this information to 1025 // Let the DataSource know we have enough data. It may use this information to
1047 // release unused network connections. 1026 // release unused network connections.
1048 if (data_source_) 1027 if (data_source_)
1049 data_source_->OnBufferingHaveEnough(false); 1028 data_source_->OnBufferingHaveEnough(false);
1050 1029
1051 // Blink expects a timeChanged() in response to a seek(). 1030 // Blink expects a timeChanged() in response to a seek().
1052 if (should_notify_time_changed_) 1031 if (should_notify_time_changed_)
1053 client_->timeChanged(); 1032 client_->timeChanged();
1054 1033
1055 // Once we have enough, start reporting the total memory usage. We'll also 1034 // Once we have enough, start reporting the total memory usage. We'll also
1056 // report once playback starts. 1035 // report once playback starts.
1057 ReportMemoryUsage(); 1036 ReportMemoryUsage();
1037
1038 UpdatePlayState();
1058 } 1039 }
1059 1040
1060 void WebMediaPlayerImpl::OnDemuxerOpened() { 1041 void WebMediaPlayerImpl::OnDemuxerOpened() {
1061 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1042 DCHECK(main_task_runner_->BelongsToCurrentThread());
1062 client_->mediaSourceOpened( 1043 client_->mediaSourceOpened(
1063 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); 1044 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
1064 } 1045 }
1065 1046
1066 void WebMediaPlayerImpl::OnAddTextTrack( 1047 void WebMediaPlayerImpl::OnAddTextTrack(
1067 const TextTrackConfig& config, 1048 const TextTrackConfig& config,
(...skipping 13 matching lines...) Expand all
1081 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id)); 1062 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
1082 1063
1083 scoped_ptr<TextTrack> text_track(new TextTrackImpl( 1064 scoped_ptr<TextTrack> text_track(new TextTrackImpl(
1084 main_task_runner_, client_, std::move(web_inband_text_track))); 1065 main_task_runner_, client_, std::move(web_inband_text_track)));
1085 1066
1086 done_cb.Run(std::move(text_track)); 1067 done_cb.Run(std::move(text_track));
1087 } 1068 }
1088 1069
1089 void WebMediaPlayerImpl::OnHidden() { 1070 void WebMediaPlayerImpl::OnHidden() {
1090 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1071 DCHECK(main_task_runner_->BelongsToCurrentThread());
1091 if (!IsSuspendUponHiddenEnabled()) 1072 UpdatePlayState();
1092 return;
1093
1094 #if defined(OS_ANDROID) // WMPI_CAST
1095 // If we're remote, the pipeline should already be suspended.
1096 if (isRemote())
1097 return;
1098 #endif
1099
1100 // Don't suspend before metadata is available, as we don't know if there is a
1101 // video track yet.
1102 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
1103 return;
1104
1105 // Don't suspend players which only have audio and have not completed
1106 // playback. The user can still control these players via the MediaSession UI.
1107 // If the player has never started playback, OnSuspendRequested() will handle
1108 // release of any idle resources.
1109 if (!hasVideo() && !paused_ && !ended_)
1110 return;
1111
1112 // Always reset the buffering strategy to normal when suspending for hidden to
1113 // prevent an idle network connection from lingering.
1114 setBufferingStrategy(WebMediaPlayer::BufferingStrategy::Normal);
1115 pipeline_controller_.Suspend();
1116 // If we're in the middle of a suspend/resume cycle we no longer want to
1117 // resume when the suspend completes.
1118 pending_suspend_resume_cycle_ = false;
1119 if (delegate_)
1120 delegate_->PlayerGone(delegate_id_);
1121 } 1073 }
1122 1074
1123 void WebMediaPlayerImpl::OnShown() { 1075 void WebMediaPlayerImpl::OnShown() {
1124 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1076 DCHECK(main_task_runner_->BelongsToCurrentThread());
1125 if (!IsSuspendUponHiddenEnabled()) 1077 must_suspend_ = false;
1126 return; 1078 UpdatePlayState();
1127
1128 #if defined(OS_ANDROID) // WMPI_CAST
1129 // If we're remote, the pipeline should stay suspended.
1130 if (isRemote())
1131 return;
1132 #endif
1133
1134 // If we do not yet have metadata, the only way we could have been suspended
1135 // is by a OnSuspendRequested() with |must_suspend| set. In that case we need
1136 // to resume, otherwise playback will be broken.
1137 //
1138 // Otherwise, resume if we should be playing.
1139 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata ||
1140 (!ended_ && !paused_)) {
1141 pipeline_controller_.Resume();
1142 }
1143 } 1079 }
1144 1080
1145 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { 1081 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
1146 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1082 DCHECK(main_task_runner_->BelongsToCurrentThread());
1147 1083
1148 #if defined(OS_ANDROID) // WMPI_CAST
1149 // If we're remote, the pipeline should already be suspended.
1150 if (isRemote())
1151 return;
1152 #endif
1153
1154 #if defined(OS_MACOSX) 1084 #if defined(OS_MACOSX)
1155 // TODO(sandersd): Idle suspend is disabled on OSX since hardware decoded 1085 // TODO(sandersd): Idle suspend is disabled on OSX since hardware decoded
1156 // frames are owned by the video decoder in the GPU process. A mechanism for 1086 // frames are owned by the video decoder in the GPU process. A mechanism for
1157 // detaching ownership from the decoder is needed. http://crbug.com/595716. 1087 // detaching ownership from the decoder is needed. http://crbug.com/595716.
1158 return; 1088 return;
1159 #else 1089 #endif
1160 // Suspend should never be requested unless required or we're already in an
1161 // idle state (paused or ended).
1162 DCHECK(must_suspend || paused_ || ended_);
1163 1090
1164 // Always suspend, but only notify the delegate if we must; this allows any 1091 if (must_suspend) {
1165 // exposed UI for player controls to continue to function even though the 1092 must_suspend_ = true;
1166 // player has now been suspended. 1093 } else {
1167 pipeline_controller_.Suspend(); 1094 is_idle_ = true;
1168 if (must_suspend && delegate_) 1095 }
1169 delegate_->PlayerGone(delegate_id_); 1096
1170 #endif 1097 UpdatePlayState();
1171 } 1098 }
1172 1099
1173 void WebMediaPlayerImpl::OnPlay() { 1100 void WebMediaPlayerImpl::OnPlay() {
1174 play(); 1101 play();
1175 client_->playbackStateChanged(); 1102 client_->playbackStateChanged();
1176 } 1103 }
1177 1104
1178 void WebMediaPlayerImpl::OnPause() { 1105 void WebMediaPlayerImpl::OnPause() {
1179 pause(); 1106 pause();
1180 client_->playbackStateChanged(); 1107 client_->playbackStateChanged();
1181 } 1108 }
1182 1109
1183 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { 1110 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1184 volume_multiplier_ = multiplier; 1111 volume_multiplier_ = multiplier;
1185 setVolume(volume_); 1112 setVolume(volume_);
1186 } 1113 }
1187 1114
1188 void WebMediaPlayerImpl::ScheduleRestart() { 1115 void WebMediaPlayerImpl::ScheduleRestart() {
1189 if (!pipeline_controller_.IsSuspended()) { 1116 // TODO(watk): All restart logic should be moved into PipelineController.
1117 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
1190 pending_suspend_resume_cycle_ = true; 1118 pending_suspend_resume_cycle_ = true;
1191 pipeline_controller_.Suspend(); 1119 UpdatePlayState();
1192 } 1120 }
1193 } 1121 }
1194 1122
1195 #if defined(OS_ANDROID) // WMPI_CAST 1123 #if defined(OS_ANDROID) // WMPI_CAST
1196 bool WebMediaPlayerImpl::isRemote() const { 1124 bool WebMediaPlayerImpl::isRemote() const {
1197 return cast_impl_.isRemote(); 1125 return cast_impl_.isRemote();
1198 } 1126 }
1199 1127
1200 void WebMediaPlayerImpl::SetMediaPlayerManager( 1128 void WebMediaPlayerImpl::SetMediaPlayerManager(
1201 RendererMediaPlayerManagerInterface* media_player_manager) { 1129 RendererMediaPlayerManagerInterface* media_player_manager) {
(...skipping 11 matching lines...) Expand all
1213 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { 1141 void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
1214 DVLOG(1) << __FUNCTION__; 1142 DVLOG(1) << __FUNCTION__;
1215 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1143 DCHECK(main_task_runner_->BelongsToCurrentThread());
1216 1144
1217 ended_ = true; 1145 ended_ = true;
1218 client_->timeChanged(); 1146 client_->timeChanged();
1219 } 1147 }
1220 1148
1221 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { 1149 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
1222 DoSeek(base::TimeDelta::FromSecondsD(t), false); 1150 DoSeek(base::TimeDelta::FromSecondsD(t), false);
1223 if (delegate_ && !delegate_->IsHidden())
1224 pipeline_controller_.Resume();
1225 1151
1226 // We already told the delegate we're paused when remoting started. 1152 // We already told the delegate we're paused when remoting started.
1227 client_->playbackStateChanged(); 1153 client_->playbackStateChanged();
1228 client_->disconnectedFromRemoteDevice(); 1154 client_->disconnectedFromRemoteDevice();
1155
1156 UpdatePlayState();
1229 } 1157 }
1230 1158
1231 void WebMediaPlayerImpl::SuspendForRemote() { 1159 void WebMediaPlayerImpl::SuspendForRemote() {
1232 if (!pipeline_controller_.IsSuspended()) { 1160 if (pipeline_controller_.IsPipelineSuspended()) {
1233 pipeline_controller_.Suspend();
1234 } else {
1235 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb|
1236 // when already suspended, we wouldn't need this case.
1237 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); 1161 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
1238 if (frame) { 1162 if (frame)
1239 compositor_->PaintFrameUsingOldRenderingPath(frame); 1163 compositor_->PaintFrameUsingOldRenderingPath(frame);
1240 }
1241 } 1164 }
1165
1166 UpdatePlayState();
1242 } 1167 }
1243 1168
1244 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { 1169 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1245 if (!video_weblayer_) 1170 if (!video_weblayer_)
1246 return pipeline_metadata_.natural_size; 1171 return pipeline_metadata_.natural_size;
1247 1172
1248 return video_weblayer_->bounds(); 1173 return video_weblayer_->bounds();
1249 } 1174 }
1250 1175
1251 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { 1176 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1252 cast_impl_.SetDeviceScaleFactor(scale_factor); 1177 cast_impl_.SetDeviceScaleFactor(scale_factor);
1253 } 1178 }
1254 #endif // defined(OS_ANDROID) // WMPI_CAST 1179 #endif // defined(OS_ANDROID) // WMPI_CAST
1255 1180
1256 void WebMediaPlayerImpl::DataSourceInitialized(bool success) { 1181 void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
1257 DVLOG(1) << __FUNCTION__; 1182 DVLOG(1) << __FUNCTION__;
1258 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1183 DCHECK(main_task_runner_->BelongsToCurrentThread());
1259 1184
1260 if (!success) { 1185 if (!success) {
1261 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); 1186 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
1187
1188 // Not really necessary, since the pipeline was never started, but it at
1189 // least this makes sure that the error handling code is in sync.
1190 UpdatePlayState();
1191
1262 return; 1192 return;
1263 } 1193 }
1264 1194
1265 StartPipeline(); 1195 StartPipeline();
1266 } 1196 }
1267 1197
1268 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) { 1198 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
1269 DVLOG(1) << __FUNCTION__; 1199 DVLOG(1) << __FUNCTION__;
1270 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading) 1200 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1271 SetNetworkState(WebMediaPlayer::NetworkStateIdle); 1201 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1379 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) { 1309 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
1380 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; 1310 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
1381 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1311 DCHECK(main_task_runner_->BelongsToCurrentThread());
1382 1312
1383 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ && 1313 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1384 data_source_->assume_fully_buffered() && 1314 data_source_->assume_fully_buffered() &&
1385 network_state_ == WebMediaPlayer::NetworkStateLoading) 1315 network_state_ == WebMediaPlayer::NetworkStateLoading)
1386 SetNetworkState(WebMediaPlayer::NetworkStateLoaded); 1316 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1387 1317
1388 ready_state_ = state; 1318 ready_state_ = state;
1319 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1320
1389 // Always notify to ensure client has the latest value. 1321 // Always notify to ensure client has the latest value.
1390 client_->readyStateChanged(); 1322 client_->readyStateChanged();
1391 } 1323 }
1392 1324
1393 blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() { 1325 blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
1394 return audio_source_provider_.get(); 1326 return audio_source_provider_.get();
1395 } 1327 }
1396 1328
1397 double WebMediaPlayerImpl::GetPipelineDuration() const { 1329 double WebMediaPlayerImpl::GetPipelineDuration() const {
1398 base::TimeDelta duration = pipeline_.GetMediaDuration(); 1330 base::TimeDelta duration = pipeline_.GetMediaDuration();
1399 1331
1400 // Return positive infinity if the resource is unbounded. 1332 // Return positive infinity if the resource is unbounded.
1401 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom- media-duration 1333 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom- media-duration
1402 if (duration == kInfiniteDuration()) 1334 if (duration == kInfiniteDuration())
1403 return std::numeric_limits<double>::infinity(); 1335 return std::numeric_limits<double>::infinity();
1404 1336
1405 return duration.InSecondsF(); 1337 return duration.InSecondsF();
1406 } 1338 }
1407 1339
1408 void WebMediaPlayerImpl::OnDurationChanged() { 1340 void WebMediaPlayerImpl::OnDurationChanged() {
1341 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1342 // especially if it changed from <5s to >5s.
1409 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) 1343 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1410 return; 1344 return;
1411 1345
1412 client_->durationChanged(); 1346 client_->durationChanged();
1413 } 1347 }
1414 1348
1415 void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) { 1349 void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) {
1416 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1350 DCHECK(main_task_runner_->BelongsToCurrentThread());
1417 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); 1351 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1418 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged"); 1352 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1461 base::WaitableEvent event(false, false); 1395 base::WaitableEvent event(false, false);
1462 compositor_task_runner_->PostTask(FROM_HERE, 1396 compositor_task_runner_->PostTask(FROM_HERE,
1463 base::Bind(&GetCurrentFrameAndSignal, 1397 base::Bind(&GetCurrentFrameAndSignal,
1464 base::Unretained(compositor_), 1398 base::Unretained(compositor_),
1465 &video_frame, 1399 &video_frame,
1466 &event)); 1400 &event));
1467 event.Wait(); 1401 event.Wait();
1468 return video_frame; 1402 return video_frame;
1469 } 1403 }
1470 1404
1471 void WebMediaPlayerImpl::NotifyPlaybackStarted() { 1405 void WebMediaPlayerImpl::UpdatePlayState() {
1472 #if defined(OS_ANDROID) // WMPI_CAST 1406 #if defined(OS_ANDROID) // WMPI_CAST
1473 // We do not tell our delegates about remote playback, because that would 1407 bool is_remote = isRemote();
1474 // keep the device awake, which is not what we want. 1408 #else
1475 if (isRemote()) 1409 bool is_remote = false;
1476 return;
1477 #endif 1410 #endif
1411 bool is_backgrounded =
1412 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden();
1413 PlayState state =
1414 UpdatePlayState_ComputePlayState(is_remote, is_backgrounded);
1415 SetDelegateState(state.delegate_state);
1416 SetMemoryReportingState(state.is_memory_reporting_enabled);
1417 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1418 }
1478 1419
1479 // NotifyPlaybackStarted() may be called by interactions while suspended, 1420 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
1480 // (play/pause in particular). Those actions won't have any effect until the 1421 if (!delegate_ || delegate_state_ == new_state)
1481 // pipeline is resumed.
1482 // TODO(dalecurtis): Should these be dropped at the call sites instead?
1483 // Alternatively, rename this method to include Maybe or Changed, and handle
1484 // multiple calls safely.
1485 if (pipeline_controller_.IsSuspended())
1486 return; 1422 return;
1487 1423
1488 if (delegate_) { 1424 delegate_state_ = new_state;
1489 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, 1425
1490 pipeline_.GetMediaDuration()); 1426 switch (delegate_state_) {
1427 case DelegateState::GONE:
1428 delegate_->PlayerGone(delegate_id_);
1429 break;
1430 case DelegateState::PLAYING:
1431 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false,
1432 pipeline_.GetMediaDuration());
1433 break;
1434 case DelegateState::PAUSED:
1435 delegate_->DidPause(delegate_id_, false);
1436 break;
1437 case DelegateState::ENDED:
1438 delegate_->DidPause(delegate_id_, true);
1439 break;
1491 } 1440 }
1492 if (!memory_usage_reporting_timer_.IsRunning()) { 1441 }
1442
1443 void WebMediaPlayerImpl::SetMemoryReportingState(
1444 bool is_memory_reporting_enabled) {
1445 if (memory_usage_reporting_timer_.IsRunning() ==
1446 is_memory_reporting_enabled) {
1447 return;
1448 }
1449
1450 if (is_memory_reporting_enabled) {
1493 memory_usage_reporting_timer_.Start(FROM_HERE, 1451 memory_usage_reporting_timer_.Start(FROM_HERE,
1494 base::TimeDelta::FromSeconds(2), this, 1452 base::TimeDelta::FromSeconds(2), this,
1495 &WebMediaPlayerImpl::ReportMemoryUsage); 1453 &WebMediaPlayerImpl::ReportMemoryUsage);
1454 } else {
1455 memory_usage_reporting_timer_.Stop();
1456 ReportMemoryUsage();
1496 } 1457 }
1497 } 1458 }
1498 1459
1499 void WebMediaPlayerImpl::NotifyPlaybackPaused() { 1460 void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
1500 #if defined(OS_ANDROID) // WMPI_CAST 1461 // Do not change the state after an error has occurred.
1501 if (isRemote()) 1462 // TODO(sandersd): Update PipelineController to remove the need for this.
1502 return; 1463 if (IsNetworkStateError(network_state_))
1503 #endif
1504
1505 // Same as above, NotifyPlaybackPaused() may be called by interactions while
1506 // suspended, but those actions won't have any effect until the pipeline is
1507 // resumed.
1508 if (pipeline_controller_.IsSuspended())
1509 return; 1464 return;
1510 1465
1511 if (delegate_) 1466 if (is_suspended) {
1512 delegate_->DidPause(delegate_id_, ended_); 1467 pipeline_controller_.Suspend();
1513 memory_usage_reporting_timer_.Stop(); 1468 } else {
1514 ReportMemoryUsage(); 1469 pipeline_controller_.Resume();
1470 }
1471 }
1472
1473 WebMediaPlayerImpl::PlayState
1474 WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
1475 bool is_backgrounded) {
1476 PlayState result;
1477
1478 // This includes both data source (before pipeline startup) and pipeline
1479 // errors.
1480 bool has_error = IsNetworkStateError(network_state_);
1481
1482 // After HaveMetadata, we know which tracks are present and the duration.
1483 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1484
1485 // After HaveFutureData, Blink will call play() if the state is not paused.
1486 bool have_future_data =
1487 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1488
1489 // Background suspend is not enabled for audio-only players.
1490 bool background_suspended = is_backgrounded && have_metadata && hasVideo();
1491
1492 // Idle suspend is enabled once there is future data. We don't want to idle
1493 // suspend before that because play() may never be triggered to leave the idle
1494 // state. There could be other theoretical problems if the page is waiting for
1495 // other events before actually calling play(), but at least we don't break
1496 // Blink.
1497 //
1498 // TODO(sandersd): Make the delegate suspend idle players immediately when
1499 // hidden.
1500 // TODO(sandersd): If Blink told us the paused state sooner, we could
1501 // idle suspend sooner.
1502 bool idle_suspended = is_idle_ && have_future_data;
1503
1504 // Combined suspend state.
1505 result.is_suspended =
1506 is_remote || must_suspend_ || idle_suspended || background_suspended;
1507
1508 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1509 // being paused implies displaying a play button, which is incorrect in this
1510 // case. For memory usage reporting, we just use the same definition (but we
1511 // don't have to).
1512 //
1513 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1514 // call pause() or seek(), so |ended_| should not affect the computation.
1515 // Despite that, |ended_| does result in a separate paused state, to simplfy
1516 // the contract for SetDelegateState().
1517 //
1518 // |has_session| is used to decide when to create a media session. Idle
1519 // suspension does not destroy the media session, because we expect that the
1520 // notification controls (and audio focus) remain. We also require:
1521 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
1522 // - |have_future_data|, since we need to know whether we are paused to
1523 // correctly configure the session.
1524 //
1525 // TODO(sandersd): If Blink told us the paused state sooner, we could create
1526 // the media session sooner.
1527 bool can_play = !has_error && !is_remote && have_future_data;
1528 bool has_session = can_play && !must_suspend_ && !background_suspended;
1529
1530 if (!has_session) {
1531 result.delegate_state = DelegateState::GONE;
1532 } else if (paused_) {
1533 // TODO(sandersd): There should be a paused+seeking state, during which
1534 // the idle timer is disabled. Without that, idle suspending before or
1535 // during seeking will have bad results.
1536 result.delegate_state =
1537 ended_ ? DelegateState::ENDED : DelegateState::PAUSED;
1538 } else {
1539 result.delegate_state = DelegateState::PLAYING;
1540 }
1541
1542 // It's not critical if some cases where memory usage can change are missed,
1543 // since media memory changes are usually gradual.
1544 result.is_memory_reporting_enabled =
1545 can_play && !result.is_suspended && !paused_;
1546
1547 return result;
1515 } 1548 }
1516 1549
1517 void WebMediaPlayerImpl::ReportMemoryUsage() { 1550 void WebMediaPlayerImpl::ReportMemoryUsage() {
1518 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1551 DCHECK(main_task_runner_->BelongsToCurrentThread());
1519 1552
1520 // About base::Unretained() usage below: We destroy |demuxer_| on the main 1553 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1521 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the 1554 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1522 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task 1555 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1523 // posted here must finish earlier. 1556 // posted here must finish earlier.
1524 1557
(...skipping 22 matching lines...) Expand all
1547 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage 1580 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
1548 << ", Video: " << stats.video_memory_usage << ", DataSource: " 1581 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1549 << (data_source_ ? data_source_->GetMemoryUsage() : 0) 1582 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
1550 << ", Demuxer: " << demuxer_memory_usage; 1583 << ", Demuxer: " << demuxer_memory_usage;
1551 1584
1552 const int64_t delta = current_memory_usage - last_reported_memory_usage_; 1585 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1553 last_reported_memory_usage_ = current_memory_usage; 1586 last_reported_memory_usage_ = current_memory_usage;
1554 adjust_allocated_memory_cb_.Run(delta); 1587 adjust_allocated_memory_cb_.Run(delta);
1555 } 1588 }
1556 1589
1557 bool WebMediaPlayerImpl::IsAutomaticResumeAllowed() {
1558 #if defined(OS_ANDROID)
1559 return !hasVideo() || (delegate_ && !delegate_->IsHidden());
1560 #else
1561 // On non-Android platforms Resume() is always allowed.
1562 return true;
1563 #endif
1564 }
1565
1566 } // namespace media 1590 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698