OLD | NEW |
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/synchronization/lock.h" | 11 #include "base/synchronization/lock.h" |
11 #include "base/threading/thread_task_runner_handle.h" | 12 #include "base/threading/thread_task_runner_handle.h" |
12 #include "content/renderer/media/audio_device_factory.h" | 13 #include "content/renderer/media/audio_device_factory.h" |
13 #include "content/renderer/media/audio_renderer_sink_cache_impl.h" | 14 #include "content/renderer/media/audio_renderer_sink_cache_impl.h" |
14 #include "media/audio/audio_device_description.h" | 15 #include "media/audio/audio_device_description.h" |
15 #include "media/base/audio_renderer_sink.h" | 16 #include "media/base/audio_renderer_sink.h" |
16 #include "url/origin.h" | 17 #include "url/origin.h" |
17 | 18 |
18 namespace content { | 19 namespace content { |
19 | 20 |
20 constexpr int kDeleteTimeoutMs = 5000; | 21 constexpr int kDeleteTimeoutMs = 5000; |
21 | 22 |
| 23 namespace { |
| 24 |
| 25 enum GetOutputDeviceInfoCacheUtilization { |
| 26 // No cached sink found. |
| 27 SINK_CACHE_MISS_NO_SINK = 0, |
| 28 |
| 29 // If session id is used to specify a device, we always have to create and |
| 30 // cache a new sink. |
| 31 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID = 1, |
| 32 |
| 33 // Output parmeters for an already-cached sink are requested. |
| 34 SINK_CACHE_HIT = 2, |
| 35 |
| 36 // For UMA. |
| 37 SINK_CACHE_LAST_ENTRY |
| 38 }; |
| 39 |
| 40 } // namespace |
| 41 |
22 // Cached sink data. | 42 // Cached sink data. |
23 struct AudioRendererSinkCacheImpl::CacheEntry { | 43 struct AudioRendererSinkCacheImpl::CacheEntry { |
24 int source_render_frame_id; | 44 int source_render_frame_id; |
25 std::string device_id; | 45 std::string device_id; |
26 url::Origin security_origin; | 46 url::Origin security_origin; |
27 scoped_refptr<media::AudioRendererSink> sink; // Sink instance | 47 scoped_refptr<media::AudioRendererSink> sink; // Sink instance |
28 bool used; // True if in use by a client. | 48 bool used; // True if in use by a client. |
29 }; | 49 }; |
30 | 50 |
31 // static | 51 // static |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 cache_entry.sink = create_sink_cb_.Run(source_render_frame_id, session_id, | 87 cache_entry.sink = create_sink_cb_.Run(source_render_frame_id, session_id, |
68 device_id, security_origin); | 88 device_id, security_origin); |
69 cache_entry.device_id = cache_entry.sink->GetOutputDeviceInfo().device_id(); | 89 cache_entry.device_id = cache_entry.sink->GetOutputDeviceInfo().device_id(); |
70 | 90 |
71 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() | 91 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() |
72 << " - used session to create new sink."; | 92 << " - used session to create new sink."; |
73 | 93 |
74 // Cache a newly-created sink. | 94 // Cache a newly-created sink. |
75 base::AutoLock auto_lock(cache_lock_); | 95 base::AutoLock auto_lock(cache_lock_); |
76 cache_.push_back(cache_entry); | 96 cache_.push_back(cache_entry); |
| 97 UMA_HISTOGRAM_ENUMERATION( |
| 98 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization", |
| 99 SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID, SINK_CACHE_LAST_ENTRY); |
77 | 100 |
78 } else { | 101 } else { |
79 // Ignore session id. | 102 // Ignore session id. |
80 base::AutoLock auto_lock(cache_lock_); | 103 base::AutoLock auto_lock(cache_lock_); |
81 | 104 |
82 auto cache_iter = | 105 auto cache_iter = |
83 FindCacheEntry_Locked(source_render_frame_id, device_id, | 106 FindCacheEntry_Locked(source_render_frame_id, device_id, |
84 security_origin, false /* unused_only */); | 107 security_origin, false /* unused_only */); |
85 | 108 |
86 if (cache_iter != cache_.end()) { | 109 if (cache_iter != cache_.end()) { |
87 // A matching cached sink is found. | 110 // A matching cached sink is found. |
88 DVLOG(1) << "GetSinkInfo: address: " << cache_iter->sink.get() | 111 DVLOG(1) << "GetSinkInfo: address: " << cache_iter->sink.get() |
89 << " - reused a cached sink."; | 112 << " - reused a cached sink."; |
90 | 113 |
| 114 UMA_HISTOGRAM_ENUMERATION( |
| 115 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization", |
| 116 SINK_CACHE_HIT, SINK_CACHE_LAST_ENTRY); |
91 return cache_iter->sink->GetOutputDeviceInfo(); | 117 return cache_iter->sink->GetOutputDeviceInfo(); |
92 } | 118 } |
93 | 119 |
94 // No matching sink found, create a new one. | 120 // No matching sink found, create a new one. |
95 cache_entry.device_id = device_id; | 121 cache_entry.device_id = device_id; |
96 cache_entry.sink = create_sink_cb_.Run( | 122 cache_entry.sink = create_sink_cb_.Run( |
97 source_render_frame_id, 0 /* session_id */, device_id, security_origin); | 123 source_render_frame_id, 0 /* session_id */, device_id, security_origin); |
98 | 124 |
99 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() | 125 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() |
100 << " - no matching cached sink found, created a new one."; | 126 << " - no matching cached sink found, created a new one."; |
101 | 127 |
102 // Cache a newly-created sink. | 128 // Cache a newly-created sink. |
103 cache_.push_back(cache_entry); | 129 cache_.push_back(cache_entry); |
| 130 UMA_HISTOGRAM_ENUMERATION( |
| 131 "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization", |
| 132 SINK_CACHE_MISS_NO_SINK, SINK_CACHE_LAST_ENTRY); |
104 } | 133 } |
105 | 134 |
106 // Schedule it for deletion. | 135 // Schedule it for deletion. |
107 DeleteLaterIfUnused(cache_entry.sink.get()); | 136 DeleteLaterIfUnused(cache_entry.sink.get()); |
108 | 137 |
109 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() | 138 DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() |
110 << " created. source_render_frame_id: " << source_render_frame_id | 139 << " created. source_render_frame_id: " << source_render_frame_id |
111 << " session_id: " << session_id << " device_id: " << device_id | 140 << " session_id: " << session_id << " device_id: " << device_id |
112 << " security_origin: " << security_origin; | 141 << " security_origin: " << security_origin; |
113 | 142 |
114 return cache_entry.sink->GetOutputDeviceInfo(); | 143 return cache_entry.sink->GetOutputDeviceInfo(); |
115 } | 144 } |
116 | 145 |
117 scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink( | 146 scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink( |
118 int source_render_frame_id, | 147 int source_render_frame_id, |
119 const std::string& device_id, | 148 const std::string& device_id, |
120 const url::Origin& security_origin) { | 149 const url::Origin& security_origin) { |
| 150 UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.SinkCache.UsedForSinkCreation", |
| 151 true); |
| 152 |
121 base::AutoLock auto_lock(cache_lock_); | 153 base::AutoLock auto_lock(cache_lock_); |
122 | 154 |
123 auto cache_iter = | 155 auto cache_iter = |
124 FindCacheEntry_Locked(source_render_frame_id, device_id, security_origin, | 156 FindCacheEntry_Locked(source_render_frame_id, device_id, security_origin, |
125 true /* unused_only */); | 157 true /* unused_only */); |
126 | 158 |
127 if (cache_iter != cache_.end()) { | 159 if (cache_iter != cache_.end()) { |
128 // Found unused sink; mark it as used and return. | 160 // Found unused sink; mark it as used and return. |
129 DVLOG(1) << "GetSink: address: " << cache_iter->sink.get() | 161 DVLOG(1) << "GetSink: address: " << cache_iter->sink.get() |
130 << " - found unused cached sink, reusing it."; | 162 << " - found unused cached sink, reusing it."; |
131 | 163 |
132 cache_iter->used = true; | 164 cache_iter->used = true; |
| 165 UMA_HISTOGRAM_BOOLEAN( |
| 166 "Media.Audio.Renderer.SinkCache.InfoSinkReusedForOutput", true); |
133 return cache_iter->sink; | 167 return cache_iter->sink; |
134 } | 168 } |
135 | 169 |
136 // No unused sink is found, create one, mark it used, cache it and return. | 170 // No unused sink is found, create one, mark it used, cache it and return. |
137 CacheEntry cache_entry = { | 171 CacheEntry cache_entry = { |
138 source_render_frame_id, device_id, security_origin, | 172 source_render_frame_id, device_id, security_origin, |
139 create_sink_cb_.Run(source_render_frame_id, 0 /* session_id */, device_id, | 173 create_sink_cb_.Run(source_render_frame_id, 0 /* session_id */, device_id, |
140 security_origin), | 174 security_origin), |
141 true /* used */}; | 175 true /* used */}; |
142 | 176 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 << "Attempt to delete a non-aquired sink."; | 232 << "Attempt to delete a non-aquired sink."; |
199 | 233 |
200 if (!force_delete_used && cache_iter->used) { | 234 if (!force_delete_used && cache_iter->used) { |
201 DVLOG(1) << "DeleteSink: address: " << sink_ptr | 235 DVLOG(1) << "DeleteSink: address: " << sink_ptr |
202 << " sink in use, skipping deletion."; | 236 << " sink in use, skipping deletion."; |
203 return; | 237 return; |
204 } | 238 } |
205 | 239 |
206 // To stop the sink before deletion if it's not used, we need to hold | 240 // To stop the sink before deletion if it's not used, we need to hold |
207 // a ref to it. | 241 // a ref to it. |
208 if (!cache_iter->used) | 242 if (!cache_iter->used) { |
209 sink_to_stop = cache_iter->sink; | 243 sink_to_stop = cache_iter->sink; |
| 244 UMA_HISTOGRAM_BOOLEAN( |
| 245 "Media.Audio.Renderer.SinkCache.InfoSinkReusedForOutput", false); |
| 246 } |
210 | 247 |
211 cache_.erase(cache_iter); | 248 cache_.erase(cache_iter); |
212 DVLOG(1) << "DeleteSink: address: " << sink_ptr; | 249 DVLOG(1) << "DeleteSink: address: " << sink_ptr; |
213 } // Lock scope; | 250 } // Lock scope; |
214 | 251 |
215 // Stop the sink out of the lock scope. | 252 // Stop the sink out of the lock scope. |
216 if (sink_to_stop.get()) { | 253 if (sink_to_stop.get()) { |
217 DCHECK_EQ(sink_ptr, sink_to_stop.get()); | 254 DCHECK_EQ(sink_ptr, sink_to_stop.get()); |
218 sink_to_stop->Stop(); | 255 sink_to_stop->Stop(); |
219 DVLOG(1) << "DeleteSink: address: " << sink_ptr << " stopped."; | 256 DVLOG(1) << "DeleteSink: address: " << sink_ptr << " stopped."; |
(...skipping 24 matching lines...) Expand all Loading... |
244 return val.device_id == device_id && | 281 return val.device_id == device_id && |
245 val.security_origin == security_origin; | 282 val.security_origin == security_origin; |
246 }); | 283 }); |
247 }; | 284 }; |
248 | 285 |
249 int AudioRendererSinkCacheImpl::GetCacheSizeForTesting() { | 286 int AudioRendererSinkCacheImpl::GetCacheSizeForTesting() { |
250 return cache_.size(); | 287 return cache_.size(); |
251 } | 288 } |
252 | 289 |
253 } // namespace content | 290 } // namespace content |
OLD | NEW |