EffectProxy.cpp revision ef225074ea06dc8ac2801b2fb9f4707dcd3f4200
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 33// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b 34const effect_descriptor_t gProxyDescriptor = { 35 EFFECT_UUID_INITIALIZER, // type 36 {0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid 37 EFFECT_CONTROL_API_VERSION, //version of effect control API 38 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | 39 EFFECT_FLAG_VOLUME_CTRL), // effect capability flags 40 0, // CPU load 41 1, // Data memory 42 "Proxy", //effect name 43 "AOSP", //implementor name 44}; 45 46 47int EffectProxyCreate(const effect_uuid_t *uuid, 48 int32_t sessionId, 49 int32_t ioId, 50 effect_handle_t *pHandle) { 51 52 effect_descriptor_t* desc; 53 audio_effect_library_t** aeli; 54 sub_effect_entry_t** sube; 55 EffectContext* pContext; 56 if (pHandle == NULL || uuid == NULL) { 57 ALOGE("EffectProxyCreate() called with NULL pointer"); 58 return -EINVAL; 59 } 60 ALOGV("EffectProxyCreate start.."); 61 pContext = new EffectContext; 62 pContext->sessionId = sessionId; 63 pContext->ioId = ioId; 64 pContext->uuid = *uuid; 65 pContext->common_itfe = &gEffectInterface; 66 67 // The sub effects will be created in effect_command when the first command 68 // for the effect is received 69 pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; 70 71 // Get the HW and SW sub effect descriptors from the effects factory 72 desc = new effect_descriptor_t[SUB_FX_COUNT]; 73 aeli = new audio_effect_library_t*[SUB_FX_COUNT]; 74 sube = new sub_effect_entry_t*[SUB_FX_COUNT]; 75 pContext->sube = new sub_effect_entry_t*[SUB_FX_COUNT]; 76 pContext->desc = new effect_descriptor_t[SUB_FX_COUNT]; 77 pContext->aeli = new audio_effect_library_t*[SUB_FX_COUNT]; 78 int retValue = EffectGetSubEffects(uuid, sube, SUB_FX_COUNT); 79 // EffectGetSubEffects returns the number of sub-effects copied. 80 if (retValue != SUB_FX_COUNT) { 81 ALOGE("EffectCreate() could not get the sub effects"); 82 delete[] sube; 83 delete[] desc; 84 delete[] aeli; 85 delete[] pContext->sube; 86 delete[] pContext->desc; 87 delete[] pContext->aeli; 88 return -EINVAL; 89 } 90 // Check which is the HW descriptor and copy the descriptors 91 // to the Context desc array 92 // Also check if there is only one HW and one SW descriptor. 93 // HW descriptor alone has the HW_TUNNEL flag. 94 desc[0] = *(effect_descriptor_t*)(sube[0])->object; 95 desc[1] = *(effect_descriptor_t*)(sube[1])->object; 96 aeli[0] = sube[0]->lib->desc; 97 aeli[1] = sube[1]->lib->desc; 98 if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && 99 !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { 100 pContext->sube[SUB_FX_OFFLOAD] = sube[0]; 101 pContext->desc[SUB_FX_OFFLOAD] = desc[0]; 102 pContext->aeli[SUB_FX_OFFLOAD] = aeli[0]; 103 pContext->sube[SUB_FX_HOST] = sube[1]; 104 pContext->desc[SUB_FX_HOST] = desc[1]; 105 pContext->aeli[SUB_FX_HOST] = aeli[1]; 106 } 107 else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && 108 !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { 109 pContext->sube[SUB_FX_HOST] = sube[0]; 110 pContext->desc[SUB_FX_HOST] = desc[0]; 111 pContext->aeli[SUB_FX_HOST] = aeli[0]; 112 pContext->sube[SUB_FX_OFFLOAD] = sube[1]; 113 pContext->desc[SUB_FX_OFFLOAD] = desc[1]; 114 pContext->aeli[SUB_FX_OFFLOAD] = aeli[1]; 115 } 116 delete[] desc; 117 delete[] aeli; 118 delete[] sube; 119#if (LOG_NDEBUG == 0) 120 effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid; 121 ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" 122 "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid, 123 uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], 124 uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], 125 uuid_print.node[4], uuid_print.node[5]); 126 ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" 127 "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid, 128 uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], 129 uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], 130 uuid_print.node[4], uuid_print.node[5]); 131#endif 132 133 pContext->replySize = PROXY_REPLY_SIZE_DEFAULT; 134 pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT); 135 136 *pHandle = (effect_handle_t)pContext; 137 ALOGV("EffectCreate end"); 138 return 0; 139} //end EffectProxyCreate 140 141int EffectProxyRelease(effect_handle_t handle) { 142 EffectContext * pContext = (EffectContext *)handle; 143 if (pContext == NULL) { 144 ALOGV("ERROR : EffectRelease called with NULL pointer"); 145 return -EINVAL; 146 } 147 ALOGV("EffectRelease"); 148 delete[] pContext->desc; 149 free(pContext->replyData); 150 151 if (pContext->eHandle[SUB_FX_HOST]) 152 pContext->aeli[SUB_FX_HOST]->release_effect(pContext->eHandle[SUB_FX_HOST]); 153 if (pContext->eHandle[SUB_FX_OFFLOAD]) 154 pContext->aeli[SUB_FX_OFFLOAD]->release_effect(pContext->eHandle[SUB_FX_OFFLOAD]); 155 delete[] pContext->aeli; 156 delete[] pContext->sube; 157 delete pContext; 158 pContext = NULL; 159 return 0; 160} /*end EffectProxyRelease */ 161 162int EffectProxyGetDescriptor(const effect_uuid_t *uuid, 163 effect_descriptor_t *pDescriptor) { 164 const effect_descriptor_t *desc = NULL; 165 166 if (pDescriptor == NULL || uuid == NULL) { 167 ALOGV("EffectGetDescriptor() called with NULL pointer"); 168 return -EINVAL; 169 } 170 desc = &gProxyDescriptor; 171 *pDescriptor = *desc; 172 return 0; 173} /* end EffectProxyGetDescriptor */ 174 175/* Effect Control Interface Implementation: Process */ 176int Effect_process(effect_handle_t self, 177 audio_buffer_t *inBuffer, 178 audio_buffer_t *outBuffer) { 179 180 EffectContext *pContext = (EffectContext *) self; 181 int ret = 0; 182 if (pContext != NULL) { 183 int index = pContext->index; 184 // if the index refers to HW , do not do anything. Just return. 185 if (index == SUB_FX_HOST) { 186 ret = (*pContext->eHandle[index])->process(pContext->eHandle[index], 187 inBuffer, outBuffer); 188 } 189 } 190 return ret; 191} /* end Effect_process */ 192 193/* Effect Control Interface Implementation: Command */ 194int Effect_command(effect_handle_t self, 195 uint32_t cmdCode, 196 uint32_t cmdSize, 197 void *pCmdData, 198 uint32_t *replySize, 199 void *pReplyData) { 200 201 EffectContext *pContext = (EffectContext *) self; 202 int status = 0; 203 if (pContext == NULL) { 204 ALOGV("Effect_command() Proxy context is NULL"); 205 return -EINVAL; 206 } 207 if (pContext->eHandle[SUB_FX_HOST] == NULL) { 208 ALOGV("Effect_command() Calling HOST EffectCreate"); 209 status = pContext->aeli[SUB_FX_HOST]->create_effect( 210 &pContext->desc[SUB_FX_HOST].uuid, 211 pContext->sessionId, pContext->ioId, 212 &(pContext->eHandle[SUB_FX_HOST])); 213 if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) { 214 ALOGV("Effect_command() Error creating SW sub effect"); 215 return status; 216 } 217 } 218 if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) { 219 ALOGV("Effect_command() Calling OFFLOAD EffectCreate"); 220 status = pContext->aeli[SUB_FX_OFFLOAD]->create_effect( 221 &pContext->desc[SUB_FX_OFFLOAD].uuid, 222 pContext->sessionId, pContext->ioId, 223 &(pContext->eHandle[SUB_FX_OFFLOAD])); 224 if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) { 225 ALOGV("Effect_command() Error creating HW effect"); 226 pContext->eHandle[SUB_FX_OFFLOAD] = NULL; 227 // Do not return error here as SW effect is created 228 // Return error if the CMD_OFFLOAD sends the index as OFFLOAD 229 } 230 pContext->index = SUB_FX_HOST; 231 } 232 // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not 233 // (2) Send the ioHandle of the effectThread when the effect 234 // is moved from one type of thread to another. 235 // pCmdData points to a memory holding effect_offload_param_t structure 236 if (cmdCode == EFFECT_CMD_OFFLOAD) { 237 ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD"); 238 if (cmdSize == 0 || pCmdData == NULL) { 239 ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data"); 240 *(int*)pReplyData = FAILED_TRANSACTION; 241 return FAILED_TRANSACTION; 242 } 243 effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData; 244 // Assign the effect context index based on isOffload field of the structure 245 pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST; 246 // if the index is HW and the HW effect is unavailable, return error 247 // and reset the index to SW 248 if (pContext->eHandle[pContext->index] == NULL) { 249 ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable"); 250 *(int*)pReplyData = FAILED_TRANSACTION; 251 return FAILED_TRANSACTION; 252 } 253 pContext->ioId = offloadParam->ioHandle; 254 ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId); 255 // Update the DSP wrapper with the new ioHandle. 256 // Pass the OFFLOAD command to the wrapper. 257 // The DSP wrapper needs to handle this CMD 258 if (pContext->eHandle[SUB_FX_OFFLOAD]) { 259 ALOGV("Effect_command: Calling OFFLOAD command"); 260 return (*pContext->eHandle[SUB_FX_OFFLOAD])->command( 261 pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, 262 pCmdData, replySize, pReplyData); 263 } 264 *(int*)pReplyData = NO_ERROR; 265 ALOGV("Effect_command OFFLOAD return 0, replyData %d", 266 *(int*)pReplyData); 267 268 return NO_ERROR; 269 } 270 271 int index = pContext->index; 272 if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) { 273 ALOGV("Effect_command: effect index is neither offload nor host"); 274 return -EINVAL; 275 } 276 277 // Getter commands are only sent to the active sub effect. 278 int *subStatus[SUB_FX_COUNT]; 279 uint32_t *subReplySize[SUB_FX_COUNT]; 280 void *subReplyData[SUB_FX_COUNT]; 281 uint32_t tmpSize; 282 int tmpStatus; 283 284 // grow temp reply buffer if needed 285 if (replySize != NULL) { 286 tmpSize = pContext->replySize; 287 while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) { 288 tmpSize *= 2; 289 } 290 if (tmpSize > pContext->replySize) { 291 ALOGV("Effect_command grow reply buf to %d", tmpSize); 292 pContext->replyData = (char *)realloc(pContext->replyData, tmpSize); 293 pContext->replySize = tmpSize; 294 } 295 if (tmpSize > *replySize) { 296 tmpSize = *replySize; 297 } 298 } else { 299 tmpSize = 0; 300 } 301 // tmpSize is now the actual reply size for the non active sub effect 302 303 // Send command to sub effects. The command is sent to all sub effects so that their internal 304 // state is kept in sync. 305 // Only the reply from the active sub effect is returned to the caller. The reply from the 306 // other sub effect is lost in pContext->replyData 307 for (int i = 0; i < SUB_FX_COUNT; i++) { 308 if (pContext->eHandle[i] == NULL) { 309 continue; 310 } 311 if (i == index) { 312 subStatus[i] = &status; 313 subReplySize[i] = replySize; 314 subReplyData[i] = pReplyData; 315 } else { 316 subStatus[i] = &tmpStatus; 317 subReplySize[i] = replySize == NULL ? NULL : &tmpSize; 318 subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData; 319 } 320 *subStatus[i] = (*pContext->eHandle[i])->command( 321 pContext->eHandle[i], cmdCode, cmdSize, 322 pCmdData, subReplySize[i], subReplyData[i]); 323 } 324 325 return status; 326} /* end Effect_command */ 327 328 329/* Effect Control Interface Implementation: get_descriptor */ 330int Effect_getDescriptor(effect_handle_t self, 331 effect_descriptor_t *pDescriptor) { 332 333 EffectContext * pContext = (EffectContext *) self; 334 const effect_descriptor_t *desc; 335 336 ALOGV("Effect_getDescriptor"); 337 if (pContext == NULL || pDescriptor == NULL) { 338 ALOGV("Effect_getDescriptor() invalid param"); 339 return -EINVAL; 340 } 341 if (pContext->desc == NULL) { 342 ALOGV("Effect_getDescriptor() could not get descriptor"); 343 return -EINVAL; 344 } 345 desc = &pContext->desc[SUB_FX_HOST]; 346 *pDescriptor = *desc; 347 pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID 348 // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability 349 if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL) 350 pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; 351 else 352 pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED; 353 return 0; 354} /* end Effect_getDescriptor */ 355 356} // namespace android 357 358__attribute__ ((visibility ("default"))) 359audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 360 .tag = AUDIO_EFFECT_LIBRARY_TAG, 361 .version = EFFECT_LIBRARY_API_VERSION, 362 .name = "Effect Proxy", 363 .implementor = "AOSP", 364 .create_effect = android::EffectProxyCreate, 365 .release_effect = android::EffectProxyRelease, 366 .get_descriptor = android::EffectProxyGetDescriptor, 367}; 368