Chromium Code Reviews| 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..48444f8fbe2b75c2d9cc7388f5c2517a6efd5599 100644 |
| --- a/content/browser/media/media_web_contents_observer.cc |
| +++ b/content/browser/media/media_web_contents_observer.cc |
| @@ -4,10 +4,13 @@ |
| #include "content/browser/media/media_web_contents_observer.h" |
| +#include "base/auto_reset.h" |
| #include "base/memory/scoped_ptr.h" |
| #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" |
| @@ -21,22 +24,22 @@ |
| namespace content { |
| MediaWebContentsObserver::MediaWebContentsObserver( |
| - WebContents* web_contents) |
| - : WebContentsObserver(web_contents) |
| -{ |
| -} |
| + WebContentsImpl* web_contents) |
| + : WebContentsObserver(web_contents), |
| + web_contents_(web_contents), |
| + render_frame_message_source_(nullptr) {} |
| -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 +49,196 @@ 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) { |
| + base::AutoReset<RenderFrameHost*> helper(&render_frame_message_source_, |
| + render_frame_host); |
|
ncarter (slow)
2015/12/02 17:49:31
If you use IPC_BEGIN_MESSAGE_MAP_WITH_PARAM, you c
DaleCurtis
2015/12/04 01:36:27
Done.
|
| + 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(MediaWebContentsObserver, msg) |
| + 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(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; |
| + |
| + if (has_audio) { |
| + AddMediaPlayerEntry(player_cookie, &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(player_cookie, &active_video_players_); |
| + |
| + // If we're not hidden and have just created a player, create a blocker. |
| + if (!video_power_save_blocker_ && !web_contents_->IsHidden()) |
| + CreateVideoPowerSaveBlocker(); |
| + } |
| +} |
| + |
| +void MediaWebContentsObserver::OnMediaPausedNotification( |
| + int64_t player_cookie) { |
| + RemoveMediaPlayerEntry(player_cookie, &active_audio_players_); |
| + RemoveMediaPlayerEntry(player_cookie, &active_video_players_); |
| + MaybeReleasePowerSaveBlockers(); |
| +} |
| + |
| +void MediaWebContentsObserver::ClearPowerSaveBlockers( |
| + RenderFrameHost* render_frame_host) { |
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_); |
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_); |
| + MaybeReleasePowerSaveBlockers(); |
| +} |
| + |
| +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( |
| + int64_t player_cookie, |
| + ActiveMediaPlayerMap* player_map) { |
| + DCHECK(std::find((*player_map)[render_frame_message_source_].begin(), |
| + (*player_map)[render_frame_message_source_].end(), |
| + player_cookie) == |
| + (*player_map)[render_frame_message_source_].end()); |
| + (*player_map)[render_frame_message_source_].push_back(player_cookie); |
| + |
| + // Notify observers of the new player. |
| + web_contents_->MediaStartedPlaying( |
| + MediaPlayerId(render_frame_message_source_, player_cookie)); |
| +} |
| + |
| +void MediaWebContentsObserver::RemoveMediaPlayerEntry( |
| + int64_t player_cookie, |
| + ActiveMediaPlayerMap* player_map) { |
| + auto it = player_map->find(render_frame_message_source_); |
| + if (it == player_map->end()) |
| + return; |
| + |
| + // Remove the player. |
| + auto player_for_removal = |
| + std::remove(it->second.begin(), it->second.end(), player_cookie); |
| + if (player_for_removal == it->second.end()) |
| + return; |
| + it->second.erase(player_for_removal); |
| + |
| + // Notify observers the player has been "paused". |
| + web_contents_->MediaPaused( |
| + MediaPlayerId(render_frame_message_source_, player_cookie)); |
| + |
| + // If there are no players left, remove the map entry. |
| + if (it->second.empty()) |
| + player_map->erase(it); |
| +} |
| + |
| +void MediaWebContentsObserver::RemoveAllMediaPlayerEntries( |
| + RenderFrameHost* render_frame_host, |
| + ActiveMediaPlayerMap* player_map) { |
| + auto it = player_map->find(render_frame_host); |
| + if (it == player_map->end()) |
| + return; |
| + |
| + // Notify all observers the player has been "paused". |
| + for (int64_t player_cookie : it->second) |
| + web_contents_->MediaPaused(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) { |
| @@ -70,6 +247,9 @@ bool MediaWebContentsObserver::OnMediaPlayerMessageReceived( |
| IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_EnterFullscreen, |
| GetMediaPlayerManager(render_frame_host), |
| BrowserMediaPlayerManager::OnEnterFullscreen) |
| + IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlayback, |
| + GetMediaPlayerManager(render_frame_host), |
| + BrowserMediaPlayerManager::OnRequestRemotePlayback) |
| IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, |
| GetMediaPlayerManager(render_frame_host), |
| BrowserMediaPlayerManager::OnInitialize) |
| @@ -94,9 +274,6 @@ bool MediaWebContentsObserver::OnMediaPlayerMessageReceived( |
| IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyMediaPlayer, |
| GetMediaPlayerManager(render_frame_host), |
| BrowserMediaPlayerManager::OnDestroyPlayer) |
| - IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlayback, |
| - GetMediaPlayerManager(render_frame_host), |
| - BrowserMediaPlayerManager::OnRequestRemotePlayback) |
| IPC_MESSAGE_FORWARD( |
| MediaPlayerHostMsg_RequestRemotePlaybackControl, |
| GetMediaPlayerManager(render_frame_host), |
| @@ -155,21 +332,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) |