HwModule.cpp revision 7288ab87a7aa730ffe97d7dc7e118123107bfcea
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 "ConfigParsingUtils.h"
24#include "audio_policy_conf.h"
25#include <hardware/audio.h>
26#include <policy.h>
27
28namespace android {
29
30HwModule::HwModule(const char *name)
31    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
32      mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
33{
34}
35
36HwModule::~HwModule()
37{
38    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
39        mOutputProfiles[i]->mSupportedDevices.clear();
40    }
41    for (size_t i = 0; i < mInputProfiles.size(); i++) {
42        mInputProfiles[i]->mSupportedDevices.clear();
43    }
44    free((void *)mName);
45}
46
47status_t HwModule::loadInput(cnode *root)
48{
49    cnode *node = root->first_child;
50
51    sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK);
52
53    while (node) {
54        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
55            profile->loadSamplingRates((char *)node->value);
56        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
57            profile->loadFormats((char *)node->value);
58        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
59            profile->loadInChannels((char *)node->value);
60        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
61            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
62                                                           mDeclaredDevices);
63        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
64            profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
65        } else if (strcmp(node->name, GAINS_TAG) == 0) {
66            profile->loadGains(node);
67        }
68        node = node->next;
69    }
70    ALOGW_IF(profile->mSupportedDevices.isEmpty(),
71            "loadInput() invalid supported devices");
72    ALOGW_IF(profile->mChannelMasks.size() == 0,
73            "loadInput() invalid supported channel masks");
74    ALOGW_IF(profile->mSamplingRates.size() == 0,
75            "loadInput() invalid supported sampling rates");
76    ALOGW_IF(profile->mFormats.size() == 0,
77            "loadInput() invalid supported formats");
78    if (!profile->mSupportedDevices.isEmpty() &&
79            (profile->mChannelMasks.size() != 0) &&
80            (profile->mSamplingRates.size() != 0) &&
81            (profile->mFormats.size() != 0)) {
82
83        ALOGV("loadInput() adding input Supported Devices %04x",
84              profile->mSupportedDevices.types());
85
86        profile->attach(this);
87        mInputProfiles.add(profile);
88        return NO_ERROR;
89    } else {
90        return BAD_VALUE;
91    }
92}
93
94status_t HwModule::loadOutput(cnode *root)
95{
96    cnode *node = root->first_child;
97
98    sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE);
99
100    while (node) {
101        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
102            profile->loadSamplingRates((char *)node->value);
103        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
104            profile->loadFormats((char *)node->value);
105        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
106            profile->loadOutChannels((char *)node->value);
107        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
108            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
109                                                           mDeclaredDevices);
110        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
111            profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
112        } else if (strcmp(node->name, GAINS_TAG) == 0) {
113            profile->loadGains(node);
114        }
115        node = node->next;
116    }
117    ALOGW_IF(profile->mSupportedDevices.isEmpty(),
118            "loadOutput() invalid supported devices");
119    ALOGW_IF(profile->mChannelMasks.size() == 0,
120            "loadOutput() invalid supported channel masks");
121    ALOGW_IF(profile->mSamplingRates.size() == 0,
122            "loadOutput() invalid supported sampling rates");
123    ALOGW_IF(profile->mFormats.size() == 0,
124            "loadOutput() invalid supported formats");
125    if (!profile->mSupportedDevices.isEmpty() &&
126            (profile->mChannelMasks.size() != 0) &&
127            (profile->mSamplingRates.size() != 0) &&
128            (profile->mFormats.size() != 0)) {
129
130        ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
131              profile->mSupportedDevices.types(), profile->mFlags);
132        profile->attach(this);
133        mOutputProfiles.add(profile);
134        return NO_ERROR;
135    } else {
136        return BAD_VALUE;
137    }
138}
139
140status_t HwModule::loadDevice(cnode *root)
141{
142    cnode *node = root->first_child;
143
144    audio_devices_t type = AUDIO_DEVICE_NONE;
145    while (node) {
146        if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
147            type = ConfigParsingUtils::parseDeviceNames((char *)node->value);
148            break;
149        }
150        node = node->next;
151    }
152    if (type == AUDIO_DEVICE_NONE ||
153            (!audio_is_input_device(type) && !audio_is_output_device(type))) {
154        ALOGW("loadDevice() bad type %08x", type);
155        return BAD_VALUE;
156    }
157    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
158    deviceDesc->mTag = String8(root->name);
159
160    node = root->first_child;
161    while (node) {
162        if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
163            deviceDesc->mAddress = String8((char *)node->value);
164        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
165            if (audio_is_input_device(type)) {
166                deviceDesc->loadInChannels((char *)node->value);
167            } else {
168                deviceDesc->loadOutChannels((char *)node->value);
169            }
170        } else if (strcmp(node->name, GAINS_TAG) == 0) {
171            deviceDesc->loadGains(node);
172        }
173        node = node->next;
174    }
175
176    ALOGV("loadDevice() adding device tag %s type %08x address %s",
177          deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
178
179    mDeclaredDevices.add(deviceDesc);
180
181    return NO_ERROR;
182}
183
184status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
185                                                  audio_devices_t device, String8 address)
186{
187    sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE);
188
189    profile->mSamplingRates.add(config->sample_rate);
190    profile->mChannelMasks.add(config->channel_mask);
191    profile->mFormats.add(config->format);
192
193    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
194    devDesc->mAddress = address;
195    profile->mSupportedDevices.add(devDesc);
196
197    profile->attach(this);
198    mOutputProfiles.add(profile);
199
200    return NO_ERROR;
201}
202
203status_t HwModule::removeOutputProfile(String8 name)
204{
205    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
206        if (mOutputProfiles[i]->mName == name) {
207            mOutputProfiles.removeAt(i);
208            break;
209        }
210    }
211
212    return NO_ERROR;
213}
214
215status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
216                                                  audio_devices_t device, String8 address)
217{
218    sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK);
219
220    profile->mSamplingRates.add(config->sample_rate);
221    profile->mChannelMasks.add(config->channel_mask);
222    profile->mFormats.add(config->format);
223
224    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
225    devDesc->mAddress = address;
226    profile->mSupportedDevices.add(devDesc);
227
228    ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
229
230    profile->attach(this);
231    mInputProfiles.add(profile);
232
233    return NO_ERROR;
234}
235
236status_t HwModule::removeInputProfile(String8 name)
237{
238    for (size_t i = 0; i < mInputProfiles.size(); i++) {
239        if (mInputProfiles[i]->mName == name) {
240            mInputProfiles.removeAt(i);
241            break;
242        }
243    }
244
245    return NO_ERROR;
246}
247
248
249void HwModule::dump(int fd)
250{
251    const size_t SIZE = 256;
252    char buffer[SIZE];
253    String8 result;
254
255    snprintf(buffer, SIZE, "  - name: %s\n", mName);
256    result.append(buffer);
257    snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
258    result.append(buffer);
259    snprintf(buffer, SIZE, "  - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
260    result.append(buffer);
261    write(fd, result.string(), result.size());
262    if (mOutputProfiles.size()) {
263        write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
264        for (size_t i = 0; i < mOutputProfiles.size(); i++) {
265            snprintf(buffer, SIZE, "    output %zu:\n", i);
266            write(fd, buffer, strlen(buffer));
267            mOutputProfiles[i]->dump(fd);
268        }
269    }
270    if (mInputProfiles.size()) {
271        write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
272        for (size_t i = 0; i < mInputProfiles.size(); i++) {
273            snprintf(buffer, SIZE, "    input %zu:\n", i);
274            write(fd, buffer, strlen(buffer));
275            mInputProfiles[i]->dump(fd);
276        }
277    }
278    if (mDeclaredDevices.size()) {
279        write(fd, "  - devices:\n", strlen("  - devices:\n"));
280        for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
281            mDeclaredDevices[i]->dump(fd, 4, i);
282        }
283    }
284}
285
286sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
287{
288    sp <HwModule> module;
289
290    for (size_t i = 0; i < size(); i++)
291    {
292        if (strcmp(itemAt(i)->mName, name) == 0) {
293            return itemAt(i);
294        }
295    }
296    return module;
297}
298
299
300sp <HwModule> HwModuleCollection::getModuleForDevice(audio_devices_t device) const
301{
302    sp <HwModule> module;
303
304    for (size_t i = 0; i < size(); i++) {
305        if (itemAt(i)->mHandle == 0) {
306            continue;
307        }
308        if (audio_is_output_device(device)) {
309            for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
310            {
311                if (itemAt(i)->mOutputProfiles[j]->mSupportedDevices.types() & device) {
312                    return itemAt(i);
313                }
314            }
315        } else {
316            for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
317                if (itemAt(i)->mInputProfiles[j]->mSupportedDevices.types() &
318                        device & ~AUDIO_DEVICE_BIT_IN) {
319                    return itemAt(i);
320                }
321            }
322        }
323    }
324    return module;
325}
326
327sp<DeviceDescriptor>  HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
328                                                              const char *device_address,
329                                                              const char *device_name) const
330{
331    String8 address = (device_address == NULL) ? String8("") : String8(device_address);
332    // handle legacy remote submix case where the address was not always specified
333    if (device_distinguishes_on_address(device) && (address.length() == 0)) {
334        address = String8("0");
335    }
336
337    for (size_t i = 0; i < size(); i++) {
338        const sp<HwModule> hwModule = itemAt(i);
339        if (hwModule->mHandle == 0) {
340            continue;
341        }
342        DeviceVector deviceList =
343                hwModule->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
344        if (!deviceList.isEmpty()) {
345            return deviceList.itemAt(0);
346        }
347        deviceList = hwModule->mDeclaredDevices.getDevicesFromType(device);
348        if (!deviceList.isEmpty()) {
349            return deviceList.itemAt(0);
350        }
351    }
352
353    sp<DeviceDescriptor> devDesc =
354            new DeviceDescriptor(device);
355    devDesc->mName = device_name;
356    devDesc->mAddress = address;
357    return devDesc;
358}
359
360status_t HwModuleCollection::dump(int fd) const
361{
362    const size_t SIZE = 256;
363    char buffer[SIZE];
364
365    snprintf(buffer, SIZE, "\nHW Modules dump:\n");
366    write(fd, buffer, strlen(buffer));
367    for (size_t i = 0; i < size(); i++) {
368        snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
369        write(fd, buffer, strlen(buffer));
370        itemAt(i)->dump(fd);
371    }
372    return NO_ERROR;
373}
374
375} //namespace android
376