Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(563)

Side by Side Diff: content/renderer/media/renderer_webmediaplayer_delegate.cc

Issue 2490783002: Refactor WebMediaPlayerDelegate interface. (Closed)
Patch Set: Unit tests. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/renderer/media/renderer_webmediaplayer_delegate.h" 5 #include "content/renderer/media/renderer_webmediaplayer_delegate.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
(...skipping 14 matching lines...) Expand all
25 content::RenderThread::Get()->RecordAction(action); 25 content::RenderThread::Get()->RecordAction(action);
26 } 26 }
27 27
28 } // namespace 28 } // namespace
29 29
30 namespace media { 30 namespace media {
31 31
32 RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate( 32 RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate(
33 content::RenderFrame* render_frame) 33 content::RenderFrame* render_frame)
34 : RenderFrameObserver(render_frame), 34 : RenderFrameObserver(render_frame),
35 idle_cleanup_timer_(true, true),
36 default_tick_clock_(new base::DefaultTickClock()), 35 default_tick_clock_(new base::DefaultTickClock()),
37 tick_clock_(default_tick_clock_.get()) { 36 tick_clock_(default_tick_clock_.get()) {
38 idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5); 37 idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
39 idle_timeout_ = base::TimeDelta::FromSeconds(15); 38 idle_timeout_ = base::TimeDelta::FromSeconds(15);
40 39
41 // To conserve resources, cleanup idle players more often on low end devices. 40 // Idle players time out more aggressively on low end devices.
42 is_low_end_device_ = base::SysInfo::IsLowEndDevice(); 41 is_low_end_device_ = base::SysInfo::IsLowEndDevice();
43 42
44 #if defined(OS_ANDROID) 43 #if defined(OS_ANDROID)
45 // On Android, due to the instability of the OS level media components, we 44 // On Android, due to the instability of the OS level media components, we
46 // consider all pre-KitKat devices to be low end. 45 // consider all pre-KitKat devices to be low end.
47 is_low_end_device_ |= 46 is_low_end_device_ |=
48 base::android::BuildInfo::GetInstance()->sdk_int() <= 18; 47 base::android::BuildInfo::GetInstance()->sdk_int() <= 18;
49 #endif 48 #endif
50 } 49 }
51 50
52 RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {} 51 RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {}
53 52
54 int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) { 53 bool RendererWebMediaPlayerDelegate::IsFrameHidden() {
55 const int delegate_id = id_map_.Add(observer); 54 return render_frame()->IsHidden() || is_frame_hidden_for_testing_ ||
56 // Start players in the idle state to ensure we capture players which are 55 is_frame_closed_;
57 // consuming resources, but which have never played.
58 AddIdleDelegate(delegate_id);
59 return delegate_id;
60 } 56 }
61 57
62 void RendererWebMediaPlayerDelegate::RemoveObserver(int delegate_id) { 58 bool RendererWebMediaPlayerDelegate::IsFrameClosed() {
63 DCHECK(id_map_.Lookup(delegate_id)); 59 return is_frame_closed_;
64 id_map_.Remove(delegate_id); 60 }
65 RemoveIdleDelegate(delegate_id); 61
66 playing_videos_.erase(delegate_id); 62 bool RendererWebMediaPlayerDelegate::IsBackgroundVideoPlaybackAllowed() {
63 // TODO(sandersd): Include a check for kResumeBackgroundVideo?
64 return background_video_allowed_;
65 }
66
67 int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) {
68 return id_map_.Add(observer);
69 }
70
71 void RendererWebMediaPlayerDelegate::RemoveObserver(int player_id) {
72 DCHECK(id_map_.Lookup(player_id));
73 id_map_.Remove(player_id);
74 idle_player_map_.erase(player_id);
75 stale_players_.erase(player_id);
76 playing_videos_.erase(player_id);
77
78 Send(
79 new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id));
80
81 ScheduleUpdateTask();
67 } 82 }
68 83
69 void RendererWebMediaPlayerDelegate::DidPlay( 84 void RendererWebMediaPlayerDelegate::DidPlay(
70 int delegate_id, 85 int player_id,
86 bool has_audio,
71 bool has_video, 87 bool has_video,
72 bool has_audio,
73 bool is_remote,
74 MediaContentType media_content_type) { 88 MediaContentType media_content_type) {
75 DCHECK(id_map_.Lookup(delegate_id)); 89 DVLOG(2) << __func__ << "(" << player_id << ", " << has_audio << ", "
90 << has_video << ", " << static_cast<int>(media_content_type) << ")";
91 DCHECK(id_map_.Lookup(player_id));
92
76 has_played_media_ = true; 93 has_played_media_ = true;
77 if (has_video && !is_remote) 94 if (has_video)
78 playing_videos_.insert(delegate_id); 95 playing_videos_.insert(player_id);
79 else 96 else
80 playing_videos_.erase(delegate_id); 97 playing_videos_.erase(player_id);
81 RemoveIdleDelegate(delegate_id);
82
83 // Upon receipt of a playback request, suspend everything that's not used.
84 if (is_low_end_device_)
85 CleanupIdleDelegates(base::TimeDelta());
86 98
87 Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying( 99 Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying(
88 routing_id(), delegate_id, has_video, has_audio, is_remote, 100 routing_id(), player_id, has_video, has_audio, false,
89 media_content_type)); 101 media_content_type));
102
103 did_play_ = true;
104 ScheduleUpdateTask();
90 } 105 }
91 106
92 void RendererWebMediaPlayerDelegate::DidPause(int delegate_id, 107 void RendererWebMediaPlayerDelegate::DidPause(int player_id) {
93 bool reached_end_of_stream) { 108 DVLOG(2) << __func__ << "(" << player_id << ")";
94 DCHECK(id_map_.Lookup(delegate_id)); 109 DCHECK(id_map_.Lookup(player_id));
95 AddIdleDelegate(delegate_id); 110 playing_videos_.erase(player_id);
96 if (reached_end_of_stream) 111 Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), player_id,
97 playing_videos_.erase(delegate_id); 112 false));
98 Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id,
99 reached_end_of_stream));
100 } 113 }
101 114
102 void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) { 115 void RendererWebMediaPlayerDelegate::PlayerGone(int player_id) {
103 DCHECK(id_map_.Lookup(delegate_id)); 116 DVLOG(2) << __func__ << "(" << player_id << ")";
104 playing_videos_.erase(delegate_id); 117 DCHECK(id_map_.Lookup(player_id));
105 Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), 118 playing_videos_.erase(player_id);
106 delegate_id)); 119 Send(
120 new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id));
107 } 121 }
108 122
109 bool RendererWebMediaPlayerDelegate::IsHidden() { 123 void RendererWebMediaPlayerDelegate::SetIdle(int player_id, bool is_idle) {
110 return render_frame()->IsHidden(); 124 DVLOG(2) << __func__ << "(" << player_id << ", " << is_idle << ")";
125 if (is_idle) {
126 if (idle_player_map_.count(player_id) || stale_players_.count(player_id))
watk 2016/12/10 00:01:30 I just found out about base::ContainsValue yesterd
sandersd (OOO until July 31) 2017/01/05 23:12:20 Acknowledged.
127 return;
128 idle_player_map_[player_id] = tick_clock_->NowTicks();
129 } else {
130 idle_player_map_.erase(player_id);
131 stale_players_.erase(player_id);
132 }
133 ScheduleUpdateTask();
111 } 134 }
112 135
113 bool RendererWebMediaPlayerDelegate::IsPlayingBackgroundVideo() { 136 bool RendererWebMediaPlayerDelegate::IsIdle(int player_id) {
114 return is_playing_background_video_; 137 return idle_player_map_.count(player_id) || stale_players_.count(player_id);
138 }
139
140 void RendererWebMediaPlayerDelegate::ClearStaleFlag(int player_id) {
141 DVLOG(2) << __func__ << "(" << player_id << ")";
142 const auto& it = stale_players_.find(player_id);
143 if (it == stale_players_.end())
144 return;
145 stale_players_.erase(it);
watk 2016/12/10 00:01:30 erase(key_type) returns the number of elements rem
sandersd (OOO until July 31) 2017/01/05 23:12:20 Done.
146 idle_player_map_[player_id] = tick_clock_->NowTicks() - idle_timeout_;
147 ScheduleUpdateTask();
148 }
149
150 bool RendererWebMediaPlayerDelegate::IsStale(int player_id) {
151 return stale_players_.count(player_id);
115 } 152 }
116 153
117 void RendererWebMediaPlayerDelegate::WasHidden() { 154 void RendererWebMediaPlayerDelegate::WasHidden() {
155 RecordAction(base::UserMetricsAction("Media.Hidden"));
156
118 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) 157 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance())
119 it.GetCurrentValue()->OnHidden(); 158 it.GetCurrentValue()->OnFrameHidden();
120 159
121 RecordAction(base::UserMetricsAction("Media.Hidden")); 160 ScheduleUpdateTask();
122 } 161 }
123 162
124 void RendererWebMediaPlayerDelegate::WasShown() { 163 void RendererWebMediaPlayerDelegate::WasShown() {
125 SetIsPlayingBackgroundVideo(false); 164 RecordAction(base::UserMetricsAction("Media.Shown"));
165 is_frame_closed_ = false;
166 background_video_allowed_ = false;
167
126 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) 168 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance())
127 it.GetCurrentValue()->OnShown(); 169 it.GetCurrentValue()->OnFrameShown();
128 170
129 RecordAction(base::UserMetricsAction("Media.Shown")); 171 ScheduleUpdateTask();
130 } 172 }
131 173
132 bool RendererWebMediaPlayerDelegate::OnMessageReceived( 174 bool RendererWebMediaPlayerDelegate::OnMessageReceived(
133 const IPC::Message& msg) { 175 const IPC::Message& msg) {
134 bool handled = true;
135 IPC_BEGIN_MESSAGE_MAP(RendererWebMediaPlayerDelegate, msg) 176 IPC_BEGIN_MESSAGE_MAP(RendererWebMediaPlayerDelegate, msg)
136 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Pause, OnMediaDelegatePause) 177 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Pause, OnMediaDelegatePause)
137 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Play, OnMediaDelegatePlay) 178 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Play, OnMediaDelegatePlay)
138 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_SuspendAllMediaPlayers, 179 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_SuspendAllMediaPlayers,
139 OnMediaDelegateSuspendAllMediaPlayers) 180 OnMediaDelegateSuspendAllMediaPlayers)
140 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier, 181 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier,
141 OnMediaDelegateVolumeMultiplierUpdate) 182 OnMediaDelegateVolumeMultiplierUpdate)
142 IPC_MESSAGE_UNHANDLED(handled = false) 183 IPC_MESSAGE_UNHANDLED(return false)
143 IPC_END_MESSAGE_MAP() 184 IPC_END_MESSAGE_MAP()
144 return handled; 185 return true;
145 } 186 }
146 187
147 void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting( 188 void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting(
148 base::TimeDelta idle_timeout, 189 base::TimeDelta idle_timeout,
149 base::TickClock* tick_clock, 190 base::TickClock* tick_clock,
150 bool is_low_end_device) { 191 bool is_low_end_device) {
151 idle_cleanup_interval_ = base::TimeDelta(); 192 idle_cleanup_interval_ = base::TimeDelta();
152 idle_timeout_ = idle_timeout; 193 idle_timeout_ = idle_timeout;
153 tick_clock_ = tick_clock; 194 tick_clock_ = tick_clock;
154 is_low_end_device_ = is_low_end_device; 195 is_low_end_device_ = is_low_end_device;
155 } 196 }
156 197
157 void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) { 198 bool RendererWebMediaPlayerDelegate::IsIdleCleanupTimerRunningForTesting()
158 Observer* observer = id_map_.Lookup(delegate_id); 199 const {
200 return idle_cleanup_timer_.IsRunning();
201 }
202
203 void RendererWebMediaPlayerDelegate::SetFrameHiddenForTesting(bool is_hidden) {
204 if (is_hidden != is_frame_hidden_for_testing_) {
205 is_frame_hidden_for_testing_ = is_hidden;
206 background_video_allowed_ &= is_hidden;
207 ScheduleUpdateTask();
208 }
209 }
210
211 void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int player_id) {
212 RecordAction(base::UserMetricsAction("Media.Controls.RemotePause"));
213
214 Observer* observer = id_map_.Lookup(player_id);
159 if (observer) { 215 if (observer) {
watk 2016/12/10 00:01:30 At some point we should call these observers "play
sandersd (OOO until July 31) 2017/01/05 23:12:20 Indeed we should. I'm going to skip that right now
160 if (playing_videos_.find(delegate_id) != playing_videos_.end()) 216 background_video_allowed_ = false;
161 SetIsPlayingBackgroundVideo(false);
162 observer->OnPause(); 217 observer->OnPause();
163 } 218 }
164
165 RecordAction(base::UserMetricsAction("Media.Controls.RemotePause"));
166 } 219 }
167 220
168 void RendererWebMediaPlayerDelegate::OnMediaDelegatePlay(int delegate_id) { 221 void RendererWebMediaPlayerDelegate::OnMediaDelegatePlay(int player_id) {
169 Observer* observer = id_map_.Lookup(delegate_id); 222 RecordAction(base::UserMetricsAction("Media.Controls.RemotePlay"));
223
224 Observer* observer = id_map_.Lookup(player_id);
170 if (observer) { 225 if (observer) {
171 if (playing_videos_.find(delegate_id) != playing_videos_.end()) 226 // TODO(sandersd): Ideally we would only set the flag if the player has
172 SetIsPlayingBackgroundVideo(IsHidden()); 227 // video, but we don't reliably know if a paused player has video.
228 if (IsFrameHidden() && !IsFrameClosed())
229 background_video_allowed_ = true;
173 observer->OnPlay(); 230 observer->OnPlay();
174 } 231 }
175
176 RecordAction(base::UserMetricsAction("Media.Controls.RemotePlay"));
177 } 232 }
178 233
179 void RendererWebMediaPlayerDelegate::OnMediaDelegateSuspendAllMediaPlayers() { 234 void RendererWebMediaPlayerDelegate::OnMediaDelegateSuspendAllMediaPlayers() {
235 is_frame_closed_ = true;
236
180 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) 237 for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance())
181 it.GetCurrentValue()->OnSuspendRequested(true); 238 it.GetCurrentValue()->OnFrameClosed();
182 } 239 }
183 240
184 void RendererWebMediaPlayerDelegate::OnMediaDelegateVolumeMultiplierUpdate( 241 void RendererWebMediaPlayerDelegate::OnMediaDelegateVolumeMultiplierUpdate(
185 int delegate_id, 242 int player_id,
186 double multiplier) { 243 double multiplier) {
187 Observer* observer = id_map_.Lookup(delegate_id); 244 Observer* observer = id_map_.Lookup(player_id);
188 if (observer) 245 if (observer)
189 observer->OnVolumeMultiplierUpdate(multiplier); 246 observer->OnVolumeMultiplierUpdate(multiplier);
190 } 247 }
191 248
192 void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) { 249 void RendererWebMediaPlayerDelegate::ScheduleUpdateTask() {
193 idle_delegate_map_[delegate_id] = tick_clock_->NowTicks(); 250 if (!pending_update_task_) {
194 if (!idle_cleanup_timer_.IsRunning()) { 251 base::ThreadTaskRunnerHandle::Get()->PostTask(
252 FROM_HERE,
253 base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask, AsWeakPtr()));
254 pending_update_task_ = true;
255 }
256 }
257
258 void RendererWebMediaPlayerDelegate::UpdateTask() {
259 DVLOG(3) << __func__;
260 pending_update_task_ = false;
261
262 // Check whether a player was played since the last UpdateTask(). We basically
263 // treat this as a parameter to UpdateTask() except that it can be changed
264 // between posting the task and UpdateTask() executing.
265 bool did_play = did_play_;
266 did_play_ = false;
267
268 // Record UMAs for background video playback.
269 RecordBackgroundVideoPlayback();
270
271 // Cleanup idle players.
watk 2016/12/10 00:01:30 Clean up
sandersd (OOO until July 31) 2017/01/05 23:12:20 Done.
272 bool aggressive_cleanup = false;
273
274 // When we reach the maximum number of idle players, clean them up
275 // aggressively. Values chosen after testing on a Galaxy Nexus device for
276 // http://crbug.com/612909.
277 if (idle_player_map_.size() > (is_low_end_device_ ? 2u : 8u))
278 aggressive_cleanup = true;
279
280 // When a player plays on a low-end device, clean up idle players
281 // aggressively.
282 if (did_play && is_low_end_device_)
283 aggressive_cleanup = true;
284
285 CleanupIdlePlayers(aggressive_cleanup ? base::TimeDelta() : idle_timeout_);
286
287 // If there are still idle players, schedule an attempt to clean them up.
288 if (idle_player_map_.empty()) {
289 idle_cleanup_timer_.Stop();
290 } else if (!idle_cleanup_timer_.IsRunning()) {
195 idle_cleanup_timer_.Start( 291 idle_cleanup_timer_.Start(
196 FROM_HERE, idle_cleanup_interval_, 292 FROM_HERE, idle_cleanup_interval_,
197 base::Bind(&RendererWebMediaPlayerDelegate::CleanupIdleDelegates, 293 base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask,
198 base::Unretained(this), idle_timeout_)); 294 base::Unretained(this)));
295 }
296 }
297
298 void RendererWebMediaPlayerDelegate::RecordBackgroundVideoPlayback() {
299 #if defined(OS_ANDROID)
300 // TODO(avayvod): This would be useful to collect on desktop too and express
301 // in actual media watch time vs. just elapsed time.
302 // See https://crbug.com/638726.
303 bool has_playing_background_video =
304 IsFrameHidden() && !IsFrameClosed() && !playing_videos_.empty();
305
306 if (has_playing_background_video != was_playing_background_video_) {
307 was_playing_background_video_ = has_playing_background_video;
308
309 if (has_playing_background_video) {
310 RecordAction(base::UserMetricsAction("Media.Session.BackgroundResume"));
311 background_video_start_time_ = base::TimeTicks::Now();
312 } else {
313 RecordAction(base::UserMetricsAction("Media.Session.BackgroundSuspend"));
314 UMA_HISTOGRAM_CUSTOM_TIMES(
315 "Media.Android.BackgroundVideoTime",
316 base::TimeTicks::Now() - background_video_start_time_,
317 base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50);
318 }
319 }
320 #endif // OS_ANDROID
321 }
322
323 void RendererWebMediaPlayerDelegate::CleanupIdlePlayers(
324 base::TimeDelta timeout) {
325 const base::TimeTicks now = tick_clock_->NowTicks();
326
327 // Create a list of stale players before making any possibly reentrant calls.
328 std::vector<int> stale_players;
329 for (const auto& it : idle_player_map_) {
330 if (now - it.second >= timeout)
331 stale_players.push_back(it.first);
199 } 332 }
200 333
201 // When we reach the maximum number of idle players, aggressively suspend idle 334 // Notify stale players.
202 // delegates to try and remain under the limit. Values chosen after testing on 335 for (int player_id : stale_players) {
203 // a Galaxy Nexus device for http://crbug.com/612909. 336 Observer* player = id_map_.Lookup(player_id);
204 if (idle_delegate_map_.size() > (is_low_end_device_ ? 2u : 8u)) 337 if (player && player->OnIdleTimeout()) {
205 CleanupIdleDelegates(base::TimeDelta()); 338 // If we fail to erase, it means that the player called SetIdle(false)
206 } 339 // inside of OnIdleTimeout(), which is banned by the API documentation.
207 340 // We actually handle that fine. If they *also* then called SetIdle(true),
208 void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) { 341 // we won't notice the idle time change and will still mark them as stale
209 // To avoid invalidating the iterator, just mark the delegate for deletion 342 // here.
210 // using a sentinel value of an empty TimeTicks. 343 // TODO(sandersd): Consider making this implementation the official API
211 if (idle_cleanup_running_) { 344 // interpretation (that is, allow calling SetIdle() from OnIdleTimeout(),
212 idle_delegate_map_[delegate_id] = base::TimeTicks(); 345 // with this same caveat).
watk 2016/12/10 00:01:30 Why did you decide to not DCHECK that SetIdle isn'
sandersd (OOO until July 31) 2017/01/05 23:12:20 Basically yes. I came up with something I think is
213 return; 346 if (idle_player_map_.erase(player_id))
214 } 347 stale_players_.insert(player_id);
215
216 idle_delegate_map_.erase(delegate_id);
217 if (idle_delegate_map_.empty())
218 idle_cleanup_timer_.Stop();
219 }
220
221 void RendererWebMediaPlayerDelegate::CleanupIdleDelegates(
222 base::TimeDelta timeout) {
223 // Drop reentrant cleanups which can occur during forced suspension when the
224 // number of idle delegates is too high for a given device.
225 if (idle_cleanup_running_)
226 return;
227
228 // Iterate over the delegates and suspend the idle ones. Note: The call to
229 // OnSuspendRequested() can trigger calls into RemoveIdleDelegate(), so for
230 // iterator validity we set |idle_cleanup_running_| to true and defer
231 // deletions.
232 DCHECK(!idle_cleanup_running_);
233 base::AutoReset<bool> scoper(&idle_cleanup_running_, true);
234 const base::TimeTicks now = tick_clock_->NowTicks();
235 for (auto& idle_delegate_entry : idle_delegate_map_) {
236 if (now - idle_delegate_entry.second > timeout) {
237 if (id_map_.Lookup(idle_delegate_entry.first)
238 ->OnSuspendRequested(false)) {
239 // If the player accepted the suspension, mark it for removal
240 // from future polls to avoid running the timer forever.
241 idle_delegate_entry.second = base::TimeTicks();
242 }
243 } 348 }
244 } 349 }
245
246 // Take care of any removals that happened during the above iteration.
247 for (auto it = idle_delegate_map_.begin(); it != idle_delegate_map_.end();) {
248 if (it->second.is_null())
249 it = idle_delegate_map_.erase(it);
250 else
251 ++it;
252 }
253
254 // Shutdown the timer if no delegates are left.
255 if (idle_delegate_map_.empty())
256 idle_cleanup_timer_.Stop();
257 }
258
259 void RendererWebMediaPlayerDelegate::SetIsPlayingBackgroundVideo(
260 bool is_playing) {
261 if (is_playing_background_video_ == is_playing) return;
262
263 // TODO(avayvod): This would be useful to collect on desktop too and express in
264 // actual media watch time vs. just elapsed time. See https://crbug.com/638726.
265 #if defined(OS_ANDROID)
266 if (is_playing_background_video_) {
267 UMA_HISTOGRAM_CUSTOM_TIMES(
268 "Media.Android.BackgroundVideoTime",
269 base::TimeTicks::Now() - background_video_playing_start_time_,
270 base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50);
271 RecordAction(base::UserMetricsAction("Media.Session.BackgroundSuspend"));
272 } else {
273 background_video_playing_start_time_ = base::TimeTicks::Now();
274 RecordAction(base::UserMetricsAction("Media.Session.BackgroundResume"));
275 }
276 #endif // OS_ANDROID
277
278 is_playing_background_video_ = is_playing;
279 } 350 }
280 351
281 void RendererWebMediaPlayerDelegate::OnDestruct() { 352 void RendererWebMediaPlayerDelegate::OnDestruct() {
282 delete this; 353 delete this;
283 } 354 }
284 355
285 } // namespace media 356 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698