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