Chromium Code Reviews| 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" | |
| 17 #include "ipc/ipc_message_macros.h" | 16 #include "ipc/ipc_message_macros.h" |
| 17 #include "mojo/public/cpp/bindings/interface_request.h" | |
| 18 | 18 |
| 19 namespace content { | 19 namespace content { |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 | 22 |
| 23 AudibleMetrics* GetAudibleMetrics() { | 23 AudibleMetrics* GetAudibleMetrics() { |
| 24 static AudibleMetrics* metrics = new AudibleMetrics(); | 24 static AudibleMetrics* metrics = new AudibleMetrics(); |
| 25 return metrics; | 25 return metrics; |
| 26 } | 26 } |
| 27 | 27 |
| 28 } // anonymous namespace | 28 } // anonymous namespace |
| 29 | 29 |
| 30 MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents) | 30 MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents) |
| 31 : WebContentsObserver(web_contents), | 31 : WebContentsObserver(web_contents), |
| 32 has_audio_wake_lock_for_testing_(false), | |
| 33 has_video_wake_lock_for_testing_(false), | |
| 32 session_controllers_manager_(this) {} | 34 session_controllers_manager_(this) {} |
| 33 | 35 |
| 34 MediaWebContentsObserver::~MediaWebContentsObserver() = default; | 36 MediaWebContentsObserver::~MediaWebContentsObserver() = default; |
| 35 | 37 |
| 36 void MediaWebContentsObserver::WebContentsDestroyed() { | 38 void MediaWebContentsObserver::WebContentsDestroyed() { |
| 37 GetAudibleMetrics()->UpdateAudibleWebContentsState(web_contents(), false); | 39 GetAudibleMetrics()->UpdateAudibleWebContentsState(web_contents(), false); |
| 38 } | 40 } |
| 39 | 41 |
| 40 void MediaWebContentsObserver::RenderFrameDeleted( | 42 void MediaWebContentsObserver::RenderFrameDeleted( |
| 41 RenderFrameHost* render_frame_host) { | 43 RenderFrameHost* render_frame_host) { |
| 42 ClearPowerSaveBlockers(render_frame_host); | 44 ClearWakeLocks(render_frame_host); |
| 43 session_controllers_manager_.RenderFrameDeleted(render_frame_host); | 45 session_controllers_manager_.RenderFrameDeleted(render_frame_host); |
| 44 | 46 |
| 45 if (fullscreen_player_ && fullscreen_player_->first == render_frame_host) | 47 if (fullscreen_player_ && fullscreen_player_->first == render_frame_host) |
| 46 fullscreen_player_.reset(); | 48 fullscreen_player_.reset(); |
| 47 } | 49 } |
| 48 | 50 |
| 49 void MediaWebContentsObserver::MaybeUpdateAudibleState() { | 51 void MediaWebContentsObserver::MaybeUpdateAudibleState() { |
| 50 AudioStreamMonitor* audio_stream_monitor = | 52 AudioStreamMonitor* audio_stream_monitor = |
| 51 static_cast<WebContentsImpl*>(web_contents())->audio_stream_monitor(); | 53 static_cast<WebContentsImpl*>(web_contents())->audio_stream_monitor(); |
| 52 | 54 |
| 53 if (audio_stream_monitor->WasRecentlyAudible()) { | 55 if (audio_stream_monitor->WasRecentlyAudible()) { |
|
DaleCurtis
2017/05/02 17:08:42
{} not necessary for single-line if.
ke.he
2017/05/04 11:58:23
Done.
| |
| 54 if (!audio_power_save_blocker_) | 56 LockAudio(); |
| 55 CreateAudioPowerSaveBlocker(); | |
| 56 } else { | 57 } else { |
| 57 audio_power_save_blocker_.reset(); | 58 CancelAudioLock(); |
| 58 } | 59 } |
| 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 |
| (...skipping 20 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()) { |
|
DaleCurtis
2017/05/02 17:08:42
Ditto
ke.he
2017/05/04 11:58:23
Done.
| |
| 100 CreateVideoPowerSaveBlocker(); | 101 LockVideo(); |
| 102 } | |
| 101 } | 103 } |
| 102 | 104 |
| 103 void MediaWebContentsObserver::WasHidden() { | 105 void MediaWebContentsObserver::WasHidden() { |
| 104 // If there are entities capturing screenshots or video (e.g., mirroring), | 106 // If there are entities capturing screenshots or video (e.g., mirroring), |
| 105 // don't release the power save blocker. | 107 // don't release the wake lock. |
| 106 if (!web_contents()->GetCapturerCount()) | 108 if (!web_contents()->GetCapturerCount()) { |
| 107 video_power_save_blocker_.reset(); | 109 GetVideoWakeLock()->CancelWakeLock(); |
|
DaleCurtis
2017/05/02 17:08:42
Put in CancelVideoLock() function like the audio o
ke.he
2017/05/04 11:58:23
Done.
| |
| 110 has_video_wake_lock_for_testing_ = false; | |
| 111 } | |
| 108 } | 112 } |
| 109 | 113 |
| 110 void MediaWebContentsObserver::RequestPersistentVideo(bool value) { | 114 void MediaWebContentsObserver::RequestPersistentVideo(bool value) { |
| 111 if (!fullscreen_player_) | 115 if (!fullscreen_player_) |
| 112 return; | 116 return; |
| 113 | 117 |
| 114 // The message is sent to the renderer even though the video is already the | 118 // 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. | 119 // fullscreen element itself. It will eventually be handled by Blink. |
| 116 Send(new MediaPlayerDelegateMsg_BecamePersistentVideo( | 120 Send(new MediaPlayerDelegateMsg_BecamePersistentVideo( |
| 117 fullscreen_player_->first->GetRoutingID(), fullscreen_player_->second, | 121 fullscreen_player_->first->GetRoutingID(), fullscreen_player_->second, |
| 118 value)); | 122 value)); |
| 119 } | 123 } |
| 120 | 124 |
| 121 void MediaWebContentsObserver::OnMediaDestroyed( | 125 void MediaWebContentsObserver::OnMediaDestroyed( |
| 122 RenderFrameHost* render_frame_host, | 126 RenderFrameHost* render_frame_host, |
| 123 int delegate_id) { | 127 int delegate_id) { |
| 124 OnMediaPaused(render_frame_host, delegate_id, true); | 128 OnMediaPaused(render_frame_host, delegate_id, true); |
| 125 } | 129 } |
| 126 | 130 |
| 127 void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host, | 131 void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host, |
| 128 int delegate_id, | 132 int delegate_id, |
| 129 bool reached_end_of_stream) { | 133 bool reached_end_of_stream) { |
| 130 const MediaPlayerId player_id(render_frame_host, delegate_id); | 134 const MediaPlayerId player_id(render_frame_host, delegate_id); |
| 131 const bool removed_audio = | 135 const bool removed_audio = |
| 132 RemoveMediaPlayerEntry(player_id, &active_audio_players_); | 136 RemoveMediaPlayerEntry(player_id, &active_audio_players_); |
| 133 const bool removed_video = | 137 const bool removed_video = |
| 134 RemoveMediaPlayerEntry(player_id, &active_video_players_); | 138 RemoveMediaPlayerEntry(player_id, &active_video_players_); |
| 135 MaybeReleasePowerSaveBlockers(); | 139 MaybeCancelVideoLock(); |
| 136 | 140 |
| 137 if (removed_audio || removed_video) { | 141 if (removed_audio || removed_video) { |
| 138 // Notify observers the player has been "paused". | 142 // Notify observers the player has been "paused". |
| 139 static_cast<WebContentsImpl*>(web_contents()) | 143 static_cast<WebContentsImpl*>(web_contents()) |
| 140 ->MediaStoppedPlaying( | 144 ->MediaStoppedPlaying( |
| 141 WebContentsObserver::MediaPlayerInfo(removed_video), player_id); | 145 WebContentsObserver::MediaPlayerInfo(removed_video), player_id); |
| 142 } | 146 } |
| 143 | 147 |
| 144 if (reached_end_of_stream) | 148 if (reached_end_of_stream) |
| 145 session_controllers_manager_.OnEnd(player_id); | 149 session_controllers_manager_.OnEnd(player_id); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 160 if (is_remote) | 164 if (is_remote) |
| 161 return; | 165 return; |
| 162 | 166 |
| 163 const MediaPlayerId id(render_frame_host, delegate_id); | 167 const MediaPlayerId id(render_frame_host, delegate_id); |
| 164 if (has_audio) | 168 if (has_audio) |
| 165 AddMediaPlayerEntry(id, &active_audio_players_); | 169 AddMediaPlayerEntry(id, &active_audio_players_); |
| 166 | 170 |
| 167 if (has_video) { | 171 if (has_video) { |
| 168 AddMediaPlayerEntry(id, &active_video_players_); | 172 AddMediaPlayerEntry(id, &active_video_players_); |
| 169 | 173 |
| 170 // If we're not hidden and have just created a player, create a blocker. | 174 // If we're not hidden and have just created a player, create a wakelock. |
| 171 if (!video_power_save_blocker_ && | 175 if (!static_cast<WebContentsImpl*>(web_contents())->IsHidden()) { |
|
DaleCurtis
2017/05/02 17:08:42
no {} necessary.
ke.he
2017/05/04 11:58:23
Done.
| |
| 172 !static_cast<WebContentsImpl*>(web_contents())->IsHidden()) { | 176 LockVideo(); |
| 173 CreateVideoPowerSaveBlocker(); | |
| 174 } | 177 } |
| 175 } | 178 } |
| 176 | 179 |
| 177 if (!session_controllers_manager_.RequestPlay( | 180 if (!session_controllers_manager_.RequestPlay( |
| 178 id, has_audio, is_remote, media_content_type)) { | 181 id, has_audio, is_remote, media_content_type)) { |
| 179 return; | 182 return; |
| 180 } | 183 } |
| 181 | 184 |
| 182 // Notify observers of the new player. | 185 // Notify observers of the new player. |
| 183 DCHECK(has_audio || has_video); | 186 DCHECK(has_audio || has_video); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 194 | 197 |
| 195 if (!is_fullscreen) { | 198 if (!is_fullscreen) { |
| 196 if (fullscreen_player_ && *fullscreen_player_ == id) | 199 if (fullscreen_player_ && *fullscreen_player_ == id) |
| 197 fullscreen_player_.reset(); | 200 fullscreen_player_.reset(); |
| 198 return; | 201 return; |
| 199 } | 202 } |
| 200 | 203 |
| 201 fullscreen_player_ = id; | 204 fullscreen_player_ = id; |
| 202 } | 205 } |
| 203 | 206 |
| 204 void MediaWebContentsObserver::ClearPowerSaveBlockers( | 207 void MediaWebContentsObserver::ClearWakeLocks( |
| 205 RenderFrameHost* render_frame_host) { | 208 RenderFrameHost* render_frame_host) { |
| 206 std::set<MediaPlayerId> removed_players; | 209 std::set<MediaPlayerId> removed_players; |
| 207 RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_, | 210 RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_, |
| 208 &removed_players); | 211 &removed_players); |
| 209 std::set<MediaPlayerId> video_players(removed_players); | 212 std::set<MediaPlayerId> video_players(removed_players); |
| 210 RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_, | 213 RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_, |
| 211 &removed_players); | 214 &removed_players); |
| 212 MaybeReleasePowerSaveBlockers(); | 215 MaybeCancelVideoLock(); |
| 213 | 216 |
| 214 // Notify all observers the player has been "paused". | 217 // Notify all observers the player has been "paused". |
| 215 WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents()); | 218 WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents()); |
| 216 for (const auto& id : removed_players) { | 219 for (const auto& id : removed_players) { |
| 217 auto it = video_players.find(id); | 220 auto it = video_players.find(id); |
| 218 bool was_video = (it != video_players.end()); | 221 bool was_video = (it != video_players.end()); |
| 219 wci->MediaStoppedPlaying(WebContentsObserver::MediaPlayerInfo(was_video), | 222 wci->MediaStoppedPlaying(WebContentsObserver::MediaPlayerInfo(was_video), |
| 220 id); | 223 id); |
| 221 } | 224 } |
| 222 } | 225 } |
| 223 | 226 |
| 224 void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() { | 227 device::mojom::WakeLockServicePtr& |
| 225 DCHECK(!audio_power_save_blocker_); | 228 MediaWebContentsObserver::GetAudioWakeLock() { |
| 226 audio_power_save_blocker_.reset(new device::PowerSaveBlocker( | 229 // Here is a lazy binding, and will not reconnect after connection error. |
| 227 device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, | 230 if (!audio_wake_lock_) { |
|
DaleCurtis
2017/05/02 17:08:42
if (audio_wake_lock_) return audio_wake_lock_.get(
| |
| 228 device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio", | 231 device::mojom::WakeLockServiceRequest request = |
| 229 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), | 232 mojo::MakeRequest(&audio_wake_lock_); |
|
DaleCurtis
2017/05/02 17:08:42
Inline into the call below?
ke.he
2017/05/04 11:58:23
See comments below:)
| |
| 230 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); | 233 device::mojom::WakeLockContext* wake_lock_context = |
|
DaleCurtis
2017/05/02 17:08:42
could be written:
if (auto* context = web_content
ke.he
2017/05/04 11:58:23
It is safe that context to be null. the "mojo::Mak
| |
| 234 web_contents()->GetWakeLockContext(); | |
| 235 if (wake_lock_context) { | |
| 236 wake_lock_context->GetWakeLock( | |
| 237 device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, | |
| 238 device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio", | |
| 239 std::move(request)); | |
| 240 } | |
| 241 } | |
| 242 return audio_wake_lock_; | |
|
DaleCurtis
2017/05/02 17:08:42
It's possible this will return nullptr if there's
ke.he
2017/05/04 11:58:23
The GetAudioWakeLock() never returns nullptr as co
| |
| 231 } | 243 } |
| 232 | 244 |
| 233 void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() { | 245 device::mojom::WakeLockServicePtr& |
| 234 DCHECK(!video_power_save_blocker_); | 246 MediaWebContentsObserver::GetVideoWakeLock() { |
| 235 DCHECK(!active_video_players_.empty()); | 247 // Here is a lazy binding, and will not reconnect after connection error. |
| 236 video_power_save_blocker_.reset(new device::PowerSaveBlocker( | 248 if (!video_wake_lock_) { |
| 237 device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, | 249 device::mojom::WakeLockServiceRequest request = |
| 238 device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video", | 250 mojo::MakeRequest(&video_wake_lock_); |
| 239 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), | 251 device::mojom::WakeLockContext* wake_lock_context = |
| 240 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); | 252 web_contents()->GetWakeLockContext(); |
| 241 #if defined(OS_ANDROID) | 253 if (wake_lock_context) { |
| 242 if (web_contents()->GetNativeView()) { | 254 wake_lock_context->GetWakeLock( |
| 243 video_power_save_blocker_.get()->InitDisplaySleepBlocker( | 255 device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, |
| 244 web_contents()->GetNativeView()); | 256 device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video", |
| 257 std::move(request)); | |
| 258 } | |
| 245 } | 259 } |
| 246 #endif | 260 return video_wake_lock_; |
| 247 } | 261 } |
| 248 | 262 |
| 249 void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() { | 263 void MediaWebContentsObserver::LockAudio() { |
| 250 // If there are no more video players, clear the video power save blocker. | 264 GetAudioWakeLock()->RequestWakeLock(); |
| 251 if (active_video_players_.empty()) | 265 has_audio_wake_lock_for_testing_ = true; |
| 252 video_power_save_blocker_.reset(); | 266 } |
| 267 | |
| 268 void MediaWebContentsObserver::CancelAudioLock() { | |
| 269 GetAudioWakeLock()->CancelWakeLock(); | |
| 270 has_audio_wake_lock_for_testing_ = false; | |
| 271 } | |
| 272 | |
| 273 void MediaWebContentsObserver::LockVideo() { | |
| 274 DCHECK(!active_video_players_.empty()); | |
| 275 GetVideoWakeLock()->RequestWakeLock(); | |
| 276 has_video_wake_lock_for_testing_ = true; | |
| 277 } | |
| 278 | |
| 279 void MediaWebContentsObserver::MaybeCancelVideoLock() { | |
| 280 // If there are no more video players, cancel the video wake lock. | |
| 281 if (active_video_players_.empty()) { | |
| 282 GetVideoWakeLock()->CancelWakeLock(); | |
| 283 has_video_wake_lock_for_testing_ = false; | |
| 284 } | |
| 253 } | 285 } |
| 254 | 286 |
| 255 void MediaWebContentsObserver::AddMediaPlayerEntry( | 287 void MediaWebContentsObserver::AddMediaPlayerEntry( |
| 256 const MediaPlayerId& id, | 288 const MediaPlayerId& id, |
| 257 ActiveMediaPlayerMap* player_map) { | 289 ActiveMediaPlayerMap* player_map) { |
| 258 (*player_map)[id.first].insert(id.second); | 290 (*player_map)[id.first].insert(id.second); |
| 259 } | 291 } |
| 260 | 292 |
| 261 bool MediaWebContentsObserver::RemoveMediaPlayerEntry( | 293 bool MediaWebContentsObserver::RemoveMediaPlayerEntry( |
| 262 const MediaPlayerId& id, | 294 const MediaPlayerId& id, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 285 if (it == player_map->end()) | 317 if (it == player_map->end()) |
| 286 return; | 318 return; |
| 287 | 319 |
| 288 for (int delegate_id : it->second) | 320 for (int delegate_id : it->second) |
| 289 removed_players->insert(MediaPlayerId(render_frame_host, delegate_id)); | 321 removed_players->insert(MediaPlayerId(render_frame_host, delegate_id)); |
| 290 | 322 |
| 291 player_map->erase(it); | 323 player_map->erase(it); |
| 292 } | 324 } |
| 293 | 325 |
| 294 } // namespace content | 326 } // namespace content |
| OLD | NEW |