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 <android-base/stringprintf.h>
21 #include <policy.h>
22 #include <system/audio.h>
23
24 #include "HwModule.h"
25 #include "IOProfile.h"
26
27 namespace android {
28
HwModule(const char * name,uint32_t halVersionMajor,uint32_t halVersionMinor)29 HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
30 : mName(String8(name)),
31 mHandle(AUDIO_MODULE_HANDLE_NONE)
32 {
33 setHalVersion(halVersionMajor, halVersionMinor);
34 }
35
HwModule(const char * name,uint32_t halVersion)36 HwModule::HwModule(const char *name, uint32_t halVersion)
37 : mName(String8(name)),
38 mHandle(AUDIO_MODULE_HANDLE_NONE),
39 mHalVersion(halVersion)
40 {
41 }
42
~HwModule()43 HwModule::~HwModule()
44 {
45 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
46 mOutputProfiles[i]->clearSupportedDevices();
47 }
48 for (size_t i = 0; i < mInputProfiles.size(); i++) {
49 mInputProfiles[i]->clearSupportedDevices();
50 }
51 }
52
getTagForDevice(audio_devices_t device,const String8 & address,audio_format_t codec)53 std::string HwModule::getTagForDevice(audio_devices_t device, const String8 &address,
54 audio_format_t codec)
55 {
56 DeviceVector declaredDevices = getDeclaredDevices();
57 sp<DeviceDescriptor> deviceDesc = declaredDevices.getDevice(device, address, codec);
58 return deviceDesc ? deviceDesc->getTagName() : std::string{};
59 }
60
addOutputProfile(const std::string & name,const audio_config_t * config,audio_devices_t device,const String8 & address,audio_output_flags_t flags)61 status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
62 audio_devices_t device, const String8& address,
63 audio_output_flags_t flags)
64 {
65 sp<IOProfile> profile = new OutputProfile(name);
66 profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
67 config->sample_rate));
68 profile->setFlags(flags);
69
70 sp<DeviceDescriptor> devDesc =
71 new DeviceDescriptor(device, getTagForDevice(device), address.c_str());
72 addDynamicDevice(devDesc);
73 // Reciprocally attach the device to the module
74 devDesc->attach(this);
75 profile->addSupportedDevice(devDesc);
76
77 return addOutputProfile(profile);
78 }
79
addOutputProfile(const sp<IOProfile> & profile)80 status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
81 {
82 profile->attach(this);
83 mOutputProfiles.add(profile);
84 mPorts.add(profile);
85 return NO_ERROR;
86 }
87
addInputProfile(const sp<IOProfile> & profile)88 status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
89 {
90 profile->attach(this);
91 mInputProfiles.add(profile);
92 mPorts.add(profile);
93 return NO_ERROR;
94 }
95
addProfile(const sp<IOProfile> & profile)96 status_t HwModule::addProfile(const sp<IOProfile> &profile)
97 {
98 switch (profile->getRole()) {
99 case AUDIO_PORT_ROLE_SOURCE:
100 return addOutputProfile(profile);
101 case AUDIO_PORT_ROLE_SINK:
102 return addInputProfile(profile);
103 case AUDIO_PORT_ROLE_NONE:
104 return BAD_VALUE;
105 }
106 return BAD_VALUE;
107 }
108
setProfiles(const IOProfileCollection & profiles)109 void HwModule::setProfiles(const IOProfileCollection &profiles)
110 {
111 for (size_t i = 0; i < profiles.size(); i++) {
112 addProfile(profiles[i]);
113 }
114 }
115
removeOutputProfile(const std::string & name)116 status_t HwModule::removeOutputProfile(const std::string& name)
117 {
118 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
119 if (mOutputProfiles[i]->getName() == name) {
120 for (const auto &device : mOutputProfiles[i]->getSupportedDevices()) {
121 removeDynamicDevice(device);
122 }
123 mOutputProfiles.removeAt(i);
124 break;
125 }
126 }
127
128 return NO_ERROR;
129 }
130
addInputProfile(const std::string & name,const audio_config_t * config,audio_devices_t device,const String8 & address,audio_input_flags_t flags)131 status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
132 audio_devices_t device, const String8& address,
133 audio_input_flags_t flags)
134 {
135 sp<IOProfile> profile = new InputProfile(name);
136 profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
137 config->sample_rate));
138 profile->setFlags(flags);
139
140 sp<DeviceDescriptor> devDesc =
141 new DeviceDescriptor(device, getTagForDevice(device), address.c_str());
142 addDynamicDevice(devDesc);
143 // Reciprocally attach the device to the module
144 devDesc->attach(this);
145 profile->addSupportedDevice(devDesc);
146
147 ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
148 name.c_str(), config->sample_rate, config->channel_mask);
149
150 return addInputProfile(profile);
151 }
152
removeInputProfile(const std::string & name)153 status_t HwModule::removeInputProfile(const std::string& name)
154 {
155 for (size_t i = 0; i < mInputProfiles.size(); i++) {
156 if (mInputProfiles[i]->getName() == name) {
157 for (const auto &device : mInputProfiles[i]->getSupportedDevices()) {
158 removeDynamicDevice(device);
159 }
160 mInputProfiles.removeAt(i);
161 break;
162 }
163 }
164
165 return NO_ERROR;
166 }
167
setDeclaredDevices(const DeviceVector & devices)168 void HwModule::setDeclaredDevices(const DeviceVector &devices)
169 {
170 mDeclaredDevices = devices;
171 for (size_t i = 0; i < devices.size(); i++) {
172 mPorts.add(devices[i]);
173 }
174 }
175
getRouteSinkDevice(const sp<AudioRoute> & route) const176 sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
177 {
178 sp<DeviceDescriptor> sinkDevice = 0;
179 if (route->getSink()->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
180 sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
181 }
182 return sinkDevice;
183 }
184
getRouteSourceDevices(const sp<AudioRoute> & route) const185 DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
186 {
187 DeviceVector sourceDevices;
188 for (const auto& source : route->getSources()) {
189 if (source->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
190 sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
191 }
192 }
193 return sourceDevices;
194 }
195
setRoutes(const AudioRouteVector & routes)196 void HwModule::setRoutes(const AudioRouteVector &routes)
197 {
198 mRoutes = routes;
199 // Now updating the streams (aka IOProfile until now) supported devices
200 refreshSupportedDevices();
201 }
202
refreshSupportedDevices()203 void HwModule::refreshSupportedDevices()
204 {
205 // Now updating the streams (aka IOProfile until now) supported devices
206 for (const auto& stream : mInputProfiles) {
207 DeviceVector sourceDevices;
208 for (const auto& route : stream->getRoutes()) {
209 sp<PolicyAudioPort> sink = route->getSink();
210 if (sink == 0 || stream != sink) {
211 ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
212 continue;
213 }
214 DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
215 if (sourceDevicesForRoute.isEmpty()) {
216 ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
217 continue;
218 }
219 sourceDevices.add(sourceDevicesForRoute);
220 }
221 if (sourceDevices.isEmpty()) {
222 ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
223 continue;
224 }
225 stream->setSupportedDevices(sourceDevices);
226 }
227 for (const auto& stream : mOutputProfiles) {
228 DeviceVector sinkDevices;
229 for (const auto& route : stream->getRoutes()) {
230 sp<PolicyAudioPort> source = findByTagName(route->getSources(), stream->getTagName());
231 if (source == 0 || stream != source) {
232 ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
233 continue;
234 }
235 sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
236 if (sinkDevice == 0) {
237 ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().c_str());
238 continue;
239 }
240 sinkDevices.add(sinkDevice);
241 }
242 stream->setSupportedDevices(sinkDevices);
243 }
244 }
245
setHandle(audio_module_handle_t handle)246 void HwModule::setHandle(audio_module_handle_t handle) {
247 ALOGW_IF(mHandle != AUDIO_MODULE_HANDLE_NONE,
248 "HwModule handle is changing from %d to %d", mHandle, handle);
249 mHandle = handle;
250 }
251
supportsPatch(const sp<PolicyAudioPort> & srcPort,const sp<PolicyAudioPort> & dstPort) const252 bool HwModule::supportsPatch(const sp<PolicyAudioPort> &srcPort,
253 const sp<PolicyAudioPort> &dstPort) const {
254 for (const auto &route : mRoutes) {
255 if (route->supportsPatch(srcPort, dstPort)) {
256 return true;
257 }
258 }
259 return false;
260 }
261
dump(String8 * dst,int spaces) const262 void HwModule::dump(String8 *dst, int spaces) const
263 {
264 dst->appendFormat("Handle: %d; \"%s\"\n", mHandle, getName());
265 if (mOutputProfiles.size()) {
266 dst->appendFormat("%*s- Output MixPorts (%zu):\n", spaces - 2, "", mOutputProfiles.size());
267 for (size_t i = 0; i < mOutputProfiles.size(); i++) {
268 const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1);
269 dst->append(prefix.c_str());
270 mOutputProfiles[i]->dump(dst, prefix.size());
271 }
272 }
273 if (mInputProfiles.size()) {
274 dst->appendFormat("%*s- Input MixPorts (%zu):\n", spaces - 2, "", mInputProfiles.size());
275 for (size_t i = 0; i < mInputProfiles.size(); i++) {
276 const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1);
277 dst->append(prefix.c_str());
278 mInputProfiles[i]->dump(dst, prefix.size());
279 }
280 }
281 mDeclaredDevices.dump(dst, String8("- Declared"), spaces - 2, true);
282 mDynamicDevices.dump(dst, String8("- Dynamic"), spaces - 2, true);
283 dumpAudioRouteVector(mRoutes, dst, spaces);
284 }
285
getModuleFromName(const char * name) const286 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
287 {
288 for (const auto& module : *this) {
289 if (strcmp(module->getName(), name) == 0) {
290 return module;
291 }
292 }
293 return nullptr;
294 }
295
getModuleForDeviceType(audio_devices_t type,audio_format_t encodedFormat,std::string * tagName) const296 sp<HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
297 audio_format_t encodedFormat,
298 std::string *tagName) const
299 {
300 for (const auto& module : *this) {
301 const auto& profiles = audio_is_output_device(type) ?
302 module->getOutputProfiles() : module->getInputProfiles();
303 for (const auto& profile : profiles) {
304 if (profile->supportsDeviceTypes({type})) {
305 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
306 DeviceVector declaredDevices = module->getDeclaredDevices();
307 sp <DeviceDescriptor> deviceDesc =
308 declaredDevices.getDevice(type, String8(), encodedFormat);
309 if (deviceDesc) {
310 if (tagName != nullptr) {
311 *tagName = deviceDesc->getTagName();
312 }
313 return module;
314 }
315 } else {
316 if (tagName != nullptr) {
317 *tagName = profile->getTag({type});
318 }
319 return module;
320 }
321 }
322 }
323 }
324 return nullptr;
325 }
326
getModuleForDevice(const sp<DeviceDescriptor> & device,audio_format_t encodedFormat) const327 sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
328 audio_format_t encodedFormat) const
329 {
330 return getModuleForDeviceType(device->type(), encodedFormat);
331 }
332
getAvailableDevicesFromModuleName(const char * name,const DeviceVector & availableDevices) const333 DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
334 const char *name, const DeviceVector &availableDevices) const
335 {
336 sp<HwModule> module = getModuleFromName(name);
337 if (module == nullptr) {
338 return DeviceVector();
339 }
340 return availableDevices.getDevicesFromHwModule(module->getHandle());
341 }
342
getDeviceDescriptor(const audio_devices_t deviceType,const char * address,const char * name,const audio_format_t encodedFormat,bool allowToCreate,bool matchAddress) const343 sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t deviceType,
344 const char *address,
345 const char *name,
346 const audio_format_t encodedFormat,
347 bool allowToCreate,
348 bool matchAddress) const
349 {
350 String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
351 // handle legacy remote submix case where the address was not always specified
352 if (audio_is_remote_submix_device(deviceType) && (devAddress.length() == 0)) {
353 devAddress = String8("0");
354 }
355
356 for (const auto& hwModule : *this) {
357 if (!allowToCreate) {
358 auto dynamicDevices = hwModule->getDynamicDevices();
359 auto dynamicDevice = dynamicDevices.getDevice(deviceType, devAddress, encodedFormat);
360 if (dynamicDevice) {
361 return dynamicDevice;
362 }
363 }
364 DeviceVector moduleDevices = hwModule->getAllDevices();
365 auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress, encodedFormat);
366
367 // Prevent overwriting moduleDevice address if connected device does not have the same
368 // address (since getDevice with empty address ignores match on address), use dynamic device
369 if (moduleDevice && allowToCreate &&
370 (!moduleDevice->address().empty() &&
371 (moduleDevice->address().compare(devAddress.c_str()) != 0))) {
372 break;
373 }
374 if (moduleDevice) {
375 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
376 moduleDevice->setEncodedFormat(encodedFormat);
377 }
378 if (allowToCreate) {
379 moduleDevice->attach(hwModule);
380 // Name may be overwritten, restored on detach.
381 moduleDevice->setAddress(devAddress.c_str());
382 // Name may be overwritten, restored on detach.
383 moduleDevice->setName(name);
384 }
385 return moduleDevice;
386 }
387 }
388 if (!allowToCreate) {
389 ALOGW("%s: could not find HW module for device %s (%s, %08x) address %s", __FUNCTION__,
390 name, audio_device_to_string(deviceType), deviceType, address);
391 return nullptr;
392 }
393 return createDevice(deviceType, address, name, encodedFormat);
394 }
395
createDevice(const audio_devices_t type,const char * address,const char * name,const audio_format_t encodedFormat) const396 sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type,
397 const char *address,
398 const char *name,
399 const audio_format_t encodedFormat) const
400 {
401 std::string tagName = {};
402 sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat, &tagName);
403 if (hwModule == 0) {
404 if (encodedFormat == AUDIO_FORMAT_DEFAULT) {
405 ALOGE("%s: could not find HW module for device type '%s' (%08x)",
406 __FUNCTION__, audio_device_to_string(type), type);
407 } else {
408 ALOGE("%s: could not find HW module for device type '%s' (%08x), "
409 "encoded format '%s'", __FUNCTION__, audio_device_to_string(type), type,
410 audio_format_to_string(encodedFormat));
411 }
412 return nullptr;
413 }
414
415 sp<DeviceDescriptor> device = new DeviceDescriptor(type, tagName, address);
416 device->setName(name);
417 device->setEncodedFormat(encodedFormat);
418 device->setDynamic();
419 // Add the device to the list of dynamic devices
420 hwModule->addDynamicDevice(device);
421 // Reciprocally attach the device to the module
422 device->attach(hwModule);
423 ALOGD("%s: adding dynamic device %s to module %s", __FUNCTION__,
424 device->toString().c_str(), hwModule->getName());
425
426 const auto &profiles = (audio_is_output_device(type) ? hwModule->getOutputProfiles() :
427 hwModule->getInputProfiles());
428 for (const auto &profile : profiles) {
429 // Add the device as supported to all profile supporting "weakly" or not the device
430 // according to its type
431 if (profile->supportsDevice(device, false /*matchAddress*/)) {
432
433 // @todo quid of audio profile? import the profile from device of the same type?
434 const auto &isoTypeDeviceForProfile =
435 profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
436 device->importAudioPortAndPickAudioProfile(isoTypeDeviceForProfile, true /* force */);
437
438 ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
439 device->toString().c_str(), profile->getTagName().c_str());
440 profile->addSupportedDevice(device);
441 }
442 }
443 return device;
444 }
445
cleanUpForDevice(const sp<DeviceDescriptor> & device)446 void HwModuleCollection::cleanUpForDevice(const sp<DeviceDescriptor> &device)
447 {
448 for (const auto& hwModule : *this) {
449 DeviceVector moduleDevices = hwModule->getAllDevices();
450 if (!moduleDevices.contains(device)) {
451 continue;
452 }
453
454 // removal of remote submix devices associated with a dynamic policy is
455 // handled by removeOutputProfile() and removeInputProfile()
456 if (audio_is_remote_submix_device(device->type()) && device->address() != "0") {
457 continue;
458 }
459
460 device->detach();
461 // Only remove from dynamic list, not from declared list!!!
462 if (!hwModule->removeDynamicDevice(device)) {
463 return;
464 }
465 ALOGV("%s: removed dynamic device %s from module %s", __FUNCTION__,
466 device->toString().c_str(), hwModule->getName());
467
468 const IOProfileCollection &profiles = audio_is_output_device(device->type()) ?
469 hwModule->getOutputProfiles() : hwModule->getInputProfiles();
470 for (const auto &profile : profiles) {
471 // For cleanup, strong match is required
472 if (profile->supportsDevice(device, true /*matchAdress*/)) {
473 ALOGV("%s: removing device %s from profile %s", __FUNCTION__,
474 device->toString().c_str(), profile->getTagName().c_str());
475 profile->removeSupportedDevice(device);
476 }
477 }
478 }
479 }
480
dump(String8 * dst) const481 void HwModuleCollection::dump(String8 *dst) const
482 {
483 dst->appendFormat("\n Hardware modules (%zu):\n", size());
484 for (size_t i = 0; i < size(); i++) {
485 const std::string prefix = base::StringPrintf(" %zu. ", i + 1);
486 dst->append(prefix.c_str());
487 itemAt(i)->dump(dst, prefix.size());
488 }
489 }
490
491
492 } //namespace android
493