Eric Laurent 464d5b3da2 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
2011-07-18 09:42:57 -07:00

474 lines
13 KiB
C++

/*
**
** Copyright 2010, 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_NDEBUG 0
#define LOG_TAG "AudioEffect"
#include <stdint.h>
#include <sys/types.h>
#include <limits.h>
#include <private/media/AudioEffectShared.h>
#include <media/AudioEffect.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
namespace android {
// ---------------------------------------------------------------------------
AudioEffect::AudioEffect()
: mStatus(NO_INIT)
{
}
AudioEffect::AudioEffect(const effect_uuid_t *type,
const effect_uuid_t *uuid,
int32_t priority,
effect_callback_t cbf,
void* user,
int sessionId,
audio_io_handle_t io
)
: mStatus(NO_INIT)
{
mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
}
AudioEffect::AudioEffect(const char *typeStr,
const char *uuidStr,
int32_t priority,
effect_callback_t cbf,
void* user,
int sessionId,
audio_io_handle_t io
)
: mStatus(NO_INIT)
{
effect_uuid_t type;
effect_uuid_t *pType = NULL;
effect_uuid_t uuid;
effect_uuid_t *pUuid = NULL;
LOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr);
if (typeStr != NULL) {
if (stringToGuid(typeStr, &type) == NO_ERROR) {
pType = &type;
}
}
if (uuidStr != NULL) {
if (stringToGuid(uuidStr, &uuid) == NO_ERROR) {
pUuid = &uuid;
}
}
mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
}
status_t AudioEffect::set(const effect_uuid_t *type,
const effect_uuid_t *uuid,
int32_t priority,
effect_callback_t cbf,
void* user,
int sessionId,
audio_io_handle_t io)
{
sp<IEffect> iEffect;
sp<IMemory> cblk;
int enabled;
LOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
if (mIEffect != 0) {
LOGW("Effect already in use");
return INVALID_OPERATION;
}
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
LOGE("set(): Could not get audioflinger");
return NO_INIT;
}
if (type == NULL && uuid == NULL) {
LOGW("Must specify at least type or uuid");
return BAD_VALUE;
}
mPriority = priority;
mCbf = cbf;
mUserData = user;
mSessionId = sessionId;
memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
if (type != NULL) {
memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t));
}
if (uuid != NULL) {
memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t));
}
mIEffectClient = new EffectClient(this);
iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
return mStatus;
}
mEnabled = (volatile int32_t)enabled;
mIEffect = iEffect;
cblk = iEffect->getCblk();
if (cblk == 0) {
mStatus = NO_INIT;
LOGE("Could not get control block");
return mStatus;
}
mIEffect = iEffect;
mCblkMemory = cblk;
mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());
int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
mCblk->buffer = (uint8_t *)mCblk + bufOffset;
iEffect->asBinder()->linkToDeath(mIEffectClient);
LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);
return mStatus;
}
AudioEffect::~AudioEffect()
{
LOGV("Destructor %p", this);
if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
if (mIEffect != NULL) {
mIEffect->disconnect();
mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
}
IPCThreadState::self()->flushCommands();
}
mIEffect.clear();
mIEffectClient.clear();
mCblkMemory.clear();
}
status_t AudioEffect::initCheck() const
{
return mStatus;
}
// -------------------------------------------------------------------------
effect_descriptor_t AudioEffect::descriptor() const
{
return mDescriptor;
}
bool AudioEffect::getEnabled() const
{
return (mEnabled != 0);
}
status_t AudioEffect::setEnabled(bool enabled)
{
if (mStatus != NO_ERROR) {
return INVALID_OPERATION;
}
status_t status = NO_ERROR;
AutoMutex lock(mLock);
if (enabled != mEnabled) {
if (enabled) {
LOGV("enable %p", this);
status = mIEffect->enable();
} else {
LOGV("disable %p", this);
status = mIEffect->disable();
}
if (status == NO_ERROR) {
mEnabled = enabled;
}
}
return status;
}
status_t AudioEffect::command(uint32_t cmdCode,
uint32_t cmdSize,
void *cmdData,
uint32_t *replySize,
void *replyData)
{
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
LOGV("command() bad status %d", mStatus);
return INVALID_OPERATION;
}
if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
if (mEnabled == (cmdCode == EFFECT_CMD_ENABLE)) {
return NO_ERROR;
}
if (replySize == NULL || *replySize != sizeof(status_t) || replyData == NULL) {
return BAD_VALUE;
}
mLock.lock();
}
status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
if (status == NO_ERROR) {
status = *(status_t *)replyData;
}
if (status == NO_ERROR) {
mEnabled = (cmdCode == EFFECT_CMD_ENABLE);
}
mLock.unlock();
}
return status;
}
status_t AudioEffect::setParameter(effect_param_t *param)
{
if (mStatus != NO_ERROR) {
return INVALID_OPERATION;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
return BAD_VALUE;
}
uint32_t size = sizeof(int);
uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
LOGV("setParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1);
return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size, &param->status);
}
status_t AudioEffect::setParameterDeferred(effect_param_t *param)
{
if (mStatus != NO_ERROR) {
return INVALID_OPERATION;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
return BAD_VALUE;
}
Mutex::Autolock _l(mCblk->lock);
int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int);
if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) {
return NO_MEMORY;
}
int *p = (int *)(mCblk->buffer + mCblk->clientIndex);
*p++ = size;
memcpy(p, param, sizeof(effect_param_t) + psize);
mCblk->clientIndex += size;
return NO_ERROR;
}
status_t AudioEffect::setParameterCommit()
{
if (mStatus != NO_ERROR) {
return INVALID_OPERATION;
}
Mutex::Autolock _l(mCblk->lock);
if (mCblk->clientIndex == 0) {
return INVALID_OPERATION;
}
uint32_t size = 0;
return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL);
}
status_t AudioEffect::getParameter(effect_param_t *param)
{
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
return INVALID_OPERATION;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
return BAD_VALUE;
}
LOGV("getParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1);
uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, &psize, param);
}
// -------------------------------------------------------------------------
void AudioEffect::binderDied()
{
LOGW("IEffect died");
mStatus = NO_INIT;
if (mCbf) {
status_t status = DEAD_OBJECT;
mCbf(EVENT_ERROR, mUserData, &status);
}
mIEffect.clear();
}
// -------------------------------------------------------------------------
void AudioEffect::controlStatusChanged(bool controlGranted)
{
LOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, mUserData);
if (controlGranted) {
if (mStatus == ALREADY_EXISTS) {
mStatus = NO_ERROR;
}
} else {
if (mStatus == NO_ERROR) {
mStatus = ALREADY_EXISTS;
}
}
if (mCbf) {
mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
}
}
void AudioEffect::enableStatusChanged(bool enabled)
{
LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
if (mStatus == ALREADY_EXISTS) {
mEnabled = enabled;
if (mCbf) {
mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
}
}
}
void AudioEffect::commandExecuted(uint32_t cmdCode,
uint32_t cmdSize,
void *cmdData,
uint32_t replySize,
void *replyData)
{
if (cmdData == NULL || replyData == NULL) {
return;
}
if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) {
effect_param_t *cmd = (effect_param_t *)cmdData;
cmd->status = *(int32_t *)replyData;
mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
}
}
// -------------------------------------------------------------------------
status_t AudioEffect::queryNumberEffects(uint32_t *numEffects)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->queryNumberEffects(numEffects);
}
status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->queryEffect(index, descriptor);
}
status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->getEffectDescriptor(uuid, descriptor);
}
// -------------------------------------------------------------------------
status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
{
if (str == NULL || guid == NULL) {
return BAD_VALUE;
}
int tmp[10];
if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
return BAD_VALUE;
}
guid->timeLow = (uint32_t)tmp[0];
guid->timeMid = (uint16_t)tmp[1];
guid->timeHiAndVersion = (uint16_t)tmp[2];
guid->clockSeq = (uint16_t)tmp[3];
guid->node[0] = (uint8_t)tmp[4];
guid->node[1] = (uint8_t)tmp[5];
guid->node[2] = (uint8_t)tmp[6];
guid->node[3] = (uint8_t)tmp[7];
guid->node[4] = (uint8_t)tmp[8];
guid->node[5] = (uint8_t)tmp[9];
return NO_ERROR;
}
status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen)
{
if (guid == NULL || str == NULL) {
return BAD_VALUE;
}
snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
guid->timeLow,
guid->timeMid,
guid->timeHiAndVersion,
guid->clockSeq,
guid->node[0],
guid->node[1],
guid->node[2],
guid->node[3],
guid->node[4],
guid->node[5]);
return NO_ERROR;
}
}; // namespace android