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