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