summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/AudioPolicyService.cpp
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2011-06-17 21:29:58 -0700
committerEric Laurent <elaurent@google.com>2011-07-18 09:42:57 -0700
commit7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745 (patch)
treeeb67cd14e679d97a9b866a0410d8e582f4639274 /services/audioflinger/AudioPolicyService.cpp
parent67a124dcac0578aed94aebf451675a5f4c8a1e4e (diff)
downloadframeworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.zip
frameworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.tar.gz
frameworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.tar.bz2
Audio framework: support for audio pre processing
Audio effect framework is extended to suport effects on output and input audio path. AudioFlinger: Support for audio effects and effect chains is moved from PlaybackThread class to ThreadBase class so that RecordThread can manage effects. Effects of type pre processing are allowed on record thread only. When a pre processing is enabled, the effect interface handle is passed down to the input stream so that the audio HAL can call the process function. The record thread loop calls the effect chain process function that will only manage the effect state and commands and skip the process function. AudioRecord: The audio session is allocated before calling getInput() into audio policy serice so that the session is known before the input theead is created and pre processings can be created on the correct session. AudioPolicyService: default pre processing for a given input source are loaded from audio_effects.conf file. When an input is created, corresponding effects are created and enabled. Change-Id: Id17119e0979b4dcf189b5c7957fec30dc3478790
Diffstat (limited to 'services/audioflinger/AudioPolicyService.cpp')
-rw-r--r--services/audioflinger/AudioPolicyService.cpp396
1 files changed, 392 insertions, 4 deletions
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 8e16d94..dd1e153 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -33,11 +33,14 @@
#include <cutils/properties.h>
#include <dlfcn.h>
#include <hardware_legacy/power.h>
+#include <media/AudioEffect.h>
+#include <media/EffectsFactoryApi.h>
#include <hardware/hardware.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <hardware/audio_policy.h>
+#include <audio_effects/audio_effects_conf.h>
namespace android {
@@ -101,6 +104,13 @@ AudioPolicyService::AudioPolicyService()
mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val);
LOGI("Loaded audio policy from %s (%s)", module->name, module->id);
+
+ // load audio pre processing modules
+ if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+ loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+ } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+ loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ }
}
AudioPolicyService::~AudioPolicyService()
@@ -110,6 +120,31 @@ AudioPolicyService::~AudioPolicyService()
mAudioCommandThread->exit();
mAudioCommandThread.clear();
+
+ // release audio pre processing resources
+ for (size_t i = 0; i < mInputSources.size(); i++) {
+ InputSourceDesc *source = mInputSources.valueAt(i);
+ Vector <EffectDesc *> effects = source->mEffects;
+ for (size_t j = 0; j < effects.size(); j++) {
+ delete effects[j]->mName;
+ Vector <effect_param_t *> params = effects[j]->mParams;
+ for (size_t k = 0; k < params.size(); k++) {
+ delete params[k];
+ }
+ params.clear();
+ delete effects[j];
+ }
+ effects.clear();
+ delete source;
+ }
+ mInputSources.clear();
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mInputs.valueAt(i)->mEffects.clear();
+ delete mInputs.valueAt(i);
+ }
+ mInputs.clear();
+
if (mpAudioPolicy && mpAudioPolicyDev)
mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
if (mpAudioPolicyDev)
@@ -276,13 +311,51 @@ audio_io_handle_t AudioPolicyService::getInput(int inputSource,
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
- audio_in_acoustics_t acoustics)
+ audio_in_acoustics_t acoustics,
+ int audioSession)
{
if (mpAudioPolicy == NULL) {
return 0;
}
Mutex::Autolock _l(mLock);
- return mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, format, channels, acoustics);
+ audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
+ format, channels, acoustics);
+
+ if (input == 0) {
+ return input;
+ }
+ // create audio pre processors according to input source
+ ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource);
+ if (index < 0) {
+ return input;
+ }
+ ssize_t idx = mInputs.indexOfKey(input);
+ InputDesc *inputDesc;
+ if (idx < 0) {
+ inputDesc = new InputDesc();
+ inputDesc->mSessionId = audioSession;
+ mInputs.add(input, inputDesc);
+ } else {
+ inputDesc = mInputs.valueAt(idx);
+ }
+
+ Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
+ for (size_t i = 0; i < effects.size(); i++) {
+ EffectDesc *effect = effects[i];
+ sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
+ status_t status = fx->initCheck();
+ if (status != NO_ERROR && status != ALREADY_EXISTS) {
+ LOGW("Failed to create Fx %s on input %d", effect->mName, input);
+ // 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]);
+ }
+ inputDesc->mEffects.add(fx);
+ }
+ setPreProcessorEnabled(inputDesc, true);
+ return input;
}
status_t AudioPolicyService::startInput(audio_io_handle_t input)
@@ -291,6 +364,7 @@ status_t AudioPolicyService::startInput(audio_io_handle_t input)
return NO_INIT;
}
Mutex::Autolock _l(mLock);
+
return mpAudioPolicy->start_input(mpAudioPolicy, input);
}
@@ -300,6 +374,7 @@ status_t AudioPolicyService::stopInput(audio_io_handle_t input)
return NO_INIT;
}
Mutex::Autolock _l(mLock);
+
return mpAudioPolicy->stop_input(mpAudioPolicy, input);
}
@@ -310,6 +385,16 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input)
}
Mutex::Autolock _l(mLock);
mpAudioPolicy->release_input(mpAudioPolicy, input);
+
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ return;
+ }
+ InputDesc *inputDesc = mInputs.valueAt(index);
+ setPreProcessorEnabled(inputDesc, false);
+ inputDesc->mEffects.clear();
+ delete inputDesc;
+ mInputs.removeItemsAt(index);
}
status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
@@ -384,7 +469,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de
}
status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id)
@@ -392,7 +477,7 @@ status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- return mpAudioPolicy->register_effect(mpAudioPolicy, desc, output, strategy, session, id);
+ return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
}
status_t AudioPolicyService::unregisterEffect(int id)
@@ -489,6 +574,15 @@ status_t AudioPolicyService::dumpPermissionDenial(int fd)
return NO_ERROR;
}
+void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabled)
+{
+ Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects;
+ for (size_t i = 0; i < fxVector.size(); i++) {
+ sp<AudioEffect> fx = fxVector.itemAt(i);
+ fx->setEnabled(enabled);
+ }
+}
+
status_t AudioPolicyService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -918,6 +1012,300 @@ int AudioPolicyService::setVoiceVolume(float volume, int delayMs)
return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
}
+// ----------------------------------------------------------------------------
+// Audio pre-processing configuration
+// ----------------------------------------------------------------------------
+
+const char *AudioPolicyService::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
+audio_source_t AudioPolicyService::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) {
+ LOGV("inputSourceNameToEnum found source %s %d", name, i);
+ break;
+ }
+ }
+ return (audio_source_t)i;
+}
+
+size_t AudioPolicyService::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 AudioPolicyService::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);
+ LOGV("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);
+ LOGV("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);
+ LOGV("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;
+ }
+ LOGV("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';
+ LOGV("readParamValue() reading string %s", param + *curSize - len);
+ return len;
+ }
+ LOGW("readParamValue() unknown param type %s", node->name);
+ return 0;
+}
+
+effect_param_t *AudioPolicyService::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) {
+ // 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));
+ LOGW("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) {
+ LOGW("loadEffectParameter() invalid parameter description %s", root->name);
+ goto error;
+ }
+
+ fx_param->psize = 0;
+ param = param->first_child;
+ while (param) {
+ LOGV("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) {
+ LOGV("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 AudioPolicyService::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
+{
+ cnode *node = root->first_child;
+ while (node) {
+ LOGV("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;
+ }
+}
+
+AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource(
+ cnode *root,
+ const Vector <EffectDesc *>& effects)
+{
+ cnode *node = root->first_child;
+ if (node == NULL) {
+ LOGW("loadInputSource() empty element %s", root->name);
+ return NULL;
+ }
+ InputSourceDesc *source = new InputSourceDesc();
+ while (node) {
+ size_t i;
+ for (i = 0; i < effects.size(); i++) {
+ if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
+ LOGV("loadInputSource() found effect %s in list", node->name);
+ break;
+ }
+ }
+ if (i == effects.size()) {
+ LOGV("loadInputSource() effect %s not in list", node->name);
+ node = node->next;
+ continue;
+ }
+ EffectDesc *effect = new EffectDesc(*effects[i]);
+ loadEffectParameters(node, effect->mParams);
+ LOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow);
+ source->mEffects.add(effect);
+ node = node->next;
+ }
+ if (source->mEffects.size() == 0) {
+ LOGW("loadInputSource() no valid effects found in source %s", root->name);
+ delete source;
+ return NULL;
+ }
+ return source;
+}
+
+status_t AudioPolicyService::loadInputSources(cnode *root, const Vector <EffectDesc *>& 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) {
+ LOGW("loadInputSources() invalid input source %s", node->name);
+ node = node->next;
+ continue;
+ }
+ LOGV("loadInputSources() loading input source %s", node->name);
+ InputSourceDesc *desc = loadInputSource(node, effects);
+ if (desc == NULL) {
+ node = node->next;
+ continue;
+ }
+ mInputSources.add(source, desc);
+ node = node->next;
+ }
+ return NO_ERROR;
+}
+
+AudioPolicyService::EffectDesc *AudioPolicyService::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) {
+ LOGW("loadEffect() invalid uuid %s", node->value);
+ return NULL;
+ }
+ EffectDesc *effect = new EffectDesc();
+ effect->mName = strdup(root->name);
+ memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t));
+
+ return effect;
+}
+
+status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
+{
+ cnode *node = config_find(root, EFFECTS_TAG);
+ if (node == NULL) {
+ return -ENOENT;
+ }
+ node = node->first_child;
+ while (node) {
+ LOGV("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 AudioPolicyService::loadPreProcessorConfig(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 <EffectDesc *> effects;
+ loadEffects(root, effects);
+ loadInputSources(root, effects);
+
+ config_free(root);
+ free(root);
+ free(data);
+
+ return NO_ERROR;
+}
+
/* implementation of the interface to the policy manager */
extern "C" {