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> |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
142 return natural_size; | 142 return natural_size; |
143 } | 143 } |
144 | 144 |
145 base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) { | 145 base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) { |
146 // We wrap currentTime() instead of using pipeline_.GetMediaTime() since there | 146 // We wrap currentTime() instead of using pipeline_.GetMediaTime() since there |
147 // are a variety of cases in which that time is not accurate; e.g., while | 147 // are a variety of cases in which that time is not accurate; e.g., while |
148 // remoting and during a pause or seek. | 148 // remoting and during a pause or seek. |
149 return base::TimeDelta::FromSecondsD(p_this->currentTime()); | 149 return base::TimeDelta::FromSecondsD(p_this->currentTime()); |
150 } | 150 } |
151 | 151 |
152 // How much time must have elapsed since loading last progressed before the | 152 // How much time must have elapsed since loading last progressed before we |
153 // player is eligible for idle suspension. | 153 // assume that the decoder will have had time to complete preroll. |
154 constexpr base::TimeDelta kLoadingToIdleTimeout = | 154 constexpr base::TimeDelta kPrerollAttemptTimeout = |
155 base::TimeDelta::FromSeconds(3); | 155 base::TimeDelta::FromSeconds(3); |
156 | 156 |
157 } // namespace | 157 } // namespace |
158 | 158 |
159 class BufferedDataSourceHostImpl; | 159 class BufferedDataSourceHostImpl; |
160 | 160 |
161 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, | 161 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, |
162 UrlData::CORS_UNSPECIFIED); | 162 UrlData::CORS_UNSPECIFIED); |
163 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); | 163 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); |
164 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, | 164 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, |
165 UrlData::CORS_USE_CREDENTIALS); | 165 UrlData::CORS_USE_CREDENTIALS); |
166 | 166 |
167 #define BIND_TO_RENDER_LOOP(function) \ | 167 #define BIND_TO_RENDER_LOOP(function) \ |
168 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ | 168 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ |
169 BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) | 169 BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) |
170 | 170 |
171 #define BIND_TO_RENDER_LOOP1(function, arg1) \ | 171 #define BIND_TO_RENDER_LOOP1(function, arg1) \ |
172 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ | 172 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ |
173 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) | 173 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) |
174 | 174 |
175 WebMediaPlayerImpl::WebMediaPlayerImpl( | 175 WebMediaPlayerImpl::WebMediaPlayerImpl( |
176 blink::WebLocalFrame* frame, | 176 blink::WebLocalFrame* frame, |
177 blink::WebMediaPlayerClient* client, | 177 blink::WebMediaPlayerClient* client, |
178 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, | 178 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, |
179 base::WeakPtr<WebMediaPlayerDelegate> delegate, | 179 base::WeakPtr<WebMediaPlayerDelegate> delegate, |
180 std::unique_ptr<RendererFactory> renderer_factory, | 180 std::unique_ptr<RendererFactory> renderer_factory, |
181 linked_ptr<UrlIndex> url_index, | 181 linked_ptr<UrlIndex> url_index, |
182 const WebMediaPlayerParams& params) | 182 const WebMediaPlayerParams& params) |
183 : frame_(frame), | 183 : frame_(frame), |
184 delegate_state_(DelegateState::GONE), | |
185 is_idle_(false), | |
186 must_suspend_(false), | |
187 network_state_(WebMediaPlayer::NetworkStateEmpty), | 184 network_state_(WebMediaPlayer::NetworkStateEmpty), |
188 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 185 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
189 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 186 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
190 preload_(MultibufferDataSource::AUTO), | 187 preload_(MultibufferDataSource::AUTO), |
191 buffering_strategy_(MultibufferDataSource::BUFFERING_STRATEGY_NORMAL), | 188 buffering_strategy_(MultibufferDataSource::BUFFERING_STRATEGY_NORMAL), |
192 main_task_runner_(frame->loadingTaskRunner()), | 189 main_task_runner_(frame->loadingTaskRunner()), |
193 media_task_runner_(params.media_task_runner()), | 190 media_task_runner_(params.media_task_runner()), |
194 worker_task_runner_(params.worker_task_runner()), | 191 worker_task_runner_(params.worker_task_runner()), |
195 media_log_(params.media_log()), | 192 media_log_(params.media_log()), |
196 pipeline_(media_task_runner_, media_log_.get()), | 193 pipeline_(media_task_runner_, media_log_.get()), |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
233 volume_(1.0), | 230 volume_(1.0), |
234 volume_multiplier_(1.0), | 231 volume_multiplier_(1.0), |
235 renderer_factory_(std::move(renderer_factory)), | 232 renderer_factory_(std::move(renderer_factory)), |
236 surface_manager_(params.surface_manager()), | 233 surface_manager_(params.surface_manager()), |
237 overlay_surface_id_(SurfaceManager::kNoSurfaceID), | 234 overlay_surface_id_(SurfaceManager::kNoSurfaceID), |
238 suppress_destruction_errors_(false), | 235 suppress_destruction_errors_(false), |
239 can_suspend_state_(CanSuspendState::UNKNOWN), | 236 can_suspend_state_(CanSuspendState::UNKNOWN), |
240 use_fallback_path_(false), | 237 use_fallback_path_(false), |
241 is_encrypted_(false), | 238 is_encrypted_(false), |
242 underflow_count_(0), | 239 underflow_count_(0), |
240 preroll_attempt_pending_(false), | |
243 observer_(params.media_observer()) { | 241 observer_(params.media_observer()) { |
244 DCHECK(!adjust_allocated_memory_cb_.is_null()); | 242 DCHECK(!adjust_allocated_memory_cb_.is_null()); |
245 DCHECK(renderer_factory_); | 243 DCHECK(renderer_factory_); |
246 DCHECK(client_); | 244 DCHECK(client_); |
247 | 245 |
248 tick_clock_.reset(new base::DefaultTickClock()); | 246 tick_clock_.reset(new base::DefaultTickClock()); |
249 | 247 |
250 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch( | 248 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch( |
251 switches::kForceVideoOverlays); | 249 switches::kForceVideoOverlays); |
252 | 250 |
253 if (delegate_) | 251 if (delegate_) { |
254 delegate_id_ = delegate_->AddObserver(this); | 252 delegate_id_ = delegate_->AddObserver(this); |
253 delegate_->SetIdle(delegate_id_, true); | |
254 } | |
255 | 255 |
256 media_log_->AddEvent( | 256 media_log_->AddEvent( |
257 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED)); | 257 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED)); |
258 | 258 |
259 if (params.initial_cdm()) | 259 if (params.initial_cdm()) |
260 SetCdm(params.initial_cdm()); | 260 SetCdm(params.initial_cdm()); |
261 | 261 |
262 // TODO(xhwang): When we use an external Renderer, many methods won't work, | 262 // TODO(xhwang): When we use an external Renderer, many methods won't work, |
263 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861 | 263 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861 |
264 audio_source_provider_ = | 264 audio_source_provider_ = |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
415 void WebMediaPlayerImpl::play() { | 415 void WebMediaPlayerImpl::play() { |
416 DVLOG(1) << __func__; | 416 DVLOG(1) << __func__; |
417 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 417 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
418 | 418 |
419 #if defined(OS_ANDROID) // WMPI_CAST | 419 #if defined(OS_ANDROID) // WMPI_CAST |
420 if (isRemote()) { | 420 if (isRemote()) { |
421 cast_impl_.play(); | 421 cast_impl_.play(); |
422 return; | 422 return; |
423 } | 423 } |
424 #endif | 424 #endif |
425 // TODO(sandersd): Do we want to reset the idle timer here? | |
426 if (delegate_) | |
427 delegate_->SetIdle(delegate_id_, false); | |
425 paused_ = false; | 428 paused_ = false; |
426 is_idle_ = false; | |
427 pipeline_.SetPlaybackRate(playback_rate_); | 429 pipeline_.SetPlaybackRate(playback_rate_); |
428 background_pause_timer_.Stop(); | 430 background_pause_timer_.Stop(); |
429 | 431 |
430 if (data_source_) | 432 if (data_source_) |
431 data_source_->MediaIsPlaying(); | 433 data_source_->MediaIsPlaying(); |
432 | 434 |
433 if (observer_) | 435 if (observer_) |
434 observer_->OnPlaying(); | 436 observer_->OnPlaying(); |
435 | 437 |
436 DCHECK(watch_time_reporter_); | 438 DCHECK(watch_time_reporter_); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
517 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 519 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
518 } | 520 } |
519 return; | 521 return; |
520 } | 522 } |
521 | 523 |
522 // Call this before setting |seeking_| so that the current media time can be | 524 // Call this before setting |seeking_| so that the current media time can be |
523 // recorded by the reporter. | 525 // recorded by the reporter. |
524 if (watch_time_reporter_) | 526 if (watch_time_reporter_) |
525 watch_time_reporter_->OnSeeking(); | 527 watch_time_reporter_->OnSeeking(); |
526 | 528 |
527 // TODO(sandersd): Ideally we would not clear the idle state if | 529 // TODO(sandersd): Move |seeking_| to PipelineController. |
528 // |pipeline_controller_| can elide the seek. | 530 // TODO(sandersd): Do we want to reset the idle timer here? |
529 is_idle_ = false; | 531 if (delegate_) |
532 delegate_->SetIdle(delegate_id_, false); | |
530 ended_ = false; | 533 ended_ = false; |
531 | |
532 seeking_ = true; | 534 seeking_ = true; |
533 seek_time_ = time; | 535 seek_time_ = time; |
534 if (paused_) | 536 if (paused_) |
535 paused_time_ = time; | 537 paused_time_ = time; |
536 pipeline_controller_.Seek(time, time_updated); | 538 pipeline_controller_.Seek(time, time_updated); |
537 | 539 |
538 // This needs to be called after Seek() so that if a resume is triggered, it | 540 // This needs to be called after Seek() so that if a resume is triggered, it |
539 // is to the correct time. | 541 // is to the correct time. |
540 UpdatePlayState(); | 542 UpdatePlayState(); |
541 } | 543 } |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
788 std::isfinite(seekable_end); | 790 std::isfinite(seekable_end); |
789 | 791 |
790 // TODO(dalecurtis): Technically this allows seeking on media which return an | 792 // TODO(dalecurtis): Technically this allows seeking on media which return an |
791 // infinite duration so long as DataSource::IsStreaming() is false. While not | 793 // infinite duration so long as DataSource::IsStreaming() is false. While not |
792 // expected, disabling this breaks semi-live players, http://crbug.com/427412. | 794 // expected, disabling this breaks semi-live players, http://crbug.com/427412. |
793 const blink::WebTimeRange seekable_range( | 795 const blink::WebTimeRange seekable_range( |
794 0.0, allow_seek_to_zero ? 0.0 : seekable_end); | 796 0.0, allow_seek_to_zero ? 0.0 : seekable_end); |
795 return blink::WebTimeRanges(&seekable_range, 1); | 797 return blink::WebTimeRanges(&seekable_range, 1); |
796 } | 798 } |
797 | 799 |
800 bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() { | |
801 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need | |
802 // to ensure that preroll always gets a chance to complete. | |
803 // See http://crbug.com/671525. | |
804 if (highest_ready_state_ >= ReadyState::ReadyStateHaveFutureData) | |
805 return false; | |
806 | |
807 if (preroll_attempt_pending_) | |
808 return true; | |
809 | |
810 // Freshly initialized; there has never been any loading progress. (Otherwise | |
811 // |preroll_attempt_pending_| would be true when the start time is null.) | |
812 if (preroll_attempt_start_time_.is_null()) | |
813 return false; | |
814 | |
815 base::TimeDelta preroll_attempt_duration = | |
816 tick_clock_->NowTicks() - preroll_attempt_start_time_; | |
817 return preroll_attempt_duration < kPrerollAttemptTimeout; | |
818 } | |
819 | |
798 bool WebMediaPlayerImpl::didLoadingProgress() { | 820 bool WebMediaPlayerImpl::didLoadingProgress() { |
799 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 821 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
800 | 822 |
801 // Note: Separate variables used to ensure both methods are called every time. | 823 // Note: Separate variables used to ensure both methods are called every time. |
802 const bool pipeline_progress = pipeline_.DidLoadingProgress(); | 824 const bool pipeline_progress = pipeline_.DidLoadingProgress(); |
803 const bool data_progress = buffered_data_source_host_.DidLoadingProgress(); | 825 const bool data_progress = buffered_data_source_host_.DidLoadingProgress(); |
804 const bool did_loading_progress = pipeline_progress || data_progress; | 826 const bool did_loading_progress = pipeline_progress || data_progress; |
805 | 827 |
806 // If we've idle suspended before reaching kHaveFutureData and loading has | 828 if (did_loading_progress && |
807 // progressed we need to spin up the renderer and figure out if we have enough | 829 highest_ready_state_ < ReadyState::ReadyStateHaveFutureData) { |
808 // data yet; |client_| may be waiting on this signal to trigger playback. The | 830 // Reset the preroll attempt clock. |
809 // idle timeout is long enough that this is a low-cost operation. | 831 preroll_attempt_pending_ = true; |
810 if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData && | 832 preroll_attempt_start_time_ = base::TimeTicks(); |
811 pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) { | 833 |
812 is_idle_ = false; | 834 // Clear any 'stale' flag and give the pipeline a chance to resume. If we |
835 // are already resumed, this will cause |preroll_attempt_start_time_| to be | |
836 // set. | |
837 // TODO(sandersd): Should this be on the same stack? It might be surprising | |
838 // that didLoadingProgress() can synchronously change state. | |
839 if (delegate_) | |
840 delegate_->ClearStaleFlag(delegate_id_); | |
813 UpdatePlayState(); | 841 UpdatePlayState(); |
814 } | 842 } |
815 | 843 |
816 if (did_loading_progress) | |
817 last_time_loading_progressed_ = tick_clock_->NowTicks(); | |
818 | |
819 return did_loading_progress; | 844 return did_loading_progress; |
820 } | 845 } |
821 | 846 |
822 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas, | 847 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas, |
823 const blink::WebRect& rect, | 848 const blink::WebRect& rect, |
824 SkPaint& paint) { | 849 SkPaint& paint) { |
825 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 850 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
826 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); | 851 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); |
827 | 852 |
828 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when | 853 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 // TODO(chcunningham): Monitor playback position vs buffered. Potentially | 1234 // TODO(chcunningham): Monitor playback position vs buffered. Potentially |
1210 // transition to HAVE_FUTURE_DATA here if not enough is buffered. | 1235 // transition to HAVE_FUTURE_DATA here if not enough is buffered. |
1211 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 1236 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
1212 | 1237 |
1213 // Let the DataSource know we have enough data. It may use this information | 1238 // Let the DataSource know we have enough data. It may use this information |
1214 // to release unused network connections. | 1239 // to release unused network connections. |
1215 if (data_source_) | 1240 if (data_source_) |
1216 data_source_->OnBufferingHaveEnough(false); | 1241 data_source_->OnBufferingHaveEnough(false); |
1217 | 1242 |
1218 // Blink expects a timeChanged() in response to a seek(). | 1243 // Blink expects a timeChanged() in response to a seek(). |
1219 if (should_notify_time_changed_) | 1244 if (should_notify_time_changed_) { |
1245 should_notify_time_changed_ = false; | |
1220 client_->timeChanged(); | 1246 client_->timeChanged(); |
1247 } | |
1221 | 1248 |
1222 // Once we have enough, start reporting the total memory usage. We'll also | 1249 // Once we have enough, start reporting the total memory usage. We'll also |
1223 // report once playback starts. | 1250 // report once playback starts. |
1224 ReportMemoryUsage(); | 1251 ReportMemoryUsage(); |
1225 | 1252 |
1226 // Report the amount of time it took to leave the underflow state. Don't | 1253 // Report the amount of time it took to leave the underflow state. Don't |
1227 // bother to report this for MSE playbacks since it's out of our control. | 1254 // bother to report this for MSE playbacks since it's out of our control. |
1228 if (underflow_timer_ && data_source_) { | 1255 if (underflow_timer_ && data_source_) { |
1229 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", | 1256 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", |
1230 underflow_timer_->Elapsed()); | 1257 underflow_timer_->Elapsed()); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1326 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1353 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1327 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 1354 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
1328 | 1355 |
1329 opaque_ = opaque; | 1356 opaque_ = opaque; |
1330 // Modify content opaqueness of cc::Layer directly so that | 1357 // Modify content opaqueness of cc::Layer directly so that |
1331 // SetContentsOpaqueIsFixed is ignored. | 1358 // SetContentsOpaqueIsFixed is ignored. |
1332 if (video_weblayer_) | 1359 if (video_weblayer_) |
1333 video_weblayer_->layer()->SetContentsOpaque(opaque_); | 1360 video_weblayer_->layer()->SetContentsOpaque(opaque_); |
1334 } | 1361 } |
1335 | 1362 |
1336 void WebMediaPlayerImpl::OnHidden() { | 1363 void WebMediaPlayerImpl::OnFrameHidden() { |
whywhat
2017/01/06 17:18:52
nit: Following discussion with Dale around naming
sandersd (OOO until July 31)
2017/01/06 23:08:35
I think I prefer to keep these names, since they a
DaleCurtis
2017/01/07 00:31:03
Saving the rename for later sgtm.
| |
1337 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1364 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1338 | 1365 |
1339 if (IsBackgroundVideoTrackOptimizationEnabled()) | 1366 if (IsBackgroundVideoTrackOptimizationEnabled()) |
1340 selectedVideoTrackChanged(nullptr); | 1367 selectedVideoTrackChanged(nullptr); |
1341 | 1368 |
1342 if (watch_time_reporter_) | 1369 if (watch_time_reporter_) |
1343 watch_time_reporter_->OnHidden(); | 1370 watch_time_reporter_->OnHidden(); |
1344 | 1371 |
1345 UpdatePlayState(); | 1372 UpdatePlayState(); |
1346 | 1373 |
1347 // Schedule suspended playing media to be paused if the user doesn't come back | 1374 // Schedule suspended playing media to be paused if the user doesn't come back |
1348 // to it within some timeout period to avoid any autoplay surprises. | 1375 // to it within some timeout period to avoid any autoplay surprises. |
1349 ScheduleIdlePauseTimer(); | 1376 ScheduleIdlePauseTimer(); |
1350 } | 1377 } |
1351 | 1378 |
1352 void WebMediaPlayerImpl::OnShown() { | 1379 void WebMediaPlayerImpl::OnFrameClosed() { |
1353 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1380 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1381 UpdatePlayState(); | |
1382 } | |
1383 | |
1384 void WebMediaPlayerImpl::OnFrameShown() { | |
1385 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1386 background_pause_timer_.Stop(); | |
1387 | |
1354 if (watch_time_reporter_) | 1388 if (watch_time_reporter_) |
1355 watch_time_reporter_->OnShown(); | 1389 watch_time_reporter_->OnShown(); |
1356 | 1390 |
1357 if (IsBackgroundVideoTrackOptimizationEnabled() && | 1391 if (IsBackgroundVideoTrackOptimizationEnabled() && |
1358 client_->hasSelectedVideoTrack()) { | 1392 client_->hasSelectedVideoTrack()) { |
1359 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); | 1393 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); |
1360 selectedVideoTrackChanged(&trackId); | 1394 selectedVideoTrackChanged(&trackId); |
1361 } | 1395 } |
1362 | 1396 |
1363 must_suspend_ = false; | |
1364 background_pause_timer_.Stop(); | |
1365 | |
1366 UpdatePlayState(); | 1397 UpdatePlayState(); |
1367 } | 1398 } |
1368 | 1399 |
1369 bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { | 1400 void WebMediaPlayerImpl::OnIdleTimeout() { |
1370 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1401 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1371 | 1402 |
1372 if (must_suspend) { | 1403 // If we are attempting preroll, clear the stale flag. |
1373 must_suspend_ = true; | 1404 if (IsPrerollAttemptNeeded()) { |
1374 UpdatePlayState(); | 1405 if (delegate_) |
1375 return true; | 1406 delegate_->ClearStaleFlag(delegate_id_); |
1407 return; | |
1376 } | 1408 } |
1377 | 1409 |
1378 // If we're beyond HaveFutureData, we can safely suspend at any time. | 1410 UpdatePlayState(); |
1379 if (highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData) { | |
1380 is_idle_ = true; | |
1381 UpdatePlayState(); | |
1382 return true; | |
1383 } | |
1384 | |
1385 // Before HaveFutureData blink will not call play(), so we must be careful to | |
1386 // only suspend if we'll eventually receive an event that will trigger a | |
1387 // resume. If the last time loading progressed was a while ago, and we still | |
1388 // haven't reached HaveFutureData, we assume that we're waiting on more data | |
1389 // to continue pre-rolling. When that data is loaded the pipeline will be | |
1390 // resumed by didLoadingProgress(). | |
1391 if (last_time_loading_progressed_.is_null() || | |
1392 (tick_clock_->NowTicks() - last_time_loading_progressed_) > | |
1393 kLoadingToIdleTimeout) { | |
1394 is_idle_ = true; | |
1395 UpdatePlayState(); | |
1396 return true; | |
1397 } | |
1398 | |
1399 return false; | |
1400 } | 1411 } |
1401 | 1412 |
1402 void WebMediaPlayerImpl::OnPlay() { | 1413 void WebMediaPlayerImpl::OnPlay() { |
1403 play(); | 1414 play(); |
1404 client_->playbackStateChanged(); | 1415 client_->playbackStateChanged(); |
1405 } | 1416 } |
1406 | 1417 |
1407 void WebMediaPlayerImpl::OnPause() { | 1418 void WebMediaPlayerImpl::OnPause() { |
1408 pause(); | 1419 pause(); |
1409 client_->playbackStateChanged(); | 1420 client_->playbackStateChanged(); |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1737 bool is_streaming = false; | 1748 bool is_streaming = false; |
1738 #else | 1749 #else |
1739 bool is_remote = false; | 1750 bool is_remote = false; |
1740 bool is_streaming = data_source_ && data_source_->IsStreaming(); | 1751 bool is_streaming = data_source_ && data_source_->IsStreaming(); |
1741 #endif | 1752 #endif |
1742 | 1753 |
1743 bool is_suspended = pipeline_controller_.IsSuspended(); | 1754 bool is_suspended = pipeline_controller_.IsSuspended(); |
1744 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden(); | 1755 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden(); |
1745 PlayState state = UpdatePlayState_ComputePlayState( | 1756 PlayState state = UpdatePlayState_ComputePlayState( |
1746 is_remote, is_streaming, is_suspended, is_backgrounded); | 1757 is_remote, is_streaming, is_suspended, is_backgrounded); |
1747 SetDelegateState(state.delegate_state); | 1758 SetDelegateState(state.delegate_state, state.is_idle); |
1748 SetMemoryReportingState(state.is_memory_reporting_enabled); | 1759 SetMemoryReportingState(state.is_memory_reporting_enabled); |
1749 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); | 1760 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); |
1750 } | 1761 } |
1751 | 1762 |
1752 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { | 1763 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state, |
1764 bool is_idle) { | |
1753 if (!delegate_) | 1765 if (!delegate_) |
1754 return; | 1766 return; |
1755 | 1767 |
1756 if (delegate_state_ == new_state) { | 1768 switch (new_state) { |
1757 if (delegate_state_ != DelegateState::PLAYING || | |
1758 autoplay_muted_ == client_->isAutoplayingMuted()) { | |
1759 return; | |
1760 } | |
1761 } | |
1762 | |
1763 delegate_state_ = new_state; | |
1764 | |
1765 switch (delegate_state_) { | |
1766 case DelegateState::GONE: | 1769 case DelegateState::GONE: |
1767 delegate_->PlayerGone(delegate_id_); | 1770 delegate_->PlayerGone(delegate_id_); |
1768 break; | 1771 break; |
1769 case DelegateState::PLAYING: { | 1772 case DelegateState::PLAYING: { |
1770 autoplay_muted_ = client_->isAutoplayingMuted(); | 1773 bool has_audio = hasAudio() && !client_->isAutoplayingMuted(); |
1771 bool has_audio = autoplay_muted_ ? false : hasAudio(); | |
1772 delegate_->DidPlay( | 1774 delegate_->DidPlay( |
1773 delegate_id_, hasVideo(), has_audio, false, | 1775 delegate_id_, has_audio, hasVideo(), |
1774 media::DurationToMediaContentType(pipeline_.GetMediaDuration())); | 1776 media::DurationToMediaContentType(pipeline_.GetMediaDuration())); |
1775 break; | 1777 break; |
1776 } | 1778 } |
1777 case DelegateState::PAUSED: | 1779 case DelegateState::PAUSED: |
1778 delegate_->DidPause(delegate_id_, false); | 1780 delegate_->DidPause(delegate_id_); |
1779 break; | |
1780 case DelegateState::ENDED: | |
1781 delegate_->DidPause(delegate_id_, true); | |
1782 break; | 1781 break; |
1783 } | 1782 } |
1783 | |
1784 delegate_->SetIdle(delegate_id_, is_idle); | |
1784 } | 1785 } |
1785 | 1786 |
1786 void WebMediaPlayerImpl::SetMemoryReportingState( | 1787 void WebMediaPlayerImpl::SetMemoryReportingState( |
1787 bool is_memory_reporting_enabled) { | 1788 bool is_memory_reporting_enabled) { |
1788 if (memory_usage_reporting_timer_.IsRunning() == | 1789 if (memory_usage_reporting_timer_.IsRunning() == |
1789 is_memory_reporting_enabled) { | 1790 is_memory_reporting_enabled) { |
1790 return; | 1791 return; |
1791 } | 1792 } |
1792 | 1793 |
1793 if (is_memory_reporting_enabled) { | 1794 if (is_memory_reporting_enabled) { |
(...skipping 25 matching lines...) Expand all Loading... | |
1819 can_suspend_state_ = | 1820 can_suspend_state_ = |
1820 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME) | 1821 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME) |
1821 ? CanSuspendState::NO | 1822 ? CanSuspendState::NO |
1822 : CanSuspendState::YES; | 1823 : CanSuspendState::YES; |
1823 } | 1824 } |
1824 } | 1825 } |
1825 #else | 1826 #else |
1826 can_suspend_state_ = CanSuspendState::YES; | 1827 can_suspend_state_ = CanSuspendState::YES; |
1827 #endif | 1828 #endif |
1828 | 1829 |
1829 if (can_suspend_state_ == CanSuspendState::NO) | 1830 if (is_suspended && can_suspend_state_ != CanSuspendState::NO) { |
1830 return; | 1831 // If we were not resumed for long enough to satisfy the preroll attempt, |
1831 | 1832 // reset the clock. |
1832 if (is_suspended) { | 1833 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) { |
1834 preroll_attempt_pending_ = true; | |
1835 preroll_attempt_start_time_ = base::TimeTicks(); | |
1836 } | |
1833 pipeline_controller_.Suspend(); | 1837 pipeline_controller_.Suspend(); |
1834 } else { | 1838 } else { |
1839 // When resuming, start the preroll attempt clock. | |
1840 if (preroll_attempt_pending_) { | |
1841 preroll_attempt_pending_ = false; | |
1842 preroll_attempt_start_time_ = tick_clock_->NowTicks(); | |
1843 } | |
1835 pipeline_controller_.Resume(); | 1844 pipeline_controller_.Resume(); |
1836 } | 1845 } |
1837 } | 1846 } |
1838 | 1847 |
1839 WebMediaPlayerImpl::PlayState | 1848 WebMediaPlayerImpl::PlayState |
1840 WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote, | 1849 WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote, |
1841 bool is_streaming, | 1850 bool is_streaming, |
1842 bool is_suspended, | 1851 bool is_suspended, |
1843 bool is_backgrounded) { | 1852 bool is_backgrounded) { |
1844 PlayState result; | 1853 PlayState result; |
1845 | 1854 |
1855 bool must_suspend = delegate_ && delegate_->IsFrameClosed(); | |
1856 bool is_stale = delegate_ && delegate_->IsStale(delegate_id_); | |
1857 | |
1846 // This includes both data source (before pipeline startup) and pipeline | 1858 // This includes both data source (before pipeline startup) and pipeline |
1847 // errors. | 1859 // errors. |
1848 bool has_error = IsNetworkStateError(network_state_); | 1860 bool has_error = IsNetworkStateError(network_state_); |
1849 | 1861 |
1850 // After HaveMetadata, we know which tracks are present and the duration. | 1862 // After HaveMetadata, we know which tracks are present and the duration. |
1851 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata; | 1863 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata; |
1852 | 1864 |
1853 // After HaveFutureData, Blink will call play() if the state is not paused; | 1865 // After HaveFutureData, Blink will call play() if the state is not paused; |
1854 // prior to this point |paused_| is not accurate. | 1866 // prior to this point |paused_| is not accurate. |
1855 bool have_future_data = | 1867 bool have_future_data = |
1856 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData; | 1868 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData; |
1857 | 1869 |
1858 // Background suspend is not enabled for audio-only players unless paused, | 1870 // Background suspend is not enabled for audio-only players unless paused, |
1859 // though in the case of audio-only the session should be kept. | 1871 // though in the case of audio-only the session should be kept. |
1860 // Videos are not suspended if the user resumed the playback via the remote | 1872 // Videos are not suspended if the user resumed the playback via the remote |
1861 // controls earlier and it's still playing. | 1873 // controls earlier and it's still playing. |
1862 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo(); | 1874 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo(); |
1863 bool can_play_backgrounded = is_backgrounded_video && !is_remote && | 1875 bool can_play_backgrounded = is_backgrounded_video && !is_remote && |
1864 hasAudio() && IsResumeBackgroundVideosEnabled(); | 1876 hasAudio() && IsResumeBackgroundVideosEnabled(); |
1865 bool is_background_playing = | 1877 bool is_background_playing = |
1866 delegate_ && delegate_->IsPlayingBackgroundVideo(); | 1878 delegate_ && delegate_->IsBackgroundVideoPlaybackAllowed(); |
whywhat
2017/01/06 17:18:51
nit: I'm a bit concerned that IsBgVideoPlaybackAll
sandersd (OOO until July 31)
2017/01/06 23:08:35
Done.
| |
1867 bool background_suspended = !is_streaming && is_backgrounded_video && | 1879 bool background_suspended = !is_streaming && is_backgrounded_video && |
1868 !(can_play_backgrounded && is_background_playing); | 1880 !(can_play_backgrounded && is_background_playing); |
1869 bool background_pause_suspended = | 1881 bool background_pause_suspended = |
1870 !is_streaming && is_backgrounded && paused_ && have_future_data; | 1882 !is_streaming && is_backgrounded && paused_ && have_future_data; |
1871 | 1883 |
1872 // Idle suspension is allowed prior to have future data since there exist | 1884 // Idle suspension is allowed prior to have future data since there exist |
1873 // mechanisms to exit the idle state when the player is capable of reaching | 1885 // mechanisms to exit the idle state when the player is capable of reaching |
1874 // the have future data state; see didLoadingProgress(). | 1886 // the have future data state; see didLoadingProgress(). |
1875 // | 1887 // |
1876 // TODO(sandersd): Make the delegate suspend idle players immediately when | 1888 // TODO(sandersd): Make the delegate suspend idle players immediately when |
1877 // hidden. | 1889 // hidden. |
1878 bool idle_suspended = | 1890 bool idle_suspended = |
1879 !is_streaming && is_idle_ && paused_ && !seeking_ && !overlay_enabled_; | 1891 !is_streaming && is_stale && paused_ && !seeking_ && !overlay_enabled_; |
1880 | 1892 |
1881 // If we're already suspended, see if we can wait for user interaction. Prior | 1893 // If we're already suspended, see if we can wait for user interaction. Prior |
1882 // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_| | 1894 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale| |
1883 // will be cleared when we receive data which may take us to HaveFutureData. | 1895 // will be cleared when we receive data which may take us to HaveFutureData. |
1884 bool can_stay_suspended = | 1896 bool can_stay_suspended = |
1885 (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_; | 1897 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_; |
1886 | 1898 |
1887 // Combined suspend state. | 1899 // Combined suspend state. |
1888 result.is_suspended = is_remote || must_suspend_ || idle_suspended || | 1900 result.is_suspended = is_remote || must_suspend || idle_suspended || |
1889 background_suspended || background_pause_suspended || | 1901 background_suspended || background_pause_suspended || |
1890 can_stay_suspended; | 1902 can_stay_suspended; |
1891 | 1903 |
1892 // We do not treat |playback_rate_| == 0 as paused. For the media session, | 1904 // We do not treat |playback_rate_| == 0 as paused. For the media session, |
1893 // being paused implies displaying a play button, which is incorrect in this | 1905 // being paused implies displaying a play button, which is incorrect in this |
1894 // case. For memory usage reporting, we just use the same definition (but we | 1906 // case. For memory usage reporting, we just use the same definition (but we |
1895 // don't have to). | 1907 // don't have to). |
1896 // | 1908 // |
1897 // Similarly, we don't consider |ended_| to be paused. Blink will immediately | 1909 // Similarly, we don't consider |ended_| to be paused. Blink will immediately |
1898 // call pause() or seek(), so |ended_| should not affect the computation. | 1910 // call pause() or seek(), so |ended_| should not affect the computation. |
1899 // Despite that, |ended_| does result in a separate paused state, to simplfy | 1911 // Despite that, |ended_| does result in a separate paused state, to simplfy |
1900 // the contract for SetDelegateState(). | 1912 // the contract for SetDelegateState(). |
1901 // | 1913 // |
1902 // |has_session| is used to decide when to create a media session. Idle | 1914 // |has_session| is used to decide when to create a media session. Idle |
1903 // suspension does not destroy the media session, because we expect that the | 1915 // suspension does not destroy the media session, because we expect that the |
1904 // notification controls (and audio focus) remain. We also require: | 1916 // notification controls (and audio focus) remain. We also require: |
1905 // - |have_metadata|, since the tracks and duration are passed to DidPlay(). | 1917 // - |have_metadata|, since the tracks and duration are passed to DidPlay(). |
1906 // - |have_future_data|, since we need to know whether we are paused to | 1918 // - |have_future_data|, since we need to know whether we are paused to |
1907 // correctly configure the session. | 1919 // correctly configure the session. |
1908 // | 1920 // |
1909 // TODO(sandersd): If Blink told us the paused state sooner, we could create | 1921 // TODO(sandersd): If Blink told us the paused state sooner, we could create |
1910 // the media session sooner. | 1922 // the media session sooner. |
1911 bool can_play = !has_error && !is_remote && have_future_data; | 1923 bool can_play = !has_error && !is_remote && have_future_data; |
1912 bool has_session_playing = | 1924 bool has_session_playing = can_play && !must_suspend && !background_suspended; |
1913 can_play && !must_suspend_ && !background_suspended; | |
1914 | 1925 |
1915 // |has_session_suspended| means the player is suspended from the media | 1926 // |has_session_suspended| means the player is suspended from the media |
1916 // element point of view but paused and can be resumed from the delegate point | 1927 // element point of view but paused and can be resumed from the delegate point |
1917 // of view. Therefore it behaves like |paused_| for the delegate. | 1928 // of view. Therefore it behaves like |paused_| for the delegate. |
1918 bool has_session_suspended = can_play && !must_suspend_ && | 1929 bool has_session_suspended = can_play && !must_suspend && |
1919 background_suspended && can_play_backgrounded; | 1930 background_suspended && can_play_backgrounded; |
1920 | 1931 |
1921 bool has_session = has_session_playing || has_session_suspended; | 1932 bool has_session = has_session_playing || has_session_suspended; |
1922 | 1933 |
1923 if (!has_session) { | 1934 if (!has_session) { |
1924 result.delegate_state = DelegateState::GONE; | 1935 result.delegate_state = DelegateState::GONE; |
1936 result.is_idle = delegate_ && delegate_->IsIdle(delegate_id_); | |
1925 } else if (paused_ || has_session_suspended) { | 1937 } else if (paused_ || has_session_suspended) { |
1938 // TODO(sandersd): Is it possible to have a suspended session, be ended, | |
1939 // and not be paused? If so we should be in a PLAYING state. | |
1926 result.delegate_state = | 1940 result.delegate_state = |
1927 ended_ ? DelegateState::ENDED : DelegateState::PAUSED; | 1941 ended_ ? DelegateState::GONE : DelegateState::PAUSED; |
1942 result.is_idle = !seeking_; | |
1928 } else { | 1943 } else { |
1929 result.delegate_state = DelegateState::PLAYING; | 1944 result.delegate_state = DelegateState::PLAYING; |
1945 result.is_idle = false; | |
1930 } | 1946 } |
1931 | 1947 |
1932 // It's not critical if some cases where memory usage can change are missed, | 1948 // It's not critical if some cases where memory usage can change are missed, |
1933 // since media memory changes are usually gradual. | 1949 // since media memory changes are usually gradual. |
1934 result.is_memory_reporting_enabled = | 1950 result.is_memory_reporting_enabled = |
1935 can_play && !result.is_suspended && !paused_; | 1951 can_play && !result.is_suspended && (!paused_ || seeking_); |
1936 | 1952 |
1937 return result; | 1953 return result; |
1938 } | 1954 } |
1939 | 1955 |
1940 void WebMediaPlayerImpl::ReportMemoryUsage() { | 1956 void WebMediaPlayerImpl::ReportMemoryUsage() { |
1941 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1957 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1942 | 1958 |
1943 // About base::Unretained() usage below: We destroy |demuxer_| on the main | 1959 // About base::Unretained() usage below: We destroy |demuxer_| on the main |
1944 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the | 1960 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the |
1945 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task | 1961 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2011 this, &WebMediaPlayerImpl::OnPause); | 2027 this, &WebMediaPlayerImpl::OnPause); |
2012 } | 2028 } |
2013 | 2029 |
2014 void WebMediaPlayerImpl::CreateWatchTimeReporter() { | 2030 void WebMediaPlayerImpl::CreateWatchTimeReporter() { |
2015 // Create the watch time reporter and synchronize its initial state. | 2031 // Create the watch time reporter and synchronize its initial state. |
2016 watch_time_reporter_.reset(new WatchTimeReporter( | 2032 watch_time_reporter_.reset(new WatchTimeReporter( |
2017 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, | 2033 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, |
2018 pipeline_metadata_.natural_size, | 2034 pipeline_metadata_.natural_size, |
2019 base::Bind(&GetCurrentTimeInternal, this))); | 2035 base::Bind(&GetCurrentTimeInternal, this))); |
2020 watch_time_reporter_->OnVolumeChange(volume_); | 2036 watch_time_reporter_->OnVolumeChange(volume_); |
2021 if (IsHidden()) | 2037 if (delegate_ && delegate_->IsFrameHidden()) |
2022 watch_time_reporter_->OnHidden(); | 2038 watch_time_reporter_->OnHidden(); |
2023 else | 2039 else |
2024 watch_time_reporter_->OnShown(); | 2040 watch_time_reporter_->OnShown(); |
2025 } | 2041 } |
2026 | 2042 |
2027 bool WebMediaPlayerImpl::IsHidden() const { | 2043 bool WebMediaPlayerImpl::IsHidden() const { |
2028 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 2044 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
2029 | 2045 |
2030 return delegate_ && delegate_->IsHidden(); | 2046 return delegate_ && delegate_->IsFrameHidden() && !delegate_->IsFrameClosed(); |
2031 } | 2047 } |
2032 | 2048 |
2033 bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const { | 2049 bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const { |
2034 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; | 2050 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; |
2035 } | 2051 } |
2036 | 2052 |
2037 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { | 2053 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { |
2038 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 2054 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
2039 | 2055 |
2040 client_->activateViewportIntersectionMonitoring(activate); | 2056 client_->activateViewportIntersectionMonitoring(activate); |
2041 } | 2057 } |
2042 | 2058 |
2043 } // namespace media | 2059 } // namespace media |
OLD | NEW |