blob: e6ace20a54cc8f6842d9dc4d163f82a976bec3a1 [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
Eric Laurent223fd5c2014-11-11 13:43:36 -0800229 // FIXME: should we have specific post processing settings for internal streams?
230 // default to media for now.
231 if (stream >= AUDIO_STREAM_PUBLIC_CNT) {
232 stream = AUDIO_STREAM_MUSIC;
233 }
bryant_liuba2b4392014-06-11 16:49:30 +0800234 ssize_t index = mOutputStreams.indexOfKey(stream);
235 if (index < 0) {
236 ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
237 return NO_ERROR;
238 }
239
240 ssize_t idx = mOutputSessions.indexOfKey(audioSession);
241 EffectVector *procDesc;
242 if (idx < 0) {
243 procDesc = new EffectVector(audioSession);
244 mOutputSessions.add(audioSession, procDesc);
245 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800246 // EffectVector is existing and we just need to increase ref count
bryant_liuba2b4392014-06-11 16:49:30 +0800247 procDesc = mOutputSessions.valueAt(idx);
248 }
bryant_liu890a5632014-08-20 18:06:13 +0800249 procDesc->mRefCount++;
250
Eric Laurent7de5ac12014-10-21 09:07:11 -0700251 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
252 audioSession, procDesc->mRefCount);
253 if (procDesc->mRefCount == 1) {
254 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
255 for (size_t i = 0; i < effects.size(); i++) {
256 EffectDesc *effect = effects[i];
257 sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0,
258 audioSession, output);
259 status_t status = fx->initCheck();
260 if (status != NO_ERROR && status != ALREADY_EXISTS) {
261 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
262 effect->mName, audioSession);
263 // fx goes out of scope and strong ref on AudioEffect is released
264 continue;
265 }
266 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
267 effect->mName, audioSession, (int32_t)stream);
268 procDesc->mEffects.add(fx);
bryant_liuba2b4392014-06-11 16:49:30 +0800269 }
Eric Laurent7de5ac12014-10-21 09:07:11 -0700270
271 procDesc->setProcessorEnabled(true);
bryant_liuba2b4392014-06-11 16:49:30 +0800272 }
bryant_liuba2b4392014-06-11 16:49:30 +0800273 return status;
274}
275
276status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
277 audio_stream_type_t stream,
278 int audioSession)
279{
280 status_t status = NO_ERROR;
281 (void) output; // argument not used for now
282 (void) stream; // argument not used for now
283
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700284 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800285 ssize_t index = mOutputSessions.indexOfKey(audioSession);
286 if (index < 0) {
287 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
288 return NO_ERROR;
289 }
290
291 EffectVector *procDesc = mOutputSessions.valueAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800292 procDesc->mRefCount--;
Eric Laurent7de5ac12014-10-21 09:07:11 -0700293 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
294 audioSession, procDesc->mRefCount);
bryant_liu890a5632014-08-20 18:06:13 +0800295 if (procDesc->mRefCount == 0) {
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700296 procDesc->setProcessorEnabled(false);
bryant_liu890a5632014-08-20 18:06:13 +0800297 procDesc->mEffects.clear();
298 delete procDesc;
299 mOutputSessions.removeItemsAt(index);
300 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
301 audioSession);
302 }
bryant_liuba2b4392014-06-11 16:49:30 +0800303 return status;
304}
305
306
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700307void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
bryant_liuba2b4392014-06-11 16:49:30 +0800308{
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700309 for (size_t i = 0; i < mEffects.size(); i++) {
310 mEffects.itemAt(i)->setEnabled(enabled);
bryant_liuba2b4392014-06-11 16:49:30 +0800311 }
312}
313
314
315// ----------------------------------------------------------------------------
316// Audio processing configuration
317// ----------------------------------------------------------------------------
318
319/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
320 MIC_SRC_TAG,
321 VOICE_UL_SRC_TAG,
322 VOICE_DL_SRC_TAG,
323 VOICE_CALL_SRC_TAG,
324 CAMCORDER_SRC_TAG,
325 VOICE_REC_SRC_TAG,
326 VOICE_COMM_SRC_TAG
327};
328
329// returns the audio_source_t enum corresponding to the input source name or
330// AUDIO_SOURCE_CNT is no match found
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700331/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
bryant_liuba2b4392014-06-11 16:49:30 +0800332{
333 int i;
334 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
335 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
336 ALOGV("inputSourceNameToEnum found source %s %d", name, i);
337 break;
338 }
339 }
340 return (audio_source_t)i;
341}
342
Eric Laurent223fd5c2014-11-11 13:43:36 -0800343const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = {
bryant_liuba2b4392014-06-11 16:49:30 +0800344 AUDIO_STREAM_DEFAULT_TAG,
345 AUDIO_STREAM_VOICE_CALL_TAG,
346 AUDIO_STREAM_SYSTEM_TAG,
347 AUDIO_STREAM_RING_TAG,
348 AUDIO_STREAM_MUSIC_TAG,
349 AUDIO_STREAM_ALARM_TAG,
350 AUDIO_STREAM_NOTIFICATION_TAG,
351 AUDIO_STREAM_BLUETOOTH_SCO_TAG,
352 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
353 AUDIO_STREAM_DTMF_TAG,
354 AUDIO_STREAM_TTS_TAG
355};
356
357// returns the audio_stream_t enum corresponding to the output stream name or
Eric Laurent223fd5c2014-11-11 13:43:36 -0800358// AUDIO_STREAM_PUBLIC_CNT is no match found
bryant_liuba2b4392014-06-11 16:49:30 +0800359audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
360{
361 int i;
Eric Laurent223fd5c2014-11-11 13:43:36 -0800362 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) {
bryant_liuba2b4392014-06-11 16:49:30 +0800363 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
364 ALOGV("streamNameToEnum found stream %s %d", name, i);
365 break;
366 }
367 }
368 return (audio_stream_type_t)i;
369}
370
371// ----------------------------------------------------------------------------
372// Audio Effect Config parser
373// ----------------------------------------------------------------------------
374
375size_t AudioPolicyEffects::growParamSize(char *param,
376 size_t size,
377 size_t *curSize,
378 size_t *totSize)
379{
380 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
381 size_t pos = ((*curSize - 1 ) / size + 1) * size;
382
383 if (pos + size > *totSize) {
384 while (pos + size > *totSize) {
385 *totSize += ((*totSize + 7) / 8) * 4;
386 }
387 param = (char *)realloc(param, *totSize);
388 }
389 *curSize = pos + size;
390 return pos;
391}
392
393size_t AudioPolicyEffects::readParamValue(cnode *node,
394 char *param,
395 size_t *curSize,
396 size_t *totSize)
397{
398 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
399 size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
400 *(short *)((char *)param + pos) = (short)atoi(node->value);
401 ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
402 return sizeof(short);
403 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
404 size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
405 *(int *)((char *)param + pos) = atoi(node->value);
406 ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
407 return sizeof(int);
408 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
409 size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
410 *(float *)((char *)param + pos) = (float)atof(node->value);
411 ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
412 return sizeof(float);
413 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
414 size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
415 if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
416 *(bool *)((char *)param + pos) = false;
417 } else {
418 *(bool *)((char *)param + pos) = true;
419 }
420 ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
421 return sizeof(bool);
422 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
423 size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
424 if (*curSize + len + 1 > *totSize) {
425 *totSize = *curSize + len + 1;
426 param = (char *)realloc(param, *totSize);
427 }
428 strncpy(param + *curSize, node->value, len);
429 *curSize += len;
430 param[*curSize] = '\0';
431 ALOGV("readParamValue() reading string %s", param + *curSize - len);
432 return len;
433 }
434 ALOGW("readParamValue() unknown param type %s", node->name);
435 return 0;
436}
437
438effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
439{
440 cnode *param;
441 cnode *value;
442 size_t curSize = sizeof(effect_param_t);
443 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
444 effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
445
446 param = config_find(root, PARAM_TAG);
447 value = config_find(root, VALUE_TAG);
448 if (param == NULL && value == NULL) {
449 // try to parse simple parameter form {int int}
450 param = root->first_child;
451 if (param != NULL) {
452 // Note: that a pair of random strings is read as 0 0
453 int *ptr = (int *)fx_param->data;
454 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
455 ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
456 *ptr++ = atoi(param->name);
457 *ptr = atoi(param->value);
458 fx_param->psize = sizeof(int);
459 fx_param->vsize = sizeof(int);
460 return fx_param;
461 }
462 }
463 if (param == NULL || value == NULL) {
464 ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
465 goto error;
466 }
467
468 fx_param->psize = 0;
469 param = param->first_child;
470 while (param) {
471 ALOGV("loadEffectParameter() reading param of type %s", param->name);
472 size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
473 if (size == 0) {
474 goto error;
475 }
476 fx_param->psize += size;
477 param = param->next;
478 }
479
480 // align start of value field on 32 bit boundary
481 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
482
483 fx_param->vsize = 0;
484 value = value->first_child;
485 while (value) {
486 ALOGV("loadEffectParameter() reading value of type %s", value->name);
487 size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
488 if (size == 0) {
489 goto error;
490 }
491 fx_param->vsize += size;
492 value = value->next;
493 }
494
495 return fx_param;
496
497error:
498 delete fx_param;
499 return NULL;
500}
501
502void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
503{
504 cnode *node = root->first_child;
505 while (node) {
506 ALOGV("loadEffectParameters() loading param %s", node->name);
507 effect_param_t *param = loadEffectParameter(node);
508 if (param == NULL) {
509 node = node->next;
510 continue;
511 }
512 params.add(param);
513 node = node->next;
514 }
515}
516
517
518AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
519 cnode *root,
520 const Vector <EffectDesc *>& effects)
521{
522 cnode *node = root->first_child;
523 if (node == NULL) {
524 ALOGW("loadInputSource() empty element %s", root->name);
525 return NULL;
526 }
527 EffectDescVector *desc = new EffectDescVector();
528 while (node) {
529 size_t i;
530 for (i = 0; i < effects.size(); i++) {
531 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
532 ALOGV("loadEffectConfig() found effect %s in list", node->name);
533 break;
534 }
535 }
536 if (i == effects.size()) {
537 ALOGV("loadEffectConfig() effect %s not in list", node->name);
538 node = node->next;
539 continue;
540 }
541 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
542 loadEffectParameters(node, effect->mParams);
543 ALOGV("loadEffectConfig() adding effect %s uuid %08x",
544 effect->mName, effect->mUuid.timeLow);
545 desc->mEffects.add(effect);
546 node = node->next;
547 }
548 if (desc->mEffects.size() == 0) {
549 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
550 delete desc;
551 return NULL;
552 }
553 return desc;
554}
555
556status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
557 const Vector <EffectDesc *>& effects)
558{
559 cnode *node = config_find(root, PREPROCESSING_TAG);
560 if (node == NULL) {
561 return -ENOENT;
562 }
563 node = node->first_child;
564 while (node) {
565 audio_source_t source = inputSourceNameToEnum(node->name);
566 if (source == AUDIO_SOURCE_CNT) {
567 ALOGW("loadInputSources() invalid input source %s", node->name);
568 node = node->next;
569 continue;
570 }
571 ALOGV("loadInputSources() loading input source %s", node->name);
572 EffectDescVector *desc = loadEffectConfig(node, effects);
573 if (desc == NULL) {
574 node = node->next;
575 continue;
576 }
577 mInputSources.add(source, desc);
578 node = node->next;
579 }
580 return NO_ERROR;
581}
582
583status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
584 const Vector <EffectDesc *>& effects)
585{
586 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
587 if (node == NULL) {
588 return -ENOENT;
589 }
590 node = node->first_child;
591 while (node) {
592 audio_stream_type_t stream = streamNameToEnum(node->name);
Eric Laurent223fd5c2014-11-11 13:43:36 -0800593 if (stream == AUDIO_STREAM_PUBLIC_CNT) {
bryant_liuba2b4392014-06-11 16:49:30 +0800594 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
595 node = node->next;
596 continue;
597 }
598 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
599 EffectDescVector *desc = loadEffectConfig(node, effects);
600 if (desc == NULL) {
601 node = node->next;
602 continue;
603 }
604 mOutputStreams.add(stream, desc);
605 node = node->next;
606 }
607 return NO_ERROR;
608}
609
610AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
611{
612 cnode *node = config_find(root, UUID_TAG);
613 if (node == NULL) {
614 return NULL;
615 }
616 effect_uuid_t uuid;
617 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
618 ALOGW("loadEffect() invalid uuid %s", node->value);
619 return NULL;
620 }
621 return new EffectDesc(root->name, uuid);
622}
623
624status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
625{
626 cnode *node = config_find(root, EFFECTS_TAG);
627 if (node == NULL) {
628 return -ENOENT;
629 }
630 node = node->first_child;
631 while (node) {
632 ALOGV("loadEffects() loading effect %s", node->name);
633 EffectDesc *effect = loadEffect(node);
634 if (effect == NULL) {
635 node = node->next;
636 continue;
637 }
638 effects.add(effect);
639 node = node->next;
640 }
641 return NO_ERROR;
642}
643
644status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
645{
646 cnode *root;
647 char *data;
648
649 data = (char *)load_file(path, NULL);
650 if (data == NULL) {
651 return -ENODEV;
652 }
653 root = config_node("", "");
654 config_load(root, data);
655
656 Vector <EffectDesc *> effects;
657 loadEffects(root, effects);
658 loadInputEffectConfigurations(root, effects);
659 loadStreamEffectConfigurations(root, effects);
660
Eric Laurent182c2f52015-01-15 14:29:19 -0800661 for (size_t i = 0; i < effects.size(); i++) {
662 delete effects[i];
663 }
664
bryant_liuba2b4392014-06-11 16:49:30 +0800665 config_free(root);
666 free(root);
667 free(data);
668
669 return NO_ERROR;
670}
671
672
673}; // namespace android