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