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

Side by Side Diff: chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc

Issue 2791203002: Switching WebRtc private API from AudioManager to AudioSystem (Closed)
Patch Set: browser_tests fixed Created 3 years, 8 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_privat e_api.h" 5 #include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_privat e_api.h"
6 6
7 #include <utility> 7 #include <utility>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/task_runner_util.h" 13 #include "base/task_runner_util.h"
14 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 14 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
15 #include "chrome/browser/extensions/extension_tab_util.h" 15 #include "chrome/browser/extensions/extension_tab_util.h"
16 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #include "content/public/browser/media_device_id.h" 17 #include "content/public/browser/media_device_id.h"
18 #include "content/public/browser/web_contents.h" 18 #include "content/public/browser/web_contents.h"
19 #include "extensions/browser/event_router.h" 19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_registry.h" 20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/error_utils.h" 21 #include "extensions/common/error_utils.h"
22 #include "extensions/common/permissions/permissions_data.h" 22 #include "extensions/common/permissions/permissions_data.h"
23 #include "media/audio/audio_device_description.h" 23 #include "media/audio/audio_system.h"
24 #include "url/gurl.h" 24 #include "url/gurl.h"
25 #include "url/origin.h" 25 #include "url/origin.h"
26 26
27 namespace extensions { 27 namespace extensions {
28 28
29 using content::BrowserThread; 29 using content::BrowserThread;
30 using content::RenderProcessHost;
31 using media::AudioDeviceDescriptions;
32 using media::AudioManager;
33
34 namespace wap = api::webrtc_audio_private; 30 namespace wap = api::webrtc_audio_private;
35 31
36 using api::webrtc_audio_private::RequestInfo; 32 using api::webrtc_audio_private::RequestInfo;
37 33
38 static base::LazyInstance<BrowserContextKeyedAPIFactory< 34 static base::LazyInstance<BrowserContextKeyedAPIFactory<
39 WebrtcAudioPrivateEventService>>::DestructorAtExit g_factory = 35 WebrtcAudioPrivateEventService>>::DestructorAtExit g_factory =
40 LAZY_INSTANCE_INITIALIZER; 36 LAZY_INSTANCE_INITIALIZER;
41 37
42 WebrtcAudioPrivateEventService::WebrtcAudioPrivateEventService( 38 WebrtcAudioPrivateEventService::WebrtcAudioPrivateEventService(
43 content::BrowserContext* context) 39 content::BrowserContext* context)
(...skipping 25 matching lines...) Expand all
69 return "WebrtcAudioPrivateEventService"; 65 return "WebrtcAudioPrivateEventService";
70 } 66 }
71 67
72 void WebrtcAudioPrivateEventService::OnDevicesChanged( 68 void WebrtcAudioPrivateEventService::OnDevicesChanged(
73 base::SystemMonitor::DeviceType device_type) { 69 base::SystemMonitor::DeviceType device_type) {
74 switch (device_type) { 70 switch (device_type) {
75 case base::SystemMonitor::DEVTYPE_AUDIO: 71 case base::SystemMonitor::DEVTYPE_AUDIO:
76 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: 72 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE:
77 SignalEvent(); 73 SignalEvent();
78 break; 74 break;
79
80 default: 75 default:
81 // No action needed. 76 // No action needed.
82 break; 77 break;
83 } 78 }
84 } 79 }
85 80
86 void WebrtcAudioPrivateEventService::SignalEvent() { 81 void WebrtcAudioPrivateEventService::SignalEvent() {
87 using api::webrtc_audio_private::OnSinksChanged::kEventName; 82 using api::webrtc_audio_private::OnSinksChanged::kEventName;
88 83
89 EventRouter* router = EventRouter::Get(browser_context_); 84 EventRouter* router = EventRouter::Get(browser_context_);
90 if (!router || !router->HasEventListener(kEventName)) 85 if (!router || !router->HasEventListener(kEventName))
91 return; 86 return;
92 87
93 for (const scoped_refptr<const extensions::Extension>& extension : 88 for (const scoped_refptr<const extensions::Extension>& extension :
94 ExtensionRegistry::Get(browser_context_)->enabled_extensions()) { 89 ExtensionRegistry::Get(browser_context_)->enabled_extensions()) {
95 const std::string& extension_id = extension->id(); 90 const std::string& extension_id = extension->id();
96 if (router->ExtensionHasEventListener(extension_id, kEventName) && 91 if (router->ExtensionHasEventListener(extension_id, kEventName) &&
97 extension->permissions_data()->HasAPIPermission("webrtcAudioPrivate")) { 92 extension->permissions_data()->HasAPIPermission("webrtcAudioPrivate")) {
98 std::unique_ptr<Event> event = base::MakeUnique<Event>( 93 std::unique_ptr<Event> event = base::MakeUnique<Event>(
99 events::WEBRTC_AUDIO_PRIVATE_ON_SINKS_CHANGED, kEventName, 94 events::WEBRTC_AUDIO_PRIVATE_ON_SINKS_CHANGED, kEventName,
100 base::MakeUnique<base::ListValue>()); 95 base::MakeUnique<base::ListValue>());
101 router->DispatchEventToExtension(extension_id, std::move(event)); 96 router->DispatchEventToExtension(extension_id, std::move(event));
102 } 97 }
103 } 98 }
104 } 99 }
105 100
106 WebrtcAudioPrivateFunction::WebrtcAudioPrivateFunction() {} 101 WebrtcAudioPrivateFunction::WebrtcAudioPrivateFunction() {}
107 102
108 WebrtcAudioPrivateFunction::~WebrtcAudioPrivateFunction() { 103 WebrtcAudioPrivateFunction::~WebrtcAudioPrivateFunction() {}
109 }
110 104
111 void WebrtcAudioPrivateFunction::GetOutputDeviceDescriptions() { 105 std::string WebrtcAudioPrivateFunction::CalculateHMAC(
112 scoped_refptr<base::SingleThreadTaskRunner> audio_manager_runner =
113 AudioManager::Get()->GetTaskRunner();
114 if (!audio_manager_runner->BelongsToCurrentThread()) {
115 DCHECK_CURRENTLY_ON(BrowserThread::UI);
116 audio_manager_runner->PostTask(
117 FROM_HERE,
118 base::Bind(&WebrtcAudioPrivateFunction::GetOutputDeviceDescriptions,
119 this));
120 return;
121 }
122
123 std::unique_ptr<AudioDeviceDescriptions> device_descriptions =
124 base::MakeUnique<AudioDeviceDescriptions>();
125 AudioManager::Get()->GetAudioOutputDeviceDescriptions(
126 device_descriptions.get());
127
128 BrowserThread::PostTask(
129 BrowserThread::IO, FROM_HERE,
130 base::Bind(&WebrtcAudioPrivateFunction::OnOutputDeviceDescriptions, this,
131 base::Passed(&device_descriptions)));
132 }
133
134 void WebrtcAudioPrivateFunction::OnOutputDeviceDescriptions(
135 std::unique_ptr<AudioDeviceDescriptions> device_descriptions) {
136 NOTREACHED();
137 }
138
139 void WebrtcAudioPrivateFunction::CalculateHMAC(const std::string& raw_id) {
140 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
141 BrowserThread::PostTask(
142 BrowserThread::IO,
143 FROM_HERE,
144 base::Bind(&WebrtcAudioPrivateFunction::CalculateHMAC, this, raw_id));
145 return;
146 }
147
148 std::string hmac = CalculateHMACImpl(raw_id);
149 BrowserThread::PostTask(
150 BrowserThread::UI,
151 FROM_HERE,
152 base::Bind(&WebrtcAudioPrivateFunction::OnHMACCalculated, this, hmac));
153 }
154
155 void WebrtcAudioPrivateFunction::OnHMACCalculated(const std::string& hmac) {
156 NOTREACHED();
157 }
158
159 std::string WebrtcAudioPrivateFunction::CalculateHMACImpl(
160 const std::string& raw_id) { 106 const std::string& raw_id) {
161 DCHECK_CURRENTLY_ON(BrowserThread::IO); 107 DCHECK_CURRENTLY_ON(BrowserThread::IO);
162 108
163 // We don't hash the default device description, and we always return 109 // We don't hash the default device description, and we always return
164 // "default" for the default device. There is code in SetActiveSink 110 // "default" for the default device. There is code in SetActiveSink
165 // that transforms "default" to the empty string, and code in 111 // that transforms "default" to the empty string, and code in
166 // GetActiveSink that ensures we return "default" if we get the 112 // GetActiveSink that ensures we return "default" if we get the
167 // empty string as the current device ID. 113 // empty string as the current device ID.
168 if (media::AudioDeviceDescription::IsDefaultDevice(raw_id)) 114 if (media::AudioDeviceDescription::IsDefaultDevice(raw_id))
169 return media::AudioDeviceDescription::kDefaultDeviceId; 115 return media::AudioDeviceDescription::kDefaultDeviceId;
170 116
171 url::Origin security_origin(source_url().GetOrigin()); 117 url::Origin security_origin(source_url().GetOrigin());
172 return content::GetHMACForMediaDeviceID(device_id_salt(), security_origin, 118 return content::GetHMACForMediaDeviceID(device_id_salt(), security_origin,
173 raw_id); 119 raw_id);
174 } 120 }
175 121
176 void WebrtcAudioPrivateFunction::InitDeviceIDSalt() { 122 void WebrtcAudioPrivateFunction::InitDeviceIDSalt() {
177 device_id_salt_ = GetProfile()->GetResourceContext()->GetMediaDeviceIDSalt(); 123 device_id_salt_ = GetProfile()->GetResourceContext()->GetMediaDeviceIDSalt();
178 } 124 }
179 125
180 std::string WebrtcAudioPrivateFunction::device_id_salt() const { 126 std::string WebrtcAudioPrivateFunction::device_id_salt() const {
181 return device_id_salt_; 127 return device_id_salt_;
182 } 128 }
183 129
184 bool WebrtcAudioPrivateGetSinksFunction::RunAsync() { 130 bool WebrtcAudioPrivateGetSinksFunction::RunAsync() {
185 DCHECK_CURRENTLY_ON(BrowserThread::UI); 131 DCHECK_CURRENTLY_ON(BrowserThread::UI);
186
187 InitDeviceIDSalt(); 132 InitDeviceIDSalt();
188 GetOutputDeviceDescriptions(); 133 BrowserThread::PostTask(
189 134 BrowserThread::IO, FROM_HERE,
135 base::Bind(
136 &WebrtcAudioPrivateGetSinksFunction::GetOutputDeviceDescriptions,
137 this));
190 return true; 138 return true;
191 } 139 }
192 140
141 void WebrtcAudioPrivateGetSinksFunction::GetOutputDeviceDescriptions() {
142 DCHECK_CURRENTLY_ON(BrowserThread::IO);
143 media::AudioSystem::Get()->GetDeviceDescriptions(
144 base::Bind(
145 &WebrtcAudioPrivateGetSinksFunction::OnOutputDeviceDescriptions,
146 this),
147 false);
148 }
149
193 void WebrtcAudioPrivateGetSinksFunction::OnOutputDeviceDescriptions( 150 void WebrtcAudioPrivateGetSinksFunction::OnOutputDeviceDescriptions(
194 std::unique_ptr<AudioDeviceDescriptions> raw_ids) { 151 media::AudioDeviceDescriptions sink_devices) {
195 DCHECK_CURRENTLY_ON(BrowserThread::IO); 152 DCHECK_CURRENTLY_ON(BrowserThread::IO);
196 153 std::unique_ptr<SyncInfoVector> results = base::MakeUnique<SyncInfoVector>();
Devlin 2017/04/06 01:42:33 optional: I sometimes find it cleaner to do: auto
o1ka 2017/04/06 11:01:22 Makes sense! Done.
197 std::vector<wap::SinkInfo> results; 154 for (const media::AudioDeviceDescription& description : sink_devices) {
198 for (const media::AudioDeviceDescription& description : *raw_ids) {
199 wap::SinkInfo info; 155 wap::SinkInfo info;
200 info.sink_id = CalculateHMACImpl(description.unique_id); 156 info.sink_id = CalculateHMAC(description.unique_id);
201 info.sink_label = description.device_name; 157 info.sink_label = description.device_name;
202 // TODO(joi): Add other parameters. 158 // TODO(joi): Add other parameters.
203 results.push_back(std::move(info)); 159 results->push_back(std::move(info));
204 } 160 }
205
206 // It's safe to directly set the results here (from a thread other
207 // than the UI thread, on which an AsyncExtensionFunction otherwise
208 // normally runs) because there is one instance of this object per
209 // function call, no actor outside of this object is modifying the
210 // results_ member, and the different method invocations on this
211 // object run strictly in sequence; first RunAsync on the UI thread,
212 // then DoQuery on the audio IO thread, then DoneOnUIThread on the
213 // UI thread.
214 results_ = wap::GetSinks::Results::Create(results);
Devlin 2017/04/06 01:42:33 I think this was indeed safe, if you wanted to avo
o1ka 2017/04/06 11:01:22 Yes, it was safe. I just prefer the code which doe
Devlin 2017/04/06 21:23:27 I don't have a strong preference. The only reason
o1ka 2017/04/07 12:10:22 Acknowledged.
215
216 BrowserThread::PostTask( 161 BrowserThread::PostTask(
217 BrowserThread::UI, 162 BrowserThread::UI, FROM_HERE,
218 FROM_HERE, 163 base::Bind(&WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread, this,
219 base::Bind(&WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread, this)); 164 base::Passed(&results)));
220 } 165 }
221 166
222 void WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread() { 167 void WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread(
168 std::unique_ptr<SyncInfoVector> results) {
169 DCHECK_CURRENTLY_ON(BrowserThread::UI);
170 results_ = wap::GetSinks::Results::Create(*results);
223 SendResponse(true); 171 SendResponse(true);
224 } 172 }
225 173
226 WebrtcAudioPrivateGetAssociatedSinkFunction:: 174 WebrtcAudioPrivateGetAssociatedSinkFunction::
227 WebrtcAudioPrivateGetAssociatedSinkFunction() { 175 WebrtcAudioPrivateGetAssociatedSinkFunction() {}
228 }
229 176
230 WebrtcAudioPrivateGetAssociatedSinkFunction:: 177 WebrtcAudioPrivateGetAssociatedSinkFunction::
231 ~WebrtcAudioPrivateGetAssociatedSinkFunction() { 178 ~WebrtcAudioPrivateGetAssociatedSinkFunction() {}
232 }
233 179
234 bool WebrtcAudioPrivateGetAssociatedSinkFunction::RunAsync() { 180 bool WebrtcAudioPrivateGetAssociatedSinkFunction::RunAsync() {
235 params_ = wap::GetAssociatedSink::Params::Create(*args_); 181 params_ = wap::GetAssociatedSink::Params::Create(*args_);
236 DCHECK_CURRENTLY_ON(BrowserThread::UI); 182 DCHECK_CURRENTLY_ON(BrowserThread::UI);
237 EXTENSION_FUNCTION_VALIDATE(params_.get()); 183 EXTENSION_FUNCTION_VALIDATE(params_.get());
238
239 InitDeviceIDSalt(); 184 InitDeviceIDSalt();
240 185
241 AudioManager::Get()->GetTaskRunner()->PostTask( 186 BrowserThread::PostTask(
242 FROM_HERE, 187 BrowserThread::IO, FROM_HERE,
243 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction:: 188 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
244 GetDevicesOnDeviceThread, this)); 189 GetInputDeviceDescriptions,
190 this));
245 191
246 return true; 192 return true;
247 } 193 }
248 194
249 void WebrtcAudioPrivateGetAssociatedSinkFunction::GetDevicesOnDeviceThread() { 195 void WebrtcAudioPrivateGetAssociatedSinkFunction::GetInputDeviceDescriptions() {
250 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 196 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 AudioManager::Get()->GetAudioInputDeviceDescriptions(&source_devices_); 197 media::AudioSystem::Get()->GetDeviceDescriptions(
252
253 BrowserThread::PostTask(
254 BrowserThread::IO,
255 FROM_HERE,
256 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction:: 198 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
257 GetRawSourceIDOnIOThread, 199 OnInputDeviceDescriptions,
258 this)); 200 this),
201 true);
259 } 202 }
260 203
261 void 204 void WebrtcAudioPrivateGetAssociatedSinkFunction::OnInputDeviceDescriptions(
262 WebrtcAudioPrivateGetAssociatedSinkFunction::GetRawSourceIDOnIOThread() { 205 media::AudioDeviceDescriptions source_devices) {
263 DCHECK_CURRENTLY_ON(BrowserThread::IO); 206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
264
265 url::Origin security_origin(GURL(params_->security_origin)); 207 url::Origin security_origin(GURL(params_->security_origin));
266 std::string source_id_in_origin(params_->source_id_in_origin); 208 std::string source_id_in_origin(params_->source_id_in_origin);
267 209
268 // Find the raw source ID for source_id_in_origin. 210 // Find the raw source ID for source_id_in_origin.
269 std::string raw_source_id; 211 std::string raw_source_id;
270 for (AudioDeviceDescriptions::const_iterator it = source_devices_.begin(); 212 for (const auto device : source_devices) {
Devlin 2017/04/06 01:42:33 const auto&
o1ka 2017/04/06 11:01:22 Done.
271 it != source_devices_.end(); ++it) {
272 const std::string& id = it->unique_id;
273 if (content::DoesMediaDeviceIDMatchHMAC(device_id_salt(), security_origin, 213 if (content::DoesMediaDeviceIDMatchHMAC(device_id_salt(), security_origin,
274 source_id_in_origin, id)) { 214 source_id_in_origin,
275 raw_source_id = id; 215 device.unique_id)) {
216 raw_source_id = device.unique_id;
276 DVLOG(2) << "Found raw ID " << raw_source_id 217 DVLOG(2) << "Found raw ID " << raw_source_id
277 << " for source ID in origin " << source_id_in_origin; 218 << " for source ID in origin " << source_id_in_origin;
278 break; 219 break;
279 } 220 }
280 } 221 }
281 222 if (raw_source_id.empty()) {
282 AudioManager::Get()->GetTaskRunner()->PostTask( 223 CalculateHMACAndReplyOnUIThread(std::string());
283 FROM_HERE, 224 return;
284 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction:: 225 }
285 GetAssociatedSinkOnDeviceThread, 226 media::AudioSystem::Get()->GetAssociatedOutputDeviceID(
286 this, 227 raw_source_id, base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
287 raw_source_id)); 228 CalculateHMACAndReplyOnUIThread,
229 this));
288 } 230 }
289 231
290 void 232 void WebrtcAudioPrivateGetAssociatedSinkFunction::
291 WebrtcAudioPrivateGetAssociatedSinkFunction::GetAssociatedSinkOnDeviceThread( 233 CalculateHMACAndReplyOnUIThread(const std::string& raw_sink_id) {
292 const std::string& raw_source_id) { 234 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 235 BrowserThread::PostTask(
294 236 BrowserThread::UI, FROM_HERE,
295 // We return an empty string if there is no associated output device. 237 base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::OnHMACCalculated,
296 std::string raw_sink_id; 238 this, CalculateHMAC(raw_sink_id)));
297 if (!raw_source_id.empty()) {
298 raw_sink_id =
299 AudioManager::Get()->GetAssociatedOutputDeviceID(raw_source_id);
300 }
301
302 CalculateHMAC(raw_sink_id);
303 } 239 }
304 240
305 void WebrtcAudioPrivateGetAssociatedSinkFunction::OnHMACCalculated( 241 void WebrtcAudioPrivateGetAssociatedSinkFunction::OnHMACCalculated(
306 const std::string& associated_sink_id) { 242 const std::string& associated_sink_id) {
307 DCHECK_CURRENTLY_ON(BrowserThread::UI); 243 DCHECK_CURRENTLY_ON(BrowserThread::UI);
308
309 if (associated_sink_id == media::AudioDeviceDescription::kDefaultDeviceId) { 244 if (associated_sink_id == media::AudioDeviceDescription::kDefaultDeviceId) {
310 DVLOG(2) << "Got default ID, replacing with empty ID."; 245 DVLOG(2) << "Got default ID, replacing with empty ID.";
311 results_ = wap::GetAssociatedSink::Results::Create(""); 246 results_ = wap::GetAssociatedSink::Results::Create("");
312 } else { 247 } else {
313 results_ = wap::GetAssociatedSink::Results::Create(associated_sink_id); 248 results_ = wap::GetAssociatedSink::Results::Create(associated_sink_id);
314 } 249 }
315
316 SendResponse(true); 250 SendResponse(true);
317 } 251 }
318 252
319 } // namespace extensions 253 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698