You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
15 KiB
387 lines
15 KiB
/*
|
|
* Copyright (C) 2013 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 "EffectProxy"
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <new>
|
|
|
|
#include <EffectProxy.h>
|
|
|
|
#include <log/log.h>
|
|
#include <utils/threads.h>
|
|
|
|
#include <media/EffectsFactoryApi.h>
|
|
|
|
namespace android {
|
|
// This is a stub proxy descriptor just to return to Factory during the initial
|
|
// GetDescriptor call. Later in the factory, it is replaced with the
|
|
// SW sub effect descriptor
|
|
// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b
|
|
const effect_descriptor_t gProxyDescriptor = {
|
|
EFFECT_UUID_INITIALIZER, // type
|
|
{0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid
|
|
EFFECT_CONTROL_API_VERSION, //version of effect control API
|
|
(EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST |
|
|
EFFECT_FLAG_VOLUME_CTRL), // effect capability flags
|
|
0, // CPU load
|
|
1, // Data memory
|
|
"Proxy", //effect name
|
|
"AOSP", //implementor name
|
|
};
|
|
|
|
|
|
int EffectProxyCreate(const effect_uuid_t *uuid,
|
|
int32_t sessionId,
|
|
int32_t ioId,
|
|
effect_handle_t *pHandle) {
|
|
|
|
effect_descriptor_t* desc;
|
|
audio_effect_library_t** aeli;
|
|
sub_effect_entry_t** sube;
|
|
EffectContext* pContext;
|
|
if (pHandle == NULL || uuid == NULL) {
|
|
ALOGE("EffectProxyCreate() called with NULL pointer");
|
|
return -EINVAL;
|
|
}
|
|
ALOGV("EffectProxyCreate start..");
|
|
pContext = new EffectContext;
|
|
pContext->sessionId = sessionId;
|
|
pContext->ioId = ioId;
|
|
pContext->uuid = *uuid;
|
|
pContext->common_itfe = &gEffectInterface;
|
|
|
|
// The sub effects will be created in effect_command when the first command
|
|
// for the effect is received
|
|
pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
|
|
|
|
// Get the HW and SW sub effect descriptors from the effects factory
|
|
desc = new effect_descriptor_t[SUB_FX_COUNT];
|
|
aeli = new audio_effect_library_t*[SUB_FX_COUNT];
|
|
sube = new sub_effect_entry_t*[SUB_FX_COUNT];
|
|
pContext->sube = new sub_effect_entry_t*[SUB_FX_COUNT];
|
|
pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
|
|
pContext->aeli = new audio_effect_library_t*[SUB_FX_COUNT];
|
|
int retValue = EffectGetSubEffects(uuid, sube, SUB_FX_COUNT);
|
|
// EffectGetSubEffects returns the number of sub-effects copied.
|
|
if (retValue != SUB_FX_COUNT) {
|
|
ALOGE("EffectCreate() could not get the sub effects");
|
|
delete[] sube;
|
|
delete[] desc;
|
|
delete[] aeli;
|
|
delete[] pContext->sube;
|
|
delete[] pContext->desc;
|
|
delete[] pContext->aeli;
|
|
delete pContext;
|
|
return -EINVAL;
|
|
}
|
|
// Check which is the HW descriptor and copy the descriptors
|
|
// to the Context desc array
|
|
// Also check if there is only one HW and one SW descriptor.
|
|
// HW descriptor alone has the HW_TUNNEL flag.
|
|
desc[0] = *(effect_descriptor_t*)(sube[0])->object;
|
|
desc[1] = *(effect_descriptor_t*)(sube[1])->object;
|
|
aeli[0] = sube[0]->lib->desc;
|
|
aeli[1] = sube[1]->lib->desc;
|
|
if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
|
|
!(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
|
|
pContext->sube[SUB_FX_OFFLOAD] = sube[0];
|
|
pContext->desc[SUB_FX_OFFLOAD] = desc[0];
|
|
pContext->aeli[SUB_FX_OFFLOAD] = aeli[0];
|
|
pContext->sube[SUB_FX_HOST] = sube[1];
|
|
pContext->desc[SUB_FX_HOST] = desc[1];
|
|
pContext->aeli[SUB_FX_HOST] = aeli[1];
|
|
}
|
|
else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
|
|
!(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
|
|
pContext->sube[SUB_FX_HOST] = sube[0];
|
|
pContext->desc[SUB_FX_HOST] = desc[0];
|
|
pContext->aeli[SUB_FX_HOST] = aeli[0];
|
|
pContext->sube[SUB_FX_OFFLOAD] = sube[1];
|
|
pContext->desc[SUB_FX_OFFLOAD] = desc[1];
|
|
pContext->aeli[SUB_FX_OFFLOAD] = aeli[1];
|
|
} else {
|
|
ALOGE("Both effects have (or don't have) EFFECT_FLAG_HW_ACC_TUNNEL flag");
|
|
delete[] sube;
|
|
delete[] desc;
|
|
delete[] aeli;
|
|
delete[] pContext->sube;
|
|
delete[] pContext->desc;
|
|
delete[] pContext->aeli;
|
|
delete pContext;
|
|
return -EINVAL;
|
|
}
|
|
delete[] desc;
|
|
delete[] aeli;
|
|
delete[] sube;
|
|
#if (LOG_NDEBUG == 0)
|
|
effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
|
|
ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
|
|
"%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid,
|
|
uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
|
|
uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
|
|
uuid_print.node[4], uuid_print.node[5]);
|
|
ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
|
|
"%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid,
|
|
uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
|
|
uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
|
|
uuid_print.node[4], uuid_print.node[5]);
|
|
#endif
|
|
|
|
pContext->replySize = PROXY_REPLY_SIZE_DEFAULT;
|
|
pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT);
|
|
|
|
*pHandle = (effect_handle_t)pContext;
|
|
ALOGV("EffectCreate end");
|
|
return 0;
|
|
} //end EffectProxyCreate
|
|
|
|
int EffectProxyRelease(effect_handle_t handle) {
|
|
EffectContext * pContext = (EffectContext *)handle;
|
|
if (pContext == NULL) {
|
|
ALOGV("ERROR : EffectRelease called with NULL pointer");
|
|
return -EINVAL;
|
|
}
|
|
ALOGV("EffectRelease");
|
|
delete[] pContext->desc;
|
|
free(pContext->replyData);
|
|
|
|
if (pContext->eHandle[SUB_FX_HOST])
|
|
pContext->aeli[SUB_FX_HOST]->release_effect(pContext->eHandle[SUB_FX_HOST]);
|
|
if (pContext->eHandle[SUB_FX_OFFLOAD])
|
|
pContext->aeli[SUB_FX_OFFLOAD]->release_effect(pContext->eHandle[SUB_FX_OFFLOAD]);
|
|
delete[] pContext->aeli;
|
|
delete[] pContext->sube;
|
|
delete pContext;
|
|
pContext = NULL;
|
|
return 0;
|
|
} /*end EffectProxyRelease */
|
|
|
|
int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
|
|
effect_descriptor_t *pDescriptor) {
|
|
const effect_descriptor_t *desc = NULL;
|
|
|
|
if (pDescriptor == NULL || uuid == NULL) {
|
|
ALOGV("EffectGetDescriptor() called with NULL pointer");
|
|
return -EINVAL;
|
|
}
|
|
desc = &gProxyDescriptor;
|
|
*pDescriptor = *desc;
|
|
return 0;
|
|
} /* end EffectProxyGetDescriptor */
|
|
|
|
/* Effect Control Interface Implementation: Process */
|
|
int Effect_process(effect_handle_t self,
|
|
audio_buffer_t *inBuffer,
|
|
audio_buffer_t *outBuffer) {
|
|
|
|
EffectContext *pContext = (EffectContext *) self;
|
|
int ret = 0;
|
|
if (pContext != NULL) {
|
|
int index = pContext->index;
|
|
// if the index refers to HW , do not do anything. Just return.
|
|
if (index == SUB_FX_HOST) {
|
|
ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
|
|
inBuffer, outBuffer);
|
|
}
|
|
}
|
|
return ret;
|
|
} /* end Effect_process */
|
|
|
|
/* Effect Control Interface Implementation: Command */
|
|
int Effect_command(effect_handle_t self,
|
|
uint32_t cmdCode,
|
|
uint32_t cmdSize,
|
|
void *pCmdData,
|
|
uint32_t *replySize,
|
|
void *pReplyData) {
|
|
|
|
EffectContext *pContext = (EffectContext *) self;
|
|
int status = 0;
|
|
if (pContext == NULL) {
|
|
ALOGV("Effect_command() Proxy context is NULL");
|
|
return -EINVAL;
|
|
}
|
|
if (pContext->eHandle[SUB_FX_HOST] == NULL) {
|
|
ALOGV("Effect_command() Calling HOST EffectCreate");
|
|
status = pContext->aeli[SUB_FX_HOST]->create_effect(
|
|
&pContext->desc[SUB_FX_HOST].uuid,
|
|
pContext->sessionId, pContext->ioId,
|
|
&(pContext->eHandle[SUB_FX_HOST]));
|
|
if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
|
|
ALOGV("Effect_command() Error creating SW sub effect");
|
|
return status;
|
|
}
|
|
}
|
|
if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
|
|
ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
|
|
status = pContext->aeli[SUB_FX_OFFLOAD]->create_effect(
|
|
&pContext->desc[SUB_FX_OFFLOAD].uuid,
|
|
pContext->sessionId, pContext->ioId,
|
|
&(pContext->eHandle[SUB_FX_OFFLOAD]));
|
|
if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
|
|
ALOGV("Effect_command() Error creating HW effect");
|
|
pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
|
|
// Do not return error here as SW effect is created
|
|
// Return error if the CMD_OFFLOAD sends the index as OFFLOAD
|
|
}
|
|
pContext->index = SUB_FX_HOST;
|
|
}
|
|
// EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not
|
|
// (2) Send the ioHandle of the effectThread when the effect
|
|
// is moved from one type of thread to another.
|
|
// pCmdData points to a memory holding effect_offload_param_t structure
|
|
if (cmdCode == EFFECT_CMD_OFFLOAD) {
|
|
ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD");
|
|
if (replySize == NULL || *replySize < sizeof(int)) {
|
|
ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no reply");
|
|
android_errorWriteLog(0x534e4554, "32448121");
|
|
return FAILED_TRANSACTION;
|
|
}
|
|
if (cmdSize == 0 || pCmdData == NULL) {
|
|
ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data");
|
|
*(int*)pReplyData = FAILED_TRANSACTION;
|
|
return FAILED_TRANSACTION;
|
|
}
|
|
effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData;
|
|
// Assign the effect context index based on isOffload field of the structure
|
|
pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST;
|
|
// if the index is HW and the HW effect is unavailable, return error
|
|
// and reset the index to SW
|
|
if (pContext->eHandle[pContext->index] == NULL) {
|
|
ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable");
|
|
*(int*)pReplyData = FAILED_TRANSACTION;
|
|
return FAILED_TRANSACTION;
|
|
}
|
|
pContext->ioId = offloadParam->ioHandle;
|
|
ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId);
|
|
// Update the DSP wrapper with the new ioHandle.
|
|
// Pass the OFFLOAD command to the wrapper.
|
|
// The DSP wrapper needs to handle this CMD
|
|
if (pContext->eHandle[SUB_FX_OFFLOAD]) {
|
|
ALOGV("Effect_command: Calling OFFLOAD command");
|
|
return (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
|
|
pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
|
|
pCmdData, replySize, pReplyData);
|
|
}
|
|
*(int*)pReplyData = NO_ERROR;
|
|
ALOGV("Effect_command OFFLOAD return 0, replyData %d",
|
|
*(int*)pReplyData);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int index = pContext->index;
|
|
if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) {
|
|
ALOGV("Effect_command: effect index is neither offload nor host");
|
|
return -EINVAL;
|
|
}
|
|
|
|
// Getter commands are only sent to the active sub effect.
|
|
int *subStatus[SUB_FX_COUNT];
|
|
uint32_t *subReplySize[SUB_FX_COUNT];
|
|
void *subReplyData[SUB_FX_COUNT];
|
|
uint32_t tmpSize;
|
|
int tmpStatus;
|
|
|
|
// grow temp reply buffer if needed
|
|
if (replySize != NULL) {
|
|
tmpSize = pContext->replySize;
|
|
while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) {
|
|
tmpSize *= 2;
|
|
}
|
|
if (tmpSize > pContext->replySize) {
|
|
ALOGV("Effect_command grow reply buf to %d", tmpSize);
|
|
pContext->replyData = (char *)realloc(pContext->replyData, tmpSize);
|
|
pContext->replySize = tmpSize;
|
|
}
|
|
if (tmpSize > *replySize) {
|
|
tmpSize = *replySize;
|
|
}
|
|
} else {
|
|
tmpSize = 0;
|
|
}
|
|
// tmpSize is now the actual reply size for the non active sub effect
|
|
|
|
// Send command to sub effects. The command is sent to all sub effects so that their internal
|
|
// state is kept in sync.
|
|
// Only the reply from the active sub effect is returned to the caller. The reply from the
|
|
// other sub effect is lost in pContext->replyData
|
|
for (int i = 0; i < SUB_FX_COUNT; i++) {
|
|
if (pContext->eHandle[i] == NULL) {
|
|
continue;
|
|
}
|
|
if (i == index) {
|
|
subStatus[i] = &status;
|
|
subReplySize[i] = replySize;
|
|
subReplyData[i] = pReplyData;
|
|
} else {
|
|
subStatus[i] = &tmpStatus;
|
|
subReplySize[i] = replySize == NULL ? NULL : &tmpSize;
|
|
subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData;
|
|
}
|
|
*subStatus[i] = (*pContext->eHandle[i])->command(
|
|
pContext->eHandle[i], cmdCode, cmdSize,
|
|
pCmdData, subReplySize[i], subReplyData[i]);
|
|
}
|
|
|
|
return status;
|
|
} /* end Effect_command */
|
|
|
|
|
|
/* Effect Control Interface Implementation: get_descriptor */
|
|
int Effect_getDescriptor(effect_handle_t self,
|
|
effect_descriptor_t *pDescriptor) {
|
|
|
|
EffectContext * pContext = (EffectContext *) self;
|
|
const effect_descriptor_t *desc;
|
|
|
|
ALOGV("Effect_getDescriptor");
|
|
if (pContext == NULL || pDescriptor == NULL) {
|
|
ALOGV("Effect_getDescriptor() invalid param");
|
|
return -EINVAL;
|
|
}
|
|
if (pContext->desc == NULL) {
|
|
ALOGV("Effect_getDescriptor() could not get descriptor");
|
|
return -EINVAL;
|
|
}
|
|
desc = &pContext->desc[SUB_FX_HOST];
|
|
*pDescriptor = *desc;
|
|
pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID
|
|
// Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability
|
|
if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL)
|
|
pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
|
|
else
|
|
pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED;
|
|
return 0;
|
|
} /* end Effect_getDescriptor */
|
|
|
|
} // namespace android
|
|
|
|
__attribute__ ((visibility ("default")))
|
|
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
|
|
.tag = AUDIO_EFFECT_LIBRARY_TAG,
|
|
.version = EFFECT_LIBRARY_API_VERSION,
|
|
.name = "Effect Proxy",
|
|
.implementor = "AOSP",
|
|
.create_effect = android::EffectProxyCreate,
|
|
.release_effect = android::EffectProxyRelease,
|
|
.get_descriptor = android::EffectProxyGetDescriptor,
|
|
};
|