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