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

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

Issue 2289543005: Allow suspension prior to reaching kHaveFutureData. (Closed)
Patch Set: Fix pause timer. Created 4 years, 3 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
« no previous file with comments | « media/blink/webmediaplayer_impl.h ('k') | media/blink/webmediaplayer_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 736 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 // TODO(dalecurtis): Technically this allows seeking on media which return an 747 // TODO(dalecurtis): Technically this allows seeking on media which return an
748 // infinite duration so long as DataSource::IsStreaming() is false. While not 748 // infinite duration so long as DataSource::IsStreaming() is false. While not
749 // expected, disabling this breaks semi-live players, http://crbug.com/427412. 749 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
750 const blink::WebTimeRange seekable_range( 750 const blink::WebTimeRange seekable_range(
751 0.0, allow_seek_to_zero ? 0.0 : seekable_end); 751 0.0, allow_seek_to_zero ? 0.0 : seekable_end);
752 return blink::WebTimeRanges(&seekable_range, 1); 752 return blink::WebTimeRanges(&seekable_range, 1);
753 } 753 }
754 754
755 bool WebMediaPlayerImpl::didLoadingProgress() { 755 bool WebMediaPlayerImpl::didLoadingProgress() {
756 DCHECK(main_task_runner_->BelongsToCurrentThread()); 756 DCHECK(main_task_runner_->BelongsToCurrentThread());
757 bool pipeline_progress = pipeline_.DidLoadingProgress(); 757
758 bool data_progress = buffered_data_source_host_.DidLoadingProgress(); 758 // Note: Separate variables used to ensure both methods are called every time.
759 return pipeline_progress || data_progress; 759 const bool pipeline_progress = pipeline_.DidLoadingProgress();
760 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
761 const bool did_loading_progress = pipeline_progress || data_progress;
762
763 // If we've idle suspended before reaching kHaveFutureData and loading has
764 // progressed we need to spin up the renderer and figure out if we have enough
765 // data yet; |client_| may be waiting on this signal to trigger playback. The
766 // idle timeout is long enough that this is a low-cost operation.
767 if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData &&
768 pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) {
769 is_idle_ = false;
770 UpdatePlayState();
771 }
772
773 return did_loading_progress;
760 } 774 }
761 775
762 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas, 776 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
763 const blink::WebRect& rect, 777 const blink::WebRect& rect,
764 unsigned char alpha, 778 unsigned char alpha,
765 SkXfermode::Mode mode) { 779 SkXfermode::Mode mode) {
766 DCHECK(main_task_runner_->BelongsToCurrentThread()); 780 DCHECK(main_task_runner_->BelongsToCurrentThread());
767 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); 781 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
768 782
769 if (is_cdm_attached_) 783 if (is_cdm_attached_)
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1233 1247
1234 must_suspend_ = false; 1248 must_suspend_ = false;
1235 background_pause_timer_.Stop(); 1249 background_pause_timer_.Stop();
1236 1250
1237 UpdatePlayState(); 1251 UpdatePlayState();
1238 } 1252 }
1239 1253
1240 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { 1254 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
1241 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1255 DCHECK(main_task_runner_->BelongsToCurrentThread());
1242 1256
1243 if (must_suspend) { 1257 if (must_suspend)
1244 must_suspend_ = true; 1258 must_suspend_ = true;
1245 } else { 1259 else
1246 // TODO(sandersd): Remove this when idleness is separate from play state.
1247 if (delegate_state_ == DelegateState::PAUSED_BUT_NOT_IDLE)
1248 return;
1249 is_idle_ = true; 1260 is_idle_ = true;
1250 }
1251 1261
1252 UpdatePlayState(); 1262 UpdatePlayState();
1253 } 1263 }
1254 1264
1255 void WebMediaPlayerImpl::OnPlay() { 1265 void WebMediaPlayerImpl::OnPlay() {
1256 play(); 1266 play();
1257 client_->playbackStateChanged(); 1267 client_->playbackStateChanged();
1258 } 1268 }
1259 1269
1260 void WebMediaPlayerImpl::OnPause() { 1270 void WebMediaPlayerImpl::OnPause() {
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1560 bool is_backgrounded = 1570 bool is_backgrounded =
1561 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden(); 1571 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden();
1562 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended, 1572 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended,
1563 is_backgrounded); 1573 is_backgrounded);
1564 SetDelegateState(state.delegate_state); 1574 SetDelegateState(state.delegate_state);
1565 SetMemoryReportingState(state.is_memory_reporting_enabled); 1575 SetMemoryReportingState(state.is_memory_reporting_enabled);
1566 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); 1576 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1567 } 1577 }
1568 1578
1569 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { 1579 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
1570 if (!delegate_ || delegate_state_ == new_state) 1580 if (!delegate_)
1581 return;
1582
1583 // Dedupe state changes in the general case, but make an exception for gone
1584 // since the delegate will use that information to decide when the idle timer
1585 // should be fired.
1586 if (delegate_state_ == new_state && new_state != DelegateState::GONE)
1571 return; 1587 return;
1572 1588
1573 delegate_state_ = new_state; 1589 delegate_state_ = new_state;
1574 1590
1575 switch (delegate_state_) { 1591 switch (delegate_state_) {
1576 case DelegateState::GONE: 1592 case DelegateState::GONE:
1577 delegate_->PlayerGone(delegate_id_); 1593 delegate_->PlayerGone(delegate_id_);
1578 break; 1594 break;
1579 case DelegateState::PLAYING: 1595 case DelegateState::PLAYING:
1580 delegate_->DidPlay( 1596 delegate_->DidPlay(
1581 delegate_id_, hasVideo(), hasAudio(), false, 1597 delegate_id_, hasVideo(), hasAudio(), false,
1582 media::DurationToMediaContentType(pipeline_.GetMediaDuration())); 1598 media::DurationToMediaContentType(pipeline_.GetMediaDuration()));
1583 break; 1599 break;
1584 case DelegateState::PAUSED: 1600 case DelegateState::PAUSED:
1585 delegate_->DidPause(delegate_id_, false); 1601 delegate_->DidPause(delegate_id_, false);
1586 break; 1602 break;
1587 case DelegateState::PAUSED_BUT_NOT_IDLE:
1588 // It doesn't really matter what happens when we enter this state, only
1589 // that we reset the idle timer when leaving it.
1590 //
1591 // TODO(sandersd): Ideally the delegate would consider idleness and play
1592 // state as orthogonal properties so that we could avoid this.
1593 delegate_->DidPause(delegate_id_, false);
1594 break;
1595 case DelegateState::ENDED: 1603 case DelegateState::ENDED:
1596 delegate_->DidPause(delegate_id_, true); 1604 delegate_->DidPause(delegate_id_, true);
1597 break; 1605 break;
1598 } 1606 }
1599 } 1607 }
1600 1608
1601 void WebMediaPlayerImpl::SetMemoryReportingState( 1609 void WebMediaPlayerImpl::SetMemoryReportingState(
1602 bool is_memory_reporting_enabled) { 1610 bool is_memory_reporting_enabled) {
1603 if (memory_usage_reporting_timer_.IsRunning() == 1611 if (memory_usage_reporting_timer_.IsRunning() ==
1604 is_memory_reporting_enabled) { 1612 is_memory_reporting_enabled) {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1671 // though in the case of audio-only the session should be kept. 1679 // though in the case of audio-only the session should be kept.
1672 // Videos are not suspended if the user resumed the playback via the remote 1680 // Videos are not suspended if the user resumed the playback via the remote
1673 // controls earlier and it's still playing. 1681 // controls earlier and it's still playing.
1674 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo(); 1682 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
1675 bool can_play_backgrounded = is_backgrounded_video && !is_remote && 1683 bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
1676 hasAudio() && IsResumeBackgroundVideosEnabled(); 1684 hasAudio() && IsResumeBackgroundVideosEnabled();
1677 bool is_background_playing = 1685 bool is_background_playing =
1678 delegate_ && delegate_->IsPlayingBackgroundVideo(); 1686 delegate_ && delegate_->IsPlayingBackgroundVideo();
1679 bool background_suspended = is_backgrounded_video && 1687 bool background_suspended = is_backgrounded_video &&
1680 !(can_play_backgrounded && is_background_playing); 1688 !(can_play_backgrounded && is_background_playing);
1689 bool background_pause_suspended = is_backgrounded && paused_;
1681 1690
1682 // The |paused_| state is not reliable until we |have_future_data|.
1683 bool background_pause_suspended =
1684 is_backgrounded && have_future_data && paused_;
1685
1686 // Idle suspend is enabled once there is future data. We don't want to idle
1687 // suspend before that because play() may never be triggered to leave the idle
1688 // state. There could be other theoretical problems if the page is waiting for
1689 // other events before actually calling play(), but at least we don't break
1690 // Blink.
1691 //
1692 // TODO(sandersd): Make the delegate suspend idle players immediately when 1691 // TODO(sandersd): Make the delegate suspend idle players immediately when
1693 // hidden. 1692 // hidden.
1694 // TODO(sandersd): If Blink told us the paused state sooner, we could 1693 bool idle_suspended = is_idle_ && paused_ && !seeking_ && !overlay_enabled_;
1695 // idle suspend sooner. 1694
1696 bool idle_suspended = is_idle_ && have_future_data; 1695 // If we're already suspended, see if we can wait for user interaction. Prior
1696 // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_|
1697 // will be cleared when we receive data which may take us to HaveFutureData.
1698 bool can_stay_suspended =
1699 (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_;
1697 1700
1698 // Combined suspend state. 1701 // Combined suspend state.
1699 result.is_suspended = 1702 result.is_suspended = is_remote || must_suspend_ || idle_suspended ||
1700 is_remote || must_suspend_ || idle_suspended || background_suspended || 1703 background_suspended || background_pause_suspended ||
1701 background_pause_suspended || 1704 can_stay_suspended;
1702 // If we're already suspended, see if we can wait for user interaction.
1703 (is_suspended && have_future_data && paused_ && !seeking_);
1704 1705
1705 // We do not treat |playback_rate_| == 0 as paused. For the media session, 1706 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1706 // being paused implies displaying a play button, which is incorrect in this 1707 // being paused implies displaying a play button, which is incorrect in this
1707 // case. For memory usage reporting, we just use the same definition (but we 1708 // case. For memory usage reporting, we just use the same definition (but we
1708 // don't have to). 1709 // don't have to).
1709 // 1710 //
1710 // Similarly, we don't consider |ended_| to be paused. Blink will immediately 1711 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1711 // call pause() or seek(), so |ended_| should not affect the computation. 1712 // call pause() or seek(), so |ended_| should not affect the computation.
1712 // Despite that, |ended_| does result in a separate paused state, to simplfy 1713 // Despite that, |ended_| does result in a separate paused state, to simplfy
1713 // the contract for SetDelegateState(). 1714 // the contract for SetDelegateState().
(...skipping 15 matching lines...) Expand all
1729 // element point of view but paused and can be resumed from the delegate point 1730 // element point of view but paused and can be resumed from the delegate point
1730 // of view. Therefore it behaves like |paused_| for the delegate. 1731 // of view. Therefore it behaves like |paused_| for the delegate.
1731 bool has_session_suspended = can_play && !must_suspend_ && 1732 bool has_session_suspended = can_play && !must_suspend_ &&
1732 background_suspended && can_play_backgrounded; 1733 background_suspended && can_play_backgrounded;
1733 1734
1734 bool has_session = has_session_playing || has_session_suspended; 1735 bool has_session = has_session_playing || has_session_suspended;
1735 1736
1736 if (!has_session) { 1737 if (!has_session) {
1737 result.delegate_state = DelegateState::GONE; 1738 result.delegate_state = DelegateState::GONE;
1738 } else if (paused_ || has_session_suspended) { 1739 } else if (paused_ || has_session_suspended) {
1739 if (seeking() || overlay_enabled_) { 1740 result.delegate_state =
1740 result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE; 1741 ended_ ? DelegateState::ENDED : DelegateState::PAUSED;
1741 } else if (ended_) {
1742 result.delegate_state = DelegateState::ENDED;
1743 } else {
1744 result.delegate_state = DelegateState::PAUSED;
1745 }
1746 } else { 1742 } else {
1747 result.delegate_state = DelegateState::PLAYING; 1743 result.delegate_state = DelegateState::PLAYING;
1748 } 1744 }
1749 1745
1750 // It's not critical if some cases where memory usage can change are missed, 1746 // It's not critical if some cases where memory usage can change are missed,
1751 // since media memory changes are usually gradual. 1747 // since media memory changes are usually gradual.
1752 result.is_memory_reporting_enabled = 1748 result.is_memory_reporting_enabled =
1753 can_play && !result.is_suspended && !paused_; 1749 can_play && !result.is_suspended && !paused_;
1754 1750
1755 return result; 1751 return result;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1789 << ", Video: " << stats.video_memory_usage << ", DataSource: " 1785 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1790 << (data_source_ ? data_source_->GetMemoryUsage() : 0) 1786 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
1791 << ", Demuxer: " << demuxer_memory_usage; 1787 << ", Demuxer: " << demuxer_memory_usage;
1792 1788
1793 const int64_t delta = current_memory_usage - last_reported_memory_usage_; 1789 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1794 last_reported_memory_usage_ = current_memory_usage; 1790 last_reported_memory_usage_ = current_memory_usage;
1795 adjust_allocated_memory_cb_.Run(delta); 1791 adjust_allocated_memory_cb_.Run(delta);
1796 } 1792 }
1797 1793
1798 void WebMediaPlayerImpl::ScheduleIdlePauseTimer() { 1794 void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
1799 // Only schedule the pause timer if we're playing and are suspended. We use 1795 // Only schedule the pause timer if we're playing and are suspended.
1800 // delegate state as a proxy for suspended here since the suspension may be in 1796 if (paused_ || !pipeline_controller_.IsSuspended())
1801 // flight at the time of this call.
1802 if (paused_ || delegate_state_ != DelegateState::GONE)
1803 return; 1797 return;
1804 1798
1805 #if defined(OS_ANDROID) 1799 #if defined(OS_ANDROID)
1806 // Remote players will be suspended and locally paused. 1800 // Remote players will be suspended and locally paused.
1807 if (isRemote()) 1801 if (isRemote())
1808 return; 1802 return;
1809 #endif 1803 #endif
1810 1804
1811 // Idle timeout chosen arbitrarily. 1805 // Idle timeout chosen arbitrarily.
1812 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), 1806 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
1813 this, &WebMediaPlayerImpl::OnPause); 1807 this, &WebMediaPlayerImpl::OnPause);
1814 } 1808 }
1815 1809
1816 void WebMediaPlayerImpl::CreateWatchTimeReporter() { 1810 void WebMediaPlayerImpl::CreateWatchTimeReporter() {
1817 // Create the watch time reporter and synchronize its initial state. 1811 // Create the watch time reporter and synchronize its initial state.
1818 watch_time_reporter_.reset(new WatchTimeReporter( 1812 watch_time_reporter_.reset(new WatchTimeReporter(
1819 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, 1813 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_,
1820 pipeline_metadata_.natural_size, 1814 pipeline_metadata_.natural_size,
1821 base::Bind(&GetCurrentTimeInternal, this))); 1815 base::Bind(&GetCurrentTimeInternal, this)));
1822 watch_time_reporter_->OnVolumeChange(volume_); 1816 watch_time_reporter_->OnVolumeChange(volume_);
1823 if (delegate_ && delegate_->IsHidden()) 1817 if (delegate_ && delegate_->IsHidden())
1824 watch_time_reporter_->OnHidden(); 1818 watch_time_reporter_->OnHidden();
1825 else 1819 else
1826 watch_time_reporter_->OnShown(); 1820 watch_time_reporter_->OnShown();
1827 } 1821 }
1828 1822
1829 } // namespace media 1823 } // namespace media
OLDNEW
« no previous file with comments | « media/blink/webmediaplayer_impl.h ('k') | media/blink/webmediaplayer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698