| 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 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 // TODO(dalecurtis): Technically this allows seeking on media which return an | 742 // TODO(dalecurtis): Technically this allows seeking on media which return an |
| 743 // infinite duration so long as DataSource::IsStreaming() is false. While not | 743 // infinite duration so long as DataSource::IsStreaming() is false. While not |
| 744 // expected, disabling this breaks semi-live players, http://crbug.com/427412. | 744 // expected, disabling this breaks semi-live players, http://crbug.com/427412. |
| 745 const blink::WebTimeRange seekable_range( | 745 const blink::WebTimeRange seekable_range( |
| 746 0.0, allow_seek_to_zero ? 0.0 : seekable_end); | 746 0.0, allow_seek_to_zero ? 0.0 : seekable_end); |
| 747 return blink::WebTimeRanges(&seekable_range, 1); | 747 return blink::WebTimeRanges(&seekable_range, 1); |
| 748 } | 748 } |
| 749 | 749 |
| 750 bool WebMediaPlayerImpl::didLoadingProgress() { | 750 bool WebMediaPlayerImpl::didLoadingProgress() { |
| 751 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 751 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 752 bool pipeline_progress = pipeline_.DidLoadingProgress(); | 752 |
| 753 bool data_progress = buffered_data_source_host_.DidLoadingProgress(); | 753 // Note: Separate variables used to ensure both methods are called every time. |
| 754 return pipeline_progress || data_progress; | 754 const bool pipeline_progress = pipeline_.DidLoadingProgress(); |
| 755 const bool data_progress = buffered_data_source_host_.DidLoadingProgress(); |
| 756 const bool did_loading_progress = pipeline_progress || data_progress; |
| 757 |
| 758 // If we've idle suspended before reaching kHaveFutureData and loading has |
| 759 // progressed we need to spin up the renderer and figure out if we have enough |
| 760 // data yet; |client_| may be waiting on this signal to trigger playback. The |
| 761 // idle timeout is long enough that this is a low-cost operation. |
| 762 if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData && |
| 763 pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) { |
| 764 is_idle_ = false; |
| 765 UpdatePlayState(); |
| 766 } |
| 767 |
| 768 return did_loading_progress; |
| 755 } | 769 } |
| 756 | 770 |
| 757 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas, | 771 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas, |
| 758 const blink::WebRect& rect, | 772 const blink::WebRect& rect, |
| 759 unsigned char alpha, | 773 unsigned char alpha, |
| 760 SkXfermode::Mode mode) { | 774 SkXfermode::Mode mode) { |
| 761 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 775 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 762 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); | 776 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); |
| 763 | 777 |
| 764 if (is_cdm_attached_) | 778 if (is_cdm_attached_) |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 | 1218 |
| 1205 must_suspend_ = false; | 1219 must_suspend_ = false; |
| 1206 background_pause_timer_.Stop(); | 1220 background_pause_timer_.Stop(); |
| 1207 | 1221 |
| 1208 UpdatePlayState(); | 1222 UpdatePlayState(); |
| 1209 } | 1223 } |
| 1210 | 1224 |
| 1211 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { | 1225 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { |
| 1212 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1226 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1213 | 1227 |
| 1214 if (must_suspend) { | 1228 if (must_suspend) |
| 1215 must_suspend_ = true; | 1229 must_suspend_ = true; |
| 1216 } else { | 1230 else |
| 1217 // TODO(sandersd): Remove this when idleness is separate from play state. | |
| 1218 if (delegate_state_ == DelegateState::PAUSED_BUT_NOT_IDLE) | |
| 1219 return; | |
| 1220 is_idle_ = true; | 1231 is_idle_ = true; |
| 1221 } | |
| 1222 | 1232 |
| 1223 UpdatePlayState(); | 1233 UpdatePlayState(); |
| 1224 } | 1234 } |
| 1225 | 1235 |
| 1226 void WebMediaPlayerImpl::OnPlay() { | 1236 void WebMediaPlayerImpl::OnPlay() { |
| 1227 play(); | 1237 play(); |
| 1228 client_->playbackStateChanged(); | 1238 client_->playbackStateChanged(); |
| 1229 } | 1239 } |
| 1230 | 1240 |
| 1231 void WebMediaPlayerImpl::OnPause() { | 1241 void WebMediaPlayerImpl::OnPause() { |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 bool is_backgrounded = | 1541 bool is_backgrounded = |
| 1532 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden(); | 1542 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden(); |
| 1533 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended, | 1543 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended, |
| 1534 is_backgrounded); | 1544 is_backgrounded); |
| 1535 SetDelegateState(state.delegate_state); | 1545 SetDelegateState(state.delegate_state); |
| 1536 SetMemoryReportingState(state.is_memory_reporting_enabled); | 1546 SetMemoryReportingState(state.is_memory_reporting_enabled); |
| 1537 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); | 1547 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); |
| 1538 } | 1548 } |
| 1539 | 1549 |
| 1540 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { | 1550 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { |
| 1541 if (!delegate_ || delegate_state_ == new_state) | 1551 if (!delegate_) |
| 1552 return; |
| 1553 |
| 1554 // Dedupe state changes in the general case, but make an exception for gone |
| 1555 // since the delegate will use that information to decide when the idle timer |
| 1556 // should be fired. |
| 1557 if (delegate_state_ == new_state && new_state != DelegateState::GONE) |
| 1542 return; | 1558 return; |
| 1543 | 1559 |
| 1544 delegate_state_ = new_state; | 1560 delegate_state_ = new_state; |
| 1545 | 1561 |
| 1546 switch (delegate_state_) { | 1562 switch (delegate_state_) { |
| 1547 case DelegateState::GONE: | 1563 case DelegateState::GONE: |
| 1548 delegate_->PlayerGone(delegate_id_); | 1564 delegate_->PlayerGone(delegate_id_); |
| 1549 break; | 1565 break; |
| 1550 case DelegateState::PLAYING: | 1566 case DelegateState::PLAYING: |
| 1551 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1567 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
| 1552 pipeline_.GetMediaDuration()); | 1568 pipeline_.GetMediaDuration()); |
| 1553 break; | 1569 break; |
| 1554 case DelegateState::PAUSED: | 1570 case DelegateState::PAUSED: |
| 1555 delegate_->DidPause(delegate_id_, false); | 1571 delegate_->DidPause(delegate_id_, false); |
| 1556 break; | 1572 break; |
| 1557 case DelegateState::PAUSED_BUT_NOT_IDLE: | |
| 1558 // It doesn't really matter what happens when we enter this state, only | |
| 1559 // that we reset the idle timer when leaving it. | |
| 1560 // | |
| 1561 // TODO(sandersd): Ideally the delegate would consider idleness and play | |
| 1562 // state as orthogonal properties so that we could avoid this. | |
| 1563 delegate_->DidPause(delegate_id_, false); | |
| 1564 break; | |
| 1565 case DelegateState::ENDED: | 1573 case DelegateState::ENDED: |
| 1566 delegate_->DidPause(delegate_id_, true); | 1574 delegate_->DidPause(delegate_id_, true); |
| 1567 break; | 1575 break; |
| 1568 } | 1576 } |
| 1569 } | 1577 } |
| 1570 | 1578 |
| 1571 void WebMediaPlayerImpl::SetMemoryReportingState( | 1579 void WebMediaPlayerImpl::SetMemoryReportingState( |
| 1572 bool is_memory_reporting_enabled) { | 1580 bool is_memory_reporting_enabled) { |
| 1573 if (memory_usage_reporting_timer_.IsRunning() == | 1581 if (memory_usage_reporting_timer_.IsRunning() == |
| 1574 is_memory_reporting_enabled) { | 1582 is_memory_reporting_enabled) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1641 // though in the case of audio-only the session should be kept. | 1649 // though in the case of audio-only the session should be kept. |
| 1642 // Videos are not suspended if the user resumed the playback via the remote | 1650 // Videos are not suspended if the user resumed the playback via the remote |
| 1643 // controls earlier and it's still playing. | 1651 // controls earlier and it's still playing. |
| 1644 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo(); | 1652 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo(); |
| 1645 bool can_play_backgrounded = is_backgrounded_video && !is_remote && | 1653 bool can_play_backgrounded = is_backgrounded_video && !is_remote && |
| 1646 hasAudio() && IsResumeBackgroundVideosEnabled(); | 1654 hasAudio() && IsResumeBackgroundVideosEnabled(); |
| 1647 bool is_background_playing = | 1655 bool is_background_playing = |
| 1648 delegate_ && delegate_->IsPlayingBackgroundVideo(); | 1656 delegate_ && delegate_->IsPlayingBackgroundVideo(); |
| 1649 bool background_suspended = is_backgrounded_video && | 1657 bool background_suspended = is_backgrounded_video && |
| 1650 !(can_play_backgrounded && is_background_playing); | 1658 !(can_play_backgrounded && is_background_playing); |
| 1659 bool background_pause_suspended = is_backgrounded && paused_; |
| 1651 | 1660 |
| 1652 // The |paused_| state is not reliable until we |have_future_data|. | |
| 1653 bool background_pause_suspended = | |
| 1654 is_backgrounded && have_future_data && paused_; | |
| 1655 | |
| 1656 // Idle suspend is enabled once there is future data. We don't want to idle | |
| 1657 // suspend before that because play() may never be triggered to leave the idle | |
| 1658 // state. There could be other theoretical problems if the page is waiting for | |
| 1659 // other events before actually calling play(), but at least we don't break | |
| 1660 // Blink. | |
| 1661 // | |
| 1662 // TODO(sandersd): Make the delegate suspend idle players immediately when | 1661 // TODO(sandersd): Make the delegate suspend idle players immediately when |
| 1663 // hidden. | 1662 // hidden. |
| 1664 // TODO(sandersd): If Blink told us the paused state sooner, we could | 1663 bool idle_suspended = is_idle_ && paused_ && !seeking_ && !overlay_enabled_; |
| 1665 // idle suspend sooner. | 1664 |
| 1666 bool idle_suspended = is_idle_ && have_future_data; | 1665 // If we're already suspended, see if we can wait for user interaction. Prior |
| 1666 // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_| |
| 1667 // will be cleared when we receive data which may take us to HaveFutureData. |
| 1668 bool can_stay_suspended = |
| 1669 (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_; |
| 1667 | 1670 |
| 1668 // Combined suspend state. | 1671 // Combined suspend state. |
| 1669 result.is_suspended = | 1672 result.is_suspended = is_remote || must_suspend_ || idle_suspended || |
| 1670 is_remote || must_suspend_ || idle_suspended || background_suspended || | 1673 background_suspended || background_pause_suspended || |
| 1671 background_pause_suspended || | 1674 can_stay_suspended; |
| 1672 // If we're already suspended, see if we can wait for user interaction. | |
| 1673 (is_suspended && have_future_data && paused_ && !seeking_); | |
| 1674 | 1675 |
| 1675 // We do not treat |playback_rate_| == 0 as paused. For the media session, | 1676 // We do not treat |playback_rate_| == 0 as paused. For the media session, |
| 1676 // being paused implies displaying a play button, which is incorrect in this | 1677 // being paused implies displaying a play button, which is incorrect in this |
| 1677 // case. For memory usage reporting, we just use the same definition (but we | 1678 // case. For memory usage reporting, we just use the same definition (but we |
| 1678 // don't have to). | 1679 // don't have to). |
| 1679 // | 1680 // |
| 1680 // Similarly, we don't consider |ended_| to be paused. Blink will immediately | 1681 // Similarly, we don't consider |ended_| to be paused. Blink will immediately |
| 1681 // call pause() or seek(), so |ended_| should not affect the computation. | 1682 // call pause() or seek(), so |ended_| should not affect the computation. |
| 1682 // Despite that, |ended_| does result in a separate paused state, to simplfy | 1683 // Despite that, |ended_| does result in a separate paused state, to simplfy |
| 1683 // the contract for SetDelegateState(). | 1684 // the contract for SetDelegateState(). |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1699 // element point of view but paused and can be resumed from the delegate point | 1700 // element point of view but paused and can be resumed from the delegate point |
| 1700 // of view. Therefore it behaves like |paused_| for the delegate. | 1701 // of view. Therefore it behaves like |paused_| for the delegate. |
| 1701 bool has_session_suspended = can_play && !must_suspend_ && | 1702 bool has_session_suspended = can_play && !must_suspend_ && |
| 1702 background_suspended && can_play_backgrounded; | 1703 background_suspended && can_play_backgrounded; |
| 1703 | 1704 |
| 1704 bool has_session = has_session_playing || has_session_suspended; | 1705 bool has_session = has_session_playing || has_session_suspended; |
| 1705 | 1706 |
| 1706 if (!has_session) { | 1707 if (!has_session) { |
| 1707 result.delegate_state = DelegateState::GONE; | 1708 result.delegate_state = DelegateState::GONE; |
| 1708 } else if (paused_ || has_session_suspended) { | 1709 } else if (paused_ || has_session_suspended) { |
| 1709 if (seeking() || overlay_enabled_) { | 1710 result.delegate_state = |
| 1710 result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE; | 1711 ended_ ? DelegateState::ENDED : DelegateState::PAUSED; |
| 1711 } else if (ended_) { | |
| 1712 result.delegate_state = DelegateState::ENDED; | |
| 1713 } else { | |
| 1714 result.delegate_state = DelegateState::PAUSED; | |
| 1715 } | |
| 1716 } else { | 1712 } else { |
| 1717 result.delegate_state = DelegateState::PLAYING; | 1713 result.delegate_state = DelegateState::PLAYING; |
| 1718 } | 1714 } |
| 1719 | 1715 |
| 1720 // It's not critical if some cases where memory usage can change are missed, | 1716 // It's not critical if some cases where memory usage can change are missed, |
| 1721 // since media memory changes are usually gradual. | 1717 // since media memory changes are usually gradual. |
| 1722 result.is_memory_reporting_enabled = | 1718 result.is_memory_reporting_enabled = |
| 1723 can_play && !result.is_suspended && !paused_; | 1719 can_play && !result.is_suspended && !paused_; |
| 1724 | 1720 |
| 1725 return result; | 1721 return result; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1759 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1755 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
| 1760 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1756 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
| 1761 << ", Demuxer: " << demuxer_memory_usage; | 1757 << ", Demuxer: " << demuxer_memory_usage; |
| 1762 | 1758 |
| 1763 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1759 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
| 1764 last_reported_memory_usage_ = current_memory_usage; | 1760 last_reported_memory_usage_ = current_memory_usage; |
| 1765 adjust_allocated_memory_cb_.Run(delta); | 1761 adjust_allocated_memory_cb_.Run(delta); |
| 1766 } | 1762 } |
| 1767 | 1763 |
| 1768 void WebMediaPlayerImpl::ScheduleIdlePauseTimer() { | 1764 void WebMediaPlayerImpl::ScheduleIdlePauseTimer() { |
| 1769 // Only schedule the pause timer if we're playing and are suspended. We use | 1765 // Only schedule the pause timer if we're playing and are suspended. |
| 1770 // delegate state as a proxy for suspended here since the suspension may be in | 1766 if (paused_ || !pipeline_controller_.IsSuspended()) |
| 1771 // flight at the time of this call. | |
| 1772 if (paused_ || delegate_state_ != DelegateState::GONE) | |
| 1773 return; | 1767 return; |
| 1774 | 1768 |
| 1775 #if defined(OS_ANDROID) | 1769 #if defined(OS_ANDROID) |
| 1776 // Remote players will be suspended and locally paused. | 1770 // Remote players will be suspended and locally paused. |
| 1777 if (isRemote()) | 1771 if (isRemote()) |
| 1778 return; | 1772 return; |
| 1779 #endif | 1773 #endif |
| 1780 | 1774 |
| 1781 // Idle timeout chosen arbitrarily. | 1775 // Idle timeout chosen arbitrarily. |
| 1782 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), | 1776 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), |
| 1783 this, &WebMediaPlayerImpl::OnPause); | 1777 this, &WebMediaPlayerImpl::OnPause); |
| 1784 } | 1778 } |
| 1785 | 1779 |
| 1786 void WebMediaPlayerImpl::CreateWatchTimeReporter() { | 1780 void WebMediaPlayerImpl::CreateWatchTimeReporter() { |
| 1787 // Create the watch time reporter and synchronize its initial state. | 1781 // Create the watch time reporter and synchronize its initial state. |
| 1788 watch_time_reporter_.reset(new WatchTimeReporter( | 1782 watch_time_reporter_.reset(new WatchTimeReporter( |
| 1789 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, | 1783 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, |
| 1790 pipeline_metadata_.natural_size, | 1784 pipeline_metadata_.natural_size, |
| 1791 base::Bind(&GetCurrentTimeInternal, this))); | 1785 base::Bind(&GetCurrentTimeInternal, this))); |
| 1792 watch_time_reporter_->OnVolumeChange(volume_); | 1786 watch_time_reporter_->OnVolumeChange(volume_); |
| 1793 if (delegate_ && delegate_->IsHidden()) | 1787 if (delegate_ && delegate_->IsHidden()) |
| 1794 watch_time_reporter_->OnHidden(); | 1788 watch_time_reporter_->OnHidden(); |
| 1795 else | 1789 else |
| 1796 watch_time_reporter_->OnShown(); | 1790 watch_time_reporter_->OnShown(); |
| 1797 } | 1791 } |
| 1798 | 1792 |
| 1799 } // namespace media | 1793 } // namespace media |
| OLD | NEW |