1 /*
2 * Copyright (C) 2014 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 "AudioPolicyEffects"
18 //#define LOG_NDEBUG 0
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <memory>
24 #include <cutils/misc.h>
25 #include <media/AudioEffect.h>
26 #include <media/EffectsConfig.h>
27 #include <system/audio.h>
28 #include <system/audio_effects/audio_effects_conf.h>
29 #include <utils/Vector.h>
30 #include <utils/SortedVector.h>
31 #include <cutils/config_utils.h>
32 #include <binder/IPCThreadState.h>
33 #include "AudioPolicyEffects.h"
34 #include "ServiceUtilities.h"
35
36 namespace android {
37
38 // ----------------------------------------------------------------------------
39 // AudioPolicyEffects Implementation
40 // ----------------------------------------------------------------------------
41
AudioPolicyEffects()42 AudioPolicyEffects::AudioPolicyEffects()
43 {
44 status_t loadResult = loadAudioEffectXmlConfig();
45 if (loadResult < 0) {
46 ALOGW("Failed to load XML effect configuration, fallback to .conf");
47 // load automatic audio effect modules
48 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
49 loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
50 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
51 loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
52 }
53 } else if (loadResult > 0) {
54 ALOGE("Effect config is partially invalid, skipped %d elements", loadResult);
55 }
56 }
57
58
~AudioPolicyEffects()59 AudioPolicyEffects::~AudioPolicyEffects()
60 {
61 size_t i = 0;
62 // release audio input processing resources
63 for (i = 0; i < mInputSources.size(); i++) {
64 delete mInputSources.valueAt(i);
65 }
66 mInputSources.clear();
67
68 for (i = 0; i < mInputSessions.size(); i++) {
69 mInputSessions.valueAt(i)->mEffects.clear();
70 delete mInputSessions.valueAt(i);
71 }
72 mInputSessions.clear();
73
74 // release audio output processing resources
75 for (i = 0; i < mOutputStreams.size(); i++) {
76 delete mOutputStreams.valueAt(i);
77 }
78 mOutputStreams.clear();
79
80 for (i = 0; i < mOutputSessions.size(); i++) {
81 mOutputSessions.valueAt(i)->mEffects.clear();
82 delete mOutputSessions.valueAt(i);
83 }
84 mOutputSessions.clear();
85 }
86
87
addInputEffects(audio_io_handle_t input,audio_source_t inputSource,audio_session_t audioSession)88 status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
89 audio_source_t inputSource,
90 audio_session_t audioSession)
91 {
92 status_t status = NO_ERROR;
93
94 // create audio pre processors according to input source
95 audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
96 AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
97
98 Mutex::Autolock _l(mLock);
99 ssize_t index = mInputSources.indexOfKey(aliasSource);
100 if (index < 0) {
101 ALOGV("addInputEffects(): no processing needs to be attached to this source");
102 return status;
103 }
104 ssize_t idx = mInputSessions.indexOfKey(audioSession);
105 EffectVector *sessionDesc;
106 if (idx < 0) {
107 sessionDesc = new EffectVector(audioSession);
108 mInputSessions.add(audioSession, sessionDesc);
109 } else {
110 // EffectVector is existing and we just need to increase ref count
111 sessionDesc = mInputSessions.valueAt(idx);
112 }
113 sessionDesc->mRefCount++;
114
115 ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
116 if (sessionDesc->mRefCount == 1) {
117 int64_t token = IPCThreadState::self()->clearCallingIdentity();
118 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
119 for (size_t i = 0; i < effects.size(); i++) {
120 EffectDesc *effect = effects[i];
121 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0,
122 0, audioSession, input);
123 status_t status = fx->initCheck();
124 if (status != NO_ERROR && status != ALREADY_EXISTS) {
125 ALOGW("addInputEffects(): failed to create Fx %s on source %d",
126 effect->mName, (int32_t)aliasSource);
127 // fx goes out of scope and strong ref on AudioEffect is released
128 continue;
129 }
130 for (size_t j = 0; j < effect->mParams.size(); j++) {
131 fx->setParameter(effect->mParams[j]);
132 }
133 ALOGV("addInputEffects(): added Fx %s on source: %d",
134 effect->mName, (int32_t)aliasSource);
135 sessionDesc->mEffects.add(fx);
136 }
137 sessionDesc->setProcessorEnabled(true);
138 IPCThreadState::self()->restoreCallingIdentity(token);
139 }
140 return status;
141 }
142
143
releaseInputEffects(audio_io_handle_t input,audio_session_t audioSession)144 status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input,
145 audio_session_t audioSession)
146 {
147 status_t status = NO_ERROR;
148
149 Mutex::Autolock _l(mLock);
150 ssize_t index = mInputSessions.indexOfKey(audioSession);
151 if (index < 0) {
152 return status;
153 }
154 EffectVector *sessionDesc = mInputSessions.valueAt(index);
155 sessionDesc->mRefCount--;
156 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
157 if (sessionDesc->mRefCount == 0) {
158 sessionDesc->setProcessorEnabled(false);
159 delete sessionDesc;
160 mInputSessions.removeItemsAt(index);
161 ALOGV("releaseInputEffects(): all effects released");
162 }
163 return status;
164 }
165
queryDefaultInputEffects(audio_session_t audioSession,effect_descriptor_t * descriptors,uint32_t * count)166 status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession,
167 effect_descriptor_t *descriptors,
168 uint32_t *count)
169 {
170 status_t status = NO_ERROR;
171
172 Mutex::Autolock _l(mLock);
173 size_t index;
174 for (index = 0; index < mInputSessions.size(); index++) {
175 if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
176 break;
177 }
178 }
179 if (index == mInputSessions.size()) {
180 *count = 0;
181 return BAD_VALUE;
182 }
183 Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
184
185 for (size_t i = 0; i < effects.size(); i++) {
186 effect_descriptor_t desc = effects[i]->descriptor();
187 if (i < *count) {
188 descriptors[i] = desc;
189 }
190 }
191 if (effects.size() > *count) {
192 status = NO_MEMORY;
193 }
194 *count = effects.size();
195 return status;
196 }
197
198
queryDefaultOutputSessionEffects(audio_session_t audioSession,effect_descriptor_t * descriptors,uint32_t * count)199 status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession,
200 effect_descriptor_t *descriptors,
201 uint32_t *count)
202 {
203 status_t status = NO_ERROR;
204
205 Mutex::Autolock _l(mLock);
206 size_t index;
207 for (index = 0; index < mOutputSessions.size(); index++) {
208 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
209 break;
210 }
211 }
212 if (index == mOutputSessions.size()) {
213 *count = 0;
214 return BAD_VALUE;
215 }
216 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
217
218 for (size_t i = 0; i < effects.size(); i++) {
219 effect_descriptor_t desc = effects[i]->descriptor();
220 if (i < *count) {
221 descriptors[i] = desc;
222 }
223 }
224 if (effects.size() > *count) {
225 status = NO_MEMORY;
226 }
227 *count = effects.size();
228 return status;
229 }
230
231
addOutputSessionEffects(audio_io_handle_t output,audio_stream_type_t stream,audio_session_t audioSession)232 status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
233 audio_stream_type_t stream,
234 audio_session_t audioSession)
235 {
236 status_t status = NO_ERROR;
237
238 Mutex::Autolock _l(mLock);
239 // create audio processors according to stream
240 // FIXME: should we have specific post processing settings for internal streams?
241 // default to media for now.
242 if (stream >= AUDIO_STREAM_PUBLIC_CNT) {
243 stream = AUDIO_STREAM_MUSIC;
244 }
245 ssize_t index = mOutputStreams.indexOfKey(stream);
246 if (index < 0) {
247 ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
248 return NO_ERROR;
249 }
250
251 ssize_t idx = mOutputSessions.indexOfKey(audioSession);
252 EffectVector *procDesc;
253 if (idx < 0) {
254 procDesc = new EffectVector(audioSession);
255 mOutputSessions.add(audioSession, procDesc);
256 } else {
257 // EffectVector is existing and we just need to increase ref count
258 procDesc = mOutputSessions.valueAt(idx);
259 }
260 procDesc->mRefCount++;
261
262 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
263 audioSession, procDesc->mRefCount);
264 if (procDesc->mRefCount == 1) {
265 // make sure effects are associated to audio server even if we are executing a binder call
266 int64_t token = IPCThreadState::self()->clearCallingIdentity();
267 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
268 for (size_t i = 0; i < effects.size(); i++) {
269 EffectDesc *effect = effects[i];
270 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0,
271 audioSession, output);
272 status_t status = fx->initCheck();
273 if (status != NO_ERROR && status != ALREADY_EXISTS) {
274 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
275 effect->mName, audioSession);
276 // fx goes out of scope and strong ref on AudioEffect is released
277 continue;
278 }
279 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
280 effect->mName, audioSession, (int32_t)stream);
281 procDesc->mEffects.add(fx);
282 }
283
284 procDesc->setProcessorEnabled(true);
285 IPCThreadState::self()->restoreCallingIdentity(token);
286 }
287 return status;
288 }
289
releaseOutputSessionEffects(audio_io_handle_t output,audio_stream_type_t stream,audio_session_t audioSession)290 status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
291 audio_stream_type_t stream,
292 audio_session_t audioSession)
293 {
294 status_t status = NO_ERROR;
295 (void) output; // argument not used for now
296 (void) stream; // argument not used for now
297
298 Mutex::Autolock _l(mLock);
299 ssize_t index = mOutputSessions.indexOfKey(audioSession);
300 if (index < 0) {
301 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
302 return NO_ERROR;
303 }
304
305 EffectVector *procDesc = mOutputSessions.valueAt(index);
306 procDesc->mRefCount--;
307 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
308 audioSession, procDesc->mRefCount);
309 if (procDesc->mRefCount == 0) {
310 procDesc->setProcessorEnabled(false);
311 procDesc->mEffects.clear();
312 delete procDesc;
313 mOutputSessions.removeItemsAt(index);
314 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
315 audioSession);
316 }
317 return status;
318 }
319
320
setProcessorEnabled(bool enabled)321 void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
322 {
323 for (size_t i = 0; i < mEffects.size(); i++) {
324 mEffects.itemAt(i)->setEnabled(enabled);
325 }
326 }
327
328
329 // ----------------------------------------------------------------------------
330 // Audio processing configuration
331 // ----------------------------------------------------------------------------
332
333 /*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
334 MIC_SRC_TAG,
335 VOICE_UL_SRC_TAG,
336 VOICE_DL_SRC_TAG,
337 VOICE_CALL_SRC_TAG,
338 CAMCORDER_SRC_TAG,
339 VOICE_REC_SRC_TAG,
340 VOICE_COMM_SRC_TAG,
341 UNPROCESSED_SRC_TAG
342 };
343
344 // returns the audio_source_t enum corresponding to the input source name or
345 // AUDIO_SOURCE_CNT is no match found
inputSourceNameToEnum(const char * name)346 /*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
347 {
348 int i;
349 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
350 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
351 ALOGV("inputSourceNameToEnum found source %s %d", name, i);
352 break;
353 }
354 }
355 return (audio_source_t)i;
356 }
357
358 const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = {
359 AUDIO_STREAM_DEFAULT_TAG,
360 AUDIO_STREAM_VOICE_CALL_TAG,
361 AUDIO_STREAM_SYSTEM_TAG,
362 AUDIO_STREAM_RING_TAG,
363 AUDIO_STREAM_MUSIC_TAG,
364 AUDIO_STREAM_ALARM_TAG,
365 AUDIO_STREAM_NOTIFICATION_TAG,
366 AUDIO_STREAM_BLUETOOTH_SCO_TAG,
367 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
368 AUDIO_STREAM_DTMF_TAG,
369 AUDIO_STREAM_TTS_TAG
370 };
371
372 // returns the audio_stream_t enum corresponding to the output stream name or
373 // AUDIO_STREAM_PUBLIC_CNT is no match found
streamNameToEnum(const char * name)374 audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
375 {
376 int i;
377 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) {
378 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
379 ALOGV("streamNameToEnum found stream %s %d", name, i);
380 break;
381 }
382 }
383 return (audio_stream_type_t)i;
384 }
385
386 // ----------------------------------------------------------------------------
387 // Audio Effect Config parser
388 // ----------------------------------------------------------------------------
389
growParamSize(char ** param,size_t size,size_t * curSize,size_t * totSize)390 size_t AudioPolicyEffects::growParamSize(char **param,
391 size_t size,
392 size_t *curSize,
393 size_t *totSize)
394 {
395 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
396 size_t pos = ((*curSize - 1 ) / size + 1) * size;
397
398 if (pos + size > *totSize) {
399 while (pos + size > *totSize) {
400 *totSize += ((*totSize + 7) / 8) * 4;
401 }
402 char *newParam = (char *)realloc(*param, *totSize);
403 if (newParam == NULL) {
404 ALOGE("%s realloc error for size %zu", __func__, *totSize);
405 return 0;
406 }
407 *param = newParam;
408 }
409 *curSize = pos + size;
410 return pos;
411 }
412
413
readParamValue(cnode * node,char ** param,size_t * curSize,size_t * totSize)414 size_t AudioPolicyEffects::readParamValue(cnode *node,
415 char **param,
416 size_t *curSize,
417 size_t *totSize)
418 {
419 size_t len = 0;
420 size_t pos;
421
422 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
423 pos = growParamSize(param, sizeof(short), curSize, totSize);
424 if (pos == 0) {
425 goto exit;
426 }
427 *(short *)(*param + pos) = (short)atoi(node->value);
428 ALOGV("readParamValue() reading short %d", *(short *)(*param + pos));
429 len = sizeof(short);
430 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
431 pos = growParamSize(param, sizeof(int), curSize, totSize);
432 if (pos == 0) {
433 goto exit;
434 }
435 *(int *)(*param + pos) = atoi(node->value);
436 ALOGV("readParamValue() reading int %d", *(int *)(*param + pos));
437 len = sizeof(int);
438 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
439 pos = growParamSize(param, sizeof(float), curSize, totSize);
440 if (pos == 0) {
441 goto exit;
442 }
443 *(float *)(*param + pos) = (float)atof(node->value);
444 ALOGV("readParamValue() reading float %f",*(float *)(*param + pos));
445 len = sizeof(float);
446 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
447 pos = growParamSize(param, sizeof(bool), curSize, totSize);
448 if (pos == 0) {
449 goto exit;
450 }
451 if (strncmp(node->value, "true", strlen("true") + 1) == 0) {
452 *(bool *)(*param + pos) = true;
453 } else {
454 *(bool *)(*param + pos) = false;
455 }
456 ALOGV("readParamValue() reading bool %s",
457 *(bool *)(*param + pos) ? "true" : "false");
458 len = sizeof(bool);
459 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
460 len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
461 if (*curSize + len + 1 > *totSize) {
462 *totSize = *curSize + len + 1;
463 *param = (char *)realloc(*param, *totSize);
464 if (*param == NULL) {
465 len = 0;
466 ALOGE("%s realloc error for string len %zu", __func__, *totSize);
467 goto exit;
468 }
469 }
470 strncpy(*param + *curSize, node->value, len);
471 *curSize += len;
472 (*param)[*curSize] = '\0';
473 ALOGV("readParamValue() reading string %s", *param + *curSize - len);
474 } else {
475 ALOGW("readParamValue() unknown param type %s", node->name);
476 }
477 exit:
478 return len;
479 }
480
loadEffectParameter(cnode * root)481 effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
482 {
483 cnode *param;
484 cnode *value;
485 size_t curSize = sizeof(effect_param_t);
486 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
487 effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
488
489 if (fx_param == NULL) {
490 ALOGE("%s malloc error for effect structure of size %zu",
491 __func__, totSize);
492 return NULL;
493 }
494
495 param = config_find(root, PARAM_TAG);
496 value = config_find(root, VALUE_TAG);
497 if (param == NULL && value == NULL) {
498 // try to parse simple parameter form {int int}
499 param = root->first_child;
500 if (param != NULL) {
501 // Note: that a pair of random strings is read as 0 0
502 int *ptr = (int *)fx_param->data;
503 #if LOG_NDEBUG == 0
504 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
505 ALOGV("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
506 #endif
507 *ptr++ = atoi(param->name);
508 *ptr = atoi(param->value);
509 fx_param->psize = sizeof(int);
510 fx_param->vsize = sizeof(int);
511 return fx_param;
512 }
513 }
514 if (param == NULL || value == NULL) {
515 ALOGW("loadEffectParameter() invalid parameter description %s",
516 root->name);
517 goto error;
518 }
519
520 fx_param->psize = 0;
521 param = param->first_child;
522 while (param) {
523 ALOGV("loadEffectParameter() reading param of type %s", param->name);
524 size_t size =
525 readParamValue(param, (char **)&fx_param, &curSize, &totSize);
526 if (size == 0) {
527 goto error;
528 }
529 fx_param->psize += size;
530 param = param->next;
531 }
532
533 // align start of value field on 32 bit boundary
534 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
535
536 fx_param->vsize = 0;
537 value = value->first_child;
538 while (value) {
539 ALOGV("loadEffectParameter() reading value of type %s", value->name);
540 size_t size =
541 readParamValue(value, (char **)&fx_param, &curSize, &totSize);
542 if (size == 0) {
543 goto error;
544 }
545 fx_param->vsize += size;
546 value = value->next;
547 }
548
549 return fx_param;
550
551 error:
552 free(fx_param);
553 return NULL;
554 }
555
loadEffectParameters(cnode * root,Vector<effect_param_t * > & params)556 void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
557 {
558 cnode *node = root->first_child;
559 while (node) {
560 ALOGV("loadEffectParameters() loading param %s", node->name);
561 effect_param_t *param = loadEffectParameter(node);
562 if (param != NULL) {
563 params.add(param);
564 }
565 node = node->next;
566 }
567 }
568
569
loadEffectConfig(cnode * root,const Vector<EffectDesc * > & effects)570 AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
571 cnode *root,
572 const Vector <EffectDesc *>& effects)
573 {
574 cnode *node = root->first_child;
575 if (node == NULL) {
576 ALOGW("loadInputSource() empty element %s", root->name);
577 return NULL;
578 }
579 EffectDescVector *desc = new EffectDescVector();
580 while (node) {
581 size_t i;
582
583 for (i = 0; i < effects.size(); i++) {
584 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
585 ALOGV("loadEffectConfig() found effect %s in list", node->name);
586 break;
587 }
588 }
589 if (i == effects.size()) {
590 ALOGV("loadEffectConfig() effect %s not in list", node->name);
591 node = node->next;
592 continue;
593 }
594 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
595 loadEffectParameters(node, effect->mParams);
596 ALOGV("loadEffectConfig() adding effect %s uuid %08x",
597 effect->mName, effect->mUuid.timeLow);
598 desc->mEffects.add(effect);
599 node = node->next;
600 }
601 if (desc->mEffects.size() == 0) {
602 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
603 delete desc;
604 return NULL;
605 }
606 return desc;
607 }
608
loadInputEffectConfigurations(cnode * root,const Vector<EffectDesc * > & effects)609 status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
610 const Vector <EffectDesc *>& effects)
611 {
612 cnode *node = config_find(root, PREPROCESSING_TAG);
613 if (node == NULL) {
614 return -ENOENT;
615 }
616 node = node->first_child;
617 while (node) {
618 audio_source_t source = inputSourceNameToEnum(node->name);
619 if (source == AUDIO_SOURCE_CNT) {
620 ALOGW("loadInputSources() invalid input source %s", node->name);
621 node = node->next;
622 continue;
623 }
624 ALOGV("loadInputSources() loading input source %s", node->name);
625 EffectDescVector *desc = loadEffectConfig(node, effects);
626 if (desc == NULL) {
627 node = node->next;
628 continue;
629 }
630 mInputSources.add(source, desc);
631 node = node->next;
632 }
633 return NO_ERROR;
634 }
635
loadStreamEffectConfigurations(cnode * root,const Vector<EffectDesc * > & effects)636 status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
637 const Vector <EffectDesc *>& effects)
638 {
639 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
640 if (node == NULL) {
641 return -ENOENT;
642 }
643 node = node->first_child;
644 while (node) {
645 audio_stream_type_t stream = streamNameToEnum(node->name);
646 if (stream == AUDIO_STREAM_PUBLIC_CNT) {
647 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
648 node = node->next;
649 continue;
650 }
651 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
652 EffectDescVector *desc = loadEffectConfig(node, effects);
653 if (desc == NULL) {
654 node = node->next;
655 continue;
656 }
657 mOutputStreams.add(stream, desc);
658 node = node->next;
659 }
660 return NO_ERROR;
661 }
662
loadEffect(cnode * root)663 AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
664 {
665 cnode *node = config_find(root, UUID_TAG);
666 if (node == NULL) {
667 return NULL;
668 }
669 effect_uuid_t uuid;
670 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
671 ALOGW("loadEffect() invalid uuid %s", node->value);
672 return NULL;
673 }
674 return new EffectDesc(root->name, uuid);
675 }
676
loadEffects(cnode * root,Vector<EffectDesc * > & effects)677 status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
678 {
679 cnode *node = config_find(root, EFFECTS_TAG);
680 if (node == NULL) {
681 return -ENOENT;
682 }
683 node = node->first_child;
684 while (node) {
685 ALOGV("loadEffects() loading effect %s", node->name);
686 EffectDesc *effect = loadEffect(node);
687 if (effect == NULL) {
688 node = node->next;
689 continue;
690 }
691 effects.add(effect);
692 node = node->next;
693 }
694 return NO_ERROR;
695 }
696
loadAudioEffectXmlConfig()697 status_t AudioPolicyEffects::loadAudioEffectXmlConfig() {
698 auto result = effectsConfig::parse();
699 if (result.parsedConfig == nullptr) {
700 return -ENOENT;
701 }
702
703 auto loadProcessingChain = [](auto& processingChain, auto& streams) {
704 for (auto& stream : processingChain) {
705 auto effectDescs = std::make_unique<EffectDescVector>();
706 for (auto& effect : stream.effects) {
707 effectDescs->mEffects.add(
708 new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
709 }
710 streams.add(stream.type, effectDescs.release());
711 }
712 };
713 loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
714 loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
715 // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
716 return result.nbSkippedElement;
717 }
718
loadAudioEffectConfig(const char * path)719 status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
720 {
721 cnode *root;
722 char *data;
723
724 data = (char *)load_file(path, NULL);
725 if (data == NULL) {
726 return -ENODEV;
727 }
728 root = config_node("", "");
729 config_load(root, data);
730
731 Vector <EffectDesc *> effects;
732 loadEffects(root, effects);
733 loadInputEffectConfigurations(root, effects);
734 loadStreamEffectConfigurations(root, effects);
735
736 for (size_t i = 0; i < effects.size(); i++) {
737 delete effects[i];
738 }
739
740 config_free(root);
741 free(root);
742 free(data);
743
744 return NO_ERROR;
745 }
746
747
748 } // namespace android
749