| Eric Laurent | 135ad07 | 2010-05-21 06:05:13 -0700 | [diff] [blame^] | 1 | /* | 
 | 2 |  * Copyright (C) 2010 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 "EffectsFactory" | 
 | 18 | //#define LOG_NDEBUG 0 | 
 | 19 |  | 
 | 20 | #include "EffectsFactory.h" | 
 | 21 | #include <dlfcn.h> | 
 | 22 |  | 
 | 23 |  | 
 | 24 | static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects | 
 | 25 | static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries | 
 | 26 | static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList | 
 | 27 | static list_elem_t *gCurLib;    // current library in enumeration process | 
 | 28 | static list_elem_t *gCurEffect; // current effect in enumeration process | 
 | 29 |  | 
 | 30 | static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries | 
 | 31 | static int gInitDone; // true is global initialization has been preformed | 
 | 32 |  | 
 | 33 | ///////////////////////////////////////////////// | 
 | 34 | //      Local functions prototypes | 
 | 35 | ///////////////////////////////////////////////// | 
 | 36 |  | 
 | 37 | static int init(); | 
 | 38 | static int loadLibrary(const char *libPath, int *handle); | 
 | 39 | static int unloadLibrary(int handle); | 
 | 40 | static int numEffectModules(); | 
 | 41 | static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc); | 
 | 42 | static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len); | 
 | 43 |  | 
 | 44 | ///////////////////////////////////////////////// | 
 | 45 | //      Effect Control Interface functions | 
 | 46 | ///////////////////////////////////////////////// | 
 | 47 |  | 
 | 48 | int Effect_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) | 
 | 49 | { | 
 | 50 |     int ret = init(); | 
 | 51 |     if (ret < 0) { | 
 | 52 |         return ret; | 
 | 53 |     } | 
 | 54 |     effect_entry_t *fx = (effect_entry_t *)self; | 
 | 55 |     pthread_mutex_lock(&gLibLock); | 
 | 56 |     if (fx->lib == NULL) { | 
 | 57 |         pthread_mutex_unlock(&gLibLock); | 
 | 58 |         return -EPIPE; | 
 | 59 |     } | 
 | 60 |     pthread_mutex_lock(&fx->lib->lock); | 
 | 61 |     pthread_mutex_unlock(&gLibLock); | 
 | 62 |  | 
 | 63 |     ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer); | 
 | 64 |     pthread_mutex_unlock(&fx->lib->lock); | 
 | 65 |     return ret; | 
 | 66 | } | 
 | 67 |  | 
 | 68 | int Effect_Command(effect_interface_t self, int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData) | 
 | 69 | { | 
 | 70 |     int ret = init(); | 
 | 71 |     if (ret < 0) { | 
 | 72 |         return ret; | 
 | 73 |     } | 
 | 74 |     effect_entry_t *fx = (effect_entry_t *)self; | 
 | 75 |     pthread_mutex_lock(&gLibLock); | 
 | 76 |     if (fx->lib == NULL) { | 
 | 77 |         pthread_mutex_unlock(&gLibLock); | 
 | 78 |         return -EPIPE; | 
 | 79 |     } | 
 | 80 |     pthread_mutex_lock(&fx->lib->lock); | 
 | 81 |     pthread_mutex_unlock(&gLibLock); | 
 | 82 |  | 
 | 83 |     ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData); | 
 | 84 |     pthread_mutex_unlock(&fx->lib->lock); | 
 | 85 |     return ret; | 
 | 86 | } | 
 | 87 |  | 
 | 88 | const struct effect_interface_s gInterface = { | 
 | 89 |         Effect_Process, | 
 | 90 |         Effect_Command | 
 | 91 | }; | 
 | 92 |  | 
 | 93 | ///////////////////////////////////////////////// | 
 | 94 | //      Effect Factory Interface functions | 
 | 95 | ///////////////////////////////////////////////// | 
 | 96 |  | 
 | 97 | int EffectQueryNumberEffects(int *pNumEffects) | 
 | 98 | { | 
 | 99 |     int ret = init(); | 
 | 100 |     if (ret < 0) { | 
 | 101 |         return ret; | 
 | 102 |     } | 
 | 103 |     if (pNumEffects == NULL) { | 
 | 104 |         return -EINVAL; | 
 | 105 |     } | 
 | 106 |  | 
 | 107 |     pthread_mutex_lock(&gLibLock); | 
 | 108 |     *pNumEffects = numEffectModules(); | 
 | 109 |     pthread_mutex_unlock(&gLibLock); | 
 | 110 |     LOGV("EffectQueryNumberEffects(): %d", *pNumEffects); | 
 | 111 |     return ret; | 
 | 112 | } | 
 | 113 |  | 
 | 114 | int EffectQueryNext(effect_descriptor_t *pDescriptor) | 
 | 115 | { | 
 | 116 |     int ret = init(); | 
 | 117 |     if (ret < 0) { | 
 | 118 |         return ret; | 
 | 119 |     } | 
 | 120 |     if (pDescriptor == NULL) { | 
 | 121 |         return -EINVAL; | 
 | 122 |     } | 
 | 123 |  | 
 | 124 |     pthread_mutex_lock(&gLibLock); | 
 | 125 |     ret = -ENOENT; | 
 | 126 |     while (gCurLib) { | 
 | 127 |         if (gCurEffect) { | 
 | 128 |             memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t)); | 
 | 129 |             gCurEffect = gCurEffect->next; | 
 | 130 |             ret = 0; | 
 | 131 |             break; | 
 | 132 |         } else { | 
 | 133 |             gCurLib = gCurLib->next; | 
 | 134 |             gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; | 
 | 135 |         } | 
 | 136 |     } | 
 | 137 |     char str[256]; | 
 | 138 |     dumpEffectDescriptor(pDescriptor, str, 256); | 
 | 139 |     LOGV("EffectQueryNext() desc:%s", str); | 
 | 140 |     pthread_mutex_unlock(&gLibLock); | 
 | 141 |     return ret; | 
 | 142 | } | 
 | 143 |  | 
 | 144 | int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) | 
 | 145 | { | 
 | 146 |     lib_entry_t *l = NULL; | 
 | 147 |     effect_descriptor_t *d = NULL; | 
 | 148 |  | 
 | 149 |     int ret = init(); | 
 | 150 |     if (ret < 0) { | 
 | 151 |         return ret; | 
 | 152 |     } | 
 | 153 |     if (pDescriptor == NULL || uuid == NULL) { | 
 | 154 |         return -EINVAL; | 
 | 155 |     } | 
 | 156 |     pthread_mutex_lock(&gLibLock); | 
 | 157 |     ret = findEffect(uuid, &l, &d); | 
 | 158 |     if (ret == 0) { | 
 | 159 |         memcpy(pDescriptor, d, sizeof(effect_descriptor_t)); | 
 | 160 |     } | 
 | 161 |     pthread_mutex_unlock(&gLibLock); | 
 | 162 |     return ret; | 
 | 163 | } | 
 | 164 |  | 
 | 165 | int EffectCreate(effect_uuid_t *uuid, effect_interface_t *pInterface) | 
 | 166 | { | 
 | 167 |     list_elem_t *e = gLibraryList; | 
 | 168 |     lib_entry_t *l = NULL; | 
 | 169 |     effect_descriptor_t *d = NULL; | 
 | 170 |     effect_interface_t itfe; | 
 | 171 |     effect_entry_t *fx; | 
 | 172 |     int found = 0; | 
 | 173 |     int ret; | 
 | 174 |  | 
 | 175 |     if (uuid == NULL || pInterface == NULL) { | 
 | 176 |         return -EINVAL; | 
 | 177 |     } | 
 | 178 |  | 
 | 179 |     LOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", | 
 | 180 |             uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, | 
 | 181 |             uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], | 
 | 182 |             uuid->node[3],uuid->node[4],uuid->node[5]); | 
 | 183 |  | 
 | 184 |     ret = init(); | 
 | 185 |  | 
 | 186 |     if (ret < 0) { | 
 | 187 |         LOGW("EffectCreate() init error: %d", ret); | 
 | 188 |         return ret; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     pthread_mutex_lock(&gLibLock); | 
 | 192 |  | 
 | 193 |     ret = findEffect(uuid, &l, &d); | 
 | 194 |     if (ret < 0){ | 
 | 195 |         goto exit; | 
 | 196 |     } | 
 | 197 |  | 
 | 198 |     // create effect in library | 
 | 199 |     ret = l->createFx(uuid, &itfe); | 
 | 200 |     if (ret < 0) { | 
 | 201 |         LOGW("EffectCreate() library %s: could not create fx %s", l->path, d->name); | 
 | 202 |         goto exit; | 
 | 203 |     } | 
 | 204 |  | 
 | 205 |     // add entry to effect list | 
 | 206 |     fx = (effect_entry_t *)malloc(sizeof(effect_entry_t)); | 
 | 207 |     fx->subItfe = itfe; | 
 | 208 |     fx->itfe = (struct effect_interface_s *)&gInterface; | 
 | 209 |     fx->lib = l; | 
 | 210 |  | 
 | 211 |     e = (list_elem_t *)malloc(sizeof(list_elem_t)); | 
 | 212 |     e->object = fx; | 
 | 213 |     e->next = gEffectList; | 
 | 214 |     gEffectList = e; | 
 | 215 |  | 
 | 216 |     *pInterface = (effect_interface_t)fx; | 
 | 217 |  | 
 | 218 |     LOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pInterface, itfe, l->path); | 
 | 219 |  | 
 | 220 | exit: | 
 | 221 |     pthread_mutex_unlock(&gLibLock); | 
 | 222 |     return ret; | 
 | 223 | } | 
 | 224 |  | 
 | 225 | int EffectRelease(effect_interface_t interface) | 
 | 226 | { | 
 | 227 |     effect_entry_t *fx; | 
 | 228 |     list_elem_t *e1; | 
 | 229 |     list_elem_t *e2; | 
 | 230 |  | 
 | 231 |     int ret = init(); | 
 | 232 |     if (ret < 0) { | 
 | 233 |         return ret; | 
 | 234 |     } | 
 | 235 |  | 
 | 236 |     // remove effect from effect list | 
 | 237 |     pthread_mutex_lock(&gLibLock); | 
 | 238 |     e1 = gEffectList; | 
 | 239 |     e2 = NULL; | 
 | 240 |     while (e1) { | 
 | 241 |         if (e1->object == interface) { | 
 | 242 |             if (e2) { | 
 | 243 |                 e2->next = e1->next; | 
 | 244 |             } else { | 
 | 245 |                 gEffectList = e1->next; | 
 | 246 |             } | 
 | 247 |             fx = (effect_entry_t *)e1->object; | 
 | 248 |             free(e1); | 
 | 249 |             break; | 
 | 250 |         } | 
 | 251 |         e2 = e1; | 
 | 252 |         e1 = e1->next; | 
 | 253 |     } | 
 | 254 |     if (e1 == NULL) { | 
 | 255 |         ret = -ENOENT; | 
 | 256 |         goto exit; | 
 | 257 |     } | 
 | 258 |  | 
 | 259 |     // release effect in library | 
 | 260 |     if (fx->lib == NULL) { | 
 | 261 |         LOGW("EffectRelease() fx %p library already unloaded", interface); | 
 | 262 |     } else { | 
 | 263 |         pthread_mutex_lock(&fx->lib->lock); | 
 | 264 |         fx->lib->releaseFx(fx->subItfe); | 
 | 265 |         pthread_mutex_unlock(&fx->lib->lock); | 
 | 266 |     } | 
 | 267 |     free(fx); | 
 | 268 |  | 
 | 269 | exit: | 
 | 270 |     pthread_mutex_unlock(&gLibLock); | 
 | 271 |     return ret; | 
 | 272 | } | 
 | 273 |  | 
 | 274 | int EffectLoadLibrary(const char *libPath, int *handle) | 
 | 275 | { | 
 | 276 |     int ret = init(); | 
 | 277 |     if (ret < 0) { | 
 | 278 |         return ret; | 
 | 279 |     } | 
 | 280 |     if (libPath == NULL || strnlen(libPath, PATH_MAX) >= PATH_MAX) { | 
 | 281 |         return -EINVAL; | 
 | 282 |     } | 
 | 283 |     return loadLibrary(libPath, handle); | 
 | 284 | } | 
 | 285 |  | 
 | 286 | int EffectUnloadLibrary(int handle) | 
 | 287 | { | 
 | 288 |     int ret = init(); | 
 | 289 |     if (ret < 0) { | 
 | 290 |         return ret; | 
 | 291 |     } | 
 | 292 |  | 
 | 293 |     return unloadLibrary(handle); | 
 | 294 | } | 
 | 295 |  | 
 | 296 | int EffectIsNullUuid(effect_uuid_t *uuid) | 
 | 297 | { | 
 | 298 |     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) { | 
 | 299 |         return 0; | 
 | 300 |     } | 
 | 301 |     return 1; | 
 | 302 | } | 
 | 303 |  | 
 | 304 | ///////////////////////////////////////////////// | 
 | 305 | //      Local functions | 
 | 306 | ///////////////////////////////////////////////// | 
 | 307 |  | 
 | 308 | int init() { | 
 | 309 |     struct dirent *ent; | 
 | 310 |     DIR *dir = NULL; | 
 | 311 |     char libpath[PATH_MAX]; | 
 | 312 |     int hdl; | 
 | 313 |  | 
 | 314 |     if (gInitDone) { | 
 | 315 |         return 0; | 
 | 316 |     } | 
 | 317 |  | 
 | 318 |     pthread_mutex_init(&gLibLock, NULL); | 
 | 319 |  | 
 | 320 |     // load built-in libraries | 
 | 321 |     dir = opendir(gEffectLibPath); | 
 | 322 |     if (dir == NULL) { | 
 | 323 |         return -ENODEV; | 
 | 324 |     } | 
 | 325 |     while ((ent = readdir(dir)) != NULL) { | 
 | 326 |         LOGV("init() reading file %s", ent->d_name); | 
 | 327 |         if ((strlen(ent->d_name) < 3) || | 
 | 328 |             strncmp(ent->d_name, "lib", 3) != 0 || | 
 | 329 |             strncmp(ent->d_name + strlen(ent->d_name) - 3, ".so", 3) != 0) { | 
 | 330 |             continue; | 
 | 331 |         } | 
 | 332 |         strcpy(libpath, gEffectLibPath); | 
 | 333 |         strcat(libpath, "/"); | 
 | 334 |         strcat(libpath, ent->d_name); | 
 | 335 |         if (loadLibrary(libpath, &hdl) < 0) { | 
 | 336 |             LOGW("init() failed to load library %s",libpath); | 
 | 337 |         } | 
 | 338 |     } | 
 | 339 |     closedir(dir); | 
 | 340 |  | 
 | 341 |     gInitDone = 1; | 
 | 342 |     LOGV("init() done"); | 
 | 343 |     return 0; | 
 | 344 | } | 
 | 345 |  | 
 | 346 |  | 
 | 347 | int loadLibrary(const char *libPath, int *handle) | 
 | 348 | { | 
 | 349 |     void *hdl; | 
 | 350 |     effect_QueryNumberEffects_t queryNumFx; | 
 | 351 |     effect_QueryNextEffect_t queryFx; | 
 | 352 |     effect_CreateEffect_t createFx; | 
 | 353 |     effect_ReleaseEffect_t releaseFx; | 
 | 354 |     int numFx; | 
 | 355 |     int fx; | 
 | 356 |     int ret; | 
 | 357 |     list_elem_t *e, *descHead = NULL; | 
 | 358 |     lib_entry_t *l; | 
 | 359 |  | 
 | 360 |     if (handle == NULL) { | 
 | 361 |         return -EINVAL; | 
 | 362 |     } | 
 | 363 |  | 
 | 364 |     *handle = 0; | 
 | 365 |  | 
 | 366 |     hdl = dlopen(libPath, RTLD_NOW); | 
 | 367 |     if (hdl == 0) { | 
 | 368 |         LOGW("could open lib %s", libPath); | 
 | 369 |         return -ENODEV; | 
 | 370 |     } | 
 | 371 |  | 
 | 372 |     // Check functions availability | 
 | 373 |     queryNumFx = (effect_QueryNumberEffects_t)dlsym(hdl, "EffectQueryNumberEffects"); | 
 | 374 |     if (queryNumFx == NULL) { | 
 | 375 |         LOGW("could not get EffectQueryNumberEffects from lib %s", libPath); | 
 | 376 |         ret = -ENODEV; | 
 | 377 |         goto error; | 
 | 378 |     } | 
 | 379 |     queryFx = (effect_QueryNextEffect_t)dlsym(hdl, "EffectQueryNext"); | 
 | 380 |     if (queryFx == NULL) { | 
 | 381 |         LOGW("could not get EffectQueryNext from lib %s", libPath); | 
 | 382 |         ret = -ENODEV; | 
 | 383 |         goto error; | 
 | 384 |     } | 
 | 385 |     createFx = (effect_CreateEffect_t)dlsym(hdl, "EffectCreate"); | 
 | 386 |     if (createFx == NULL) { | 
 | 387 |         LOGW("could not get EffectCreate from lib %s", libPath); | 
 | 388 |         ret = -ENODEV; | 
 | 389 |         goto error; | 
 | 390 |     } | 
 | 391 |     releaseFx = (effect_ReleaseEffect_t)dlsym(hdl, "EffectRelease"); | 
 | 392 |     if (releaseFx == NULL) { | 
 | 393 |         LOGW("could not get EffectRelease from lib %s", libPath); | 
 | 394 |         ret = -ENODEV; | 
 | 395 |         goto error; | 
 | 396 |     } | 
 | 397 |  | 
 | 398 |     // load effect descriptors | 
 | 399 |     ret = queryNumFx(&numFx); | 
 | 400 |     if (ret) { | 
 | 401 |         goto error; | 
 | 402 |     } | 
 | 403 |  | 
 | 404 |     for (fx = 0; fx < numFx; fx++) { | 
 | 405 |         effect_descriptor_t *d = malloc(sizeof(effect_descriptor_t)); | 
 | 406 |         if (d == NULL) { | 
 | 407 |             ret = -ENOMEM; | 
 | 408 |             goto error; | 
 | 409 |         } | 
 | 410 |         ret = queryFx(d); | 
 | 411 |         if (ret == 0) { | 
 | 412 | #if (LOG_NDEBUG==0) | 
 | 413 |             char s[256]; | 
 | 414 |             dumpEffectDescriptor(d, s, 256); | 
 | 415 |             LOGV("loadLibrary() read descriptor %p:%s",d, s); | 
 | 416 | #endif | 
 | 417 |             if (d->apiVersion != EFFECT_API_VERSION) { | 
 | 418 |                 LOGW("Bad API version %04x on lib %s", d->apiVersion, libPath); | 
 | 419 |                 free(d); | 
 | 420 |                 continue; | 
 | 421 |             } | 
 | 422 |             e = malloc(sizeof(list_elem_t)); | 
 | 423 |             if (e == NULL) { | 
 | 424 |                 free(d); | 
 | 425 |                 ret = -ENOMEM; | 
 | 426 |                 goto error; | 
 | 427 |             } | 
 | 428 |             e->object = d; | 
 | 429 |             e->next = descHead; | 
 | 430 |             descHead = e; | 
 | 431 |         } else { | 
 | 432 |             LOGW("Error querying effect # %d on lib %s", fx, libPath); | 
 | 433 |         } | 
 | 434 |     } | 
 | 435 |     // add entry for library in gLibraryList | 
 | 436 |     l = malloc(sizeof(lib_entry_t)); | 
 | 437 |     l->handle = hdl; | 
 | 438 |     strncpy(l->path, libPath, PATH_MAX); | 
 | 439 |     l->createFx = createFx; | 
 | 440 |     l->releaseFx = releaseFx; | 
 | 441 |     l->effects = descHead; | 
 | 442 |     pthread_mutex_init(&l->lock, NULL); | 
 | 443 |  | 
 | 444 |     e = malloc(sizeof(list_elem_t)); | 
 | 445 |     pthread_mutex_lock(&gLibLock); | 
 | 446 |     e->next = gLibraryList; | 
 | 447 |     e->object = l; | 
 | 448 |     gLibraryList = e; | 
 | 449 |     pthread_mutex_unlock(&gLibLock); | 
 | 450 |     LOGV("loadLibrary() linked library %p", l); | 
 | 451 |  | 
 | 452 |     *handle = (int)hdl; | 
 | 453 |  | 
 | 454 |     return 0; | 
 | 455 |  | 
 | 456 | error: | 
 | 457 |     LOGW("loadLibrary() error: %d on lib: %s", ret, libPath); | 
 | 458 |     while (descHead) { | 
 | 459 |         free(descHead->object); | 
 | 460 |         e = descHead->next; | 
 | 461 |         free(descHead); | 
 | 462 |         descHead = e;; | 
 | 463 |     } | 
 | 464 |     dlclose(hdl); | 
 | 465 |     return ret; | 
 | 466 | } | 
 | 467 |  | 
 | 468 | int unloadLibrary(int handle) | 
 | 469 | { | 
 | 470 |     void *hdl; | 
 | 471 |     int ret; | 
 | 472 |     list_elem_t *el1, *el2; | 
 | 473 |     lib_entry_t *l; | 
 | 474 |     effect_entry_t *fx; | 
 | 475 |  | 
 | 476 |     pthread_mutex_lock(&gLibLock); | 
 | 477 |     el1 = gLibraryList; | 
 | 478 |     el2 = NULL; | 
 | 479 |     while (el1) { | 
 | 480 |         l = (lib_entry_t *)el1->object; | 
 | 481 |         if (handle == (int)l->handle) { | 
 | 482 |             if (el2) { | 
 | 483 |                 el2->next = el1->next; | 
 | 484 |             } else { | 
 | 485 |                 gLibraryList = el1->next; | 
 | 486 |             } | 
 | 487 |             free(el1); | 
 | 488 |             break; | 
 | 489 |         } | 
 | 490 |         el2 = el1; | 
 | 491 |         el1 = el1->next; | 
 | 492 |     } | 
 | 493 |     pthread_mutex_unlock(&gLibLock); | 
 | 494 |     if (el1 == NULL) { | 
 | 495 |         return -ENOENT; | 
 | 496 |     } | 
 | 497 |  | 
 | 498 |     // clear effect descriptor list | 
 | 499 |     el1 = l->effects; | 
 | 500 |     while (el1) { | 
 | 501 |         free(el1->object); | 
 | 502 |         el2 = el1->next; | 
 | 503 |         free(el1); | 
 | 504 |         el1 = el2; | 
 | 505 |     } | 
 | 506 |  | 
 | 507 |     // disable all effects from this library | 
 | 508 |     pthread_mutex_lock(&l->lock); | 
 | 509 |     el1 = gEffectList; | 
 | 510 |     while (el1) { | 
 | 511 |         fx = (effect_entry_t *)el1->object; | 
 | 512 |         if (fx->lib == l) { | 
 | 513 |             fx->lib = NULL; | 
 | 514 |         } | 
 | 515 |         el1 = el1->next; | 
 | 516 |     } | 
 | 517 |     pthread_mutex_unlock(&l->lock); | 
 | 518 |  | 
 | 519 |     dlclose(l->handle); | 
 | 520 |     free(l); | 
 | 521 |     return 0; | 
 | 522 | } | 
 | 523 |  | 
 | 524 |  | 
 | 525 |  | 
 | 526 | int numEffectModules() { | 
 | 527 |     list_elem_t *e = gLibraryList; | 
 | 528 |     int cnt = 0; | 
 | 529 |  | 
 | 530 |     // Reset pointers for EffectQueryNext() | 
 | 531 |     gCurLib = e; | 
 | 532 |     if (e) { | 
 | 533 |         gCurEffect = ((lib_entry_t *)e->object)->effects; | 
 | 534 |     } | 
 | 535 |     while (e) { | 
 | 536 |         lib_entry_t *l = (lib_entry_t *)e->object; | 
 | 537 |         list_elem_t *efx = l->effects; | 
 | 538 |         while (efx) { | 
 | 539 |             cnt++; | 
 | 540 |             efx = efx->next; | 
 | 541 |         } | 
 | 542 |         e = e->next; | 
 | 543 |     } | 
 | 544 |     return cnt; | 
 | 545 | } | 
 | 546 |  | 
 | 547 | int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc) | 
 | 548 | { | 
 | 549 |     list_elem_t *e = gLibraryList; | 
 | 550 |     lib_entry_t *l = NULL; | 
 | 551 |     effect_descriptor_t *d = NULL; | 
 | 552 |     int found = 0; | 
 | 553 |     int ret = 0; | 
 | 554 |  | 
 | 555 |     while (e && !found) { | 
 | 556 |         l = (lib_entry_t *)e->object; | 
 | 557 |         list_elem_t *efx = l->effects; | 
 | 558 |         while (efx) { | 
 | 559 |             d = (effect_descriptor_t *)efx->object; | 
 | 560 |             if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { | 
 | 561 |                 found = 1; | 
 | 562 |                 break; | 
 | 563 |             } | 
 | 564 |             efx = efx->next; | 
 | 565 |         } | 
 | 566 |         e = e->next; | 
 | 567 |     } | 
 | 568 |     if (!found) { | 
 | 569 |         LOGV("findEffect() effect not found"); | 
 | 570 |         ret = -ENOENT; | 
 | 571 |     } else { | 
 | 572 |         LOGV("findEffect() found effect: %s in lib %s", d->name, l->path); | 
 | 573 |         *lib = l; | 
 | 574 |         *desc = d; | 
 | 575 |     } | 
 | 576 |  | 
 | 577 |     return ret; | 
 | 578 | } | 
 | 579 |  | 
 | 580 | void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) { | 
 | 581 |     char s[256]; | 
 | 582 |  | 
 | 583 |     snprintf(str, len, "\nEffect Descriptor %p:\n", desc); | 
 | 584 |     sprintf(s, "- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", | 
 | 585 |             desc->uuid.timeLow, desc->uuid.timeMid, desc->uuid.timeHiAndVersion, | 
 | 586 |             desc->uuid.clockSeq, desc->uuid.node[0], desc->uuid.node[1],desc->uuid.node[2], | 
 | 587 |             desc->uuid.node[3],desc->uuid.node[4],desc->uuid.node[5]); | 
 | 588 |     strncat(str, s, len); | 
 | 589 |     sprintf(s, "- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", | 
 | 590 |                 desc->type.timeLow, desc->type.timeMid, desc->type.timeHiAndVersion, | 
 | 591 |                 desc->type.clockSeq, desc->type.node[0], desc->type.node[1],desc->type.node[2], | 
 | 592 |                 desc->type.node[3],desc->type.node[4],desc->type.node[5]); | 
 | 593 |     strncat(str, s, len); | 
 | 594 |     sprintf(s, "- apiVersion: %04X\n- flags: %08X\n", | 
 | 595 |             desc->apiVersion, desc->flags); | 
 | 596 |     strncat(str, s, len); | 
 | 597 |     sprintf(s, "- name: %s\n", desc->name); | 
 | 598 |     strncat(str, s, len); | 
 | 599 |     sprintf(s, "- implementor: %s\n", desc->implementor); | 
 | 600 |     strncat(str, s, len); | 
 | 601 | } | 
 | 602 |  |