blob: eed545e3abfd50686864bcec16f7dbd88b52652d [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
Eric Laurent4b2fcd82016-01-15 18:00:39 -080060 for (i = 0; i < mInputSessions.size(); i++) {
61 mInputSessions.valueAt(i)->mEffects.clear();
62 delete mInputSessions.valueAt(i);
bryant_liuba2b4392014-06-11 16:49:30 +080063 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -080064 mInputSessions.clear();
bryant_liuba2b4392014-06-11 16:49:30 +080065
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,
Eric Laurent4b2fcd82016-01-15 18:00:39 -080082 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +080083{
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 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -080096 ssize_t idx = mInputSessions.indexOfKey(audioSession);
97 EffectVector *sessionDesc;
bryant_liuba2b4392014-06-11 16:49:30 +080098 if (idx < 0) {
Eric Laurent4b2fcd82016-01-15 18:00:39 -080099 sessionDesc = new EffectVector(audioSession);
100 mInputSessions.add(audioSession, sessionDesc);
bryant_liuba2b4392014-06-11 16:49:30 +0800101 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800102 // EffectVector is existing and we just need to increase ref count
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800103 sessionDesc = mInputSessions.valueAt(idx);
bryant_liuba2b4392014-06-11 16:49:30 +0800104 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800105 sessionDesc->mRefCount++;
bryant_liu890a5632014-08-20 18:06:13 +0800106
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800107 ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
108 if (sessionDesc->mRefCount == 1) {
Eric Laurent7de5ac12014-10-21 09:07:11 -0700109 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
110 for (size_t i = 0; i < effects.size(); i++) {
111 EffectDesc *effect = effects[i];
Svet Ganovbe71aa22015-04-28 12:06:02 -0700112 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0,
113 0, audioSession, input);
Eric Laurent7de5ac12014-10-21 09:07:11 -0700114 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 Laurent4b2fcd82016-01-15 18:00:39 -0800126 sessionDesc->mEffects.add(fx);
bryant_liuba2b4392014-06-11 16:49:30 +0800127 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800128 sessionDesc->setProcessorEnabled(true);
bryant_liuba2b4392014-06-11 16:49:30 +0800129 }
bryant_liuba2b4392014-06-11 16:49:30 +0800130 return status;
131}
132
133
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800134status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input,
135 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800136{
137 status_t status = NO_ERROR;
138
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700139 Mutex::Autolock _l(mLock);
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800140 ssize_t index = mInputSessions.indexOfKey(audioSession);
bryant_liuba2b4392014-06-11 16:49:30 +0800141 if (index < 0) {
142 return status;
143 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800144 EffectVector *sessionDesc = mInputSessions.valueAt(index);
145 sessionDesc->mRefCount--;
146 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
147 if (sessionDesc->mRefCount == 0) {
148 sessionDesc->setProcessorEnabled(false);
149 delete sessionDesc;
150 mInputSessions.removeItemsAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800151 ALOGV("releaseInputEffects(): all effects released");
152 }
bryant_liuba2b4392014-06-11 16:49:30 +0800153 return status;
154}
155
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800156status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession,
bryant_liuba2b4392014-06-11 16:49:30 +0800157 effect_descriptor_t *descriptors,
158 uint32_t *count)
159{
160 status_t status = NO_ERROR;
161
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700162 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800163 size_t index;
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800164 for (index = 0; index < mInputSessions.size(); index++) {
165 if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
bryant_liuba2b4392014-06-11 16:49:30 +0800166 break;
167 }
168 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800169 if (index == mInputSessions.size()) {
bryant_liuba2b4392014-06-11 16:49:30 +0800170 *count = 0;
171 return BAD_VALUE;
172 }
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800173 Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
bryant_liuba2b4392014-06-11 16:49:30 +0800174
175 for (size_t i = 0; i < effects.size(); i++) {
176 effect_descriptor_t desc = effects[i]->descriptor();
177 if (i < *count) {
178 descriptors[i] = desc;
179 }
180 }
181 if (effects.size() > *count) {
182 status = NO_MEMORY;
183 }
184 *count = effects.size();
185 return status;
186}
187
188
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800189status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession,
bryant_liuba2b4392014-06-11 16:49:30 +0800190 effect_descriptor_t *descriptors,
191 uint32_t *count)
192{
193 status_t status = NO_ERROR;
194
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700195 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800196 size_t index;
197 for (index = 0; index < mOutputSessions.size(); index++) {
198 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
199 break;
200 }
201 }
202 if (index == mOutputSessions.size()) {
203 *count = 0;
204 return BAD_VALUE;
205 }
206 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
207
208 for (size_t i = 0; i < effects.size(); i++) {
209 effect_descriptor_t desc = effects[i]->descriptor();
210 if (i < *count) {
211 descriptors[i] = desc;
212 }
213 }
214 if (effects.size() > *count) {
215 status = NO_MEMORY;
216 }
217 *count = effects.size();
218 return status;
219}
220
221
222status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
223 audio_stream_type_t stream,
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800224 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800225{
226 status_t status = NO_ERROR;
227
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700228 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800229 // create audio processors according to stream
Eric Laurent223fd5c2014-11-11 13:43:36 -0800230 // FIXME: should we have specific post processing settings for internal streams?
231 // default to media for now.
232 if (stream >= AUDIO_STREAM_PUBLIC_CNT) {
233 stream = AUDIO_STREAM_MUSIC;
234 }
bryant_liuba2b4392014-06-11 16:49:30 +0800235 ssize_t index = mOutputStreams.indexOfKey(stream);
236 if (index < 0) {
237 ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
238 return NO_ERROR;
239 }
240
241 ssize_t idx = mOutputSessions.indexOfKey(audioSession);
242 EffectVector *procDesc;
243 if (idx < 0) {
244 procDesc = new EffectVector(audioSession);
245 mOutputSessions.add(audioSession, procDesc);
246 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800247 // EffectVector is existing and we just need to increase ref count
bryant_liuba2b4392014-06-11 16:49:30 +0800248 procDesc = mOutputSessions.valueAt(idx);
249 }
bryant_liu890a5632014-08-20 18:06:13 +0800250 procDesc->mRefCount++;
251
Eric Laurent7de5ac12014-10-21 09:07:11 -0700252 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
253 audioSession, procDesc->mRefCount);
254 if (procDesc->mRefCount == 1) {
255 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
256 for (size_t i = 0; i < effects.size(); i++) {
257 EffectDesc *effect = effects[i];
Svet Ganovbe71aa22015-04-28 12:06:02 -0700258 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0,
Eric Laurent7de5ac12014-10-21 09:07:11 -0700259 audioSession, output);
260 status_t status = fx->initCheck();
261 if (status != NO_ERROR && status != ALREADY_EXISTS) {
262 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
263 effect->mName, audioSession);
264 // fx goes out of scope and strong ref on AudioEffect is released
265 continue;
266 }
267 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
268 effect->mName, audioSession, (int32_t)stream);
269 procDesc->mEffects.add(fx);
bryant_liuba2b4392014-06-11 16:49:30 +0800270 }
Eric Laurent7de5ac12014-10-21 09:07:11 -0700271
272 procDesc->setProcessorEnabled(true);
bryant_liuba2b4392014-06-11 16:49:30 +0800273 }
bryant_liuba2b4392014-06-11 16:49:30 +0800274 return status;
275}
276
277status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
278 audio_stream_type_t stream,
Eric Laurent4b2fcd82016-01-15 18:00:39 -0800279 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800280{
281 status_t status = NO_ERROR;
282 (void) output; // argument not used for now
283 (void) stream; // argument not used for now
284
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700285 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800286 ssize_t index = mOutputSessions.indexOfKey(audioSession);
287 if (index < 0) {
288 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
289 return NO_ERROR;
290 }
291
292 EffectVector *procDesc = mOutputSessions.valueAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800293 procDesc->mRefCount--;
Eric Laurent7de5ac12014-10-21 09:07:11 -0700294 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
295 audioSession, procDesc->mRefCount);
bryant_liu890a5632014-08-20 18:06:13 +0800296 if (procDesc->mRefCount == 0) {
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700297 procDesc->setProcessorEnabled(false);
bryant_liu890a5632014-08-20 18:06:13 +0800298 procDesc->mEffects.clear();
299 delete procDesc;
300 mOutputSessions.removeItemsAt(index);
301 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
302 audioSession);
303 }
bryant_liuba2b4392014-06-11 16:49:30 +0800304 return status;
305}
306
307
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700308void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
bryant_liuba2b4392014-06-11 16:49:30 +0800309{
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700310 for (size_t i = 0; i < mEffects.size(); i++) {
311 mEffects.itemAt(i)->setEnabled(enabled);
bryant_liuba2b4392014-06-11 16:49:30 +0800312 }
313}
314
315
316// ----------------------------------------------------------------------------
317// Audio processing configuration
318// ----------------------------------------------------------------------------
319
320/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
321 MIC_SRC_TAG,
322 VOICE_UL_SRC_TAG,
323 VOICE_DL_SRC_TAG,
324 VOICE_CALL_SRC_TAG,
325 CAMCORDER_SRC_TAG,
326 VOICE_REC_SRC_TAG,
rago8a397d52015-12-02 11:27:57 -0800327 VOICE_COMM_SRC_TAG,
328 UNPROCESSED_SRC_TAG
bryant_liuba2b4392014-06-11 16:49:30 +0800329};
330
331// returns the audio_source_t enum corresponding to the input source name or
332// AUDIO_SOURCE_CNT is no match found
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700333/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
bryant_liuba2b4392014-06-11 16:49:30 +0800334{
335 int i;
336 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
337 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
338 ALOGV("inputSourceNameToEnum found source %s %d", name, i);
339 break;
340 }
341 }
342 return (audio_source_t)i;
343}
344
Eric Laurent223fd5c2014-11-11 13:43:36 -0800345const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = {
bryant_liuba2b4392014-06-11 16:49:30 +0800346 AUDIO_STREAM_DEFAULT_TAG,
347 AUDIO_STREAM_VOICE_CALL_TAG,
348 AUDIO_STREAM_SYSTEM_TAG,
349 AUDIO_STREAM_RING_TAG,
350 AUDIO_STREAM_MUSIC_TAG,
351 AUDIO_STREAM_ALARM_TAG,
352 AUDIO_STREAM_NOTIFICATION_TAG,
353 AUDIO_STREAM_BLUETOOTH_SCO_TAG,
354 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
355 AUDIO_STREAM_DTMF_TAG,
356 AUDIO_STREAM_TTS_TAG
357};
358
359// returns the audio_stream_t enum corresponding to the output stream name or
Eric Laurent223fd5c2014-11-11 13:43:36 -0800360// AUDIO_STREAM_PUBLIC_CNT is no match found
bryant_liuba2b4392014-06-11 16:49:30 +0800361audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
362{
363 int i;
Eric Laurent223fd5c2014-11-11 13:43:36 -0800364 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) {
bryant_liuba2b4392014-06-11 16:49:30 +0800365 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
366 ALOGV("streamNameToEnum found stream %s %d", name, i);
367 break;
368 }
369 }
370 return (audio_stream_type_t)i;
371}
372
373// ----------------------------------------------------------------------------
374// Audio Effect Config parser
375// ----------------------------------------------------------------------------
376
377size_t AudioPolicyEffects::growParamSize(char *param,
378 size_t size,
379 size_t *curSize,
380 size_t *totSize)
381{
382 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
383 size_t pos = ((*curSize - 1 ) / size + 1) * size;
384
385 if (pos + size > *totSize) {
386 while (pos + size > *totSize) {
387 *totSize += ((*totSize + 7) / 8) * 4;
388 }
389 param = (char *)realloc(param, *totSize);
390 }
391 *curSize = pos + size;
392 return pos;
393}
394
395size_t AudioPolicyEffects::readParamValue(cnode *node,
396 char *param,
397 size_t *curSize,
398 size_t *totSize)
399{
400 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
401 size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
402 *(short *)((char *)param + pos) = (short)atoi(node->value);
403 ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
404 return sizeof(short);
405 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
406 size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
407 *(int *)((char *)param + pos) = atoi(node->value);
408 ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
409 return sizeof(int);
410 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
411 size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
412 *(float *)((char *)param + pos) = (float)atof(node->value);
413 ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
414 return sizeof(float);
415 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
416 size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
417 if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
418 *(bool *)((char *)param + pos) = false;
419 } else {
420 *(bool *)((char *)param + pos) = true;
421 }
422 ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
423 return sizeof(bool);
424 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
425 size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
426 if (*curSize + len + 1 > *totSize) {
427 *totSize = *curSize + len + 1;
428 param = (char *)realloc(param, *totSize);
429 }
430 strncpy(param + *curSize, node->value, len);
431 *curSize += len;
432 param[*curSize] = '\0';
433 ALOGV("readParamValue() reading string %s", param + *curSize - len);
434 return len;
435 }
436 ALOGW("readParamValue() unknown param type %s", node->name);
437 return 0;
438}
439
440effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
441{
442 cnode *param;
443 cnode *value;
444 size_t curSize = sizeof(effect_param_t);
445 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
446 effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
447
448 param = config_find(root, PARAM_TAG);
449 value = config_find(root, VALUE_TAG);
450 if (param == NULL && value == NULL) {
451 // try to parse simple parameter form {int int}
452 param = root->first_child;
453 if (param != NULL) {
454 // Note: that a pair of random strings is read as 0 0
455 int *ptr = (int *)fx_param->data;
456 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
457 ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
458 *ptr++ = atoi(param->name);
459 *ptr = atoi(param->value);
460 fx_param->psize = sizeof(int);
461 fx_param->vsize = sizeof(int);
462 return fx_param;
463 }
464 }
465 if (param == NULL || value == NULL) {
466 ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
467 goto error;
468 }
469
470 fx_param->psize = 0;
471 param = param->first_child;
472 while (param) {
473 ALOGV("loadEffectParameter() reading param of type %s", param->name);
474 size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
475 if (size == 0) {
476 goto error;
477 }
478 fx_param->psize += size;
479 param = param->next;
480 }
481
482 // align start of value field on 32 bit boundary
483 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
484
485 fx_param->vsize = 0;
486 value = value->first_child;
487 while (value) {
488 ALOGV("loadEffectParameter() reading value of type %s", value->name);
489 size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
490 if (size == 0) {
491 goto error;
492 }
493 fx_param->vsize += size;
494 value = value->next;
495 }
496
497 return fx_param;
498
499error:
500 delete fx_param;
501 return NULL;
502}
503
504void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
505{
506 cnode *node = root->first_child;
507 while (node) {
508 ALOGV("loadEffectParameters() loading param %s", node->name);
509 effect_param_t *param = loadEffectParameter(node);
510 if (param == NULL) {
511 node = node->next;
512 continue;
513 }
514 params.add(param);
515 node = node->next;
516 }
517}
518
519
520AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
521 cnode *root,
522 const Vector <EffectDesc *>& effects)
523{
524 cnode *node = root->first_child;
525 if (node == NULL) {
526 ALOGW("loadInputSource() empty element %s", root->name);
527 return NULL;
528 }
529 EffectDescVector *desc = new EffectDescVector();
530 while (node) {
531 size_t i;
532 for (i = 0; i < effects.size(); i++) {
533 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
534 ALOGV("loadEffectConfig() found effect %s in list", node->name);
535 break;
536 }
537 }
538 if (i == effects.size()) {
539 ALOGV("loadEffectConfig() effect %s not in list", node->name);
540 node = node->next;
541 continue;
542 }
543 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
544 loadEffectParameters(node, effect->mParams);
545 ALOGV("loadEffectConfig() adding effect %s uuid %08x",
546 effect->mName, effect->mUuid.timeLow);
547 desc->mEffects.add(effect);
548 node = node->next;
549 }
550 if (desc->mEffects.size() == 0) {
551 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
552 delete desc;
553 return NULL;
554 }
555 return desc;
556}
557
558status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
559 const Vector <EffectDesc *>& effects)
560{
561 cnode *node = config_find(root, PREPROCESSING_TAG);
562 if (node == NULL) {
563 return -ENOENT;
564 }
565 node = node->first_child;
566 while (node) {
567 audio_source_t source = inputSourceNameToEnum(node->name);
568 if (source == AUDIO_SOURCE_CNT) {
569 ALOGW("loadInputSources() invalid input source %s", node->name);
570 node = node->next;
571 continue;
572 }
573 ALOGV("loadInputSources() loading input source %s", node->name);
574 EffectDescVector *desc = loadEffectConfig(node, effects);
575 if (desc == NULL) {
576 node = node->next;
577 continue;
578 }
579 mInputSources.add(source, desc);
580 node = node->next;
581 }
582 return NO_ERROR;
583}
584
585status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
586 const Vector <EffectDesc *>& effects)
587{
588 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
589 if (node == NULL) {
590 return -ENOENT;
591 }
592 node = node->first_child;
593 while (node) {
594 audio_stream_type_t stream = streamNameToEnum(node->name);
Eric Laurent223fd5c2014-11-11 13:43:36 -0800595 if (stream == AUDIO_STREAM_PUBLIC_CNT) {
bryant_liuba2b4392014-06-11 16:49:30 +0800596 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
597 node = node->next;
598 continue;
599 }
600 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
601 EffectDescVector *desc = loadEffectConfig(node, effects);
602 if (desc == NULL) {
603 node = node->next;
604 continue;
605 }
606 mOutputStreams.add(stream, desc);
607 node = node->next;
608 }
609 return NO_ERROR;
610}
611
612AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
613{
614 cnode *node = config_find(root, UUID_TAG);
615 if (node == NULL) {
616 return NULL;
617 }
618 effect_uuid_t uuid;
619 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
620 ALOGW("loadEffect() invalid uuid %s", node->value);
621 return NULL;
622 }
623 return new EffectDesc(root->name, uuid);
624}
625
626status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
627{
628 cnode *node = config_find(root, EFFECTS_TAG);
629 if (node == NULL) {
630 return -ENOENT;
631 }
632 node = node->first_child;
633 while (node) {
634 ALOGV("loadEffects() loading effect %s", node->name);
635 EffectDesc *effect = loadEffect(node);
636 if (effect == NULL) {
637 node = node->next;
638 continue;
639 }
640 effects.add(effect);
641 node = node->next;
642 }
643 return NO_ERROR;
644}
645
646status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
647{
648 cnode *root;
649 char *data;
650
651 data = (char *)load_file(path, NULL);
652 if (data == NULL) {
653 return -ENODEV;
654 }
655 root = config_node("", "");
656 config_load(root, data);
657
658 Vector <EffectDesc *> effects;
659 loadEffects(root, effects);
660 loadInputEffectConfigurations(root, effects);
661 loadStreamEffectConfigurations(root, effects);
662
Eric Laurent182c2f52015-01-15 14:29:19 -0800663 for (size_t i = 0; i < effects.size(); i++) {
664 delete effects[i];
665 }
666
bryant_liuba2b4392014-06-11 16:49:30 +0800667 config_free(root);
668 free(root);
669 free(data);
670
671 return NO_ERROR;
672}
673
674
675}; // namespace android