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 #include <cutils/misc.h> 26 #include <cutils/config_utils.h> 27 #include <audio_effects/audio_effects_conf.h> 28 29 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects 30 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries 31 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList 32 static uint32_t gNumEffects; // total number number of effects 33 static list_elem_t *gCurLib; // current library in enumeration process 34 static list_elem_t *gCurEffect; // current effect in enumeration process 35 static uint32_t gCurEffectIdx; // current effect index in enumeration process 36 static lib_entry_t *gCachedLibrary; // last library accessed by getLibrary() 37 38 static int gInitDone; // true is global initialization has been preformed 39 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects 40 // was not modified since last call to EffectQueryNumberEffects() 41 42 43 ///////////////////////////////////////////////// 44 // Local functions prototypes 45 ///////////////////////////////////////////////// 46 47 static int init(); 48 static int loadEffectConfigFile(const char *path); 49 static int loadLibraries(cnode *root); 50 static int loadLibrary(cnode *root, const char *name); 51 static int loadEffects(cnode *root); 52 static int loadEffect(cnode *node); 53 static lib_entry_t *getLibrary(const char *path); 54 static void resetEffectEnumeration(); 55 static uint32_t updateNumEffects(); 56 static int findEffect(effect_uuid_t *type, 57 effect_uuid_t *uuid, 58 lib_entry_t **lib, 59 effect_descriptor_t **desc); 60 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len); 61 static int stringToUuid(const char *str, effect_uuid_t *uuid); 62 static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen); 63 64 ///////////////////////////////////////////////// 65 // Effect Control Interface functions 66 ///////////////////////////////////////////////// 67 68 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 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)->process(fx->subItfe, inBuffer, outBuffer); 84 pthread_mutex_unlock(&fx->lib->lock); 85 return ret; 86 } 87 88 int Effect_Command(effect_handle_t self, 89 uint32_t cmdCode, 90 uint32_t cmdSize, 91 void *pCmdData, 92 uint32_t *replySize, 93 void *pReplyData) 94 { 95 int ret = init(); 96 if (ret < 0) { 97 return ret; 98 } 99 effect_entry_t *fx = (effect_entry_t *)self; 100 pthread_mutex_lock(&gLibLock); 101 if (fx->lib == NULL) { 102 pthread_mutex_unlock(&gLibLock); 103 return -EPIPE; 104 } 105 pthread_mutex_lock(&fx->lib->lock); 106 pthread_mutex_unlock(&gLibLock); 107 108 ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData); 109 pthread_mutex_unlock(&fx->lib->lock); 110 return ret; 111 } 112 113 int Effect_GetDescriptor(effect_handle_t self, 114 effect_descriptor_t *desc) 115 { 116 int ret = init(); 117 if (ret < 0) { 118 return ret; 119 } 120 effect_entry_t *fx = (effect_entry_t *)self; 121 pthread_mutex_lock(&gLibLock); 122 if (fx->lib == NULL) { 123 pthread_mutex_unlock(&gLibLock); 124 return -EPIPE; 125 } 126 pthread_mutex_lock(&fx->lib->lock); 127 pthread_mutex_unlock(&gLibLock); 128 129 ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc); 130 pthread_mutex_unlock(&fx->lib->lock); 131 return ret; 132 } 133 134 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 135 { 136 int ret = init(); 137 if (ret < 0) { 138 return ret; 139 } 140 effect_entry_t *fx = (effect_entry_t *)self; 141 pthread_mutex_lock(&gLibLock); 142 if (fx->lib == NULL) { 143 pthread_mutex_unlock(&gLibLock); 144 return -EPIPE; 145 } 146 pthread_mutex_lock(&fx->lib->lock); 147 pthread_mutex_unlock(&gLibLock); 148 149 if ((*fx->subItfe)->process_reverse != NULL) { 150 ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer); 151 } else { 152 ret = -ENOSYS; 153 } 154 pthread_mutex_unlock(&fx->lib->lock); 155 return ret; 156 } 157 158 159 const struct effect_interface_s gInterface = { 160 Effect_Process, 161 Effect_Command, 162 Effect_GetDescriptor, 163 NULL 164 }; 165 166 const struct effect_interface_s gInterfaceWithReverse = { 167 Effect_Process, 168 Effect_Command, 169 Effect_GetDescriptor, 170 Effect_ProcessReverse 171 }; 172 173 ///////////////////////////////////////////////// 174 // Effect Factory Interface functions 175 ///////////////////////////////////////////////// 176 177 int EffectQueryNumberEffects(uint32_t *pNumEffects) 178 { 179 int ret = init(); 180 if (ret < 0) { 181 return ret; 182 } 183 if (pNumEffects == NULL) { 184 return -EINVAL; 185 } 186 187 pthread_mutex_lock(&gLibLock); 188 *pNumEffects = gNumEffects; 189 gCanQueryEffect = 1; 190 pthread_mutex_unlock(&gLibLock); 191 LOGV("EffectQueryNumberEffects(): %d", *pNumEffects); 192 return ret; 193 } 194 195 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) 196 { 197 int ret = init(); 198 if (ret < 0) { 199 return ret; 200 } 201 if (pDescriptor == NULL || 202 index >= gNumEffects) { 203 return -EINVAL; 204 } 205 if (gCanQueryEffect == 0) { 206 return -ENOSYS; 207 } 208 209 pthread_mutex_lock(&gLibLock); 210 ret = -ENOENT; 211 if (index < gCurEffectIdx) { 212 resetEffectEnumeration(); 213 } 214 while (gCurLib) { 215 if (gCurEffect) { 216 if (index == gCurEffectIdx) { 217 memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t)); 218 ret = 0; 219 break; 220 } else { 221 gCurEffect = gCurEffect->next; 222 gCurEffectIdx++; 223 } 224 } else { 225 gCurLib = gCurLib->next; 226 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; 227 } 228 } 229 230 #if (LOG_NDEBUG == 0) 231 char str[256]; 232 dumpEffectDescriptor(pDescriptor, str, 256); 233 LOGV("EffectQueryEffect() desc:%s", str); 234 #endif 235 pthread_mutex_unlock(&gLibLock); 236 return ret; 237 } 238 239 int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) 240 { 241 lib_entry_t *l = NULL; 242 effect_descriptor_t *d = NULL; 243 244 int ret = init(); 245 if (ret < 0) { 246 return ret; 247 } 248 if (pDescriptor == NULL || uuid == NULL) { 249 return -EINVAL; 250 } 251 pthread_mutex_lock(&gLibLock); 252 ret = findEffect(NULL, uuid, &l, &d); 253 if (ret == 0) { 254 memcpy(pDescriptor, d, sizeof(effect_descriptor_t)); 255 } 256 pthread_mutex_unlock(&gLibLock); 257 return ret; 258 } 259 260 int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle) 261 { 262 list_elem_t *e = gLibraryList; 263 lib_entry_t *l = NULL; 264 effect_descriptor_t *d = NULL; 265 effect_handle_t itfe; 266 effect_entry_t *fx; 267 int found = 0; 268 int ret; 269 270 if (uuid == NULL || pHandle == NULL) { 271 return -EINVAL; 272 } 273 274 LOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", 275 uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, 276 uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], 277 uuid->node[3],uuid->node[4],uuid->node[5]); 278 279 ret = init(); 280 281 if (ret < 0) { 282 LOGW("EffectCreate() init error: %d", ret); 283 return ret; 284 } 285 286 pthread_mutex_lock(&gLibLock); 287 288 ret = findEffect(NULL, uuid, &l, &d); 289 if (ret < 0){ 290 goto exit; 291 } 292 293 // create effect in library 294 ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe); 295 if (ret != 0) { 296 LOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret); 297 goto exit; 298 } 299 300 // add entry to effect list 301 fx = (effect_entry_t *)malloc(sizeof(effect_entry_t)); 302 fx->subItfe = itfe; 303 if ((*itfe)->process_reverse != NULL) { 304 fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse; 305 LOGV("EffectCreate() gInterfaceWithReverse"); 306 } else { 307 fx->itfe = (struct effect_interface_s *)&gInterface; 308 LOGV("EffectCreate() gInterface"); 309 } 310 fx->lib = l; 311 312 e = (list_elem_t *)malloc(sizeof(list_elem_t)); 313 e->object = fx; 314 e->next = gEffectList; 315 gEffectList = e; 316 317 *pHandle = (effect_handle_t)fx; 318 319 LOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name); 320 321 exit: 322 pthread_mutex_unlock(&gLibLock); 323 return ret; 324 } 325 326 int EffectRelease(effect_handle_t handle) 327 { 328 effect_entry_t *fx; 329 list_elem_t *e1; 330 list_elem_t *e2; 331 332 int ret = init(); 333 if (ret < 0) { 334 return ret; 335 } 336 337 // remove effect from effect list 338 pthread_mutex_lock(&gLibLock); 339 e1 = gEffectList; 340 e2 = NULL; 341 while (e1) { 342 if (e1->object == handle) { 343 if (e2) { 344 e2->next = e1->next; 345 } else { 346 gEffectList = e1->next; 347 } 348 fx = (effect_entry_t *)e1->object; 349 free(e1); 350 break; 351 } 352 e2 = e1; 353 e1 = e1->next; 354 } 355 if (e1 == NULL) { 356 ret = -ENOENT; 357 goto exit; 358 } 359 360 // release effect in library 361 if (fx->lib == NULL) { 362 LOGW("EffectRelease() fx %p library already unloaded", handle); 363 } else { 364 pthread_mutex_lock(&fx->lib->lock); 365 fx->lib->desc->release_effect(fx->subItfe); 366 pthread_mutex_unlock(&fx->lib->lock); 367 } 368 free(fx); 369 370 exit: 371 pthread_mutex_unlock(&gLibLock); 372 return ret; 373 } 374 375 int EffectIsNullUuid(effect_uuid_t *uuid) 376 { 377 if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) { 378 return 0; 379 } 380 return 1; 381 } 382 383 ///////////////////////////////////////////////// 384 // Local functions 385 ///////////////////////////////////////////////// 386 387 int init() { 388 int hdl; 389 390 if (gInitDone) { 391 return 0; 392 } 393 394 pthread_mutex_init(&gLibLock, NULL); 395 396 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { 397 loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE); 398 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { 399 loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); 400 } 401 402 updateNumEffects(); 403 gInitDone = 1; 404 LOGV("init() done"); 405 return 0; 406 } 407 408 int loadEffectConfigFile(const char *path) 409 { 410 cnode *root; 411 char *data; 412 413 data = load_file(path, NULL); 414 if (data == NULL) { 415 return -ENODEV; 416 } 417 root = config_node("", ""); 418 config_load(root, data); 419 loadLibraries(root); 420 loadEffects(root); 421 config_free(root); 422 free(root); 423 free(data); 424 425 return 0; 426 } 427 428 int loadLibraries(cnode *root) 429 { 430 cnode *node; 431 432 node = config_find(root, LIBRARIES_TAG); 433 if (node == NULL) { 434 return -ENOENT; 435 } 436 node = node->first_child; 437 while (node) { 438 loadLibrary(node, node->name); 439 node = node->next; 440 } 441 return 0; 442 } 443 444 int loadLibrary(cnode *root, const char *name) 445 { 446 cnode *node; 447 void *hdl; 448 audio_effect_library_t *desc; 449 list_elem_t *e; 450 lib_entry_t *l; 451 452 node = config_find(root, PATH_TAG); 453 if (node == NULL) { 454 return -EINVAL; 455 } 456 457 hdl = dlopen(node->value, RTLD_NOW); 458 if (hdl == NULL) { 459 LOGW("loadLibrary() failed to open %s", node->value); 460 goto error; 461 } 462 463 desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 464 if (desc == NULL) { 465 LOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 466 goto error; 467 } 468 469 if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) { 470 LOGW("getLibrary() bad tag %08x in lib info struct", desc->tag); 471 goto error; 472 } 473 474 if (EFFECT_API_VERSION_MAJOR(desc->version) != 475 EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) { 476 LOGW("loadLibrary() bad lib version %08x", desc->version); 477 goto error; 478 } 479 480 // add entry for library in gLibraryList 481 l = malloc(sizeof(lib_entry_t)); 482 l->name = strndup(name, PATH_MAX); 483 l->path = strndup(node->value, PATH_MAX); 484 l->handle = hdl; 485 l->desc = desc; 486 l->effects = NULL; 487 pthread_mutex_init(&l->lock, NULL); 488 489 e = malloc(sizeof(list_elem_t)); 490 e->object = l; 491 pthread_mutex_lock(&gLibLock); 492 e->next = gLibraryList; 493 gLibraryList = e; 494 pthread_mutex_unlock(&gLibLock); 495 LOGV("getLibrary() linked library %p for path %s", l, node->value); 496 497 return 0; 498 499 error: 500 if (hdl != NULL) { 501 dlclose(hdl); 502 } 503 return -EINVAL; 504 } 505 506 int loadEffects(cnode *root) 507 { 508 cnode *node; 509 510 node = config_find(root, EFFECTS_TAG); 511 if (node == NULL) { 512 return -ENOENT; 513 } 514 node = node->first_child; 515 while (node) { 516 loadEffect(node); 517 node = node->next; 518 } 519 return 0; 520 } 521 522 int loadEffect(cnode *root) 523 { 524 cnode *node; 525 effect_uuid_t uuid; 526 lib_entry_t *l; 527 effect_descriptor_t *d; 528 list_elem_t *e; 529 530 node = config_find(root, LIBRARY_TAG); 531 if (node == NULL) { 532 return -EINVAL; 533 } 534 535 l = getLibrary(node->value); 536 if (l == NULL) { 537 LOGW("loadEffect() could not get library %s", node->value); 538 return -EINVAL; 539 } 540 541 node = config_find(root, UUID_TAG); 542 if (node == NULL) { 543 return -EINVAL; 544 } 545 if (stringToUuid(node->value, &uuid) != 0) { 546 LOGW("loadEffect() invalid uuid %s", node->value); 547 return -EINVAL; 548 } 549 550 d = malloc(sizeof(effect_descriptor_t)); 551 if (l->desc->get_descriptor(&uuid, d) != 0) { 552 char s[40]; 553 uuidToString(&uuid, s, 40); 554 LOGW("Error querying effect %s on lib %s", s, l->name); 555 free(d); 556 return -EINVAL; 557 } 558 #if (LOG_NDEBUG==0) 559 char s[256]; 560 dumpEffectDescriptor(d, s, 256); 561 LOGV("loadEffect() read descriptor %p:%s",d, s); 562 #endif 563 if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != 564 EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { 565 LOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); 566 free(d); 567 return -EINVAL; 568 } 569 e = malloc(sizeof(list_elem_t)); 570 e->object = d; 571 e->next = l->effects; 572 l->effects = e; 573 574 return 0; 575 } 576 577 lib_entry_t *getLibrary(const char *name) 578 { 579 list_elem_t *e; 580 581 if (gCachedLibrary && 582 !strncmp(gCachedLibrary->name, name, PATH_MAX)) { 583 return gCachedLibrary; 584 } 585 586 e = gLibraryList; 587 while (e) { 588 lib_entry_t *l = (lib_entry_t *)e->object; 589 if (!strcmp(l->name, name)) { 590 gCachedLibrary = l; 591 return l; 592 } 593 e = e->next; 594 } 595 596 return NULL; 597 } 598 599 600 void resetEffectEnumeration() 601 { 602 gCurLib = gLibraryList; 603 gCurEffect = NULL; 604 if (gCurLib) { 605 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; 606 } 607 gCurEffectIdx = 0; 608 } 609 610 uint32_t updateNumEffects() { 611 list_elem_t *e; 612 uint32_t cnt = 0; 613 614 resetEffectEnumeration(); 615 616 e = gLibraryList; 617 while (e) { 618 lib_entry_t *l = (lib_entry_t *)e->object; 619 list_elem_t *efx = l->effects; 620 while (efx) { 621 cnt++; 622 efx = efx->next; 623 } 624 e = e->next; 625 } 626 gNumEffects = cnt; 627 gCanQueryEffect = 0; 628 return cnt; 629 } 630 631 int findEffect(effect_uuid_t *type, 632 effect_uuid_t *uuid, 633 lib_entry_t **lib, 634 effect_descriptor_t **desc) 635 { 636 list_elem_t *e = gLibraryList; 637 lib_entry_t *l = NULL; 638 effect_descriptor_t *d = NULL; 639 int found = 0; 640 int ret = 0; 641 642 while (e && !found) { 643 l = (lib_entry_t *)e->object; 644 list_elem_t *efx = l->effects; 645 while (efx) { 646 d = (effect_descriptor_t *)efx->object; 647 if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) { 648 found = 1; 649 break; 650 } 651 if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { 652 found = 1; 653 break; 654 } 655 efx = efx->next; 656 } 657 e = e->next; 658 } 659 if (!found) { 660 LOGV("findEffect() effect not found"); 661 ret = -ENOENT; 662 } else { 663 LOGV("findEffect() found effect: %s in lib %s", d->name, l->name); 664 *lib = l; 665 if (desc) { 666 *desc = d; 667 } 668 } 669 670 return ret; 671 } 672 673 void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) { 674 char s[256]; 675 676 snprintf(str, len, "\nEffect Descriptor %p:\n", desc); 677 strncat(str, "- TYPE: ", len); 678 uuidToString(&desc->uuid, s, 256); 679 snprintf(str, len, "- UUID: %s\n", s); 680 uuidToString(&desc->type, s, 256); 681 snprintf(str, len, "- TYPE: %s\n", s); 682 sprintf(s, "- apiVersion: %08X\n- flags: %08X\n", 683 desc->apiVersion, desc->flags); 684 strncat(str, s, len); 685 sprintf(s, "- name: %s\n", desc->name); 686 strncat(str, s, len); 687 sprintf(s, "- implementor: %s\n", desc->implementor); 688 strncat(str, s, len); 689 } 690 691 int stringToUuid(const char *str, effect_uuid_t *uuid) 692 { 693 int tmp[10]; 694 695 if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 696 tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { 697 return -EINVAL; 698 } 699 uuid->timeLow = (uint32_t)tmp[0]; 700 uuid->timeMid = (uint16_t)tmp[1]; 701 uuid->timeHiAndVersion = (uint16_t)tmp[2]; 702 uuid->clockSeq = (uint16_t)tmp[3]; 703 uuid->node[0] = (uint8_t)tmp[4]; 704 uuid->node[1] = (uint8_t)tmp[5]; 705 uuid->node[2] = (uint8_t)tmp[6]; 706 uuid->node[3] = (uint8_t)tmp[7]; 707 uuid->node[4] = (uint8_t)tmp[8]; 708 uuid->node[5] = (uint8_t)tmp[9]; 709 710 return 0; 711 } 712 713 int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen) 714 { 715 716 snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 717 uuid->timeLow, 718 uuid->timeMid, 719 uuid->timeHiAndVersion, 720 uuid->clockSeq, 721 uuid->node[0], 722 uuid->node[1], 723 uuid->node[2], 724 uuid->node[3], 725 uuid->node[4], 726 uuid->node[5]); 727 728 return 0; 729 } 730 731