1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "APM::HwModule"
18 //#define LOG_NDEBUG 0
19
20 #include "HwModule.h"
21 #include "IOProfile.h"
22 #include "AudioGain.h"
23 #include <policy.h>
24 #include <system/audio.h>
25
26 namespace android {
27
HwModule(const char * name,uint32_t halVersionMajor,uint32_t halVersionMinor)28 HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
29 : mName(String8(name)),
30 mHandle(AUDIO_MODULE_HANDLE_NONE)
31 {
32 setHalVersion(halVersionMajor, halVersionMinor);
33 }
34
~HwModule()35 HwModule::~HwModule()
36 {
37 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
38 mOutputProfiles[i]->clearSupportedDevices();
39 }
40 for (size_t i = 0; i < mInputProfiles.size(); i++) {
41 mInputProfiles[i]->clearSupportedDevices();
42 }
43 }
44
addOutputProfile(const String8 & name,const audio_config_t * config,audio_devices_t device,const String8 & address)45 status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
46 audio_devices_t device, const String8& address)
47 {
48 sp<IOProfile> profile = new OutputProfile(name);
49
50 profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
51 config->sample_rate));
52
53 sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
54 devDesc->setAddress(address);
55 addDynamicDevice(devDesc);
56 // Reciprocally attach the device to the module
57 devDesc->attach(this);
58 profile->addSupportedDevice(devDesc);
59
60 return addOutputProfile(profile);
61 }
62
addOutputProfile(const sp<IOProfile> & profile)63 status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
64 {
65 profile->attach(this);
66 mOutputProfiles.add(profile);
67 mPorts.add(profile);
68 return NO_ERROR;
69 }
70
addInputProfile(const sp<IOProfile> & profile)71 status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
72 {
73 profile->attach(this);
74 mInputProfiles.add(profile);
75 mPorts.add(profile);
76 return NO_ERROR;
77 }
78
addProfile(const sp<IOProfile> & profile)79 status_t HwModule::addProfile(const sp<IOProfile> &profile)
80 {
81 switch (profile->getRole()) {
82 case AUDIO_PORT_ROLE_SOURCE:
83 return addOutputProfile(profile);
84 case AUDIO_PORT_ROLE_SINK:
85 return addInputProfile(profile);
86 case AUDIO_PORT_ROLE_NONE:
87 return BAD_VALUE;
88 }
89 return BAD_VALUE;
90 }
91
setProfiles(const IOProfileCollection & profiles)92 void HwModule::setProfiles(const IOProfileCollection &profiles)
93 {
94 for (size_t i = 0; i < profiles.size(); i++) {
95 addProfile(profiles[i]);
96 }
97 }
98
removeOutputProfile(const String8 & name)99 status_t HwModule::removeOutputProfile(const String8& name)
100 {
101 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
102 if (mOutputProfiles[i]->getName() == name) {
103 for (const auto &device : mOutputProfiles[i]->getSupportedDevices()) {
104 removeDynamicDevice(device);
105 }
106 mOutputProfiles.removeAt(i);
107 break;
108 }
109 }
110
111 return NO_ERROR;
112 }
113
addInputProfile(const String8 & name,const audio_config_t * config,audio_devices_t device,const String8 & address)114 status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
115 audio_devices_t device, const String8& address)
116 {
117 sp<IOProfile> profile = new InputProfile(name);
118 profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
119 config->sample_rate));
120
121 sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
122 devDesc->setAddress(address);
123 addDynamicDevice(devDesc);
124 // Reciprocally attach the device to the module
125 devDesc->attach(this);
126 profile->addSupportedDevice(devDesc);
127
128 ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
129 name.string(), config->sample_rate, config->channel_mask);
130
131 return addInputProfile(profile);
132 }
133
removeInputProfile(const String8 & name)134 status_t HwModule::removeInputProfile(const String8& name)
135 {
136 for (size_t i = 0; i < mInputProfiles.size(); i++) {
137 if (mInputProfiles[i]->getName() == name) {
138 for (const auto &device : mInputProfiles[i]->getSupportedDevices()) {
139 removeDynamicDevice(device);
140 }
141 mInputProfiles.removeAt(i);
142 break;
143 }
144 }
145
146 return NO_ERROR;
147 }
148
setDeclaredDevices(const DeviceVector & devices)149 void HwModule::setDeclaredDevices(const DeviceVector &devices)
150 {
151 mDeclaredDevices = devices;
152 for (size_t i = 0; i < devices.size(); i++) {
153 mPorts.add(devices[i]);
154 }
155 }
156
getRouteSinkDevice(const sp<AudioRoute> & route) const157 sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
158 {
159 sp<DeviceDescriptor> sinkDevice = 0;
160 if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
161 sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
162 }
163 return sinkDevice;
164 }
165
getRouteSourceDevices(const sp<AudioRoute> & route) const166 DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
167 {
168 DeviceVector sourceDevices;
169 for (const auto& source : route->getSources()) {
170 if (source->getType() == AUDIO_PORT_TYPE_DEVICE) {
171 sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
172 }
173 }
174 return sourceDevices;
175 }
176
setRoutes(const AudioRouteVector & routes)177 void HwModule::setRoutes(const AudioRouteVector &routes)
178 {
179 mRoutes = routes;
180 // Now updating the streams (aka IOProfile until now) supported devices
181 refreshSupportedDevices();
182 }
183
refreshSupportedDevices()184 void HwModule::refreshSupportedDevices()
185 {
186 // Now updating the streams (aka IOProfile until now) supported devices
187 for (const auto& stream : mInputProfiles) {
188 DeviceVector sourceDevices;
189 for (const auto& route : stream->getRoutes()) {
190 sp<AudioPort> sink = route->getSink();
191 if (sink == 0 || stream != sink) {
192 ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
193 continue;
194 }
195 DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
196 if (sourceDevicesForRoute.isEmpty()) {
197 ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
198 continue;
199 }
200 sourceDevices.add(sourceDevicesForRoute);
201 }
202 if (sourceDevices.isEmpty()) {
203 ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
204 continue;
205 }
206 stream->setSupportedDevices(sourceDevices);
207 }
208 for (const auto& stream : mOutputProfiles) {
209 DeviceVector sinkDevices;
210 for (const auto& route : stream->getRoutes()) {
211 sp<AudioPort> source = route->getSources().findByTagName(stream->getTagName());
212 if (source == 0 || stream != source) {
213 ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
214 continue;
215 }
216 sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
217 if (sinkDevice == 0) {
218 ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
219 continue;
220 }
221 sinkDevices.add(sinkDevice);
222 }
223 stream->setSupportedDevices(sinkDevices);
224 }
225 }
226
setHandle(audio_module_handle_t handle)227 void HwModule::setHandle(audio_module_handle_t handle) {
228 ALOGW_IF(mHandle != AUDIO_MODULE_HANDLE_NONE,
229 "HwModule handle is changing from %d to %d", mHandle, handle);
230 mHandle = handle;
231 }
232
supportsPatch(const sp<AudioPort> & srcPort,const sp<AudioPort> & dstPort) const233 bool HwModule::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const {
234 for (const auto &route : mRoutes) {
235 if (route->supportsPatch(srcPort, dstPort)) {
236 return true;
237 }
238 }
239 return false;
240 }
241
dump(String8 * dst) const242 void HwModule::dump(String8 *dst) const
243 {
244 dst->appendFormat(" - name: %s\n", getName());
245 dst->appendFormat(" - handle: %d\n", mHandle);
246 dst->appendFormat(" - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
247 if (mOutputProfiles.size()) {
248 dst->append(" - outputs:\n");
249 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
250 dst->appendFormat(" output %zu:\n", i);
251 mOutputProfiles[i]->dump(dst);
252 }
253 }
254 if (mInputProfiles.size()) {
255 dst->append(" - inputs:\n");
256 for (size_t i = 0; i < mInputProfiles.size(); i++) {
257 dst->appendFormat(" input %zu:\n", i);
258 mInputProfiles[i]->dump(dst);
259 }
260 }
261 mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
262 mDynamicDevices.dump(dst, String8("Dynamic"), 2, true);
263 mRoutes.dump(dst, 2);
264 }
265
getModuleFromName(const char * name) const266 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
267 {
268 for (const auto& module : *this) {
269 if (strcmp(module->getName(), name) == 0) {
270 return module;
271 }
272 }
273 return nullptr;
274 }
275
getModuleForDeviceTypes(audio_devices_t type,audio_format_t encodedFormat) const276 sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
277 audio_format_t encodedFormat) const
278 {
279 for (const auto& module : *this) {
280 const auto& profiles = audio_is_output_device(type) ?
281 module->getOutputProfiles() : module->getInputProfiles();
282 for (const auto& profile : profiles) {
283 if (profile->supportsDeviceTypes(type)) {
284 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
285 DeviceVector declaredDevices = module->getDeclaredDevices();
286 sp <DeviceDescriptor> deviceDesc =
287 declaredDevices.getDevice(type, String8(), encodedFormat);
288 if (deviceDesc) {
289 return module;
290 }
291 } else {
292 return module;
293 }
294 }
295 }
296 }
297 return nullptr;
298 }
299
getModuleForDevice(const sp<DeviceDescriptor> & device,audio_format_t encodedFormat) const300 sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
301 audio_format_t encodedFormat) const
302 {
303 return getModuleForDeviceTypes(device->type(), encodedFormat);
304 }
305
getAvailableDevicesFromModuleName(const char * name,const DeviceVector & availableDevices) const306 DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
307 const char *name, const DeviceVector &availableDevices) const
308 {
309 sp<HwModule> module = getModuleFromName(name);
310 if (module == nullptr) {
311 return DeviceVector();
312 }
313 return availableDevices.getDevicesFromHwModule(module->getHandle());
314 }
315
getDeviceDescriptor(const audio_devices_t deviceType,const char * address,const char * name,const audio_format_t encodedFormat,bool allowToCreate,bool matchAddress) const316 sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t deviceType,
317 const char *address,
318 const char *name,
319 const audio_format_t encodedFormat,
320 bool allowToCreate,
321 bool matchAddress) const
322 {
323 String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
324 // handle legacy remote submix case where the address was not always specified
325 if (device_distinguishes_on_address(deviceType) && (devAddress.length() == 0)) {
326 devAddress = String8("0");
327 }
328
329 for (const auto& hwModule : *this) {
330 DeviceVector moduleDevices = hwModule->getAllDevices();
331 auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress, encodedFormat);
332 if (moduleDevice) {
333 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
334 moduleDevice->setEncodedFormat(encodedFormat);
335 }
336 moduleDevice->setAddress(devAddress);
337 if (allowToCreate) {
338 moduleDevice->attach(hwModule);
339 }
340 return moduleDevice;
341 }
342 }
343 if (!allowToCreate) {
344 ALOGV("%s: could not find HW module for device %s %04x address %s", __FUNCTION__,
345 name, deviceType, address);
346 return nullptr;
347 }
348 return createDevice(deviceType, address, name, encodedFormat);
349 }
350
createDevice(const audio_devices_t type,const char * address,const char * name,const audio_format_t encodedFormat) const351 sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type,
352 const char *address,
353 const char *name,
354 const audio_format_t encodedFormat) const
355 {
356 sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
357 if (hwModule == 0) {
358 ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
359 address);
360 return nullptr;
361 }
362 sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
363 device->setName(String8(name));
364 device->setAddress(String8(address));
365 device->setEncodedFormat(encodedFormat);
366
367 // Add the device to the list of dynamic devices
368 hwModule->addDynamicDevice(device);
369 // Reciprocally attach the device to the module
370 device->attach(hwModule);
371 ALOGD("%s: adding dynamic device %s to module %s", __FUNCTION__,
372 device->toString().c_str(), hwModule->getName());
373
374 const auto &profiles = (audio_is_output_device(type) ? hwModule->getOutputProfiles() :
375 hwModule->getInputProfiles());
376 for (const auto &profile : profiles) {
377 // Add the device as supported to all profile supporting "weakly" or not the device
378 // according to its type
379 if (profile->supportsDevice(device, false /*matchAdress*/)) {
380
381 // @todo quid of audio profile? import the profile from device of the same type?
382 const auto &isoTypeDeviceForProfile =
383 profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
384 device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
385
386 ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
387 device->toString().c_str(), profile->getTagName().c_str());
388 profile->addSupportedDevice(device);
389 }
390 }
391 return device;
392 }
393
cleanUpForDevice(const sp<DeviceDescriptor> & device)394 void HwModuleCollection::cleanUpForDevice(const sp<DeviceDescriptor> &device)
395 {
396 for (const auto& hwModule : *this) {
397 DeviceVector moduleDevices = hwModule->getAllDevices();
398 if (!moduleDevices.contains(device)) {
399 continue;
400 }
401
402 // removal of remote submix devices associated with a dynamic policy is
403 // handled by removeOutputProfile() and removeInputProfile()
404 if (audio_is_remote_submix_device(device->type()) && device->address() != "0") {
405 continue;
406 }
407
408 device->detach();
409 // Only remove from dynamic list, not from declared list!!!
410 if (!hwModule->getDynamicDevices().contains(device)) {
411 return;
412 }
413 hwModule->removeDynamicDevice(device);
414 ALOGV("%s: removed dynamic device %s from module %s", __FUNCTION__,
415 device->toString().c_str(), hwModule->getName());
416
417 const IOProfileCollection &profiles = audio_is_output_device(device->type()) ?
418 hwModule->getOutputProfiles() : hwModule->getInputProfiles();
419 for (const auto &profile : profiles) {
420 // For cleanup, strong match is required
421 if (profile->supportsDevice(device, true /*matchAdress*/)) {
422 ALOGV("%s: removing device %s from profile %s", __FUNCTION__,
423 device->toString().c_str(), profile->getTagName().c_str());
424 profile->removeSupportedDevice(device);
425 }
426 }
427 }
428 }
429
dump(String8 * dst) const430 void HwModuleCollection::dump(String8 *dst) const
431 {
432 dst->append("\nHW Modules dump:\n");
433 for (size_t i = 0; i < size(); i++) {
434 dst->appendFormat("- HW Module %zu:\n", i + 1);
435 itemAt(i)->dump(dst);
436 }
437 }
438
439
440 } //namespace android
441