AudioPolicyEffects.cpp revision ba2b43990a7b4f0f2c425cf6cdfc63376a45772c
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AudioPolicyEffects"
18#define LOG_NDEBUG 0
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <cutils/misc.h>
24#include <media/AudioEffect.h>
25#include <system/audio.h>
26#include <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
90    ssize_t index = mInputSources.indexOfKey(aliasSource);
91    if (index < 0) {
92        ALOGV("addInputEffects(): no processing needs to be attached to this source");
93        return status;
94    }
95    ssize_t idx = mInputs.indexOfKey(input);
96    EffectVector *inputDesc;
97    if (idx < 0) {
98        inputDesc = new EffectVector(audioSession);
99        mInputs.add(input, inputDesc);
100    } else {
101        inputDesc = mInputs.valueAt(idx);
102    }
103
104    Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
105    for (size_t i = 0; i < effects.size(); i++) {
106        EffectDesc *effect = effects[i];
107        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
108        status_t status = fx->initCheck();
109        if (status != NO_ERROR && status != ALREADY_EXISTS) {
110            ALOGW("addInputEffects(): failed to create Fx %s on source %d",
111                  effect->mName, (int32_t)aliasSource);
112            // fx goes out of scope and strong ref on AudioEffect is released
113            continue;
114        }
115        for (size_t j = 0; j < effect->mParams.size(); j++) {
116            fx->setParameter(effect->mParams[j]);
117        }
118        ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource);
119        inputDesc->mEffects.add(fx);
120    }
121    setProcessorEnabled(inputDesc, true);
122
123    return status;
124}
125
126
127status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input)
128{
129    status_t status = NO_ERROR;
130
131    ssize_t index = mInputs.indexOfKey(input);
132    if (index < 0) {
133        return status;
134    }
135    EffectVector *inputDesc = mInputs.valueAt(index);
136    setProcessorEnabled(inputDesc, false);
137    delete inputDesc;
138    mInputs.removeItemsAt(index);
139    ALOGV("releaseInputEffects(): all effects released");
140    return status;
141}
142
143status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession,
144                                                      effect_descriptor_t *descriptors,
145                                                      uint32_t *count)
146{
147    status_t status = NO_ERROR;
148
149    size_t index;
150    for (index = 0; index < mInputs.size(); index++) {
151        if (mInputs.valueAt(index)->mSessionId == audioSession) {
152            break;
153        }
154    }
155    if (index == mInputs.size()) {
156        *count = 0;
157        return BAD_VALUE;
158    }
159    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
160
161    for (size_t i = 0; i < effects.size(); i++) {
162        effect_descriptor_t desc = effects[i]->descriptor();
163        if (i < *count) {
164            descriptors[i] = desc;
165        }
166    }
167    if (effects.size() > *count) {
168        status = NO_MEMORY;
169    }
170    *count = effects.size();
171    return status;
172}
173
174
175status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession,
176                         effect_descriptor_t *descriptors,
177                         uint32_t *count)
178{
179    status_t status = NO_ERROR;
180
181    size_t index;
182    for (index = 0; index < mOutputSessions.size(); index++) {
183        if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
184            break;
185        }
186    }
187    if (index == mOutputSessions.size()) {
188        *count = 0;
189        return BAD_VALUE;
190    }
191    Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
192
193    for (size_t i = 0; i < effects.size(); i++) {
194        effect_descriptor_t desc = effects[i]->descriptor();
195        if (i < *count) {
196            descriptors[i] = desc;
197        }
198    }
199    if (effects.size() > *count) {
200        status = NO_MEMORY;
201    }
202    *count = effects.size();
203    return status;
204}
205
206
207status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
208                         audio_stream_type_t stream,
209                         int audioSession)
210{
211    status_t status = NO_ERROR;
212
213    // create audio processors according to stream
214    ssize_t index = mOutputStreams.indexOfKey(stream);
215    if (index < 0) {
216        ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
217        return NO_ERROR;
218    }
219
220    ssize_t idx = mOutputSessions.indexOfKey(audioSession);
221    EffectVector *procDesc;
222    if (idx < 0) {
223        procDesc = new EffectVector(audioSession);
224        mOutputSessions.add(audioSession, procDesc);
225    } else {
226        procDesc = mOutputSessions.valueAt(idx);
227    }
228
229    Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
230    for (size_t i = 0; i < effects.size(); i++) {
231        EffectDesc *effect = effects[i];
232        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, audioSession, output);
233        status_t status = fx->initCheck();
234        if (status != NO_ERROR && status != ALREADY_EXISTS) {
235            ALOGE("addOutputSessionEffects(): failed to create Fx  %s on session %d",
236                  effect->mName, audioSession);
237            // fx goes out of scope and strong ref on AudioEffect is released
238            continue;
239        }
240        ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
241              effect->mName, audioSession, (int32_t)stream);
242        procDesc->mEffects.add(fx);
243    }
244
245    setProcessorEnabled(procDesc, true);
246
247    return status;
248}
249
250status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
251                         audio_stream_type_t stream,
252                         int audioSession)
253{
254    status_t status = NO_ERROR;
255    (void) output; // argument not used for now
256    (void) stream; // argument not used for now
257
258    ssize_t index = mOutputSessions.indexOfKey(audioSession);
259    if (index < 0) {
260        ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
261        return NO_ERROR;
262    }
263
264    EffectVector *procDesc = mOutputSessions.valueAt(index);
265    setProcessorEnabled(procDesc, false);
266    procDesc->mEffects.clear();
267    delete procDesc;
268    mOutputSessions.removeItemsAt(index);
269    ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
270          audioSession);
271    return status;
272}
273
274
275void AudioPolicyEffects::setProcessorEnabled(const EffectVector *effectVector, bool enabled)
276{
277    const Vector<sp<AudioEffect> > &fxVector = effectVector->mEffects;
278    for (size_t i = 0; i < fxVector.size(); i++) {
279        fxVector.itemAt(i)->setEnabled(enabled);
280    }
281}
282
283
284// ----------------------------------------------------------------------------
285// Audio processing configuration
286// ----------------------------------------------------------------------------
287
288/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
289    MIC_SRC_TAG,
290    VOICE_UL_SRC_TAG,
291    VOICE_DL_SRC_TAG,
292    VOICE_CALL_SRC_TAG,
293    CAMCORDER_SRC_TAG,
294    VOICE_REC_SRC_TAG,
295    VOICE_COMM_SRC_TAG
296};
297
298// returns the audio_source_t enum corresponding to the input source name or
299// AUDIO_SOURCE_CNT is no match found
300audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
301{
302    int i;
303    for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
304        if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
305            ALOGV("inputSourceNameToEnum found source %s %d", name, i);
306            break;
307        }
308    }
309    return (audio_source_t)i;
310}
311
312const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_CNT+1] = {
313    AUDIO_STREAM_DEFAULT_TAG,
314    AUDIO_STREAM_VOICE_CALL_TAG,
315    AUDIO_STREAM_SYSTEM_TAG,
316    AUDIO_STREAM_RING_TAG,
317    AUDIO_STREAM_MUSIC_TAG,
318    AUDIO_STREAM_ALARM_TAG,
319    AUDIO_STREAM_NOTIFICATION_TAG,
320    AUDIO_STREAM_BLUETOOTH_SCO_TAG,
321    AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
322    AUDIO_STREAM_DTMF_TAG,
323    AUDIO_STREAM_TTS_TAG
324};
325
326// returns the audio_stream_t enum corresponding to the output stream name or
327// AUDIO_STREAM_CNT is no match found
328audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
329{
330    int i;
331    for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_CNT; i++) {
332        if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
333            ALOGV("streamNameToEnum found stream %s %d", name, i);
334            break;
335        }
336    }
337    return (audio_stream_type_t)i;
338}
339
340// ----------------------------------------------------------------------------
341// Audio Effect Config parser
342// ----------------------------------------------------------------------------
343
344size_t AudioPolicyEffects::growParamSize(char *param,
345                                         size_t size,
346                                         size_t *curSize,
347                                         size_t *totSize)
348{
349    // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
350    size_t pos = ((*curSize - 1 ) / size + 1) * size;
351
352    if (pos + size > *totSize) {
353        while (pos + size > *totSize) {
354            *totSize += ((*totSize + 7) / 8) * 4;
355        }
356        param = (char *)realloc(param, *totSize);
357    }
358    *curSize = pos + size;
359    return pos;
360}
361
362size_t AudioPolicyEffects::readParamValue(cnode *node,
363                                          char *param,
364                                          size_t *curSize,
365                                          size_t *totSize)
366{
367    if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
368        size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
369        *(short *)((char *)param + pos) = (short)atoi(node->value);
370        ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
371        return sizeof(short);
372    } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
373        size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
374        *(int *)((char *)param + pos) = atoi(node->value);
375        ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
376        return sizeof(int);
377    } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
378        size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
379        *(float *)((char *)param + pos) = (float)atof(node->value);
380        ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
381        return sizeof(float);
382    } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
383        size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
384        if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
385            *(bool *)((char *)param + pos) = false;
386        } else {
387            *(bool *)((char *)param + pos) = true;
388        }
389        ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
390        return sizeof(bool);
391    } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
392        size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
393        if (*curSize + len + 1 > *totSize) {
394            *totSize = *curSize + len + 1;
395            param = (char *)realloc(param, *totSize);
396        }
397        strncpy(param + *curSize, node->value, len);
398        *curSize += len;
399        param[*curSize] = '\0';
400        ALOGV("readParamValue() reading string %s", param + *curSize - len);
401        return len;
402    }
403    ALOGW("readParamValue() unknown param type %s", node->name);
404    return 0;
405}
406
407effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
408{
409    cnode *param;
410    cnode *value;
411    size_t curSize = sizeof(effect_param_t);
412    size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
413    effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
414
415    param = config_find(root, PARAM_TAG);
416    value = config_find(root, VALUE_TAG);
417    if (param == NULL && value == NULL) {
418        // try to parse simple parameter form {int int}
419        param = root->first_child;
420        if (param != NULL) {
421            // Note: that a pair of random strings is read as 0 0
422            int *ptr = (int *)fx_param->data;
423            int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
424            ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
425            *ptr++ = atoi(param->name);
426            *ptr = atoi(param->value);
427            fx_param->psize = sizeof(int);
428            fx_param->vsize = sizeof(int);
429            return fx_param;
430        }
431    }
432    if (param == NULL || value == NULL) {
433        ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
434        goto error;
435    }
436
437    fx_param->psize = 0;
438    param = param->first_child;
439    while (param) {
440        ALOGV("loadEffectParameter() reading param of type %s", param->name);
441        size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
442        if (size == 0) {
443            goto error;
444        }
445        fx_param->psize += size;
446        param = param->next;
447    }
448
449    // align start of value field on 32 bit boundary
450    curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
451
452    fx_param->vsize = 0;
453    value = value->first_child;
454    while (value) {
455        ALOGV("loadEffectParameter() reading value of type %s", value->name);
456        size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
457        if (size == 0) {
458            goto error;
459        }
460        fx_param->vsize += size;
461        value = value->next;
462    }
463
464    return fx_param;
465
466error:
467    delete fx_param;
468    return NULL;
469}
470
471void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
472{
473    cnode *node = root->first_child;
474    while (node) {
475        ALOGV("loadEffectParameters() loading param %s", node->name);
476        effect_param_t *param = loadEffectParameter(node);
477        if (param == NULL) {
478            node = node->next;
479            continue;
480        }
481        params.add(param);
482        node = node->next;
483    }
484}
485
486
487AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
488                                                            cnode *root,
489                                                            const Vector <EffectDesc *>& effects)
490{
491    cnode *node = root->first_child;
492    if (node == NULL) {
493        ALOGW("loadInputSource() empty element %s", root->name);
494        return NULL;
495    }
496    EffectDescVector *desc = new EffectDescVector();
497    while (node) {
498        size_t i;
499        for (i = 0; i < effects.size(); i++) {
500            if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
501                ALOGV("loadEffectConfig() found effect %s in list", node->name);
502                break;
503            }
504        }
505        if (i == effects.size()) {
506            ALOGV("loadEffectConfig() effect %s not in list", node->name);
507            node = node->next;
508            continue;
509        }
510        EffectDesc *effect = new EffectDesc(*effects[i]);   // deep copy
511        loadEffectParameters(node, effect->mParams);
512        ALOGV("loadEffectConfig() adding effect %s uuid %08x",
513              effect->mName, effect->mUuid.timeLow);
514        desc->mEffects.add(effect);
515        node = node->next;
516    }
517    if (desc->mEffects.size() == 0) {
518        ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
519        delete desc;
520        return NULL;
521    }
522    return desc;
523}
524
525status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
526                                                           const Vector <EffectDesc *>& effects)
527{
528    cnode *node = config_find(root, PREPROCESSING_TAG);
529    if (node == NULL) {
530        return -ENOENT;
531    }
532    node = node->first_child;
533    while (node) {
534        audio_source_t source = inputSourceNameToEnum(node->name);
535        if (source == AUDIO_SOURCE_CNT) {
536            ALOGW("loadInputSources() invalid input source %s", node->name);
537            node = node->next;
538            continue;
539        }
540        ALOGV("loadInputSources() loading input source %s", node->name);
541        EffectDescVector *desc = loadEffectConfig(node, effects);
542        if (desc == NULL) {
543            node = node->next;
544            continue;
545        }
546        mInputSources.add(source, desc);
547        node = node->next;
548    }
549    return NO_ERROR;
550}
551
552status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
553                                                            const Vector <EffectDesc *>& effects)
554{
555    cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
556    if (node == NULL) {
557        return -ENOENT;
558    }
559    node = node->first_child;
560    while (node) {
561        audio_stream_type_t stream = streamNameToEnum(node->name);
562        if (stream == AUDIO_STREAM_CNT) {
563            ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
564            node = node->next;
565            continue;
566        }
567        ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
568        EffectDescVector *desc = loadEffectConfig(node, effects);
569        if (desc == NULL) {
570            node = node->next;
571            continue;
572        }
573        mOutputStreams.add(stream, desc);
574        node = node->next;
575    }
576    return NO_ERROR;
577}
578
579AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
580{
581    cnode *node = config_find(root, UUID_TAG);
582    if (node == NULL) {
583        return NULL;
584    }
585    effect_uuid_t uuid;
586    if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
587        ALOGW("loadEffect() invalid uuid %s", node->value);
588        return NULL;
589    }
590    return new EffectDesc(root->name, uuid);
591}
592
593status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
594{
595    cnode *node = config_find(root, EFFECTS_TAG);
596    if (node == NULL) {
597        return -ENOENT;
598    }
599    node = node->first_child;
600    while (node) {
601        ALOGV("loadEffects() loading effect %s", node->name);
602        EffectDesc *effect = loadEffect(node);
603        if (effect == NULL) {
604            node = node->next;
605            continue;
606        }
607        effects.add(effect);
608        node = node->next;
609    }
610    return NO_ERROR;
611}
612
613status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
614{
615    cnode *root;
616    char *data;
617
618    data = (char *)load_file(path, NULL);
619    if (data == NULL) {
620        return -ENODEV;
621    }
622    root = config_node("", "");
623    config_load(root, data);
624
625    Vector <EffectDesc *> effects;
626    loadEffects(root, effects);
627    loadInputEffectConfigurations(root, effects);
628    loadStreamEffectConfigurations(root, effects);
629
630    config_free(root);
631    free(root);
632    free(data);
633
634    return NO_ERROR;
635}
636
637
638}; // namespace android
639