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

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

Issue 1942803002: Caching AudioOutputDevice instances in mixer manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase, fix for sleep() compile error on win and a bit of cleanup around timeouts. Created 4 years, 7 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
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698