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_impl.cc

Issue 1942803002: Caching AudioOutputDevice instances in mixer manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: First round of comments addressed 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.
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 };
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),
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_);
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.
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 sink_ref.sink->Stop(); // Sink must be stopped before deletion.
192 sinks_.erase(iter);
193 DVLOG(1) << "DeleteSink: address: " << sink << " deleted. ";
194 } else {
195 DVLOG(1) << "DeleteSink: address: " << sink
196 << " sink in use, skipping deletion.";
197 }
198
199 return;
200 } // for
201
202 // If we got here and |force_delete_used| is not set it means the sink
203 // scheduled for deletion get aquired and released before scheduled deletion -
204 // this is ok.
205 DCHECK(!force_delete_used) << "DeleteSink: address: " << sink
206 << " could not find a sink which is supposed to be"
207 << " in use. Wrong key? source_render_frame_id: "
208 << key.source_render_frame_id
209 << " device_id: " << key.device_id
210 << " security_origin: " << key.security_origin;
211 }
212
213 scoped_refptr<media::AudioRendererSink>
214 AudioRendererSinkCacheImpl::InsertNewSinkWhileLockHeld(const SinkKey& key,
215 bool used) {
216 sinks_lock_.AssertAcquired();
217 const AudioRendererSinkMap::iterator& iter = sinks_.insert(std::make_pair(
218 key, AudioRendererSinkReference(
219 create_sink_cb_.Run(key.source_render_frame_id, 0, key.device_id,
220 key.security_origin),
221 used)));
222 return iter->second.sink;
223 }
224
225 AudioRendererSinkCacheImpl::SinkKey::SinkKey(int source_render_frame_id,
226 const std::string& device_id,
227 const url::Origin& security_origin)
228 : source_render_frame_id(source_render_frame_id),
229 device_id(device_id),
230 security_origin(security_origin) {}
231
232 AudioRendererSinkCacheImpl::SinkKey::SinkKey(const SinkKey& other) = default;
233
234 AudioRendererSinkCacheImpl::AudioRendererSinkReference::
235 AudioRendererSinkReference(scoped_refptr<media::AudioRendererSink> sink,
236 bool used)
237 : sink(sink), used(used) {}
238
239 AudioRendererSinkCacheImpl::AudioRendererSinkReference::
240 AudioRendererSinkReference(const AudioRendererSinkReference& other) =
241 default;
242
243 AudioRendererSinkCacheImpl::AudioRendererSinkReference::
244 ~AudioRendererSinkReference() {}
245
246 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698