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