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

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

Issue 2566113002: AudioRendererSinKCache: Do not use unhealthy sinks (Closed)
Patch Set: 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 <algorithm> 5 #include <algorithm>
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/memory/ptr_util.h" 9 #include "base/memory/ptr_util.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
(...skipping 19 matching lines...) Expand all
30 // cache a new sink. 30 // cache a new sink.
31 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID = 1, 31 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID = 1,
32 32
33 // Output parmeters for an already-cached sink are requested. 33 // Output parmeters for an already-cached sink are requested.
34 SINK_CACHE_HIT = 2, 34 SINK_CACHE_HIT = 2,
35 35
36 // For UMA. 36 // For UMA.
37 SINK_CACHE_LAST_ENTRY 37 SINK_CACHE_LAST_ENTRY
38 }; 38 };
39 39
40 bool SinkIsHealthy(media::AudioRendererSink* sink) {
41 return sink->GetOutputDeviceInfo().device_status() ==
42 media::OUTPUT_DEVICE_STATUS_OK;
43 }
44
40 } // namespace 45 } // namespace
41 46
42 // Cached sink data. 47 // Cached sink data.
43 struct AudioRendererSinkCacheImpl::CacheEntry { 48 struct AudioRendererSinkCacheImpl::CacheEntry {
44 int source_render_frame_id; 49 int source_render_frame_id;
45 std::string device_id; 50 std::string device_id;
46 url::Origin security_origin; 51 url::Origin security_origin;
47 scoped_refptr<media::AudioRendererSink> sink; // Sink instance 52 scoped_refptr<media::AudioRendererSink> sink; // Sink instance
48 bool used; // True if in use by a client. 53 bool used; // True if in use by a client.
49 }; 54 };
(...skipping 24 matching lines...) Expand all
74 // is being destroyed anyways. 79 // is being destroyed anyways.
75 for (auto& entry : cache_) 80 for (auto& entry : cache_)
76 entry.sink->Stop(); 81 entry.sink->Stop();
77 } 82 }
78 83
79 media::OutputDeviceInfo AudioRendererSinkCacheImpl::GetSinkInfo( 84 media::OutputDeviceInfo AudioRendererSinkCacheImpl::GetSinkInfo(
80 int source_render_frame_id, 85 int source_render_frame_id,
81 int session_id, 86 int session_id,
82 const std::string& device_id, 87 const std::string& device_id,
83 const url::Origin& security_origin) { 88 const url::Origin& security_origin) {
84 CacheEntry cache_entry = {source_render_frame_id,
85 std::string() /* device_id */, security_origin,
86 nullptr /* sink */, false /* not used */};
87
88 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, 89 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
89 device_id)) { 90 device_id)) {
90 // We are provided with session id instead of device id. Session id is 91 // We are provided with session id instead of device id. Session id is
91 // unique, so we can't find any matching sink. Creating a new one. 92 // unique, so we can't find any matching sink. Creating a new one.
92 cache_entry.sink = create_sink_cb_.Run(source_render_frame_id, session_id, 93 scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run(
93 device_id, security_origin); 94 source_render_frame_id, session_id, device_id, security_origin);
94 cache_entry.device_id = cache_entry.sink->GetOutputDeviceInfo().device_id();
95 95
96 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() 96 CacheUnusedSinkIfHealthy(source_render_frame_id,
97 << " - used session to create new sink."; 97 sink->GetOutputDeviceInfo().device_id(),
98 98 security_origin, sink);
99 // Cache a newly-created sink.
100 base::AutoLock auto_lock(cache_lock_);
101 cache_.push_back(cache_entry);
102 UMA_HISTOGRAM_ENUMERATION( 99 UMA_HISTOGRAM_ENUMERATION(
103 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization", 100 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
104 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID, SINK_CACHE_LAST_ENTRY); 101 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID, SINK_CACHE_LAST_ENTRY);
105 102 return sink->GetOutputDeviceInfo();
106 } else { 103 }
107 // Ignore session id. 104 // Ignore session id.
105 {
108 base::AutoLock auto_lock(cache_lock_); 106 base::AutoLock auto_lock(cache_lock_);
109
110 auto cache_iter = 107 auto cache_iter =
111 FindCacheEntry_Locked(source_render_frame_id, device_id, 108 FindCacheEntry_Locked(source_render_frame_id, device_id,
112 security_origin, false /* unused_only */); 109 security_origin, false /* unused_only */);
113
114 if (cache_iter != cache_.end()) { 110 if (cache_iter != cache_.end()) {
115 // A matching cached sink is found. 111 // A matching cached sink is found.
116 DVLOG(1) << "GetSinkInfo: address: " << cache_iter->sink.get()
117 << " - reused a cached sink.";
118
119 UMA_HISTOGRAM_ENUMERATION( 112 UMA_HISTOGRAM_ENUMERATION(
120 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization", 113 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
121 SINK_CACHE_HIT, SINK_CACHE_LAST_ENTRY); 114 SINK_CACHE_HIT, SINK_CACHE_LAST_ENTRY);
122 return cache_iter->sink->GetOutputDeviceInfo(); 115 return cache_iter->sink->GetOutputDeviceInfo();
123 } 116 }
124
125 // No matching sink found, create a new one.
126 cache_entry.device_id = device_id;
127 cache_entry.sink = create_sink_cb_.Run(
128 source_render_frame_id, 0 /* session_id */, device_id, security_origin);
129
130 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get()
131 << " - no matching cached sink found, created a new one.";
132
133 // Cache a newly-created sink.
134 cache_.push_back(cache_entry);
135 UMA_HISTOGRAM_ENUMERATION(
136 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
137 SINK_CACHE_MISS_NO_SINK, SINK_CACHE_LAST_ENTRY);
138 } 117 }
139 118
140 // Schedule it for deletion. 119 // No matching sink found, create a new one.
141 DeleteLaterIfUnused(cache_entry.sink.get()); 120 scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run(
121 source_render_frame_id, 0 /* session_id */, device_id, security_origin);
122 CacheUnusedSinkIfHealthy(source_render_frame_id, device_id, security_origin,
123 sink);
124 UMA_HISTOGRAM_ENUMERATION(
125 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
126 SINK_CACHE_MISS_NO_SINK, SINK_CACHE_LAST_ENTRY);
142 127
143 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() 128 //|sink| is ref-counted, so it's ok if it is removed from cache before we get
144 << " created. source_render_frame_id: " << source_render_frame_id 129 // here.
145 << " session_id: " << session_id << " device_id: " << device_id 130 return sink->GetOutputDeviceInfo();
146 << " security_origin: " << security_origin;
147
148 return cache_entry.sink->GetOutputDeviceInfo();
149 } 131 }
150 132
151 scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink( 133 scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink(
152 int source_render_frame_id, 134 int source_render_frame_id,
153 const std::string& device_id, 135 const std::string& device_id,
154 const url::Origin& security_origin) { 136 const url::Origin& security_origin) {
155 UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.SinkCache.UsedForSinkCreation", 137 UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.SinkCache.UsedForSinkCreation",
156 true); 138 true);
157 139
158 base::AutoLock auto_lock(cache_lock_); 140 base::AutoLock auto_lock(cache_lock_);
159 141
160 auto cache_iter = 142 auto cache_iter =
161 FindCacheEntry_Locked(source_render_frame_id, device_id, security_origin, 143 FindCacheEntry_Locked(source_render_frame_id, device_id, security_origin,
162 true /* unused sink only */); 144 true /* unused sink only */);
163 145
164 if (cache_iter != cache_.end()) { 146 if (cache_iter != cache_.end()) {
165 // Found unused sink; mark it as used and return. 147 // Found unused sink; mark it as used and return.
166 DVLOG(1) << "GetSink: address: " << cache_iter->sink.get()
167 << " - found unused cached sink, reusing it.";
168
169 cache_iter->used = true; 148 cache_iter->used = true;
170 UMA_HISTOGRAM_BOOLEAN( 149 UMA_HISTOGRAM_BOOLEAN(
171 "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", true); 150 "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", true);
172 return cache_iter->sink; 151 return cache_iter->sink;
173 } 152 }
174 153
175 // No unused sink is found, create one, mark it used, cache it and return. 154 // No unused sink is found, create one, mark it used, cache it and return.
176 CacheEntry cache_entry = { 155 CacheEntry cache_entry = {
177 source_render_frame_id, device_id, security_origin, 156 source_render_frame_id, device_id, security_origin,
178 create_sink_cb_.Run(source_render_frame_id, 0 /* session_id */, device_id, 157 create_sink_cb_.Run(source_render_frame_id, 0 /* session_id */, device_id,
179 security_origin), 158 security_origin),
180 true /* used */}; 159 true /* used */};
181 160
182 cache_.push_back(cache_entry); 161 if (SinkIsHealthy(cache_entry.sink.get()))
162 cache_.push_back(cache_entry);
183 163
184 DVLOG(1) << "GetSink: address: " << cache_entry.sink.get()
185 << " - no unused cached sink found, created a new one."
186 << " source_render_frame_id: " << source_render_frame_id
187 << " device_id: " << device_id
188 << " security_origin: " << security_origin;
189 return cache_entry.sink; 164 return cache_entry.sink;
190 } 165 }
191 166
192 void AudioRendererSinkCacheImpl::ReleaseSink( 167 void AudioRendererSinkCacheImpl::ReleaseSink(
193 const media::AudioRendererSink* sink_ptr) { 168 const media::AudioRendererSink* sink_ptr) {
194 // We don't know the sink state, so won't reuse it. Delete it immediately. 169 // We don't know the sink state, so won't reuse it. Delete it immediately.
195 DeleteSink(sink_ptr, true); 170 DeleteSink(sink_ptr, true);
196 } 171 }
197 172
198 void AudioRendererSinkCacheImpl::DeleteLaterIfUnused( 173 void AudioRendererSinkCacheImpl::DeleteLaterIfUnused(
(...skipping 13 matching lines...) Expand all
212 187
213 { 188 {
214 base::AutoLock auto_lock(cache_lock_); 189 base::AutoLock auto_lock(cache_lock_);
215 190
216 // Looking up the sink by its pointer. 191 // Looking up the sink by its pointer.
217 auto cache_iter = std::find_if(cache_.begin(), cache_.end(), 192 auto cache_iter = std::find_if(cache_.begin(), cache_.end(),
218 [sink_ptr](const CacheEntry& val) { 193 [sink_ptr](const CacheEntry& val) {
219 return val.sink.get() == sink_ptr; 194 return val.sink.get() == sink_ptr;
220 }); 195 });
221 196
222 if (cache_iter == cache_.end()) { 197 if (cache_iter == cache_.end())
223 // If |force_delete_used| is not set it means the sink scheduled for
224 // deletion got aquired and released before scheduled deletion - it's ok.
225 DCHECK(!force_delete_used)
226 << "DeleteSink: address: " << sink_ptr
227 << " could not find a sink which is supposed to be in use";
228
229 DVLOG(1) << "DeleteSink: address: " << sink_ptr
230 << " force_delete_used = false - already deleted.";
231 return; 198 return;
232 }
233 199
234 // When |force_delete_used| is set, it's expected that we are deleting a 200 // When |force_delete_used| is set, it's expected that we are deleting a
235 // used sink. 201 // used sink.
236 DCHECK((!force_delete_used) || (force_delete_used && cache_iter->used)) 202 DCHECK((!force_delete_used) || (force_delete_used && cache_iter->used))
237 << "Attempt to delete a non-aquired sink."; 203 << "Attempt to delete a non-aquired sink.";
238 204
239 if (!force_delete_used && cache_iter->used) { 205 if (!force_delete_used && cache_iter->used)
240 DVLOG(1) << "DeleteSink: address: " << sink_ptr
241 << " sink in use, skipping deletion.";
242 return; 206 return;
243 }
244 207
245 // To stop the sink before deletion if it's not used, we need to hold 208 // To stop the sink before deletion if it's not used, we need to hold
246 // a ref to it. 209 // a ref to it.
247 if (!cache_iter->used) { 210 if (!cache_iter->used) {
248 sink_to_stop = cache_iter->sink; 211 sink_to_stop = cache_iter->sink;
249 UMA_HISTOGRAM_BOOLEAN( 212 UMA_HISTOGRAM_BOOLEAN(
250 "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", false); 213 "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", false);
251 } 214 }
252 215
253 cache_.erase(cache_iter); 216 cache_.erase(cache_iter);
254 DVLOG(1) << "DeleteSink: address: " << sink_ptr;
255 } // Lock scope; 217 } // Lock scope;
256 218
257 // Stop the sink out of the lock scope. 219 // Stop the sink out of the lock scope.
258 if (sink_to_stop.get()) { 220 if (sink_to_stop.get()) {
259 DCHECK_EQ(sink_ptr, sink_to_stop.get()); 221 DCHECK_EQ(sink_ptr, sink_to_stop.get());
260 sink_to_stop->Stop(); 222 sink_to_stop->Stop();
261 DVLOG(1) << "DeleteSink: address: " << sink_ptr << " stopped.";
262 } 223 }
263 } 224 }
264 225
265 AudioRendererSinkCacheImpl::CacheContainer::iterator 226 AudioRendererSinkCacheImpl::CacheContainer::iterator
266 AudioRendererSinkCacheImpl::FindCacheEntry_Locked( 227 AudioRendererSinkCacheImpl::FindCacheEntry_Locked(
267 int source_render_frame_id, 228 int source_render_frame_id,
268 const std::string& device_id, 229 const std::string& device_id,
269 const url::Origin& security_origin, 230 const url::Origin& security_origin,
270 bool unused_only) { 231 bool unused_only) {
271 return std::find_if( 232 return std::find_if(
272 cache_.begin(), cache_.end(), 233 cache_.begin(), cache_.end(),
273 [source_render_frame_id, &device_id, &security_origin, 234 [source_render_frame_id, &device_id, &security_origin,
274 unused_only](const CacheEntry& val) { 235 unused_only](const CacheEntry& val) {
275 if (val.used && unused_only) 236 if (val.used && unused_only)
276 return false; 237 return false;
277 if (val.source_render_frame_id != source_render_frame_id) 238 if (val.source_render_frame_id != source_render_frame_id)
278 return false; 239 return false;
279 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && 240 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) &&
280 media::AudioDeviceDescription::IsDefaultDevice(val.device_id)) { 241 media::AudioDeviceDescription::IsDefaultDevice(val.device_id)) {
281 // Both device IDs represent the same default device => do not compare 242 // Both device IDs represent the same default device => do not compare
282 // them; the default device is always authorized => ignore security 243 // them; the default device is always authorized => ignore security
283 // origin. 244 // origin.
284 return true; 245 return true;
285 } 246 }
286 return val.device_id == device_id && 247 return val.device_id == device_id &&
287 val.security_origin == security_origin; 248 val.security_origin == security_origin;
288 }); 249 });
289 }; 250 };
290 251
252 void AudioRendererSinkCacheImpl::CacheUnusedSinkIfHealthy(
253 int source_render_frame_id,
254 const std::string& device_id,
255 const url::Origin& security_origin,
256 scoped_refptr<media::AudioRendererSink> sink) {
257 if (!SinkIsHealthy(sink.get()))
258 return;
259
260 CacheEntry cache_entry = {source_render_frame_id, device_id, security_origin,
261 sink, false /* not used */};
262
263 {
264 base::AutoLock auto_lock(cache_lock_);
265 cache_.push_back(cache_entry);
266 }
267
268 DeleteLaterIfUnused(cache_entry.sink.get());
269 }
270
291 int AudioRendererSinkCacheImpl::GetCacheSizeForTesting() { 271 int AudioRendererSinkCacheImpl::GetCacheSizeForTesting() {
292 return cache_.size(); 272 return cache_.size();
293 } 273 }
294 274
295 } // namespace content 275 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/audio_renderer_sink_cache_impl.h ('k') | content/renderer/media/audio_renderer_sink_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698