OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/bind.h" | |
6 #include "base/location.h" | |
7 #include "base/memory/ptr_util.h" | |
8 #include "base/synchronization/lock.h" | |
9 #include "base/threading/thread_task_runner_handle.h" | |
10 #include "content/renderer/media/audio_device_factory.h" | |
11 #include "content/renderer/media/audio_renderer_sink_cache_impl.h" | |
12 #include "url/origin.h" | |
13 | |
14 namespace { | |
15 enum { kDeleteTimeoutMs = 5000 }; | |
miu
2016/05/19 22:27:15
As of a few weeks ago, they've just started allowi
o1ka
2016/05/23 16:16:54
Thanks. Done.
| |
16 } // namespace | |
17 | |
18 namespace content { | |
19 | |
20 // static | |
21 std::unique_ptr<AudioRendererSinkCache> AudioRendererSinkCache::Create() { | |
22 return base::WrapUnique(new AudioRendererSinkCacheImpl( | |
23 base::ThreadTaskRunnerHandle::Get(), | |
24 base::Bind(AudioDeviceFactory::NewAudioRendererMixerSink), | |
25 kDeleteTimeoutMs)); | |
26 } | |
27 | |
28 AudioRendererSinkCacheImpl::AudioRendererSinkCacheImpl( | |
29 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
30 const CreateSinkCallback& create_sink_cb, | |
31 int delete_timeout_ms) | |
32 : delete_timeout_ms_(delete_timeout_ms), | |
miu
2016/05/19 22:27:15
nit: For consistency/readability, try to maintain
o1ka
2016/05/23 16:16:54
Done.
| |
33 task_runner_(task_runner), | |
34 create_sink_cb_(create_sink_cb), | |
35 weak_ptr_factory_(this) {} | |
36 | |
37 AudioRendererSinkCacheImpl::~AudioRendererSinkCacheImpl() { | |
38 // We just release all the cached sinks here. | |
39 } | |
40 | |
41 media::OutputDeviceInfo AudioRendererSinkCacheImpl::GetSinkInfo( | |
42 int source_render_frame_id, | |
43 int session_id, | |
44 const std::string& device_id, | |
45 const url::Origin& security_origin) { | |
46 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, | |
47 device_id)) { | |
48 // We are provided with session id instead of device id. Session id is | |
49 // unique, so we can't find any matching sink. Creating a new one. | |
50 scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run( | |
51 source_render_frame_id, session_id, device_id, security_origin); | |
52 | |
53 const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); | |
54 DVLOG(1) << "GetSinkInfo: address: " << sink.get() | |
55 << " - used session to create new sink. source_render_frame_id: " | |
56 << source_render_frame_id << " session_id: " << session_id | |
57 << " device_id: " << device_id | |
58 << " security_origin: " << security_origin << " Device info: [" | |
59 << device_info.AsHumanReadableString() << "] "; | |
60 | |
61 const SinkKey key(source_render_frame_id, device_info.device_id(), | |
62 security_origin); | |
63 | |
64 base::AutoLock auto_lock(sinks_lock_); | |
miu
2016/05/19 22:27:15
Try to minimize how long this lock is held (here a
o1ka
2016/05/23 16:16:54
Done.
DaleCurtis
2016/05/23 18:29:08
I don't think the original comment is good advice.
| |
65 // Cache a newly-created sink, using device id obtained from the sink. | |
66 sinks_.insert(std::make_pair( | |
67 key, AudioRendererSinkReference(sink, false /*not in use*/))); | |
68 // And schedule it for deletion. | |
69 DeleteLaterIfUnused(key, sink.get()); | |
70 return device_info; | |
71 } | |
72 | |
73 // We are provided with the actual device id. | |
74 const SinkKey key(source_render_frame_id, device_id, security_origin); | |
75 base::AutoLock auto_lock(sinks_lock_); | |
76 | |
77 { | |
78 auto sink_iter = sinks_.find(key); | |
79 if (sink_iter != sinks_.end()) { | |
80 // A matching cached sink is found. | |
81 DVLOG(1) << "GetSinkInfo: address: " << sink_iter->second.sink.get() | |
82 << " - reusing a cached sink. source_render_frame_id: " | |
83 << source_render_frame_id << " session_id: " << session_id | |
84 << " device_id: " << device_id | |
85 << " security_origin: " << security_origin << " Device info: [" | |
86 << sink_iter->second.sink->GetOutputDeviceInfo() | |
87 .AsHumanReadableString() | |
88 << "] "; | |
89 return sink_iter->second.sink->GetOutputDeviceInfo(); | |
90 } | |
91 } | |
92 | |
93 // No matching sink is found, create one and cache it - still under the lock, | |
94 // see the comment to InsertNewSinkWhileLockHeld(). | |
95 scoped_refptr<media::AudioRendererSink> sink = | |
96 InsertNewSinkWhileLockHeld(key, false /*not in use*/); | |
97 DVLOG(1) << "GetSinkInfo: address: " << sink | |
98 << " - no matching cached sink found, created a new one." | |
99 << " source_render_frame_id: " << source_render_frame_id | |
100 << " session_id: " << session_id << " device_id: " << device_id | |
101 << " security_origin: " << security_origin << " Device info: [" | |
102 << sink->GetOutputDeviceInfo().AsHumanReadableString() << "] "; | |
103 // Schedule it for deletion. | |
104 DeleteLaterIfUnused(key, sink.get()); | |
105 return sink->GetOutputDeviceInfo(); | |
106 } | |
107 | |
108 scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink( | |
109 int source_render_frame_id, | |
110 const std::string& device_id, | |
111 const url::Origin& security_origin) { | |
112 const SinkKey key(source_render_frame_id, device_id, security_origin); | |
113 base::AutoLock auto_lock(sinks_lock_); | |
114 | |
115 const auto range = sinks_.equal_range(key); | |
116 for (auto iter = range.first; iter != range.second; ++iter) { | |
117 if (iter->second.used) | |
118 continue; | |
119 | |
120 // Found unused sink; mark it as used and return. | |
121 DVLOG(1) << "GetSink: address: " << iter->second.sink.get() | |
122 << " - found unused cached sink, reusing it." | |
123 << " source_render_frame_id: " << source_render_frame_id | |
124 << " device_id: " << device_id | |
125 << " security_origin: " << security_origin; | |
126 | |
127 iter->second.used = true; | |
128 return iter->second.sink; | |
129 } | |
130 | |
131 // No unused sink is found, create one, mark it used, cache it and return. | |
132 scoped_refptr<media::AudioRendererSink> sink = | |
133 InsertNewSinkWhileLockHeld(key, true); | |
134 DVLOG(1) << "GetSink: address: " << sink.get() | |
135 << " - no unused cached sink found, created a new one." | |
136 << " source_render_frame_id: " << source_render_frame_id | |
137 << " device_id: " << device_id | |
138 << " security_origin: " << security_origin; | |
139 return sink; | |
140 } | |
141 | |
142 void AudioRendererSinkCacheImpl::ReleaseSink( | |
143 int source_render_frame_id, | |
144 const std::string& device_id, | |
145 const url::Origin& security_origin, | |
146 const media::AudioRendererSink* sink) { | |
147 // We don't know the sink state, so won't reused it. Delete it immediately. | |
miu
2016/05/19 22:27:15
typo: s/reused/reuse/
o1ka
2016/05/23 16:16:54
Done.
| |
148 DeleteSink(SinkKey(source_render_frame_id, device_id, security_origin), sink, | |
149 true); | |
150 } | |
151 | |
152 void AudioRendererSinkCacheImpl::DeleteLaterIfUnused( | |
153 const SinkKey& key, | |
154 const media::AudioRendererSink* sink) { | |
155 DVLOG(1) << "DeleteLaterIfUnused: address: " << sink; | |
156 | |
157 task_runner_->PostDelayedTask( | |
158 FROM_HERE, base::Bind(&AudioRendererSinkCacheImpl::DeleteSink, | |
159 weak_ptr_factory_.GetWeakPtr(), key, sink, | |
160 false /*do not delete if used*/), | |
161 base::TimeDelta::FromMilliseconds(delete_timeout_ms_)); | |
162 } | |
163 | |
164 void AudioRendererSinkCacheImpl::DeleteSink( | |
165 const SinkKey& key, | |
166 const media::AudioRendererSink* sink, | |
167 bool force_delete_used) { | |
168 DCHECK(sink); | |
169 base::AutoLock auto_lock(sinks_lock_); | |
170 | |
171 const auto range = sinks_.equal_range(key); | |
172 for (auto iter = range.first; iter != range.second; ++iter) { | |
173 if (iter->second.sink.get() != sink) | |
174 continue; | |
175 | |
176 const AudioRendererSinkReference& sink_ref(iter->second); | |
177 | |
178 DVLOG(1) << "DeleteSink: address: " << sink | |
179 << " force_delete_used: " << force_delete_used | |
180 << " in use: " << sink_ref.used | |
181 << " source_render_frame_id: " << key.source_render_frame_id | |
182 << " device_id: " << key.device_id | |
183 << " security_origin: " << key.security_origin; | |
184 | |
185 // When |force_delete_used| is set, it's expected that we are deleting a | |
186 // used sink. | |
187 DCHECK((!force_delete_used) || (force_delete_used && sink_ref.used)) | |
188 << "Attempt to delete a non-aquired sink."; | |
189 | |
190 if (force_delete_used || !sink_ref.used) { // We can delete it. | |
191 if (!sink_ref.used) | |
192 sink_ref.sink->Stop(); // Stop the sink before deletion if not used. | |
193 sinks_.erase(iter); | |
194 DVLOG(1) << "DeleteSink: address: " << sink << " deleted. "; | |
195 } else { | |
196 DVLOG(1) << "DeleteSink: address: " << sink | |
197 << " sink in use, skipping deletion."; | |
198 } | |
199 | |
200 return; | |
201 } // for | |
202 | |
203 // If we got here and |force_delete_used| is not set it means the sink | |
204 // scheduled for deletion get aquired and released before scheduled deletion - | |
205 // this is ok. | |
206 DCHECK(!force_delete_used) << "DeleteSink: address: " << sink | |
207 << " could not find a sink which is supposed to be" | |
208 << " in use. Wrong key? source_render_frame_id: " | |
209 << key.source_render_frame_id | |
210 << " device_id: " << key.device_id | |
211 << " security_origin: " << key.security_origin; | |
212 } | |
213 | |
214 scoped_refptr<media::AudioRendererSink> | |
215 AudioRendererSinkCacheImpl::InsertNewSinkWhileLockHeld(const SinkKey& key, | |
216 bool used) { | |
217 sinks_lock_.AssertAcquired(); | |
218 const AudioRendererSinkMap::iterator& iter = sinks_.insert(std::make_pair( | |
219 key, AudioRendererSinkReference( | |
220 create_sink_cb_.Run(key.source_render_frame_id, 0, key.device_id, | |
221 key.security_origin), | |
222 used))); | |
223 return iter->second.sink; | |
224 } | |
225 | |
226 AudioRendererSinkCacheImpl::SinkKey::SinkKey(int source_render_frame_id, | |
227 const std::string& device_id, | |
228 const url::Origin& security_origin) | |
229 : source_render_frame_id(source_render_frame_id), | |
230 device_id(device_id), | |
231 security_origin(security_origin) {} | |
232 | |
233 AudioRendererSinkCacheImpl::SinkKey::SinkKey(const SinkKey& other) = default; | |
234 | |
235 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
236 AudioRendererSinkReference(scoped_refptr<media::AudioRendererSink> sink, | |
237 bool used) | |
238 : sink(sink), used(used) {} | |
239 | |
240 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
241 AudioRendererSinkReference(const AudioRendererSinkReference& other) = | |
242 default; | |
243 | |
244 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
245 ~AudioRendererSinkReference() {} | |
246 | |
247 } // namespace content | |
OLD | NEW |