| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/browser/media/media_web_contents_observer.h" | 5 #include "content/browser/media/media_web_contents_observer.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "build/build_config.h" | 9 #include "build/build_config.h" |
| 10 #include "content/browser/media/audible_metrics.h" | 10 #include "content/browser/media/audible_metrics.h" |
| 11 #include "content/browser/media/audio_stream_monitor.h" | 11 #include "content/browser/media/audio_stream_monitor.h" |
| 12 #include "content/browser/web_contents/web_contents_impl.h" | 12 #include "content/browser/web_contents/web_contents_impl.h" |
| 13 #include "content/common/media/media_player_delegate_messages.h" | 13 #include "content/common/media/media_player_delegate_messages.h" |
| 14 #include "content/public/browser/render_frame_host.h" | 14 #include "content/public/browser/render_frame_host.h" |
| 15 #include "content/public/browser/web_contents.h" | 15 #include "content/public/browser/web_contents.h" |
| 16 #include "device/power_save_blocker/power_save_blocker.h" | 16 #include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h" |
| 17 #include "ipc/ipc_message_macros.h" | 17 #include "ipc/ipc_message_macros.h" |
| 18 #include "mojo/public/cpp/bindings/interface_request.h" |
| 18 | 19 |
| 19 namespace content { | 20 namespace content { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 AudibleMetrics* GetAudibleMetrics() { | 24 AudibleMetrics* GetAudibleMetrics() { |
| 24 static AudibleMetrics* metrics = new AudibleMetrics(); | 25 static AudibleMetrics* metrics = new AudibleMetrics(); |
| 25 return metrics; | 26 return metrics; |
| 26 } | 27 } |
| 27 | 28 |
| 28 } // anonymous namespace | 29 } // anonymous namespace |
| 29 | 30 |
| 30 MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents) | 31 MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents) |
| 31 : WebContentsObserver(web_contents), | 32 : WebContentsObserver(web_contents), |
| 33 has_audio_wake_lock_for_testing_(false), |
| 34 has_video_wake_lock_for_testing_(false), |
| 32 session_controllers_manager_(this) {} | 35 session_controllers_manager_(this) {} |
| 33 | 36 |
| 34 MediaWebContentsObserver::~MediaWebContentsObserver() = default; | 37 MediaWebContentsObserver::~MediaWebContentsObserver() = default; |
| 35 | 38 |
| 36 void MediaWebContentsObserver::WebContentsDestroyed() { | 39 void MediaWebContentsObserver::WebContentsDestroyed() { |
| 37 GetAudibleMetrics()->UpdateAudibleWebContentsState(web_contents(), false); | 40 GetAudibleMetrics()->UpdateAudibleWebContentsState(web_contents(), false); |
| 38 } | 41 } |
| 39 | 42 |
| 40 void MediaWebContentsObserver::RenderFrameDeleted( | 43 void MediaWebContentsObserver::RenderFrameDeleted( |
| 41 RenderFrameHost* render_frame_host) { | 44 RenderFrameHost* render_frame_host) { |
| 42 ClearPowerSaveBlockers(render_frame_host); | 45 ClearWakeLocks(render_frame_host); |
| 43 session_controllers_manager_.RenderFrameDeleted(render_frame_host); | 46 session_controllers_manager_.RenderFrameDeleted(render_frame_host); |
| 44 | 47 |
| 45 if (fullscreen_player_ && fullscreen_player_->first == render_frame_host) | 48 if (fullscreen_player_ && fullscreen_player_->first == render_frame_host) |
| 46 fullscreen_player_.reset(); | 49 fullscreen_player_.reset(); |
| 47 } | 50 } |
| 48 | 51 |
| 49 void MediaWebContentsObserver::MaybeUpdateAudibleState() { | 52 void MediaWebContentsObserver::MaybeUpdateAudibleState() { |
| 50 AudioStreamMonitor* audio_stream_monitor = | 53 AudioStreamMonitor* audio_stream_monitor = |
| 51 static_cast<WebContentsImpl*>(web_contents())->audio_stream_monitor(); | 54 static_cast<WebContentsImpl*>(web_contents())->audio_stream_monitor(); |
| 52 | 55 |
| 53 if (audio_stream_monitor->WasRecentlyAudible()) { | 56 if (audio_stream_monitor->WasRecentlyAudible()) |
| 54 if (!audio_power_save_blocker_) | 57 LockAudio(); |
| 55 CreateAudioPowerSaveBlocker(); | 58 else |
| 56 } else { | 59 CancelAudioLock(); |
| 57 audio_power_save_blocker_.reset(); | |
| 58 } | |
| 59 | 60 |
| 60 GetAudibleMetrics()->UpdateAudibleWebContentsState( | 61 GetAudibleMetrics()->UpdateAudibleWebContentsState( |
| 61 web_contents(), audio_stream_monitor->IsCurrentlyAudible()); | 62 web_contents(), audio_stream_monitor->IsCurrentlyAudible()); |
| 62 } | 63 } |
| 63 | 64 |
| 64 bool MediaWebContentsObserver::HasActiveEffectivelyFullscreenVideo() const { | 65 bool MediaWebContentsObserver::HasActiveEffectivelyFullscreenVideo() const { |
| 65 if (!web_contents()->IsFullscreen() || !fullscreen_player_) | 66 if (!web_contents()->IsFullscreen() || !fullscreen_player_) |
| 66 return false; | 67 return false; |
| 67 | 68 |
| 68 // Check that the player is active. | 69 // Check that the player is active. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 88 OnMediaPlaying) | 89 OnMediaPlaying) |
| 89 IPC_MESSAGE_HANDLER( | 90 IPC_MESSAGE_HANDLER( |
| 90 MediaPlayerDelegateHostMsg_OnMediaEffectivelyFullscreenChange, | 91 MediaPlayerDelegateHostMsg_OnMediaEffectivelyFullscreenChange, |
| 91 OnMediaEffectivelyFullscreenChange) | 92 OnMediaEffectivelyFullscreenChange) |
| 92 IPC_MESSAGE_UNHANDLED(handled = false) | 93 IPC_MESSAGE_UNHANDLED(handled = false) |
| 93 IPC_END_MESSAGE_MAP() | 94 IPC_END_MESSAGE_MAP() |
| 94 return handled; | 95 return handled; |
| 95 } | 96 } |
| 96 | 97 |
| 97 void MediaWebContentsObserver::WasShown() { | 98 void MediaWebContentsObserver::WasShown() { |
| 98 // Restore power save blocker if there are active video players running. | 99 // Restore wake lock if there are active video players running. |
| 99 if (!active_video_players_.empty() && !video_power_save_blocker_) | 100 if (!active_video_players_.empty()) |
| 100 CreateVideoPowerSaveBlocker(); | 101 LockVideo(); |
| 101 } | 102 } |
| 102 | 103 |
| 103 void MediaWebContentsObserver::WasHidden() { | 104 void MediaWebContentsObserver::WasHidden() { |
| 104 // If there are entities capturing screenshots or video (e.g., mirroring), | 105 // If there are entities capturing screenshots or video (e.g., mirroring), |
| 105 // don't release the power save blocker. | 106 // don't release the wake lock. |
| 106 if (!web_contents()->GetCapturerCount()) | 107 if (!web_contents()->GetCapturerCount()) { |
| 107 video_power_save_blocker_.reset(); | 108 GetVideoWakeLock()->CancelWakeLock(); |
| 109 has_video_wake_lock_for_testing_ = false; |
| 110 } |
| 108 } | 111 } |
| 109 | 112 |
| 110 void MediaWebContentsObserver::RequestPersistentVideo(bool value) { | 113 void MediaWebContentsObserver::RequestPersistentVideo(bool value) { |
| 111 if (!fullscreen_player_) | 114 if (!fullscreen_player_) |
| 112 return; | 115 return; |
| 113 | 116 |
| 114 // The message is sent to the renderer even though the video is already the | 117 // The message is sent to the renderer even though the video is already the |
| 115 // fullscreen element itself. It will eventually be handled by Blink. | 118 // fullscreen element itself. It will eventually be handled by Blink. |
| 116 Send(new MediaPlayerDelegateMsg_BecamePersistentVideo( | 119 Send(new MediaPlayerDelegateMsg_BecamePersistentVideo( |
| 117 fullscreen_player_->first->GetRoutingID(), fullscreen_player_->second, | 120 fullscreen_player_->first->GetRoutingID(), fullscreen_player_->second, |
| 118 value)); | 121 value)); |
| 119 } | 122 } |
| 120 | 123 |
| 121 void MediaWebContentsObserver::OnMediaDestroyed( | 124 void MediaWebContentsObserver::OnMediaDestroyed( |
| 122 RenderFrameHost* render_frame_host, | 125 RenderFrameHost* render_frame_host, |
| 123 int delegate_id) { | 126 int delegate_id) { |
| 124 OnMediaPaused(render_frame_host, delegate_id, true); | 127 OnMediaPaused(render_frame_host, delegate_id, true); |
| 125 } | 128 } |
| 126 | 129 |
| 127 void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host, | 130 void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host, |
| 128 int delegate_id, | 131 int delegate_id, |
| 129 bool reached_end_of_stream) { | 132 bool reached_end_of_stream) { |
| 130 const MediaPlayerId player_id(render_frame_host, delegate_id); | 133 const MediaPlayerId player_id(render_frame_host, delegate_id); |
| 131 const bool removed_audio = | 134 const bool removed_audio = |
| 132 RemoveMediaPlayerEntry(player_id, &active_audio_players_); | 135 RemoveMediaPlayerEntry(player_id, &active_audio_players_); |
| 133 const bool removed_video = | 136 const bool removed_video = |
| 134 RemoveMediaPlayerEntry(player_id, &active_video_players_); | 137 RemoveMediaPlayerEntry(player_id, &active_video_players_); |
| 135 MaybeReleasePowerSaveBlockers(); | 138 MaybeCancelVideoLock(); |
| 136 | 139 |
| 137 if (removed_audio || removed_video) { | 140 if (removed_audio || removed_video) { |
| 138 // Notify observers the player has been "paused". | 141 // Notify observers the player has been "paused". |
| 139 static_cast<WebContentsImpl*>(web_contents()) | 142 static_cast<WebContentsImpl*>(web_contents()) |
| 140 ->MediaStoppedPlaying( | 143 ->MediaStoppedPlaying( |
| 141 WebContentsObserver::MediaPlayerInfo(removed_video), player_id); | 144 WebContentsObserver::MediaPlayerInfo(removed_video), player_id); |
| 142 } | 145 } |
| 143 | 146 |
| 144 if (reached_end_of_stream) | 147 if (reached_end_of_stream) |
| 145 session_controllers_manager_.OnEnd(player_id); | 148 session_controllers_manager_.OnEnd(player_id); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 160 if (is_remote) | 163 if (is_remote) |
| 161 return; | 164 return; |
| 162 | 165 |
| 163 const MediaPlayerId id(render_frame_host, delegate_id); | 166 const MediaPlayerId id(render_frame_host, delegate_id); |
| 164 if (has_audio) | 167 if (has_audio) |
| 165 AddMediaPlayerEntry(id, &active_audio_players_); | 168 AddMediaPlayerEntry(id, &active_audio_players_); |
| 166 | 169 |
| 167 if (has_video) { | 170 if (has_video) { |
| 168 AddMediaPlayerEntry(id, &active_video_players_); | 171 AddMediaPlayerEntry(id, &active_video_players_); |
| 169 | 172 |
| 170 // If we're not hidden and have just created a player, create a blocker. | 173 // If we're not hidden and have just created a player, create a wakelock. |
| 171 if (!video_power_save_blocker_ && | 174 if (!static_cast<WebContentsImpl*>(web_contents())->IsHidden()) |
| 172 !static_cast<WebContentsImpl*>(web_contents())->IsHidden()) { | 175 LockVideo(); |
| 173 CreateVideoPowerSaveBlocker(); | |
| 174 } | |
| 175 } | 176 } |
| 176 | 177 |
| 177 if (!session_controllers_manager_.RequestPlay( | 178 if (!session_controllers_manager_.RequestPlay( |
| 178 id, has_audio, is_remote, media_content_type)) { | 179 id, has_audio, is_remote, media_content_type)) { |
| 179 return; | 180 return; |
| 180 } | 181 } |
| 181 | 182 |
| 182 // Notify observers of the new player. | 183 // Notify observers of the new player. |
| 183 DCHECK(has_audio || has_video); | 184 DCHECK(has_audio || has_video); |
| 184 static_cast<WebContentsImpl*>(web_contents()) | 185 static_cast<WebContentsImpl*>(web_contents()) |
| 185 ->MediaStartedPlaying(WebContentsObserver::MediaPlayerInfo(has_video), | 186 ->MediaStartedPlaying(WebContentsObserver::MediaPlayerInfo(has_video), |
| 186 id); | 187 id); |
| 187 } | 188 } |
| 188 | 189 |
| 189 void MediaWebContentsObserver::OnMediaEffectivelyFullscreenChange( | 190 void MediaWebContentsObserver::OnMediaEffectivelyFullscreenChange( |
| 190 RenderFrameHost* render_frame_host, | 191 RenderFrameHost* render_frame_host, |
| 191 int delegate_id, | 192 int delegate_id, |
| 192 bool is_fullscreen) { | 193 bool is_fullscreen) { |
| 193 const MediaPlayerId id(render_frame_host, delegate_id); | 194 const MediaPlayerId id(render_frame_host, delegate_id); |
| 194 | 195 |
| 195 if (!is_fullscreen) { | 196 if (!is_fullscreen) { |
| 196 if (fullscreen_player_ && *fullscreen_player_ == id) | 197 if (fullscreen_player_ && *fullscreen_player_ == id) |
| 197 fullscreen_player_.reset(); | 198 fullscreen_player_.reset(); |
| 198 return; | 199 return; |
| 199 } | 200 } |
| 200 | 201 |
| 201 fullscreen_player_ = id; | 202 fullscreen_player_ = id; |
| 202 } | 203 } |
| 203 | 204 |
| 204 void MediaWebContentsObserver::ClearPowerSaveBlockers( | 205 void MediaWebContentsObserver::ClearWakeLocks( |
| 205 RenderFrameHost* render_frame_host) { | 206 RenderFrameHost* render_frame_host) { |
| 206 std::set<MediaPlayerId> removed_players; | 207 std::set<MediaPlayerId> removed_players; |
| 207 RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_, | 208 RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_, |
| 208 &removed_players); | 209 &removed_players); |
| 209 std::set<MediaPlayerId> video_players(removed_players); | 210 std::set<MediaPlayerId> video_players(removed_players); |
| 210 RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_, | 211 RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_, |
| 211 &removed_players); | 212 &removed_players); |
| 212 MaybeReleasePowerSaveBlockers(); | 213 MaybeCancelVideoLock(); |
| 213 | 214 |
| 214 // Notify all observers the player has been "paused". | 215 // Notify all observers the player has been "paused". |
| 215 WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents()); | 216 WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents()); |
| 216 for (const auto& id : removed_players) { | 217 for (const auto& id : removed_players) { |
| 217 auto it = video_players.find(id); | 218 auto it = video_players.find(id); |
| 218 bool was_video = (it != video_players.end()); | 219 bool was_video = (it != video_players.end()); |
| 219 wci->MediaStoppedPlaying(WebContentsObserver::MediaPlayerInfo(was_video), | 220 wci->MediaStoppedPlaying(WebContentsObserver::MediaPlayerInfo(was_video), |
| 220 id); | 221 id); |
| 221 } | 222 } |
| 222 } | 223 } |
| 223 | 224 |
| 224 void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() { | 225 device::mojom::WakeLockService* MediaWebContentsObserver::GetAudioWakeLock() { |
| 225 DCHECK(!audio_power_save_blocker_); | 226 // Here is a lazy binding, and will not reconnect after connection error. |
| 226 audio_power_save_blocker_.reset(new device::PowerSaveBlocker( | 227 if (!audio_wake_lock_) { |
| 227 device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, | 228 device::mojom::WakeLockServiceRequest request = |
| 228 device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio", | 229 mojo::MakeRequest(&audio_wake_lock_); |
| 229 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), | 230 device::mojom::WakeLockContext* wake_lock_context = |
| 230 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); | 231 web_contents()->GetWakeLockContext(); |
| 232 if (wake_lock_context) { |
| 233 wake_lock_context->GetWakeLock( |
| 234 device::mojom::WakeLockType::PreventAppSuspension, |
| 235 device::mojom::WakeLockReason::ReasonAudioPlayback, "Playing audio", |
| 236 std::move(request)); |
| 237 } |
| 238 } |
| 239 return audio_wake_lock_.get(); |
| 231 } | 240 } |
| 232 | 241 |
| 233 void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() { | 242 device::mojom::WakeLockService* MediaWebContentsObserver::GetVideoWakeLock() { |
| 234 DCHECK(!video_power_save_blocker_); | 243 // Here is a lazy binding, and will not reconnect after connection error. |
| 235 DCHECK(!active_video_players_.empty()); | 244 if (!video_wake_lock_) { |
| 236 video_power_save_blocker_.reset(new device::PowerSaveBlocker( | 245 device::mojom::WakeLockServiceRequest request = |
| 237 device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, | 246 mojo::MakeRequest(&video_wake_lock_); |
| 238 device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video", | 247 device::mojom::WakeLockContext* wake_lock_context = |
| 239 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), | 248 web_contents()->GetWakeLockContext(); |
| 240 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); | 249 if (wake_lock_context) { |
| 241 #if defined(OS_ANDROID) | 250 wake_lock_context->GetWakeLock( |
| 242 if (web_contents()->GetNativeView()) { | 251 device::mojom::WakeLockType::PreventDisplaySleep, |
| 243 video_power_save_blocker_.get()->InitDisplaySleepBlocker( | 252 device::mojom::WakeLockReason::ReasonVideoPlayback, "Playing video", |
| 244 web_contents()->GetNativeView()); | 253 std::move(request)); |
| 254 } |
| 245 } | 255 } |
| 246 #endif | 256 return video_wake_lock_.get(); |
| 247 } | 257 } |
| 248 | 258 |
| 249 void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() { | 259 void MediaWebContentsObserver::LockAudio() { |
| 250 // If there are no more video players, clear the video power save blocker. | 260 GetAudioWakeLock()->RequestWakeLock(); |
| 261 has_audio_wake_lock_for_testing_ = true; |
| 262 } |
| 263 |
| 264 void MediaWebContentsObserver::CancelAudioLock() { |
| 265 GetAudioWakeLock()->CancelWakeLock(); |
| 266 has_audio_wake_lock_for_testing_ = false; |
| 267 } |
| 268 |
| 269 void MediaWebContentsObserver::LockVideo() { |
| 270 DCHECK(!active_video_players_.empty()); |
| 271 GetVideoWakeLock()->RequestWakeLock(); |
| 272 has_video_wake_lock_for_testing_ = true; |
| 273 } |
| 274 |
| 275 void MediaWebContentsObserver::CancelVideoLock() { |
| 276 GetVideoWakeLock()->CancelWakeLock(); |
| 277 has_video_wake_lock_for_testing_ = false; |
| 278 } |
| 279 |
| 280 void MediaWebContentsObserver::MaybeCancelVideoLock() { |
| 281 // If there are no more video players, cancel the video wake lock. |
| 251 if (active_video_players_.empty()) | 282 if (active_video_players_.empty()) |
| 252 video_power_save_blocker_.reset(); | 283 CancelVideoLock(); |
| 253 } | 284 } |
| 254 | 285 |
| 255 void MediaWebContentsObserver::AddMediaPlayerEntry( | 286 void MediaWebContentsObserver::AddMediaPlayerEntry( |
| 256 const MediaPlayerId& id, | 287 const MediaPlayerId& id, |
| 257 ActiveMediaPlayerMap* player_map) { | 288 ActiveMediaPlayerMap* player_map) { |
| 258 (*player_map)[id.first].insert(id.second); | 289 (*player_map)[id.first].insert(id.second); |
| 259 } | 290 } |
| 260 | 291 |
| 261 bool MediaWebContentsObserver::RemoveMediaPlayerEntry( | 292 bool MediaWebContentsObserver::RemoveMediaPlayerEntry( |
| 262 const MediaPlayerId& id, | 293 const MediaPlayerId& id, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 285 if (it == player_map->end()) | 316 if (it == player_map->end()) |
| 286 return; | 317 return; |
| 287 | 318 |
| 288 for (int delegate_id : it->second) | 319 for (int delegate_id : it->second) |
| 289 removed_players->insert(MediaPlayerId(render_frame_host, delegate_id)); | 320 removed_players->insert(MediaPlayerId(render_frame_host, delegate_id)); |
| 290 | 321 |
| 291 player_map->erase(it); | 322 player_map->erase(it); |
| 292 } | 323 } |
| 293 | 324 |
| 294 } // namespace content | 325 } // namespace content |
| OLD | NEW |