blob: 3c1c042dff85047c1a2ab6631ae543cf4450ff01 [file] [log] [blame]
bryant_liuba2b4392014-06-11 16:49:30 +08001/*
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"
Eric Laurent897a4082014-07-11 16:51:53 -070018//#define LOG_NDEBUG 0
bryant_liuba2b4392014-06-11 16:49:30 +080019
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 <hardware/audio_effect.h>
27#include <audio_effects/audio_effects_conf.h>
28#include <utils/Vector.h>
29#include <utils/SortedVector.h>
30#include <cutils/config_utils.h>
31#include "AudioPolicyEffects.h"
32#include "ServiceUtilities.h"
33
34namespace android {
35
36// ----------------------------------------------------------------------------
37// AudioPolicyEffects Implementation
38// ----------------------------------------------------------------------------
39
40AudioPolicyEffects::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
51AudioPolicyEffects::~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 < mInputs.size(); i++) {
61 mInputs.valueAt(i)->mEffects.clear();
62 delete mInputs.valueAt(i);
63 }
64 mInputs.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
80status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
81 audio_source_t inputSource,
82 int 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
Eric Laurent8b1e80b2014-10-07 09:08:47 -070090 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +080091 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 = mInputs.indexOfKey(input);
97 EffectVector *inputDesc;
98 if (idx < 0) {
99 inputDesc = new EffectVector(audioSession);
100 mInputs.add(input, inputDesc);
101 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800102 // EffectVector is existing and we just need to increase ref count
bryant_liuba2b4392014-06-11 16:49:30 +0800103 inputDesc = mInputs.valueAt(idx);
104 }
bryant_liu890a5632014-08-20 18:06:13 +0800105 inputDesc->mRefCount++;
106
107 ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
bryant_liuba2b4392014-06-11 16:49:30 +0800108
109 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
110 for (size_t i = 0; i < effects.size(); i++) {
111 EffectDesc *effect = effects[i];
112 sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
113 status_t status = fx->initCheck();
114 if (status != NO_ERROR && status != ALREADY_EXISTS) {
115 ALOGW("addInputEffects(): failed to create Fx %s on source %d",
116 effect->mName, (int32_t)aliasSource);
117 // fx goes out of scope and strong ref on AudioEffect is released
118 continue;
119 }
120 for (size_t j = 0; j < effect->mParams.size(); j++) {
121 fx->setParameter(effect->mParams[j]);
122 }
123 ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource);
124 inputDesc->mEffects.add(fx);
125 }
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700126 inputDesc->setProcessorEnabled(true);
bryant_liuba2b4392014-06-11 16:49:30 +0800127
128 return status;
129}
130
131
132status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input)
133{
134 status_t status = NO_ERROR;
135
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700136 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800137 ssize_t index = mInputs.indexOfKey(input);
138 if (index < 0) {
139 return status;
140 }
141 EffectVector *inputDesc = mInputs.valueAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800142 inputDesc->mRefCount--;
143 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
144 if (inputDesc->mRefCount == 0) {
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700145 inputDesc->setProcessorEnabled(false);
bryant_liu890a5632014-08-20 18:06:13 +0800146 delete inputDesc;
147 mInputs.removeItemsAt(index);
148 ALOGV("releaseInputEffects(): all effects released");
149 }
bryant_liuba2b4392014-06-11 16:49:30 +0800150 return status;
151}
152
153status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession,
154 effect_descriptor_t *descriptors,
155 uint32_t *count)
156{
157 status_t status = NO_ERROR;
158
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700159 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800160 size_t index;
161 for (index = 0; index < mInputs.size(); index++) {
162 if (mInputs.valueAt(index)->mSessionId == audioSession) {
163 break;
164 }
165 }
166 if (index == mInputs.size()) {
167 *count = 0;
168 return BAD_VALUE;
169 }
170 Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
171
172 for (size_t i = 0; i < effects.size(); i++) {
173 effect_descriptor_t desc = effects[i]->descriptor();
174 if (i < *count) {
175 descriptors[i] = desc;
176 }
177 }
178 if (effects.size() > *count) {
179 status = NO_MEMORY;
180 }
181 *count = effects.size();
182 return status;
183}
184
185
186status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession,
187 effect_descriptor_t *descriptors,
188 uint32_t *count)
189{
190 status_t status = NO_ERROR;
191
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700192 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800193 size_t index;
194 for (index = 0; index < mOutputSessions.size(); index++) {
195 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
196 break;
197 }
198 }
199 if (index == mOutputSessions.size()) {
200 *count = 0;
201 return BAD_VALUE;
202 }
203 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
204
205 for (size_t i = 0; i < effects.size(); i++) {
206 effect_descriptor_t desc = effects[i]->descriptor();
207 if (i < *count) {
208 descriptors[i] = desc;
209 }
210 }
211 if (effects.size() > *count) {
212 status = NO_MEMORY;
213 }
214 *count = effects.size();
215 return status;
216}
217
218
219status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
220 audio_stream_type_t stream,
221 int audioSession)
222{
223 status_t status = NO_ERROR;
224
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700225 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800226 // create audio processors according to stream
227 ssize_t index = mOutputStreams.indexOfKey(stream);
228 if (index < 0) {
229 ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
230 return NO_ERROR;
231 }
232
233 ssize_t idx = mOutputSessions.indexOfKey(audioSession);
234 EffectVector *procDesc;
235 if (idx < 0) {
236 procDesc = new EffectVector(audioSession);
237 mOutputSessions.add(audioSession, procDesc);
238 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800239 // EffectVector is existing and we just need to increase ref count
bryant_liuba2b4392014-06-11 16:49:30 +0800240 procDesc = mOutputSessions.valueAt(idx);
241 }
bryant_liu890a5632014-08-20 18:06:13 +0800242 procDesc->mRefCount++;
243
244 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount);
bryant_liuba2b4392014-06-11 16:49:30 +0800245
246 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
247 for (size_t i = 0; i < effects.size(); i++) {
248 EffectDesc *effect = effects[i];
249 sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, audioSession, output);
250 status_t status = fx->initCheck();
251 if (status != NO_ERROR && status != ALREADY_EXISTS) {
252 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
253 effect->mName, audioSession);
254 // fx goes out of scope and strong ref on AudioEffect is released
255 continue;
256 }
257 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
258 effect->mName, audioSession, (int32_t)stream);
259 procDesc->mEffects.add(fx);
260 }
261
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700262 procDesc->setProcessorEnabled(true);
bryant_liuba2b4392014-06-11 16:49:30 +0800263
264 return status;
265}
266
267status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
268 audio_stream_type_t stream,
269 int audioSession)
270{
271 status_t status = NO_ERROR;
272 (void) output; // argument not used for now
273 (void) stream; // argument not used for now
274
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700275 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800276 ssize_t index = mOutputSessions.indexOfKey(audioSession);
277 if (index < 0) {
278 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
279 return NO_ERROR;
280 }
281
282 EffectVector *procDesc = mOutputSessions.valueAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800283 procDesc->mRefCount--;
284 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount);
285 if (procDesc->mRefCount == 0) {
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700286 procDesc->setProcessorEnabled(false);
bryant_liu890a5632014-08-20 18:06:13 +0800287 procDesc->mEffects.clear();
288 delete procDesc;
289 mOutputSessions.removeItemsAt(index);
290 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
291 audioSession);
292 }
bryant_liuba2b4392014-06-11 16:49:30 +0800293 return status;
294}
295
296
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700297void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
bryant_liuba2b4392014-06-11 16:49:30 +0800298{
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700299 for (size_t i = 0; i < mEffects.size(); i++) {
300 mEffects.itemAt(i)->setEnabled(enabled);
bryant_liuba2b4392014-06-11 16:49:30 +0800301 }
302}
303
304
305// ----------------------------------------------------------------------------
306// Audio processing configuration
307// ----------------------------------------------------------------------------
308
309/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
310 MIC_SRC_TAG,
311 VOICE_UL_SRC_TAG,
312 VOICE_DL_SRC_TAG,
313 VOICE_CALL_SRC_TAG,
314 CAMCORDER_SRC_TAG,
315 VOICE_REC_SRC_TAG,
316 VOICE_COMM_SRC_TAG
317};
318
319// returns the audio_source_t enum corresponding to the input source name or
320// AUDIO_SOURCE_CNT is no match found
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700321/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
bryant_liuba2b4392014-06-11 16:49:30 +0800322{
323 int i;
324 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
325 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
326 ALOGV("inputSourceNameToEnum found source %s %d", name, i);
327 break;
328 }
329 }
330 return (audio_source_t)i;
331}
332
333const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_CNT+1] = {
334 AUDIO_STREAM_DEFAULT_TAG,
335 AUDIO_STREAM_VOICE_CALL_TAG,
336 AUDIO_STREAM_SYSTEM_TAG,
337 AUDIO_STREAM_RING_TAG,
338 AUDIO_STREAM_MUSIC_TAG,
339 AUDIO_STREAM_ALARM_TAG,
340 AUDIO_STREAM_NOTIFICATION_TAG,
341 AUDIO_STREAM_BLUETOOTH_SCO_TAG,
342 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
343 AUDIO_STREAM_DTMF_TAG,
344 AUDIO_STREAM_TTS_TAG
345};
346
347// returns the audio_stream_t enum corresponding to the output stream name or
348// AUDIO_STREAM_CNT is no match found
349audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
350{
351 int i;
352 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_CNT; i++) {
353 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
354 ALOGV("streamNameToEnum found stream %s %d", name, i);
355 break;
356 }
357 }
358 return (audio_stream_type_t)i;
359}
360
361// ----------------------------------------------------------------------------
362// Audio Effect Config parser
363// ----------------------------------------------------------------------------
364
365size_t AudioPolicyEffects::growParamSize(char *param,
366 size_t size,
367 size_t *curSize,
368 size_t *totSize)
369{
370 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
371 size_t pos = ((*curSize - 1 ) / size + 1) * size;
372
373 if (pos + size > *totSize) {
374 while (pos + size > *totSize) {
375 *totSize += ((*totSize + 7) / 8) * 4;
376 }
377 param = (char *)realloc(param, *totSize);
378 }
379 *curSize = pos + size;
380 return pos;
381}
382
383size_t AudioPolicyEffects::readParamValue(cnode *node,
384 char *param,
385 size_t *curSize,
386 size_t *totSize)
387{
388 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
389 size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
390 *(short *)((char *)param + pos) = (short)atoi(node->value);
391 ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
392 return sizeof(short);
393 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
394 size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
395 *(int *)((char *)param + pos) = atoi(node->value);
396 ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
397 return sizeof(int);
398 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
399 size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
400 *(float *)((char *)param + pos) = (float)atof(node->value);
401 ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
402 return sizeof(float);
403 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
404 size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
405 if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
406 *(bool *)((char *)param + pos) = false;
407 } else {
408 *(bool *)((char *)param + pos) = true;
409 }
410 ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
411 return sizeof(bool);
412 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
413 size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
414 if (*curSize + len + 1 > *totSize) {
415 *totSize = *curSize + len + 1;
416 param = (char *)realloc(param, *totSize);
417 }
418 strncpy(param + *curSize, node->value, len);
419 *curSize += len;
420 param[*curSize] = '\0';
421 ALOGV("readParamValue() reading string %s", param + *curSize - len);
422 return len;
423 }
424 ALOGW("readParamValue() unknown param type %s", node->name);
425 return 0;
426}
427
428effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
429{
430 cnode *param;
431 cnode *value;
432 size_t curSize = sizeof(effect_param_t);
433 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
434 effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
435
436 param = config_find(root, PARAM_TAG);
437 value = config_find(root, VALUE_TAG);
438 if (param == NULL && value == NULL) {
439 // try to parse simple parameter form {int int}
440 param = root->first_child;
441 if (param != NULL) {
442 // Note: that a pair of random strings is read as 0 0
443 int *ptr = (int *)fx_param->data;
444 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
445 ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
446 *ptr++ = atoi(param->name);
447 *ptr = atoi(param->value);
448 fx_param->psize = sizeof(int);
449 fx_param->vsize = sizeof(int);
450 return fx_param;
451 }
452 }
453 if (param == NULL || value == NULL) {
454 ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
455 goto error;
456 }
457
458 fx_param->psize = 0;
459 param = param->first_child;
460 while (param) {
461 ALOGV("loadEffectParameter() reading param of type %s", param->name);
462 size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
463 if (size == 0) {
464 goto error;
465 }
466 fx_param->psize += size;
467 param = param->next;
468 }
469
470 // align start of value field on 32 bit boundary
471 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
472
473 fx_param->vsize = 0;
474 value = value->first_child;
475 while (value) {
476 ALOGV("loadEffectParameter() reading value of type %s", value->name);
477 size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
478 if (size == 0) {
479 goto error;
480 }
481 fx_param->vsize += size;
482 value = value->next;
483 }
484
485 return fx_param;
486
487error:
488 delete fx_param;
489 return NULL;
490}
491
492void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
493{
494 cnode *node = root->first_child;
495 while (node) {
496 ALOGV("loadEffectParameters() loading param %s", node->name);
497 effect_param_t *param = loadEffectParameter(node);
498 if (param == NULL) {
499 node = node->next;
500 continue;
501 }
502 params.add(param);
503 node = node->next;
504 }
505}
506
507
508AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
509 cnode *root,
510 const Vector <EffectDesc *>& effects)
511{
512 cnode *node = root->first_child;
513 if (node == NULL) {
514 ALOGW("loadInputSource() empty element %s", root->name);
515 return NULL;
516 }
517 EffectDescVector *desc = new EffectDescVector();
518 while (node) {
519 size_t i;
520 for (i = 0; i < effects.size(); i++) {
521 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
522 ALOGV("loadEffectConfig() found effect %s in list", node->name);
523 break;
524 }
525 }
526 if (i == effects.size()) {
527 ALOGV("loadEffectConfig() effect %s not in list", node->name);
528 node = node->next;
529 continue;
530 }
531 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
532 loadEffectParameters(node, effect->mParams);
533 ALOGV("loadEffectConfig() adding effect %s uuid %08x",
534 effect->mName, effect->mUuid.timeLow);
535 desc->mEffects.add(effect);
536 node = node->next;
537 }
538 if (desc->mEffects.size() == 0) {
539 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
540 delete desc;
541 return NULL;
542 }
543 return desc;
544}
545
546status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
547 const Vector <EffectDesc *>& effects)
548{
549 cnode *node = config_find(root, PREPROCESSING_TAG);
550 if (node == NULL) {
551 return -ENOENT;
552 }
553 node = node->first_child;
554 while (node) {
555 audio_source_t source = inputSourceNameToEnum(node->name);
556 if (source == AUDIO_SOURCE_CNT) {
557 ALOGW("loadInputSources() invalid input source %s", node->name);
558 node = node->next;
559 continue;
560 }
561 ALOGV("loadInputSources() loading input source %s", node->name);
562 EffectDescVector *desc = loadEffectConfig(node, effects);
563 if (desc == NULL) {
564 node = node->next;
565 continue;
566 }
567 mInputSources.add(source, desc);
568 node = node->next;
569 }
570 return NO_ERROR;
571}
572
573status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
574 const Vector <EffectDesc *>& effects)
575{
576 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
577 if (node == NULL) {
578 return -ENOENT;
579 }
580 node = node->first_child;
581 while (node) {
582 audio_stream_type_t stream = streamNameToEnum(node->name);
583 if (stream == AUDIO_STREAM_CNT) {
584 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
585 node = node->next;
586 continue;
587 }
588 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
589 EffectDescVector *desc = loadEffectConfig(node, effects);
590 if (desc == NULL) {
591 node = node->next;
592 continue;
593 }
594 mOutputStreams.add(stream, desc);
595 node = node->next;
596 }
597 return NO_ERROR;
598}
599
600AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
601{
602 cnode *node = config_find(root, UUID_TAG);
603 if (node == NULL) {
604 return NULL;
605 }
606 effect_uuid_t uuid;
607 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
608 ALOGW("loadEffect() invalid uuid %s", node->value);
609 return NULL;
610 }
611 return new EffectDesc(root->name, uuid);
612}
613
614status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
615{
616 cnode *node = config_find(root, EFFECTS_TAG);
617 if (node == NULL) {
618 return -ENOENT;
619 }
620 node = node->first_child;
621 while (node) {
622 ALOGV("loadEffects() loading effect %s", node->name);
623 EffectDesc *effect = loadEffect(node);
624 if (effect == NULL) {
625 node = node->next;
626 continue;
627 }
628 effects.add(effect);
629 node = node->next;
630 }
631 return NO_ERROR;
632}
633
634status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
635{
636 cnode *root;
637 char *data;
638
639 data = (char *)load_file(path, NULL);
640 if (data == NULL) {
641 return -ENODEV;
642 }
643 root = config_node("", "");
644 config_load(root, data);
645
646 Vector <EffectDesc *> effects;
647 loadEffects(root, effects);
648 loadInputEffectConfigurations(root, effects);
649 loadStreamEffectConfigurations(root, effects);
650
651 config_free(root);
652 free(root);
653 free(data);
654
655 return NO_ERROR;
656}
657
658
659}; // namespace android