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
28 namespace android {
29
HwModule(const char * name)30 HwModule::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
~HwModule()36 HwModule::~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
loadInput(cnode * root)47 status_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
loadOutput(cnode * root)94 status_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
loadDevice(cnode * root)140 status_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
addOutputProfile(String8 name,const audio_config_t * config,audio_devices_t device,String8 address)184 status_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
removeOutputProfile(String8 name)203 status_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
addInputProfile(String8 name,const audio_config_t * config,audio_devices_t device,String8 address)215 status_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
removeInputProfile(String8 name)236 status_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
dump(int fd)249 void 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
getModuleFromName(const char * name) const286 sp <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
getModuleForDevice(audio_devices_t device) const300 sp <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
getDeviceDescriptor(const audio_devices_t device,const char * device_address,const char * device_name) const327 sp<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
dump(int fd) const360 status_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