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 |