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