diff options
Diffstat (limited to 'media/libmedia/AudioEffect.cpp')
| -rw-r--r-- | media/libmedia/AudioEffect.cpp | 481 | 
1 files changed, 481 insertions, 0 deletions
| diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp new file mode 100644 index 000000000000..0f3e24532631 --- /dev/null +++ b/media/libmedia/AudioEffect.cpp @@ -0,0 +1,481 @@ +/* +** +** 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 <cutils/atomic.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 output +                ) +    : mStatus(NO_INIT) +{ +    mStatus = set(type, uuid, priority, cbf, user, sessionId, output); +} + +AudioEffect::AudioEffect(const char *typeStr, +                const char *uuidStr, +                int32_t priority, +                effect_callback_t cbf, +                void* user, +                int sessionId, +                audio_io_handle_t output +                ) +    : 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, output); +} + +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 output) +{ +    sp<IEffect> iEffect; +    sp<IMemory> cblk; +    int enabled; + +    LOGV("set %p mUserData: %p", this, user); + +    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, output, 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) { +        setEnabled(false); +        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; +    } + +    if (enabled) { +        LOGV("enable %p", this); +        if (android_atomic_or(1, &mEnabled) == 0) { +           return mIEffect->enable(); +        } +    } else { +        LOGV("disable %p", this); +        if (android_atomic_and(~1, &mEnabled) == 1) { +           return mIEffect->disable(); +        } +    } +    return NO_ERROR; +} + +status_t AudioEffect::command(uint32_t cmdCode, +                              uint32_t cmdSize, +                              void *cmdData, +                              uint32_t *replySize, +                              void *replyData) +{ +    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { +        return INVALID_OPERATION; +    } + +    status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData); +    if (status != NO_ERROR) { +        return status; +    } +    status = *(status_t *)replyData; +    if (status != NO_ERROR) { +        return status; +    } + +    if (cmdCode == EFFECT_CMD_ENABLE) { +        android_atomic_or(1, &mEnabled); +    } +    if (cmdCode == EFFECT_CMD_DISABLE) { +        android_atomic_and(~1, &mEnabled); +    } +    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, ¶m->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) { +        if (enabled) { +            android_atomic_or(1, &mEnabled); +        } else { +            android_atomic_and(~1, &mEnabled); +        } +        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::loadEffectLibrary(const char *libPath, int *handle) +{ +    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); +    if (af == 0) return PERMISSION_DENIED; +    return af->loadEffectLibrary(libPath, handle); +} + +status_t AudioEffect::unloadEffectLibrary(int handle) +{ +    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); +    if (af == 0) return PERMISSION_DENIED; +    return af->unloadEffectLibrary(handle); +} + +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 + | 
