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

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

Issue 2333983002: Reduce number of active codecs on low end devices. (Closed)
Patch Set: Fix windows. Created 4 years, 3 months 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"
11 #include "base/metrics/user_metrics_action.h" 11 #include "base/metrics/user_metrics_action.h"
12 #include "base/sys_info.h"
12 #include "content/common/media/media_player_delegate_messages.h" 13 #include "content/common/media/media_player_delegate_messages.h"
13 #include "content/public/renderer/render_frame.h" 14 #include "content/public/renderer/render_frame.h"
14 #include "content/public/renderer/render_thread.h" 15 #include "content/public/renderer/render_thread.h"
15 #include "third_party/WebKit/public/platform/WebMediaPlayer.h" 16 #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
16 17
18 #if defined(OS_ANDROID)
19 #include "base/android/build_info.h"
20 #endif
21
17 namespace { 22 namespace {
18 23
19 void RecordAction(const base::UserMetricsAction& action) { 24 void RecordAction(const base::UserMetricsAction& action) {
20 content::RenderThread::Get()->RecordAction(action); 25 content::RenderThread::Get()->RecordAction(action);
21 } 26 }
22 27
23 } // namespace 28 } // namespace
24 29
25 namespace media { 30 namespace media {
26 31
27 RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate( 32 RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate(
28 content::RenderFrame* render_frame) 33 content::RenderFrame* render_frame)
29 : RenderFrameObserver(render_frame), 34 : RenderFrameObserver(render_frame),
35 idle_cleanup_timer_(true, true),
30 default_tick_clock_(new base::DefaultTickClock()), 36 default_tick_clock_(new base::DefaultTickClock()),
31 tick_clock_(default_tick_clock_.get()) { 37 tick_clock_(default_tick_clock_.get()) {
32 idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5); 38 idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
33 idle_timeout_ = base::TimeDelta::FromSeconds(15); 39 idle_timeout_ = base::TimeDelta::FromSeconds(15);
40
41 // To conserve resources, cleanup idle players more often on low end devices.
42 is_low_end_device_ = base::SysInfo::IsLowEndDevice();
43
44 #if defined(OS_ANDROID)
45 // On Android, due to the instability of the OS level media components, we
46 // consider all pre-KitKat devices to be low end.
47 is_low_end_device_ |=
48 base::android::BuildInfo::GetInstance()->sdk_int() <= 18;
49 #endif
34 } 50 }
35 51
36 RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {} 52 RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {}
37 53
38 int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) { 54 int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) {
39 const int delegate_id = id_map_.Add(observer); 55 const int delegate_id = id_map_.Add(observer);
40 // Start players in the idle state to ensure we capture players which are 56 // Start players in the idle state to ensure we capture players which are
41 // consuming resources, but which have never played. 57 // consuming resources, but which have never played.
42 AddIdleDelegate(delegate_id); 58 AddIdleDelegate(delegate_id);
43 return delegate_id; 59 return delegate_id;
(...skipping 12 matching lines...) Expand all
56 bool has_audio, 72 bool has_audio,
57 bool is_remote, 73 bool is_remote,
58 MediaContentType media_content_type) { 74 MediaContentType media_content_type) {
59 DCHECK(id_map_.Lookup(delegate_id)); 75 DCHECK(id_map_.Lookup(delegate_id));
60 has_played_media_ = true; 76 has_played_media_ = true;
61 if (has_video && !is_remote) 77 if (has_video && !is_remote)
62 playing_videos_.insert(delegate_id); 78 playing_videos_.insert(delegate_id);
63 else 79 else
64 playing_videos_.erase(delegate_id); 80 playing_videos_.erase(delegate_id);
65 RemoveIdleDelegate(delegate_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
66 Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying( 87 Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying(
67 routing_id(), delegate_id, has_video, has_audio, is_remote, 88 routing_id(), delegate_id, has_video, has_audio, is_remote,
68 media_content_type)); 89 media_content_type));
69 } 90 }
70 91
71 void RendererWebMediaPlayerDelegate::DidPause(int delegate_id, 92 void RendererWebMediaPlayerDelegate::DidPause(int delegate_id,
72 bool reached_end_of_stream) { 93 bool reached_end_of_stream) {
73 DCHECK(id_map_.Lookup(delegate_id)); 94 DCHECK(id_map_.Lookup(delegate_id));
74 AddIdleDelegate(delegate_id); 95 AddIdleDelegate(delegate_id);
75 if (reached_end_of_stream) 96 if (reached_end_of_stream)
76 playing_videos_.erase(delegate_id); 97 playing_videos_.erase(delegate_id);
77 Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id, 98 Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id,
78 reached_end_of_stream)); 99 reached_end_of_stream));
79 } 100 }
80 101
81 void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) { 102 void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) {
82 DCHECK(id_map_.Lookup(delegate_id)); 103 DCHECK(id_map_.Lookup(delegate_id));
83 RemoveIdleDelegate(delegate_id);
84 playing_videos_.erase(delegate_id); 104 playing_videos_.erase(delegate_id);
85 Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), 105 Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(),
86 delegate_id)); 106 delegate_id));
87 } 107 }
88 108
89 bool RendererWebMediaPlayerDelegate::IsHidden() { 109 bool RendererWebMediaPlayerDelegate::IsHidden() {
90 return render_frame()->IsHidden(); 110 return render_frame()->IsHidden();
91 } 111 }
92 112
93 bool RendererWebMediaPlayerDelegate::IsPlayingBackgroundVideo() { 113 bool RendererWebMediaPlayerDelegate::IsPlayingBackgroundVideo() {
(...skipping 25 matching lines...) Expand all
119 OnMediaDelegateSuspendAllMediaPlayers) 139 OnMediaDelegateSuspendAllMediaPlayers)
120 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier, 140 IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier,
121 OnMediaDelegateVolumeMultiplierUpdate) 141 OnMediaDelegateVolumeMultiplierUpdate)
122 IPC_MESSAGE_UNHANDLED(handled = false) 142 IPC_MESSAGE_UNHANDLED(handled = false)
123 IPC_END_MESSAGE_MAP() 143 IPC_END_MESSAGE_MAP()
124 return handled; 144 return handled;
125 } 145 }
126 146
127 void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting( 147 void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting(
128 base::TimeDelta idle_timeout, 148 base::TimeDelta idle_timeout,
129 base::TickClock* tick_clock) { 149 base::TickClock* tick_clock,
150 bool is_low_end_device) {
130 idle_cleanup_interval_ = base::TimeDelta(); 151 idle_cleanup_interval_ = base::TimeDelta();
131 idle_timeout_ = idle_timeout; 152 idle_timeout_ = idle_timeout;
132 tick_clock_ = tick_clock; 153 tick_clock_ = tick_clock;
154 is_low_end_device_ = is_low_end_device;
133 } 155 }
134 156
135 void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) { 157 void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) {
136 Observer* observer = id_map_.Lookup(delegate_id); 158 Observer* observer = id_map_.Lookup(delegate_id);
137 if (observer) { 159 if (observer) {
138 if (playing_videos_.find(delegate_id) != playing_videos_.end()) 160 if (playing_videos_.find(delegate_id) != playing_videos_.end())
139 SetIsPlayingBackgroundVideo(false); 161 SetIsPlayingBackgroundVideo(false);
140 observer->OnPause(); 162 observer->OnPause();
141 } 163 }
142 164
(...skipping 21 matching lines...) Expand all
164 double multiplier) { 186 double multiplier) {
165 Observer* observer = id_map_.Lookup(delegate_id); 187 Observer* observer = id_map_.Lookup(delegate_id);
166 if (observer) 188 if (observer)
167 observer->OnVolumeMultiplierUpdate(multiplier); 189 observer->OnVolumeMultiplierUpdate(multiplier);
168 } 190 }
169 191
170 void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) { 192 void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) {
171 idle_delegate_map_[delegate_id] = tick_clock_->NowTicks(); 193 idle_delegate_map_[delegate_id] = tick_clock_->NowTicks();
172 if (!idle_cleanup_timer_.IsRunning()) { 194 if (!idle_cleanup_timer_.IsRunning()) {
173 idle_cleanup_timer_.Start( 195 idle_cleanup_timer_.Start(
174 FROM_HERE, idle_cleanup_interval_, this, 196 FROM_HERE, idle_cleanup_interval_,
175 &RendererWebMediaPlayerDelegate::CleanupIdleDelegates); 197 base::Bind(&RendererWebMediaPlayerDelegate::CleanupIdleDelegates,
198 base::Unretained(this), idle_timeout_));
176 } 199 }
200
201 // When we reach the maximum number of idle players, aggressively suspend idle
202 // delegates to try and remain under the limit. Values chosen after testing on
203 // a Galaxy Nexus device for http://crbug.com/612909.
204 if (idle_delegate_map_.size() > (is_low_end_device_ ? 2u : 8u))
205 CleanupIdleDelegates(base::TimeDelta());
177 } 206 }
178 207
179 void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) { 208 void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) {
180 // To avoid invalidating the iterator, just mark the delegate for deletion 209 // To avoid invalidating the iterator, just mark the delegate for deletion
181 // using a sentinel value of an empty TimeTicks. 210 // using a sentinel value of an empty TimeTicks.
182 if (idle_cleanup_running_) { 211 if (idle_cleanup_running_) {
183 idle_delegate_map_[delegate_id] = base::TimeTicks(); 212 idle_delegate_map_[delegate_id] = base::TimeTicks();
184 return; 213 return;
185 } 214 }
186 215
187 idle_delegate_map_.erase(delegate_id); 216 idle_delegate_map_.erase(delegate_id);
188 if (idle_delegate_map_.empty()) 217 if (idle_delegate_map_.empty())
189 idle_cleanup_timer_.Stop(); 218 idle_cleanup_timer_.Stop();
190 } 219 }
191 220
192 void RendererWebMediaPlayerDelegate::CleanupIdleDelegates() { 221 void RendererWebMediaPlayerDelegate::CleanupIdleDelegates(
222 base::TimeDelta timeout) {
193 // Iterate over the delegates and suspend the idle ones. Note: The call to 223 // Iterate over the delegates and suspend the idle ones. Note: The call to
194 // OnHidden() can trigger calls into RemoveIdleDelegate(), so for iterator 224 // OnHidden() can trigger calls into RemoveIdleDelegate(), so for iterator
195 // validity we set |idle_cleanup_running_| to true and defer deletions. 225 // validity we set |idle_cleanup_running_| to true and defer deletions.
196 base::AutoReset<bool> scoper(&idle_cleanup_running_, true); 226 base::AutoReset<bool> scoper(&idle_cleanup_running_, true);
197 const base::TimeTicks now = tick_clock_->NowTicks(); 227 const base::TimeTicks now = tick_clock_->NowTicks();
198 for (auto& idle_delegate_entry : idle_delegate_map_) { 228 for (auto& idle_delegate_entry : idle_delegate_map_) {
199 if (now - idle_delegate_entry.second > idle_timeout_) { 229 if (now - idle_delegate_entry.second > timeout) {
200 id_map_.Lookup(idle_delegate_entry.first)->OnSuspendRequested(false); 230 id_map_.Lookup(idle_delegate_entry.first)->OnSuspendRequested(false);
201 231
202 // Whether or not the player accepted the suspension, mark it for removal 232 // Whether or not the player accepted the suspension, mark it for removal
203 // from future polls to avoid running the timer forever. 233 // from future polls to avoid running the timer forever.
204 idle_delegate_entry.second = base::TimeTicks(); 234 idle_delegate_entry.second = base::TimeTicks();
205 } 235 }
206 } 236 }
207 237
208 // Take care of any removals that happened during the above iteration. 238 // Take care of any removals that happened during the above iteration.
209 for (auto it = idle_delegate_map_.begin(); it != idle_delegate_map_.end();) { 239 for (auto it = idle_delegate_map_.begin(); it != idle_delegate_map_.end();) {
(...skipping 28 matching lines...) Expand all
238 #endif // OS_ANDROID 268 #endif // OS_ANDROID
239 269
240 is_playing_background_video_ = is_playing; 270 is_playing_background_video_ = is_playing;
241 } 271 }
242 272
243 void RendererWebMediaPlayerDelegate::OnDestruct() { 273 void RendererWebMediaPlayerDelegate::OnDestruct() {
244 delete this; 274 delete this;
245 } 275 }
246 276
247 } // namespace media 277 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698