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 |