EffectProxy.cpp revision 60c60df7db278d2fa5c90b0fa14f99a61d50272b
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "EffectProxy" 18//#define LOG_NDEBUG 0 19 20#include <cutils/log.h> 21#include <assert.h> 22#include <stdlib.h> 23#include <string.h> 24#include <new> 25#include <EffectProxy.h> 26#include <utils/threads.h> 27#include <media/EffectsFactoryApi.h> 28 29namespace android { 30// This is a dummy proxy descriptor just to return to Factory during the initial 31// GetDescriptor call. Later in the factory, it is replaced with the 32// SW sub effect descriptor 33const effect_descriptor_t gProxyDescriptor = { 34 EFFECT_UUID_INITIALIZER, // type 35 EFFECT_UUID_INITIALIZER, // uuid 36 EFFECT_CONTROL_API_VERSION, //version of effect control API 37 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | 38 EFFECT_FLAG_VOLUME_CTRL), // effect capability flags 39 0, // CPU load 40 1, // Data memory 41 "Proxy", //effect name 42 "AOSP", //implementor name 43}; 44 45 46static const effect_descriptor_t *const gDescriptors[] = 47{ 48 &gProxyDescriptor, 49}; 50 51int EffectProxyCreate(const effect_uuid_t *uuid, 52 int32_t sessionId, 53 int32_t ioId, 54 effect_handle_t *pHandle) { 55 56 effect_descriptor_t* desc; 57 EffectContext* pContext; 58 if (pHandle == NULL || uuid == NULL) { 59 ALOGE("EffectProxyCreate() called with NULL pointer"); 60 return -EINVAL; 61 } 62 ALOGV("EffectProxyCreate start.."); 63 pContext = new EffectContext; 64 pContext->sessionId = sessionId; 65 pContext->ioId = ioId; 66 pContext->uuid = *uuid; 67 pContext->common_itfe = &gEffectInterface; 68 // The sub effects will be created in effect_command when the first command 69 // for the effect is received 70 pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; 71 72 // Get the HW and SW sub effect descriptors from the effects factory 73 desc = new effect_descriptor_t[SUB_FX_COUNT]; 74 pContext->desc = new effect_descriptor_t[SUB_FX_COUNT]; 75 int retValue = EffectGetSubEffects(uuid, desc, 76 sizeof(effect_descriptor_t) * SUB_FX_COUNT); 77 // EffectGetSubEffects returns the number of sub-effects copied. 78 if (retValue != SUB_FX_COUNT) { 79 ALOGE("EffectCreate() could not get the sub effects"); 80 delete desc; 81 delete pContext->desc; 82 return -EINVAL; 83 } 84 // Check which is the HW descriptor and copy the descriptors 85 // to the Context desc array 86 // Also check if there is only one HW and one SW descriptor. 87 // HW descriptor alone has the HW_TUNNEL flag. 88 if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && 89 !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { 90 pContext->desc[SUB_FX_OFFLOAD] = desc[0]; 91 pContext->desc[SUB_FX_HOST] = desc[1]; 92 } 93 else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && 94 !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { 95 pContext->desc[SUB_FX_HOST] = desc[0]; 96 pContext->desc[SUB_FX_OFFLOAD] = desc[1]; 97 } 98 delete desc; 99#if (LOG_NDEBUG == 0) 100 effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid; 101 ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" 102 "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid, 103 uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], 104 uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], 105 uuid_print.node[4], uuid_print.node[5]); 106 ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" 107 "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid, 108 uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], 109 uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], 110 uuid_print.node[4], uuid_print.node[5]); 111#endif 112 *pHandle = (effect_handle_t)pContext; 113 ALOGV("EffectCreate end"); 114 return 0; 115} //end EffectProxyCreate 116 117int EffectProxyRelease(effect_handle_t handle) { 118 EffectContext * pContext = (EffectContext *)handle; 119 if (pContext == NULL) { 120 ALOGV("ERROR : EffectRelease called with NULL pointer"); 121 return -EINVAL; 122 } 123 ALOGV("EffectRelease"); 124 delete pContext->desc; 125 if (pContext->eHandle[SUB_FX_HOST]) 126 EffectRelease(pContext->eHandle[SUB_FX_HOST]); 127 if (pContext->eHandle[SUB_FX_OFFLOAD]) 128 EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]); 129 delete pContext; 130 pContext = NULL; 131 return 0; 132} /*end EffectProxyRelease */ 133 134int EffectProxyGetDescriptor(const effect_uuid_t *uuid, 135 effect_descriptor_t *pDescriptor) { 136 const effect_descriptor_t *desc = NULL; 137 138 if (pDescriptor == NULL || uuid == NULL) { 139 ALOGV("EffectGetDescriptor() called with NULL pointer"); 140 return -EINVAL; 141 } 142 desc = &gProxyDescriptor; 143 *pDescriptor = *desc; 144 return 0; 145} /* end EffectProxyGetDescriptor */ 146 147/* Effect Control Interface Implementation: Process */ 148int Effect_process(effect_handle_t self, 149 audio_buffer_t *inBuffer, 150 audio_buffer_t *outBuffer) { 151 152 EffectContext *pContext = (EffectContext *) self; 153 int ret = 0; 154 if (pContext != NULL) { 155 int index = pContext->index; 156 // if the index refers to HW , do not do anything. Just return. 157 if (index == SUB_FX_HOST) { 158 ALOGV("Calling CoreProcess"); 159 ret = (*pContext->eHandle[index])->process(pContext->eHandle[index], 160 inBuffer, outBuffer); 161 } 162 } 163 return ret; 164} /* end Effect_process */ 165 166/* Effect Control Interface Implementation: Command */ 167int Effect_command(effect_handle_t self, 168 uint32_t cmdCode, 169 uint32_t cmdSize, 170 void *pCmdData, 171 uint32_t *replySize, 172 void *pReplyData) { 173 174 EffectContext *pContext = (EffectContext *) self; 175 int status; 176 if (pContext == NULL) { 177 ALOGV("Effect_command() Proxy context is NULL"); 178 return -EINVAL; 179 } 180 if (pContext->eHandle[SUB_FX_HOST] == NULL) { 181 ALOGV("Effect_command() Calling HOST EffectCreate"); 182 status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid, 183 pContext->sessionId, pContext->ioId, 184 &(pContext->eHandle[SUB_FX_HOST])); 185 if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) { 186 ALOGV("Effect_command() Error creating SW sub effect"); 187 return status; 188 } 189 } 190 if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) { 191 ALOGV("Effect_command() Calling OFFLOAD EffectCreate"); 192 status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid, 193 pContext->sessionId, pContext->ioId, 194 &(pContext->eHandle[SUB_FX_OFFLOAD])); 195 if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) { 196 ALOGV("Effect_command() Error creating HW effect"); 197 // Do not return error here as SW effect is created 198 // Return error if the CMD_OFFLOAD sends the index as OFFLOAD 199 } 200 pContext->index = SUB_FX_HOST; 201 } 202 // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not 203 // (2) Send the ioHandle of the effectThread when the effect 204 // is moved from one type of thread to another. 205 // pCmdData points to a memory holding effect_offload_param_t structure 206 if (cmdCode == EFFECT_CMD_OFFLOAD) { 207 ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD"); 208 if (cmdSize == 0 || pCmdData == NULL) { 209 ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data"); 210 *(int*)pReplyData = FAILED_TRANSACTION; 211 return FAILED_TRANSACTION; 212 } 213 effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData; 214 // Assign the effect context index based on isOffload field of the structure 215 pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST; 216 // if the index is HW and the HW effect is unavailable, return error 217 // and reset the index to SW 218 if (pContext->eHandle[pContext->index] == NULL) { 219 ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable"); 220 *(int*)pReplyData = FAILED_TRANSACTION; 221 return FAILED_TRANSACTION; 222 } 223 pContext->ioId = offloadParam->ioHandle; 224 ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId); 225 // Update the DSP wrapper with the new ioHandle. 226 // Pass the OFFLOAD command to the wrapper. 227 // The DSP wrapper needs to handle this CMD 228 if (pContext->eHandle[SUB_FX_OFFLOAD]) 229 status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( 230 pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, 231 pCmdData, replySize, pReplyData); 232 return status; 233 } 234 235 int index = pContext->index; 236 if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) { 237 ALOGV("Effect_command: effect index is neither offload nor host"); 238 return -EINVAL; 239 } 240 ALOGV("Effect_command: pContext->eHandle[%d]: %p", 241 index, pContext->eHandle[index]); 242 if (pContext->eHandle[SUB_FX_HOST]) 243 (*pContext->eHandle[SUB_FX_HOST])->command( 244 pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize, 245 pCmdData, replySize, pReplyData); 246 if (pContext->eHandle[SUB_FX_OFFLOAD]) { 247 // In case of SET CMD, when the offload stream is unavailable, 248 // we will store the effect param values in the DSP effect wrapper. 249 // When the offload effects get enabled, we send these values to the 250 // DSP during Effect_config. 251 // So,we send the params to DSP wrapper also 252 (*pContext->eHandle[SUB_FX_OFFLOAD])->command( 253 pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, 254 pCmdData, replySize, pReplyData); 255 } 256 return 0; 257} /* end Effect_command */ 258 259 260/* Effect Control Interface Implementation: get_descriptor */ 261int Effect_getDescriptor(effect_handle_t self, 262 effect_descriptor_t *pDescriptor) { 263 264 EffectContext * pContext = (EffectContext *) self; 265 const effect_descriptor_t *desc; 266 267 ALOGV("Effect_getDescriptor"); 268 if (pContext == NULL || pDescriptor == NULL) { 269 ALOGV("Effect_getDescriptor() invalid param"); 270 return -EINVAL; 271 } 272 if (pContext->desc == NULL) { 273 ALOGV("Effect_getDescriptor() could not get descriptor"); 274 return -EINVAL; 275 } 276 desc = &pContext->desc[SUB_FX_HOST]; 277 *pDescriptor = *desc; 278 pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID 279 // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability 280 if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL) 281 pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; 282 else 283 pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED; 284 return 0; 285} /* end Effect_getDescriptor */ 286 287} // namespace android 288 289__attribute__ ((visibility ("default"))) 290audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 291 tag : AUDIO_EFFECT_LIBRARY_TAG, 292 version : EFFECT_LIBRARY_API_VERSION, 293 name : "Effect Proxy", 294 implementor : "AOSP", 295 create_effect : android::EffectProxyCreate, 296 release_effect : android::EffectProxyRelease, 297 get_descriptor : android::EffectProxyGetDescriptor, 298}; 299