1 // Copyright (c) 2013 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 "extensions/browser/api/audio/audio_api.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/values.h"
12 #include "components/prefs/pref_registry_simple.h"
13 #include "extensions/browser/api/audio/audio_device_id_calculator.h"
14 #include "extensions/browser/api/audio/pref_names.h"
15 #include "extensions/browser/event_router.h"
16 #include "extensions/common/api/audio.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/features/behavior_feature.h"
19 #include "extensions/common/features/feature_provider.h"
20
21 namespace extensions {
22
23 namespace audio = api::audio;
24
25 namespace {
26
CreateIdCalculator(content::BrowserContext * context)27 std::unique_ptr<AudioDeviceIdCalculator> CreateIdCalculator(
28 content::BrowserContext* context) {
29 return std::make_unique<AudioDeviceIdCalculator>(context);
30 }
31
32 // Checks if an extension is whitelisted to use deprecated version of audio API.
33 // TODO(tbarzic): Retire this whitelist and remove the deprecated API methods,
34 // properties and events. This is currently targeted for M-60
35 // (http://crbug.com/697279).
CanUseDeprecatedAudioApi(const Extension * extension)36 bool CanUseDeprecatedAudioApi(const Extension* extension) {
37 if (!extension)
38 return false;
39
40 const Feature* allow_deprecated_audio_api_feature =
41 FeatureProvider::GetBehaviorFeatures()->GetFeature(
42 behavior_feature::kAllowDeprecatedAudioApi);
43 if (!allow_deprecated_audio_api_feature)
44 return false;
45
46 return allow_deprecated_audio_api_feature->IsAvailableToExtension(extension)
47 .is_available();
48 }
49
CanReceiveDeprecatedAudioEvent(content::BrowserContext * browser_context,Feature::Context target_context,const Extension * extension,Event * event,const base::DictionaryValue * filter)50 bool CanReceiveDeprecatedAudioEvent(content::BrowserContext* browser_context,
51 Feature::Context target_context,
52 const Extension* extension,
53 Event* event,
54 const base::DictionaryValue* filter) {
55 return CanUseDeprecatedAudioApi(extension);
56 }
57
58 } // namespace
59
60 static base::LazyInstance<
61 BrowserContextKeyedAPIFactory<AudioAPI>>::DestructorAtExit g_factory =
62 LAZY_INSTANCE_INITIALIZER;
63
RegisterUserPrefs(PrefRegistrySimple * registry)64 void AudioAPI::RegisterUserPrefs(PrefRegistrySimple* registry) {
65 registry->RegisterListPref(kAudioApiStableDeviceIds);
66 }
67
68 // static
GetFactoryInstance()69 BrowserContextKeyedAPIFactory<AudioAPI>* AudioAPI::GetFactoryInstance() {
70 return g_factory.Pointer();
71 }
72
AudioAPI(content::BrowserContext * context)73 AudioAPI::AudioAPI(content::BrowserContext* context)
74 : browser_context_(context),
75 stable_id_calculator_(CreateIdCalculator(context)),
76 service_(AudioService::CreateInstance(stable_id_calculator_.get())),
77 audio_service_observer_(this) {
78 audio_service_observer_.Add(service_.get());
79 }
80
~AudioAPI()81 AudioAPI::~AudioAPI() {}
82
GetService() const83 AudioService* AudioAPI::GetService() const {
84 return service_.get();
85 }
86
OnDeviceChanged()87 void AudioAPI::OnDeviceChanged() {
88 EventRouter* event_router = EventRouter::Get(browser_context_);
89 if (!event_router)
90 return;
91
92 std::unique_ptr<Event> event(new Event(
93 events::AUDIO_ON_DEVICE_CHANGED, audio::OnDeviceChanged::kEventName,
94 std::unique_ptr<base::ListValue>(new base::ListValue())));
95 event->will_dispatch_callback =
96 base::BindRepeating(&CanReceiveDeprecatedAudioEvent);
97 event_router->BroadcastEvent(std::move(event));
98 }
99
OnLevelChanged(const std::string & id,int level)100 void AudioAPI::OnLevelChanged(const std::string& id, int level) {
101 EventRouter* event_router = EventRouter::Get(browser_context_);
102 if (!event_router)
103 return;
104
105 audio::LevelChangedEvent raw_event;
106 raw_event.device_id = id;
107 raw_event.level = level;
108
109 std::unique_ptr<base::ListValue> event_args =
110 audio::OnLevelChanged::Create(raw_event);
111 std::unique_ptr<Event> event(new Event(events::AUDIO_ON_LEVEL_CHANGED,
112 audio::OnLevelChanged::kEventName,
113 std::move(event_args)));
114 event_router->BroadcastEvent(std::move(event));
115 }
116
OnMuteChanged(bool is_input,bool is_muted)117 void AudioAPI::OnMuteChanged(bool is_input, bool is_muted) {
118 EventRouter* event_router = EventRouter::Get(browser_context_);
119 if (!event_router)
120 return;
121
122 // Dispatch onMuteChanged event.
123 audio::MuteChangedEvent raw_event;
124 raw_event.stream_type =
125 is_input ? audio::STREAM_TYPE_INPUT : audio::STREAM_TYPE_OUTPUT;
126 raw_event.is_muted = is_muted;
127 std::unique_ptr<base::ListValue> event_args =
128 audio::OnMuteChanged::Create(raw_event);
129 std::unique_ptr<Event> event(new Event(events::AUDIO_ON_MUTE_CHANGED,
130 audio::OnMuteChanged::kEventName,
131 std::move(event_args)));
132 event_router->BroadcastEvent(std::move(event));
133 }
134
OnDevicesChanged(const DeviceInfoList & devices)135 void AudioAPI::OnDevicesChanged(const DeviceInfoList& devices) {
136 EventRouter* event_router = EventRouter::Get(browser_context_);
137 if (!event_router)
138 return;
139
140 std::unique_ptr<base::ListValue> args =
141 audio::OnDeviceListChanged::Create(devices);
142 std::unique_ptr<Event> event(new Event(events::AUDIO_ON_DEVICES_CHANGED,
143 audio::OnDeviceListChanged::kEventName,
144 std::move(args)));
145 event_router->BroadcastEvent(std::move(event));
146 }
147
148 ///////////////////////////////////////////////////////////////////////////////
149
Run()150 ExtensionFunction::ResponseAction AudioGetInfoFunction::Run() {
151 if (!CanUseDeprecatedAudioApi(extension())) {
152 return RespondNow(
153 Error("audio.getInfo is deprecated, use audio.getDevices instead."));
154 }
155
156 AudioService* service =
157 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
158 DCHECK(service);
159 OutputInfo output_info;
160 InputInfo input_info;
161 if (!service->GetInfo(&output_info, &input_info)) {
162 return RespondNow(
163 Error("Error occurred when querying audio device information."));
164 }
165
166 return RespondNow(
167 ArgumentList(audio::GetInfo::Results::Create(output_info, input_info)));
168 }
169
170 ///////////////////////////////////////////////////////////////////////////////
171
Run()172 ExtensionFunction::ResponseAction AudioGetDevicesFunction::Run() {
173 std::unique_ptr<audio::GetDevices::Params> params(
174 audio::GetDevices::Params::Create(*args_));
175 EXTENSION_FUNCTION_VALIDATE(params.get());
176
177 AudioService* service =
178 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
179 DCHECK(service);
180
181 std::vector<api::audio::AudioDeviceInfo> devices;
182 if (!service->GetDevices(params->filter.get(), &devices)) {
183 return RespondNow(
184 Error("Error occurred when querying audio device information."));
185 }
186
187 return RespondNow(ArgumentList(audio::GetDevices::Results::Create(devices)));
188 }
189
190 ///////////////////////////////////////////////////////////////////////////////
191
Run()192 ExtensionFunction::ResponseAction AudioSetActiveDevicesFunction::Run() {
193 std::unique_ptr<audio::SetActiveDevices::Params> params(
194 audio::SetActiveDevices::Params::Create(*args_));
195 EXTENSION_FUNCTION_VALIDATE(params.get());
196
197 AudioService* service =
198 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
199 DCHECK(service);
200
201 if (params->ids.as_device_id_lists) {
202 if (!service->SetActiveDeviceLists(
203 params->ids.as_device_id_lists->input,
204 params->ids.as_device_id_lists->output)) {
205 return RespondNow(Error("Failed to set active devices."));
206 }
207 } else if (params->ids.as_strings) {
208 if (!CanUseDeprecatedAudioApi(extension())) {
209 return RespondNow(
210 Error("String list |ids| is deprecated, use DeviceIdLists type."));
211 }
212 service->SetActiveDevices(*params->ids.as_strings);
213 }
214 return RespondNow(NoArguments());
215 }
216
217 ///////////////////////////////////////////////////////////////////////////////
218
Run()219 ExtensionFunction::ResponseAction AudioSetPropertiesFunction::Run() {
220 std::unique_ptr<audio::SetProperties::Params> params(
221 audio::SetProperties::Params::Create(*args_));
222 EXTENSION_FUNCTION_VALIDATE(params.get());
223
224 AudioService* service =
225 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
226 DCHECK(service);
227
228 if (!CanUseDeprecatedAudioApi(extension())) {
229 if (params->properties.volume)
230 return RespondNow(Error("|volume| property is deprecated, use |level|."));
231
232 if (params->properties.gain)
233 return RespondNow(Error("|gain| property is deprecated, use |level|."));
234
235 if (params->properties.is_muted) {
236 return RespondNow(
237 Error("|isMuted| property is deprecated, use |audio.setMute|."));
238 }
239 }
240
241 bool level_set = !!params->properties.level;
242 int level_value = level_set ? *params->properties.level : -1;
243
244 int volume_value = params->properties.volume.get() ?
245 *params->properties.volume : -1;
246
247 int gain_value = params->properties.gain.get() ?
248 *params->properties.gain : -1;
249
250 // |volume_value| and |gain_value| are deprecated in favor of |level_value|;
251 // they are kept around only to ensure backward-compatibility and should be
252 // ignored if |level_value| is set.
253 if (!service->SetDeviceSoundLevel(params->id,
254 level_set ? level_value : volume_value,
255 level_set ? level_value : gain_value))
256 return RespondNow(Error("Could not set volume/gain properties"));
257
258 if (params->properties.is_muted.get() &&
259 !service->SetMuteForDevice(params->id, *params->properties.is_muted)) {
260 return RespondNow(Error("Could not set mute property."));
261 }
262
263 return RespondNow(NoArguments());
264 }
265
266 ///////////////////////////////////////////////////////////////////////////////
267
Run()268 ExtensionFunction::ResponseAction AudioSetMuteFunction::Run() {
269 std::unique_ptr<audio::SetMute::Params> params(
270 audio::SetMute::Params::Create(*args_));
271 EXTENSION_FUNCTION_VALIDATE(params.get());
272
273 AudioService* service =
274 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
275 DCHECK(service);
276
277 if (!service->SetMute(params->stream_type == audio::STREAM_TYPE_INPUT,
278 params->is_muted)) {
279 return RespondNow(Error("Could not set mute state."));
280 }
281 return RespondNow(NoArguments());
282 }
283
284 ///////////////////////////////////////////////////////////////////////////////
285
Run()286 ExtensionFunction::ResponseAction AudioGetMuteFunction::Run() {
287 std::unique_ptr<audio::GetMute::Params> params(
288 audio::GetMute::Params::Create(*args_));
289 EXTENSION_FUNCTION_VALIDATE(params.get());
290
291 AudioService* service =
292 AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService();
293 DCHECK(service);
294
295 bool value = false;
296 if (!service->GetMute(params->stream_type == audio::STREAM_TYPE_INPUT,
297 &value)) {
298 return RespondNow(Error("Could not get mute state."));
299 }
300 return RespondNow(ArgumentList(audio::GetMute::Results::Create(value)));
301 }
302
303 } // namespace extensions
304