• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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