| Index: content/browser/media/media_web_contents_observer.cc
|
| diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
|
| index c17a9ff23c32cc3674a1ce1bc44609e58ec7c75f..dc79efa14bbb9145f213da0fb9eeb4d2ec813e71 100644
|
| --- a/content/browser/media/media_web_contents_observer.cc
|
| +++ b/content/browser/media/media_web_contents_observer.cc
|
| @@ -8,6 +8,8 @@
|
| #include "base/stl_util.h"
|
| #include "content/browser/media/cdm/browser_cdm_manager.h"
|
| #include "content/browser/renderer_host/render_process_host_impl.h"
|
| +#include "content/browser/web_contents/web_contents_impl.h"
|
| +#include "content/common/frame_messages.h"
|
| #include "content/public/browser/render_frame_host.h"
|
| #include "content/public/browser/web_contents.h"
|
| #include "ipc/ipc_message_macros.h"
|
| @@ -20,23 +22,20 @@
|
|
|
| namespace content {
|
|
|
| -MediaWebContentsObserver::MediaWebContentsObserver(
|
| - WebContents* web_contents)
|
| - : WebContentsObserver(web_contents)
|
| -{
|
| -}
|
| +MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents)
|
| + : WebContentsObserver(web_contents) {}
|
|
|
| -MediaWebContentsObserver::~MediaWebContentsObserver() {
|
| -}
|
| +MediaWebContentsObserver::~MediaWebContentsObserver() {}
|
|
|
| void MediaWebContentsObserver::RenderFrameDeleted(
|
| RenderFrameHost* render_frame_host) {
|
| + ClearPowerSaveBlockers(render_frame_host);
|
| +
|
| #if defined(OS_ANDROID)
|
| - uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
|
| // Always destroy the media players before CDMs because we do not support
|
| // detaching CDMs from media players yet. See http://crbug.com/330324
|
| - media_player_managers_.erase(key);
|
| -#endif
|
| + media_player_managers_.erase(render_frame_host);
|
| +
|
| // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
|
| // and BrowserCdmManager all run on browser UI thread. So this call is okay.
|
| // In the future we need to support the case where MediaWebContentsObserver
|
| @@ -46,22 +45,212 @@ void MediaWebContentsObserver::RenderFrameDeleted(
|
| BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID());
|
| if (browser_cdm_manager)
|
| browser_cdm_manager->RenderFrameDeleted(render_frame_host->GetRoutingID());
|
| +#endif
|
| }
|
|
|
| -#if defined(OS_ANDROID)
|
| +void MediaWebContentsObserver::MaybeUpdateAudibleState(bool recently_audible) {
|
| + if (recently_audible) {
|
| + if (!audio_power_save_blocker_)
|
| + CreateAudioPowerSaveBlocker();
|
| + } else {
|
| + audio_power_save_blocker_.reset();
|
| + }
|
| +}
|
|
|
| bool MediaWebContentsObserver::OnMessageReceived(
|
| const IPC::Message& msg,
|
| RenderFrameHost* render_frame_host) {
|
| + if (OnMediaPlayerDelegateMessageReceived(msg, render_frame_host))
|
| + return true;
|
| +
|
| +#if defined(OS_ANDROID)
|
| if (OnMediaPlayerMessageReceived(msg, render_frame_host))
|
| return true;
|
|
|
| if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host))
|
| return true;
|
| +#endif
|
|
|
| return false;
|
| }
|
|
|
| +bool MediaWebContentsObserver::OnMediaPlayerDelegateMessageReceived(
|
| + const IPC::Message& msg,
|
| + RenderFrameHost* render_frame_host) {
|
| + bool handled = true;
|
| + // TODO(dalecurtis): These should no longer be FrameHostMsg.
|
| + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserver, msg,
|
| + render_frame_host)
|
| + IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
|
| + OnMediaPlayingNotification)
|
| + IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
|
| + OnMediaPausedNotification)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP()
|
| + return handled;
|
| +}
|
| +
|
| +void MediaWebContentsObserver::OnMediaPlayingNotification(
|
| + RenderFrameHost* render_frame_host,
|
| + int64_t player_cookie,
|
| + bool has_video,
|
| + bool has_audio,
|
| + bool is_remote) {
|
| + // Ignore the videos playing remotely and don't hold the wake lock for the
|
| + // screen. TODO(dalecurtis): Is this correct? It means observers will not
|
| + // receive play and pause messages.
|
| + if (is_remote)
|
| + return;
|
| +
|
| + const MediaPlayerId id(render_frame_host, player_cookie);
|
| + if (has_audio) {
|
| + AddMediaPlayerEntry(id, &active_audio_players_);
|
| +
|
| + // If we don't have audio stream monitoring, allocate the audio power save
|
| + // blocker here instead of during NotifyNavigationStateChanged().
|
| + if (!audio_power_save_blocker_ &&
|
| + !AudioStreamMonitor::monitoring_available()) {
|
| + CreateAudioPowerSaveBlocker();
|
| + }
|
| + }
|
| +
|
| + if (has_video) {
|
| + AddMediaPlayerEntry(id, &active_video_players_);
|
| +
|
| + // If we're not hidden and have just created a player, create a blocker.
|
| + if (!video_power_save_blocker_ &&
|
| + !static_cast<WebContentsImpl*>(web_contents())->IsHidden()) {
|
| + CreateVideoPowerSaveBlocker();
|
| + }
|
| + }
|
| +
|
| + // Notify observers of the new player.
|
| + DCHECK(has_audio || has_video);
|
| + static_cast<WebContentsImpl*>(web_contents())->MediaStartedPlaying(id);
|
| +}
|
| +
|
| +void MediaWebContentsObserver::OnMediaPausedNotification(
|
| + RenderFrameHost* render_frame_host,
|
| + int64_t player_cookie) {
|
| + const MediaPlayerId id(render_frame_host, player_cookie);
|
| + const bool removed_audio = RemoveMediaPlayerEntry(id, &active_audio_players_);
|
| + const bool removed_video = RemoveMediaPlayerEntry(id, &active_video_players_);
|
| + MaybeReleasePowerSaveBlockers();
|
| +
|
| + if (removed_audio || removed_video) {
|
| + // Notify observers the player has been "paused".
|
| + static_cast<WebContentsImpl*>(web_contents())->MediaStoppedPlaying(id);
|
| + }
|
| +}
|
| +
|
| +void MediaWebContentsObserver::ClearPowerSaveBlockers(
|
| + RenderFrameHost* render_frame_host) {
|
| + std::set<MediaPlayerId> removed_players;
|
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_,
|
| + &removed_players);
|
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_,
|
| + &removed_players);
|
| + MaybeReleasePowerSaveBlockers();
|
| +
|
| + // Notify all observers the player has been "paused".
|
| + WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents());
|
| + for (const auto& id : removed_players)
|
| + wci->MediaStoppedPlaying(id);
|
| +}
|
| +
|
| +void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() {
|
| + DCHECK(!audio_power_save_blocker_);
|
| + audio_power_save_blocker_ = PowerSaveBlocker::Create(
|
| + PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
|
| + PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
|
| +}
|
| +
|
| +void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() {
|
| + DCHECK(!video_power_save_blocker_);
|
| + DCHECK(!active_video_players_.empty());
|
| + video_power_save_blocker_ = PowerSaveBlocker::Create(
|
| + PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
|
| + PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
|
| +// TODO(mfomitchev): Support PowerSaveBlocker on Aura - crbug.com/546718.
|
| +#if defined(OS_ANDROID) && !defined(USE_AURA)
|
| + static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
|
| + ->InitDisplaySleepBlocker(web_contents());
|
| +#endif
|
| +}
|
| +
|
| +void MediaWebContentsObserver::WasShown() {
|
| + // Restore power save blocker if there are active video players running.
|
| + if (!active_video_players_.empty() && !video_power_save_blocker_)
|
| + CreateVideoPowerSaveBlocker();
|
| +}
|
| +
|
| +void MediaWebContentsObserver::WasHidden() {
|
| + // If there are entities capturing screenshots or video (e.g., mirroring),
|
| + // don't release the power save blocker.
|
| + if (!web_contents()->GetCapturerCount())
|
| + video_power_save_blocker_.reset();
|
| +}
|
| +
|
| +void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() {
|
| + // If there are no more audio players and we don't have audio stream
|
| + // monitoring, release the audio power save blocker here instead of during
|
| + // NotifyNavigationStateChanged().
|
| + if (active_audio_players_.empty() &&
|
| + !AudioStreamMonitor::monitoring_available()) {
|
| + audio_power_save_blocker_.reset();
|
| + }
|
| +
|
| + // If there are no more video players, clear the video power save blocker.
|
| + if (active_video_players_.empty())
|
| + video_power_save_blocker_.reset();
|
| +}
|
| +
|
| +void MediaWebContentsObserver::AddMediaPlayerEntry(
|
| + const MediaPlayerId& id,
|
| + ActiveMediaPlayerMap* player_map) {
|
| + DCHECK(std::find((*player_map)[id.first].begin(),
|
| + (*player_map)[id.first].end(),
|
| + id.second) == (*player_map)[id.first].end());
|
| + (*player_map)[id.first].push_back(id.second);
|
| +}
|
| +
|
| +bool MediaWebContentsObserver::RemoveMediaPlayerEntry(
|
| + const MediaPlayerId& id,
|
| + ActiveMediaPlayerMap* player_map) {
|
| + auto it = player_map->find(id.first);
|
| + if (it == player_map->end())
|
| + return false;
|
| +
|
| + // Remove the player.
|
| + auto player_for_removal =
|
| + std::remove(it->second.begin(), it->second.end(), id.second);
|
| + if (player_for_removal == it->second.end())
|
| + return false;
|
| + it->second.erase(player_for_removal);
|
| +
|
| + // If there are no players left, remove the map entry.
|
| + if (it->second.empty())
|
| + player_map->erase(it);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void MediaWebContentsObserver::RemoveAllMediaPlayerEntries(
|
| + RenderFrameHost* render_frame_host,
|
| + ActiveMediaPlayerMap* player_map,
|
| + std::set<MediaPlayerId>* removed_players) {
|
| + auto it = player_map->find(render_frame_host);
|
| + if (it == player_map->end())
|
| + return;
|
| +
|
| + for (int64_t player_cookie : it->second)
|
| + removed_players->insert(MediaPlayerId(render_frame_host, player_cookie));
|
| +
|
| + player_map->erase(it);
|
| +}
|
| +
|
| +#if defined(OS_ANDROID)
|
| +
|
| bool MediaWebContentsObserver::OnMediaPlayerMessageReceived(
|
| const IPC::Message& msg,
|
| RenderFrameHost* render_frame_host) {
|
| @@ -155,21 +344,21 @@ void MediaWebContentsObserver::OnSetCdm(RenderFrameHost* render_frame_host,
|
|
|
| BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
|
| RenderFrameHost* render_frame_host) {
|
| - uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
|
| - if (!media_player_managers_.contains(key)) {
|
| - media_player_managers_.set(
|
| - key,
|
| - make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host)));
|
| - }
|
| - return media_player_managers_.get(key);
|
| + auto it = media_player_managers_.find(render_frame_host);
|
| + if (it != media_player_managers_.end())
|
| + return it->second;
|
| +
|
| + BrowserMediaPlayerManager* manager =
|
| + BrowserMediaPlayerManager::Create(render_frame_host);
|
| + media_player_managers_.set(render_frame_host, make_scoped_ptr(manager));
|
| + return manager;
|
| }
|
|
|
| #if defined(VIDEO_HOLE)
|
| void MediaWebContentsObserver::OnFrameInfoUpdated() {
|
| - for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
|
| - iter != media_player_managers_.end(); ++iter) {
|
| - BrowserMediaPlayerManager* manager = iter->second;
|
| - manager->OnFrameInfoUpdated();
|
| + for (auto it = media_player_managers_.begin();
|
| + it != media_player_managers_.end(); ++it) {
|
| + it->second->OnFrameInfoUpdated();
|
| }
|
| }
|
| #endif // defined(VIDEO_HOLE)
|
|
|