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