OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
miu
2016/05/12 21:53:06
To be consistent with how this is done for other i
o1ka
2016/05/17 17:17:23
Done.
| |
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/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 | |
13 namespace content { | |
14 | |
15 // static | |
16 std::unique_ptr<AudioRendererSinkCache> | |
17 AudioRendererSinkCache::CreateDefault() { | |
chcunningham
2016/05/12 19:56:31
You named MixerManager's method ::Create() (no Def
o1ka
2016/05/17 17:17:23
Done.
| |
18 return base::WrapUnique(new AudioRendererSinkCacheImpl( | |
19 base::ThreadTaskRunnerHandle::Get(), | |
20 base::Bind(AudioDeviceFactory::NewAudioRendererMixerSink))); | |
21 } | |
22 | |
23 AudioRendererSinkCacheImpl::AudioRendererSinkCacheImpl( | |
24 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
25 const CreateSinkCallback& create_sink_cb) | |
26 : task_runner_(task_runner), | |
27 create_sink_cb_(create_sink_cb), | |
28 weak_ptr_factory_(this) {} | |
29 | |
30 AudioRendererSinkCacheImpl::~AudioRendererSinkCacheImpl() { | |
31 for (auto& iter : sinks_) | |
miu
2016/05/12 21:53:06
Consider (for safety):
sinks_lock_.AssertNotHel
o1ka
2016/05/17 17:17:23
AFAIK there is no AssertNotHeld() in chromium, onl
| |
32 iter.second.sink->Stop(); | |
33 } | |
34 | |
35 media::OutputDeviceInfo AudioRendererSinkCacheImpl::GetSinkInfo( | |
36 int source_render_frame_id, | |
37 int session_id, | |
38 const std::string& device_id, | |
39 const url::Origin& security_origin) { | |
40 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, | |
41 device_id)) { | |
42 // We are provided with session id instead of device id. Session id is | |
43 // unique, so we can't find any matching sink. Creating a new one. | |
44 scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run( | |
45 source_render_frame_id, session_id, device_id, security_origin); | |
46 | |
47 const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); | |
48 DVLOG(1) << "GetSinkInfo: address: " << sink.get() | |
49 << " - used session to create new sink. source_render_frame_id: " | |
50 << source_render_frame_id << " session_id: " << session_id | |
51 << " device_id: " << device_id | |
52 << " security_origin: " << security_origin << " Device info: [" | |
53 << device_info.AsHumanReadableString() << "] "; | |
54 | |
55 base::AutoLock auto_lock(sinks_lock_); | |
56 // Cache a newly-created sink, using device id obtained from the sink. | |
57 sinks_.insert( | |
58 std::make_pair(SinkKey(source_render_frame_id, device_info.device_id(), | |
miu
2016/05/12 21:53:06
Does session_id need to be in the SinkKey?
o1ka
2016/05/17 17:17:23
No. Session_id is a mapping between an open input
| |
59 security_origin), | |
60 AudioRendererSinkReference(sink, false /*not in use*/))); | |
61 // And schedule it for deletion. | |
62 DeleteLaterIfUnused(sink.get()); | |
63 return device_info; | |
64 } | |
65 | |
66 // We are provided with the actual device id. | |
67 const SinkKey key(source_render_frame_id, device_id, security_origin); | |
68 base::AutoLock auto_lock(sinks_lock_); | |
69 | |
70 { | |
71 auto sink_iter = sinks_.find(key); | |
72 if (sink_iter != sinks_.end()) { | |
73 // A matching cached sink is found. | |
74 DVLOG(1) << "GetSinkInfo: address: " << sink_iter->second.sink.get() | |
75 << " - reusing a cached sink. source_render_frame_id: " | |
76 << source_render_frame_id << " session_id: " << session_id | |
77 << " device_id: " << device_id | |
78 << " security_origin: " << security_origin << " Device info: [" | |
79 << sink_iter->second.sink->GetOutputDeviceInfo() | |
80 .AsHumanReadableString() | |
81 << "] "; | |
82 return sink_iter->second.sink->GetOutputDeviceInfo(); | |
83 } | |
84 } | |
85 | |
86 // No matching sink is found, create one and cache it - still under the lock, | |
87 // see the comment to InsertNewSink(). | |
88 media::AudioRendererSink* sink = InsertNewSink(key, false /*not in use*/); | |
89 DVLOG(1) << "GetSinkInfo: address: " << sink | |
90 << " - no matching cached sink found, created a new one." | |
91 << " source_render_frame_id: " << source_render_frame_id | |
92 << " session_id: " << session_id << " device_id: " << device_id | |
93 << " security_origin: " << security_origin << " Device info: [" | |
94 << sink->GetOutputDeviceInfo().AsHumanReadableString() << "] "; | |
95 // Schedule it for deletion. | |
96 DeleteLaterIfUnused(sink); | |
97 return sink->GetOutputDeviceInfo(); | |
98 } | |
99 | |
100 media::AudioRendererSink* AudioRendererSinkCacheImpl::GetSink( | |
101 int source_render_frame_id, | |
102 const std::string& device_id, | |
103 const url::Origin& security_origin) { | |
104 const SinkKey key(source_render_frame_id, device_id, security_origin); | |
105 base::AutoLock auto_lock(sinks_lock_); | |
106 | |
107 const auto range = sinks_.equal_range(key); | |
108 for (auto iter = range.first; iter != range.second; ++iter) { | |
109 if (!iter->second.used) { | |
110 // Found unused sink; mark it as used and return. | |
111 DVLOG(1) << "GetSink: address: " << iter->second.sink.get() | |
112 << " - found unused cached sink, reusing it." | |
113 << " source_render_frame_id: " << source_render_frame_id | |
114 << " device_id: " << device_id | |
115 << " security_origin: " << security_origin; | |
116 | |
117 iter->second.used = true; | |
118 return iter->second.sink.get(); | |
119 } | |
120 } | |
121 | |
122 // No unused sink is found, create one, mark it used, cache it and return. | |
123 media::AudioRendererSink* sink = InsertNewSink(key, true); | |
miu
2016/05/12 21:53:06
Should there be an upper-bound, where we decide to
o1ka
2016/05/17 17:17:23
No, not for now at least. Temporary sinks created
| |
124 DVLOG(1) << "GetSink: address: " << sink | |
125 << " - no unused cached sink found, created a new one." | |
126 << " source_render_frame_id: " << source_render_frame_id | |
127 << " device_id: " << device_id | |
128 << " security_origin: " << security_origin; | |
129 return sink; | |
130 } | |
131 | |
132 void AudioRendererSinkCacheImpl::ReleaseSink(media::AudioRendererSink* sink) { | |
133 // We don't know the sink state, so won't reused it. Delete it immediately. | |
134 DeleteSink(sink, true); | |
135 } | |
136 | |
137 void AudioRendererSinkCacheImpl::DeleteLaterIfUnused( | |
138 media::AudioRendererSink* sink) { | |
139 DVLOG(1) << "DeleteLaterIfUnused: address: " << sink; | |
140 | |
141 task_runner_->PostDelayedTask( | |
142 FROM_HERE, base::Bind(&AudioRendererSinkCacheImpl::DeleteSink, | |
143 weak_ptr_factory_.GetWeakPtr(), sink, | |
144 false /*do not delete if used*/), | |
145 base::TimeDelta::FromMilliseconds(kDeleteTimeoutMs)); | |
146 } | |
147 | |
148 void AudioRendererSinkCacheImpl::DeleteSink(media::AudioRendererSink* sink, | |
149 bool force_delete_used) { | |
150 DCHECK(sink); | |
151 base::AutoLock auto_lock(sinks_lock_); | |
152 | |
153 // The sink key is not used for look up, to keep the interface simple: | |
154 // otherwise both the key and the sink pointer needs to be specified, since | |
155 // the key is not unique. Looking up by the key won't give any significant | |
156 // performance improvement, since the number of sinks is small. | |
157 for (auto iter = sinks_.begin(); iter != sinks_.end(); ++iter) { | |
158 if (iter->second.sink.get() == sink) { // Sink is found. | |
miu
2016/05/12 21:53:06
nit: Invert the if-statement expression so the ~25
o1ka
2016/05/17 17:17:24
Done. (I hope I did not miss anything)
| |
159 AudioRendererSinkReference& sink_ref(iter->second); | |
160 | |
161 DVLOG(1) << "DeleteSink: address: " << sink | |
162 << " force_delete_used: " << force_delete_used | |
163 << " in use: " << sink_ref.used << " source_render_frame_id: " | |
164 << iter->first.source_render_frame_id | |
165 << " device_id: " << iter->first.device_id | |
166 << " security_origin: " << iter->first.security_origin; | |
167 | |
168 // When |force_delete_used| is set, it's expected that we are deleting a | |
169 // used sink. | |
170 DCHECK((!force_delete_used) || (force_delete_used && sink_ref.used)) | |
171 << "Attempt to delete a non-aquired sink."; | |
172 | |
173 if (force_delete_used || !sink_ref.used) { // We can delete it. | |
174 sink_ref.sink->Stop(); // Sink must be stopped before deletion. | |
175 sinks_.erase(iter); | |
176 DVLOG(1) << "DeleteSink: address: " << sink << " deleted. "; | |
177 } else { | |
178 DVLOG(1) << "DeleteSink: address: " << sink | |
179 << " sink in use, skipping deletion."; | |
180 } | |
181 | |
182 return; | |
183 } | |
184 } | |
185 | |
186 // If we get here and |force_delete_used| is not set it means the sink | |
187 // scheduled for deletion get aquired and released before scheduled deletion - | |
chcunningham
2016/05/12 19:56:31
s/get/got/
o1ka
2016/05/17 17:17:24
Done.
| |
188 // this is ok. | |
189 DCHECK(!force_delete_used) << "Attempt to delete non-existing sink."; | |
190 } | |
191 | |
192 media::AudioRendererSink* AudioRendererSinkCacheImpl::InsertNewSink( | |
chcunningham
2016/05/12 19:56:31
I'm used to seeing such methods named *_Locked - n
miu
2016/05/12 21:53:06
I've also seen people name methods like this: Inse
o1ka
2016/05/17 17:17:24
Done.
| |
193 const SinkKey& key, | |
194 bool used) { | |
195 sinks_lock_.AssertAcquired(); | |
196 const AudioRendererSinkMap::iterator& iter = sinks_.insert(std::make_pair( | |
197 key, AudioRendererSinkReference( | |
198 create_sink_cb_.Run(key.source_render_frame_id, 0, key.device_id, | |
199 key.security_origin), | |
200 used))); | |
201 return iter->second.sink.get(); | |
202 } | |
203 | |
204 AudioRendererSinkCacheImpl::SinkKey::SinkKey(int source_render_frame_id, | |
205 const std::string& device_id, | |
206 const url::Origin& security_origin) | |
207 : source_render_frame_id(source_render_frame_id), | |
208 device_id(device_id), | |
209 security_origin(security_origin) {} | |
210 | |
211 AudioRendererSinkCacheImpl::SinkKey::SinkKey(const SinkKey& other) = default; | |
212 | |
213 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
214 AudioRendererSinkReference(scoped_refptr<media::AudioRendererSink> sink, | |
215 bool used) | |
216 : sink(sink), used(used) {} | |
217 | |
218 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
219 AudioRendererSinkReference(const AudioRendererSinkReference& other) = | |
220 default; | |
221 | |
222 AudioRendererSinkCacheImpl::AudioRendererSinkReference:: | |
223 ~AudioRendererSinkReference() {} | |
224 | |
225 } // namespace content | |
OLD | NEW |