From 56ec4ffcbae8aeac6c5245fc7b825d02e2e6cefd Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 23 Jan 2015 16:45:18 -0800 Subject: Refactor AudioPolicyManager AudioPolicyManager implementation is now split into the following files: files managerdefault/Gains.* class AudioGain class VolumeCurvePoint class StreamDescriptor files managerdefault/Devices.* class DeviceDescriptor class DeviceVector files managerdefault/Ports.* class AudioPort class AudioPortConfig class AudioPatch files managerdefault/IOProfile.* class IOProfile files managerdefault/HwModule.* class HwModule files managerdefault/AudioInputDescriptor.* class AudioInputDescriptor files managerdefault/AudioOutputDescriptor.* class AudioOutputDescriptor All files for libaudiopolicyservice are moved under service/ All files for libaudiopolicymanager are moved under manager/ Change-Id: I43758be1894e37d34db194b51a19ae24461e066e --- .../audiopolicy/service/AudioPolicyEffects.cpp | 673 +++++++++++++++++++++ 1 file changed, 673 insertions(+) create mode 100644 services/audiopolicy/service/AudioPolicyEffects.cpp (limited to 'services/audiopolicy/service/AudioPolicyEffects.cpp') diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp new file mode 100644 index 0000000..e6ace20 --- /dev/null +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -0,0 +1,673 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicyEffects" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AudioPolicyEffects.h" +#include "ServiceUtilities.h" + +namespace android { + +// ---------------------------------------------------------------------------- +// AudioPolicyEffects Implementation +// ---------------------------------------------------------------------------- + +AudioPolicyEffects::AudioPolicyEffects() +{ + // load automatic audio effect modules + if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { + loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); + } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { + loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); + } +} + + +AudioPolicyEffects::~AudioPolicyEffects() +{ + size_t i = 0; + // release audio input processing resources + for (i = 0; i < mInputSources.size(); i++) { + delete mInputSources.valueAt(i); + } + mInputSources.clear(); + + for (i = 0; i < mInputs.size(); i++) { + mInputs.valueAt(i)->mEffects.clear(); + delete mInputs.valueAt(i); + } + mInputs.clear(); + + // release audio output processing resources + for (i = 0; i < mOutputStreams.size(); i++) { + delete mOutputStreams.valueAt(i); + } + mOutputStreams.clear(); + + for (i = 0; i < mOutputSessions.size(); i++) { + mOutputSessions.valueAt(i)->mEffects.clear(); + delete mOutputSessions.valueAt(i); + } + mOutputSessions.clear(); +} + + +status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, + audio_source_t inputSource, + int audioSession) +{ + status_t status = NO_ERROR; + + // create audio pre processors according to input source + audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ? + AUDIO_SOURCE_VOICE_RECOGNITION : inputSource; + + Mutex::Autolock _l(mLock); + ssize_t index = mInputSources.indexOfKey(aliasSource); + if (index < 0) { + ALOGV("addInputEffects(): no processing needs to be attached to this source"); + return status; + } + ssize_t idx = mInputs.indexOfKey(input); + EffectVector *inputDesc; + if (idx < 0) { + inputDesc = new EffectVector(audioSession); + mInputs.add(input, inputDesc); + } else { + // EffectVector is existing and we just need to increase ref count + inputDesc = mInputs.valueAt(idx); + } + inputDesc->mRefCount++; + + ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); + if (inputDesc->mRefCount == 1) { + Vector effects = mInputSources.valueAt(index)->mEffects; + for (size_t i = 0; i < effects.size(); i++) { + EffectDesc *effect = effects[i]; + sp fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, + audioSession, input); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + ALOGW("addInputEffects(): failed to create Fx %s on source %d", + effect->mName, (int32_t)aliasSource); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + for (size_t j = 0; j < effect->mParams.size(); j++) { + fx->setParameter(effect->mParams[j]); + } + ALOGV("addInputEffects(): added Fx %s on source: %d", + effect->mName, (int32_t)aliasSource); + inputDesc->mEffects.add(fx); + } + inputDesc->setProcessorEnabled(true); + } + return status; +} + + +status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input) +{ + status_t status = NO_ERROR; + + Mutex::Autolock _l(mLock); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + return status; + } + EffectVector *inputDesc = mInputs.valueAt(index); + inputDesc->mRefCount--; + ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); + if (inputDesc->mRefCount == 0) { + inputDesc->setProcessorEnabled(false); + delete inputDesc; + mInputs.removeItemsAt(index); + ALOGV("releaseInputEffects(): all effects released"); + } + return status; +} + +status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) +{ + status_t status = NO_ERROR; + + Mutex::Autolock _l(mLock); + size_t index; + for (index = 0; index < mInputs.size(); index++) { + if (mInputs.valueAt(index)->mSessionId == audioSession) { + break; + } + } + if (index == mInputs.size()) { + *count = 0; + return BAD_VALUE; + } + Vector< sp > effects = mInputs.valueAt(index)->mEffects; + + for (size_t i = 0; i < effects.size(); i++) { + effect_descriptor_t desc = effects[i]->descriptor(); + if (i < *count) { + descriptors[i] = desc; + } + } + if (effects.size() > *count) { + status = NO_MEMORY; + } + *count = effects.size(); + return status; +} + + +status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) +{ + status_t status = NO_ERROR; + + Mutex::Autolock _l(mLock); + size_t index; + for (index = 0; index < mOutputSessions.size(); index++) { + if (mOutputSessions.valueAt(index)->mSessionId == audioSession) { + break; + } + } + if (index == mOutputSessions.size()) { + *count = 0; + return BAD_VALUE; + } + Vector< sp > effects = mOutputSessions.valueAt(index)->mEffects; + + for (size_t i = 0; i < effects.size(); i++) { + effect_descriptor_t desc = effects[i]->descriptor(); + if (i < *count) { + descriptors[i] = desc; + } + } + if (effects.size() > *count) { + status = NO_MEMORY; + } + *count = effects.size(); + return status; +} + + +status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession) +{ + status_t status = NO_ERROR; + + Mutex::Autolock _l(mLock); + // create audio processors according to stream + // FIXME: should we have specific post processing settings for internal streams? + // default to media for now. + if (stream >= AUDIO_STREAM_PUBLIC_CNT) { + stream = AUDIO_STREAM_MUSIC; + } + ssize_t index = mOutputStreams.indexOfKey(stream); + if (index < 0) { + ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); + return NO_ERROR; + } + + ssize_t idx = mOutputSessions.indexOfKey(audioSession); + EffectVector *procDesc; + if (idx < 0) { + procDesc = new EffectVector(audioSession); + mOutputSessions.add(audioSession, procDesc); + } else { + // EffectVector is existing and we just need to increase ref count + procDesc = mOutputSessions.valueAt(idx); + } + procDesc->mRefCount++; + + ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", + audioSession, procDesc->mRefCount); + if (procDesc->mRefCount == 1) { + Vector effects = mOutputStreams.valueAt(index)->mEffects; + for (size_t i = 0; i < effects.size(); i++) { + EffectDesc *effect = effects[i]; + sp fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, + audioSession, output); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", + effect->mName, audioSession); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d", + effect->mName, audioSession, (int32_t)stream); + procDesc->mEffects.add(fx); + } + + procDesc->setProcessorEnabled(true); + } + return status; +} + +status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession) +{ + status_t status = NO_ERROR; + (void) output; // argument not used for now + (void) stream; // argument not used for now + + Mutex::Autolock _l(mLock); + ssize_t index = mOutputSessions.indexOfKey(audioSession); + if (index < 0) { + ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream"); + return NO_ERROR; + } + + EffectVector *procDesc = mOutputSessions.valueAt(index); + procDesc->mRefCount--; + ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", + audioSession, procDesc->mRefCount); + if (procDesc->mRefCount == 0) { + procDesc->setProcessorEnabled(false); + procDesc->mEffects.clear(); + delete procDesc; + mOutputSessions.removeItemsAt(index); + ALOGV("releaseOutputSessionEffects(): output processing released from session: %d", + audioSession); + } + return status; +} + + +void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled) +{ + for (size_t i = 0; i < mEffects.size(); i++) { + mEffects.itemAt(i)->setEnabled(enabled); + } +} + + +// ---------------------------------------------------------------------------- +// Audio processing configuration +// ---------------------------------------------------------------------------- + +/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = { + MIC_SRC_TAG, + VOICE_UL_SRC_TAG, + VOICE_DL_SRC_TAG, + VOICE_CALL_SRC_TAG, + CAMCORDER_SRC_TAG, + VOICE_REC_SRC_TAG, + VOICE_COMM_SRC_TAG +}; + +// returns the audio_source_t enum corresponding to the input source name or +// AUDIO_SOURCE_CNT is no match found +/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name) +{ + int i; + for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) { + if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) { + ALOGV("inputSourceNameToEnum found source %s %d", name, i); + break; + } + } + return (audio_source_t)i; +} + +const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = { + AUDIO_STREAM_DEFAULT_TAG, + AUDIO_STREAM_VOICE_CALL_TAG, + AUDIO_STREAM_SYSTEM_TAG, + AUDIO_STREAM_RING_TAG, + AUDIO_STREAM_MUSIC_TAG, + AUDIO_STREAM_ALARM_TAG, + AUDIO_STREAM_NOTIFICATION_TAG, + AUDIO_STREAM_BLUETOOTH_SCO_TAG, + AUDIO_STREAM_ENFORCED_AUDIBLE_TAG, + AUDIO_STREAM_DTMF_TAG, + AUDIO_STREAM_TTS_TAG +}; + +// returns the audio_stream_t enum corresponding to the output stream name or +// AUDIO_STREAM_PUBLIC_CNT is no match found +audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name) +{ + int i; + for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) { + if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) { + ALOGV("streamNameToEnum found stream %s %d", name, i); + break; + } + } + return (audio_stream_type_t)i; +} + +// ---------------------------------------------------------------------------- +// Audio Effect Config parser +// ---------------------------------------------------------------------------- + +size_t AudioPolicyEffects::growParamSize(char *param, + size_t size, + size_t *curSize, + size_t *totSize) +{ + // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int) + size_t pos = ((*curSize - 1 ) / size + 1) * size; + + if (pos + size > *totSize) { + while (pos + size > *totSize) { + *totSize += ((*totSize + 7) / 8) * 4; + } + param = (char *)realloc(param, *totSize); + } + *curSize = pos + size; + return pos; +} + +size_t AudioPolicyEffects::readParamValue(cnode *node, + char *param, + size_t *curSize, + size_t *totSize) +{ + if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(short), curSize, totSize); + *(short *)((char *)param + pos) = (short)atoi(node->value); + ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos)); + return sizeof(short); + } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(int), curSize, totSize); + *(int *)((char *)param + pos) = atoi(node->value); + ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos)); + return sizeof(int); + } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(float), curSize, totSize); + *(float *)((char *)param + pos) = (float)atof(node->value); + ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos)); + return sizeof(float); + } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(bool), curSize, totSize); + if (strncmp(node->value, "false", strlen("false") + 1) == 0) { + *(bool *)((char *)param + pos) = false; + } else { + *(bool *)((char *)param + pos) = true; + } + ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false"); + return sizeof(bool); + } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) { + size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX); + if (*curSize + len + 1 > *totSize) { + *totSize = *curSize + len + 1; + param = (char *)realloc(param, *totSize); + } + strncpy(param + *curSize, node->value, len); + *curSize += len; + param[*curSize] = '\0'; + ALOGV("readParamValue() reading string %s", param + *curSize - len); + return len; + } + ALOGW("readParamValue() unknown param type %s", node->name); + return 0; +} + +effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root) +{ + cnode *param; + cnode *value; + size_t curSize = sizeof(effect_param_t); + size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); + effect_param_t *fx_param = (effect_param_t *)malloc(totSize); + + param = config_find(root, PARAM_TAG); + value = config_find(root, VALUE_TAG); + if (param == NULL && value == NULL) { + // try to parse simple parameter form {int int} + param = root->first_child; + if (param != NULL) { + // Note: that a pair of random strings is read as 0 0 + int *ptr = (int *)fx_param->data; + int *ptr2 = (int *)((char *)param + sizeof(effect_param_t)); + ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2); + *ptr++ = atoi(param->name); + *ptr = atoi(param->value); + fx_param->psize = sizeof(int); + fx_param->vsize = sizeof(int); + return fx_param; + } + } + if (param == NULL || value == NULL) { + ALOGW("loadEffectParameter() invalid parameter description %s", root->name); + goto error; + } + + fx_param->psize = 0; + param = param->first_child; + while (param) { + ALOGV("loadEffectParameter() reading param of type %s", param->name); + size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize); + if (size == 0) { + goto error; + } + fx_param->psize += size; + param = param->next; + } + + // align start of value field on 32 bit boundary + curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int); + + fx_param->vsize = 0; + value = value->first_child; + while (value) { + ALOGV("loadEffectParameter() reading value of type %s", value->name); + size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize); + if (size == 0) { + goto error; + } + fx_param->vsize += size; + value = value->next; + } + + return fx_param; + +error: + delete fx_param; + return NULL; +} + +void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector & params) +{ + cnode *node = root->first_child; + while (node) { + ALOGV("loadEffectParameters() loading param %s", node->name); + effect_param_t *param = loadEffectParameter(node); + if (param == NULL) { + node = node->next; + continue; + } + params.add(param); + node = node->next; + } +} + + +AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig( + cnode *root, + const Vector & effects) +{ + cnode *node = root->first_child; + if (node == NULL) { + ALOGW("loadInputSource() empty element %s", root->name); + return NULL; + } + EffectDescVector *desc = new EffectDescVector(); + while (node) { + size_t i; + for (i = 0; i < effects.size(); i++) { + if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) { + ALOGV("loadEffectConfig() found effect %s in list", node->name); + break; + } + } + if (i == effects.size()) { + ALOGV("loadEffectConfig() effect %s not in list", node->name); + node = node->next; + continue; + } + EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy + loadEffectParameters(node, effect->mParams); + ALOGV("loadEffectConfig() adding effect %s uuid %08x", + effect->mName, effect->mUuid.timeLow); + desc->mEffects.add(effect); + node = node->next; + } + if (desc->mEffects.size() == 0) { + ALOGW("loadEffectConfig() no valid effects found in config %s", root->name); + delete desc; + return NULL; + } + return desc; +} + +status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root, + const Vector & effects) +{ + cnode *node = config_find(root, PREPROCESSING_TAG); + if (node == NULL) { + return -ENOENT; + } + node = node->first_child; + while (node) { + audio_source_t source = inputSourceNameToEnum(node->name); + if (source == AUDIO_SOURCE_CNT) { + ALOGW("loadInputSources() invalid input source %s", node->name); + node = node->next; + continue; + } + ALOGV("loadInputSources() loading input source %s", node->name); + EffectDescVector *desc = loadEffectConfig(node, effects); + if (desc == NULL) { + node = node->next; + continue; + } + mInputSources.add(source, desc); + node = node->next; + } + return NO_ERROR; +} + +status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root, + const Vector & effects) +{ + cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG); + if (node == NULL) { + return -ENOENT; + } + node = node->first_child; + while (node) { + audio_stream_type_t stream = streamNameToEnum(node->name); + if (stream == AUDIO_STREAM_PUBLIC_CNT) { + ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name); + node = node->next; + continue; + } + ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name); + EffectDescVector *desc = loadEffectConfig(node, effects); + if (desc == NULL) { + node = node->next; + continue; + } + mOutputStreams.add(stream, desc); + node = node->next; + } + return NO_ERROR; +} + +AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root) +{ + cnode *node = config_find(root, UUID_TAG); + if (node == NULL) { + return NULL; + } + effect_uuid_t uuid; + if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) { + ALOGW("loadEffect() invalid uuid %s", node->value); + return NULL; + } + return new EffectDesc(root->name, uuid); +} + +status_t AudioPolicyEffects::loadEffects(cnode *root, Vector & effects) +{ + cnode *node = config_find(root, EFFECTS_TAG); + if (node == NULL) { + return -ENOENT; + } + node = node->first_child; + while (node) { + ALOGV("loadEffects() loading effect %s", node->name); + EffectDesc *effect = loadEffect(node); + if (effect == NULL) { + node = node->next; + continue; + } + effects.add(effect); + node = node->next; + } + return NO_ERROR; +} + +status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path) +{ + cnode *root; + char *data; + + data = (char *)load_file(path, NULL); + if (data == NULL) { + return -ENODEV; + } + root = config_node("", ""); + config_load(root, data); + + Vector effects; + loadEffects(root, effects); + loadInputEffectConfigurations(root, effects); + loadStreamEffectConfigurations(root, effects); + + for (size_t i = 0; i < effects.size(); i++) { + delete effects[i]; + } + + config_free(root); + free(root); + free(data); + + return NO_ERROR; +} + + +}; // namespace android -- cgit v1.1