Chromium Code Reviews| Index: content/browser/web_contents/web_contents_impl.cc |
| diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc |
| index 501ae9aa0f4ed99da6be0385031b7cc5c55f39de..5347cf596b5d768899160afacaa0ca655a47b1fb 100644 |
| --- a/content/browser/web_contents/web_contents_impl.cc |
| +++ b/content/browser/web_contents/web_contents_impl.cc |
| @@ -38,6 +38,7 @@ |
| #include "content/browser/geolocation/geolocation_dispatcher_host.h" |
| #include "content/browser/host_zoom_map_impl.h" |
| #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| +#include "content/browser/media/audio_stream_monitor.h" |
| #include "content/browser/media/midi_dispatcher_host.h" |
| #include "content/browser/message_port_message_filter.h" |
| #include "content/browser/message_port_service.h" |
| @@ -1009,6 +1010,18 @@ bool WebContentsImpl::IsBeingDestroyed() const { |
| void WebContentsImpl::NotifyNavigationStateChanged( |
| InvalidateTypes changed_flags) { |
| + // Create and release the audio power save blocker depending on whether the |
| + // tab is actively producing audio or not. |
| + if (changed_flags == INVALIDATE_TYPE_TAB && |
| + AudioStreamMonitor::tab_audio_indicator_available()) { |
| + if (WasRecentlyAudible()) { |
| + if (!audio_power_save_blocker_) |
| + CreateAudioPowerSaveBlocker(); |
| + } else { |
| + audio_power_save_blocker_.reset(); |
| + } |
| + } |
| + |
| if (delegate_) |
| delegate_->NavigationStateChanged(this, changed_flags); |
| } |
| @@ -1042,6 +1055,10 @@ void WebContentsImpl::WasShown() { |
| rvh->ResizeRectChanged(GetRootWindowResizerRect()); |
| } |
| + // Restore power save blocker if there are active video players running. |
| + if (!active_video_players_.empty()) |
| + CreateVideoPowerSaveBlocker(); |
| + |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown()); |
| should_normally_be_visible_ = true; |
| @@ -1066,6 +1083,9 @@ void WebContentsImpl::WasHidden() { |
| } |
| } |
| + // Release any video power save blockers held as video is not visible. |
| + video_power_save_blocker_.reset(); |
|
miu
2014/09/05 18:20:25
Seems like this should go in the block of code a f
DaleCurtis
2014/09/05 18:30:14
Fair enough, I thought capturing already had its o
miu
2014/09/05 18:44:31
It's a subtle point: It's not *capturing* that has
DaleCurtis
2014/09/05 22:13:35
Done. Did you want to modify IncrementCapturerCoun
miu
2014/09/06 02:50:59
Looks like it already does. IIUC, DecrementCaptur
|
| + |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden()); |
| should_normally_be_visible_ = false; |
| @@ -2388,6 +2408,11 @@ void WebContentsImpl::InsertCSS(const std::string& css) { |
| GetMainFrame()->GetRoutingID(), css)); |
| } |
| +bool WebContentsImpl::WasRecentlyAudible() { |
| + AudioStreamMonitor* const monitor = AudioStreamMonitor::FromWebContents(this); |
| + return monitor ? monitor->WasRecentlyAudible() : false; |
| +} |
| + |
| bool WebContentsImpl::FocusLocationBarByDefault() { |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| if (entry && entry->GetURL() == GURL(url::kAboutBlankURL)) |
| @@ -2999,42 +3024,67 @@ void WebContentsImpl::OnUpdateFaviconURL( |
| DidUpdateFaviconURL(candidates)); |
| } |
| +void WebContentsImpl::CreateAudioPowerSaveBlocker() { |
| + DCHECK(!audio_power_save_blocker_); |
| + audio_power_save_blocker_ = PowerSaveBlocker::Create( |
| + PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing Audio"); |
| +} |
| + |
| +void WebContentsImpl::CreateVideoPowerSaveBlocker() { |
| + DCHECK(!video_power_save_blocker_); |
| + DCHECK(!active_video_players_.empty()); |
| + video_power_save_blocker_ = PowerSaveBlocker::Create( |
| + PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing Video"); |
| +#if defined(OS_ANDROID) |
| + static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get()) |
| + ->InitDisplaySleepBlocker(GetView()->GetNativeView()); |
| +#endif |
| +} |
| + |
| +void WebContentsImpl::MaybeReleasePowerSaveBlockers() { |
| + // If there are no more audio players and we don't have audio power level |
| + // analysis, release the audio power save blocker here instead of during |
| + // NotifyNavigationStateChanged(). |
| + if (active_audio_players_.empty() && |
| + !AudioStreamMonitor::tab_audio_indicator_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 WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie, |
| bool has_video, |
| bool has_audio) { |
| #if !defined(OS_CHROMEOS) |
| - scoped_ptr<PowerSaveBlocker> blocker; |
| - if (has_video) { |
| - blocker = PowerSaveBlocker::Create( |
| - PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing video"); |
| -#if defined(OS_ANDROID) |
| - static_cast<PowerSaveBlockerImpl*>(blocker.get()) |
| - ->InitDisplaySleepBlocker(GetView()->GetNativeView()); |
| -#endif |
| - } else if (has_audio) { |
| - blocker = PowerSaveBlocker::Create( |
| - PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing audio"); |
| + if (has_audio) { |
| + AddMediaPlayerEntry(player_cookie, &active_audio_players_); |
| + |
| + // If we don't have audio power level analysis, allocate the audio power |
| + // save blocker here instead of during NotifyNavigationStateChanged(). |
| + if (!audio_power_save_blocker_ && |
| + !AudioStreamMonitor::tab_audio_indicator_available()) { |
| + CreateAudioPowerSaveBlocker(); |
| + } |
| } |
| - if (blocker) { |
| - uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_message_source_); |
| - if (!power_save_blockers_.contains(key)) { |
| - power_save_blockers_.add(key, |
| - make_scoped_ptr(new PowerSaveBlockerMapEntry)); |
| - } |
| - PowerSaveBlockerMapEntry* map_entry = |
| - power_save_blockers_.get(key); |
| - map_entry->set(player_cookie, blocker.Pass()); |
| + if (has_video) { |
| + AddMediaPlayerEntry(player_cookie, &active_video_players_); |
| + |
| + // If we're not hidden and just created a video player, create a blocker. |
| + if (!video_power_save_blocker_ && !IsHidden()) |
| + CreateVideoPowerSaveBlocker(); |
| } |
| #endif // !defined(OS_CHROMEOS) |
| } |
| void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) { |
| #if !defined(OS_CHROMEOS) |
| - uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_message_source_); |
| - PowerSaveBlockerMapEntry* map_entry = power_save_blockers_.get(key); |
| - if (map_entry) |
| - map_entry->erase(player_cookie); |
| + RemoveMediaPlayerEntry(player_cookie, &active_audio_players_); |
| + RemoveMediaPlayerEntry(player_cookie, &active_video_players_); |
| + MaybeReleasePowerSaveBlockers(); |
| #endif // !defined(OS_CHROMEOS) |
| } |
| @@ -3053,7 +3103,6 @@ void WebContentsImpl::NotifyBeforeFormRepostWarningShow() { |
| BeforeFormRepostWarningShow()); |
| } |
| - |
| void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() { |
| Activate(); |
| if (delegate_) |
| @@ -4203,17 +4252,18 @@ BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const { |
| void WebContentsImpl::ClearPowerSaveBlockers( |
| RenderFrameHost* render_frame_host) { |
| #if !defined(OS_CHROMEOS) |
| - uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host); |
| - scoped_ptr<PowerSaveBlockerMapEntry> map_entry = |
| - power_save_blockers_.take_and_erase(key); |
| - if (map_entry) |
| - map_entry->clear(); |
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_); |
| + RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_); |
| + MaybeReleasePowerSaveBlockers(); |
| #endif |
| } |
| void WebContentsImpl::ClearAllPowerSaveBlockers() { |
| #if !defined(OS_CHROMEOS) |
| - power_save_blockers_.clear(); |
| + active_audio_players_.clear(); |
| + active_video_players_.clear(); |
| + audio_power_save_blocker_.reset(); |
| + video_power_save_blocker_.reset(); |
| #endif |
| } |
| @@ -4239,6 +4289,45 @@ void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) { |
| delegate_->UpdatePreferredSize(this, new_size); |
| } |
| +void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie, |
| + ActiveMediaPlayerMap* player_map) { |
| + const uintptr_t key = |
| + reinterpret_cast<uintptr_t>(render_frame_message_source_); |
| + DCHECK(std::find((*player_map)[key].begin(), |
| + (*player_map)[key].end(), |
| + player_cookie) == (*player_map)[key].end()); |
| + (*player_map)[key].push_back(player_cookie); |
| +} |
| + |
| +void WebContentsImpl::RemoveMediaPlayerEntry(int64 player_cookie, |
| + ActiveMediaPlayerMap* player_map) { |
| + const uintptr_t key = |
| + reinterpret_cast<uintptr_t>(render_frame_message_source_); |
| + ActiveMediaPlayerMap::iterator it = player_map->find(key); |
| + if (it == player_map->end()) |
| + return; |
| + |
| + // Remove the player. |
| + PlayerList::iterator player_it = |
| + std::find(it->second.begin(), it->second.end(), player_cookie); |
| + if (player_it != it->second.end()) |
| + it->second.erase(player_it); |
| + |
| + // If there are no players left, remove the map entry. |
| + if (it->second.empty()) |
| + player_map->erase(it); |
| +} |
| + |
| +void WebContentsImpl::RemoveAllMediaPlayerEntries( |
| + RenderFrameHost* render_frame_host, |
| + ActiveMediaPlayerMap* player_map) { |
| + ActiveMediaPlayerMap::iterator it = |
| + player_map->find(reinterpret_cast<uintptr_t>(render_frame_host)); |
| + if (it == player_map->end()) |
| + return; |
| + player_map->erase(it); |
| +} |
| + |
| void WebContentsImpl::ResumeResponseDeferredAtStart() { |
| FrameTreeNode* node = frame_tree_.root(); |
| node->render_manager()->ResumeResponseDeferredAtStart(); |