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 22 #include <dlfcn.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include <cutils/config_utils.h> 28 #include <cutils/misc.h> 29 #include <cutils/properties.h> 30 #include <log/log.h> 31 32 #include <system/audio_effects/audio_effects_conf.h> 33 34 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects 35 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries 36 static list_elem_t *gSkippedEffects; // list of effects skipped because of duplicate uuid 37 // list of effect_descriptor and list of sub effects : all currently loaded 38 // It does not contain effects without sub effects. 39 static list_sub_elem_t *gSubEffectList; 40 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList 41 static uint32_t gNumEffects; // total number number of effects 42 static list_elem_t *gCurLib; // current library in enumeration process 43 static list_elem_t *gCurEffect; // current effect in enumeration process 44 static uint32_t gCurEffectIdx; // current effect index in enumeration process 45 static lib_entry_t *gCachedLibrary; // last library accessed by getLibrary() 46 47 static int gInitDone; // true is global initialization has been preformed 48 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects 49 // was not modified since last call to EffectQueryNumberEffects() 50 51 static list_elem_t *gLibraryFailedList; //list of lib_failed_entry_t: libraries failed to load 52 53 ///////////////////////////////////////////////// 54 // Local functions prototypes 55 ///////////////////////////////////////////////// 56 57 static int init(); 58 static int loadEffectConfigFile(const char *path); 59 static int loadLibraries(cnode *root); 60 static int loadLibrary(cnode *root, const char *name); 61 static int loadEffects(cnode *root); 62 static int loadEffect(cnode *node); 63 // To get and add the effect pointed by the passed node to the gSubEffectList 64 static int addSubEffect(cnode *root); 65 static lib_entry_t *getLibrary(const char *path); 66 static void resetEffectEnumeration(); 67 static uint32_t updateNumEffects(); 68 static int findEffect(const effect_uuid_t *type, 69 const effect_uuid_t *uuid, 70 lib_entry_t **lib, 71 effect_descriptor_t **desc); 72 // To search a subeffect in the gSubEffectList 73 static int findSubEffect(const effect_uuid_t *uuid, 74 lib_entry_t **lib, 75 effect_descriptor_t **desc); 76 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent); 77 static int stringToUuid(const char *str, effect_uuid_t *uuid); 78 static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen); 79 80 ///////////////////////////////////////////////// 81 // Effect Control Interface functions 82 ///////////////////////////////////////////////// 83 84 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 85 { 86 int ret = init(); 87 if (ret < 0) { 88 return ret; 89 } 90 effect_entry_t *fx = (effect_entry_t *)self; 91 pthread_mutex_lock(&gLibLock); 92 if (fx->lib == NULL) { 93 pthread_mutex_unlock(&gLibLock); 94 return -EPIPE; 95 } 96 pthread_mutex_lock(&fx->lib->lock); 97 pthread_mutex_unlock(&gLibLock); 98 99 ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer); 100 pthread_mutex_unlock(&fx->lib->lock); 101 return ret; 102 } 103 104 int Effect_Command(effect_handle_t self, 105 uint32_t cmdCode, 106 uint32_t cmdSize, 107 void *pCmdData, 108 uint32_t *replySize, 109 void *pReplyData) 110 { 111 int ret = init(); 112 if (ret < 0) { 113 return ret; 114 } 115 effect_entry_t *fx = (effect_entry_t *)self; 116 pthread_mutex_lock(&gLibLock); 117 if (fx->lib == NULL) { 118 pthread_mutex_unlock(&gLibLock); 119 return -EPIPE; 120 } 121 pthread_mutex_lock(&fx->lib->lock); 122 pthread_mutex_unlock(&gLibLock); 123 124 ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData); 125 pthread_mutex_unlock(&fx->lib->lock); 126 return ret; 127 } 128 129 int Effect_GetDescriptor(effect_handle_t self, 130 effect_descriptor_t *desc) 131 { 132 int ret = init(); 133 if (ret < 0) { 134 return ret; 135 } 136 effect_entry_t *fx = (effect_entry_t *)self; 137 pthread_mutex_lock(&gLibLock); 138 if (fx->lib == NULL) { 139 pthread_mutex_unlock(&gLibLock); 140 return -EPIPE; 141 } 142 pthread_mutex_lock(&fx->lib->lock); 143 pthread_mutex_unlock(&gLibLock); 144 145 ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc); 146 pthread_mutex_unlock(&fx->lib->lock); 147 return ret; 148 } 149 150 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 151 { 152 int ret = init(); 153 if (ret < 0) { 154 return ret; 155 } 156 effect_entry_t *fx = (effect_entry_t *)self; 157 pthread_mutex_lock(&gLibLock); 158 if (fx->lib == NULL) { 159 pthread_mutex_unlock(&gLibLock); 160 return -EPIPE; 161 } 162 pthread_mutex_lock(&fx->lib->lock); 163 pthread_mutex_unlock(&gLibLock); 164 165 if ((*fx->subItfe)->process_reverse != NULL) { 166 ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer); 167 } else { 168 ret = -ENOSYS; 169 } 170 pthread_mutex_unlock(&fx->lib->lock); 171 return ret; 172 } 173 174 175 const struct effect_interface_s gInterface = { 176 Effect_Process, 177 Effect_Command, 178 Effect_GetDescriptor, 179 NULL 180 }; 181 182 const struct effect_interface_s gInterfaceWithReverse = { 183 Effect_Process, 184 Effect_Command, 185 Effect_GetDescriptor, 186 Effect_ProcessReverse 187 }; 188 189 ///////////////////////////////////////////////// 190 // Effect Factory Interface functions 191 ///////////////////////////////////////////////// 192 193 int EffectQueryNumberEffects(uint32_t *pNumEffects) 194 { 195 int ret = init(); 196 if (ret < 0) { 197 return ret; 198 } 199 if (pNumEffects == NULL) { 200 return -EINVAL; 201 } 202 203 pthread_mutex_lock(&gLibLock); 204 *pNumEffects = gNumEffects; 205 gCanQueryEffect = 1; 206 pthread_mutex_unlock(&gLibLock); 207 ALOGV("EffectQueryNumberEffects(): %d", *pNumEffects); 208 return ret; 209 } 210 211 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) 212 { 213 int ret = init(); 214 if (ret < 0) { 215 return ret; 216 } 217 if (pDescriptor == NULL || 218 index >= gNumEffects) { 219 return -EINVAL; 220 } 221 if (gCanQueryEffect == 0) { 222 return -ENOSYS; 223 } 224 225 pthread_mutex_lock(&gLibLock); 226 ret = -ENOENT; 227 if (index < gCurEffectIdx) { 228 resetEffectEnumeration(); 229 } 230 while (gCurLib) { 231 if (gCurEffect) { 232 if (index == gCurEffectIdx) { 233 *pDescriptor = *(effect_descriptor_t *)gCurEffect->object; 234 ret = 0; 235 break; 236 } else { 237 gCurEffect = gCurEffect->next; 238 gCurEffectIdx++; 239 } 240 } else { 241 gCurLib = gCurLib->next; 242 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; 243 } 244 } 245 246 #if (LOG_NDEBUG == 0) 247 char str[512]; 248 dumpEffectDescriptor(pDescriptor, str, sizeof(str), 0 /* indent */); 249 ALOGV("EffectQueryEffect() desc:%s", str); 250 #endif 251 pthread_mutex_unlock(&gLibLock); 252 return ret; 253 } 254 255 int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) 256 { 257 lib_entry_t *l = NULL; 258 effect_descriptor_t *d = NULL; 259 260 int ret = init(); 261 if (ret < 0) { 262 return ret; 263 } 264 if (pDescriptor == NULL || uuid == NULL) { 265 return -EINVAL; 266 } 267 pthread_mutex_lock(&gLibLock); 268 ret = findEffect(NULL, uuid, &l, &d); 269 if (ret == 0) { 270 *pDescriptor = *d; 271 } 272 pthread_mutex_unlock(&gLibLock); 273 return ret; 274 } 275 276 int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle) 277 { 278 list_elem_t *e = gLibraryList; 279 lib_entry_t *l = NULL; 280 effect_descriptor_t *d = NULL; 281 effect_handle_t itfe; 282 effect_entry_t *fx; 283 int found = 0; 284 int ret; 285 286 if (uuid == NULL || pHandle == NULL) { 287 return -EINVAL; 288 } 289 290 ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", 291 uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, 292 uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], 293 uuid->node[3],uuid->node[4],uuid->node[5]); 294 295 ret = init(); 296 297 if (ret < 0) { 298 ALOGW("EffectCreate() init error: %d", ret); 299 return ret; 300 } 301 302 pthread_mutex_lock(&gLibLock); 303 304 ret = findEffect(NULL, uuid, &l, &d); 305 if (ret < 0){ 306 // Sub effects are not associated with the library->effects, 307 // so, findEffect will fail. Search for the effect in gSubEffectList. 308 ret = findSubEffect(uuid, &l, &d); 309 if (ret < 0 ) { 310 goto exit; 311 } 312 } 313 314 // create effect in library 315 ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe); 316 if (ret != 0) { 317 ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret); 318 goto exit; 319 } 320 321 // add entry to effect list 322 fx = (effect_entry_t *)malloc(sizeof(effect_entry_t)); 323 fx->subItfe = itfe; 324 if ((*itfe)->process_reverse != NULL) { 325 fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse; 326 ALOGV("EffectCreate() gInterfaceWithReverse"); 327 } else { 328 fx->itfe = (struct effect_interface_s *)&gInterface; 329 ALOGV("EffectCreate() gInterface"); 330 } 331 fx->lib = l; 332 333 e = (list_elem_t *)malloc(sizeof(list_elem_t)); 334 e->object = fx; 335 e->next = gEffectList; 336 gEffectList = e; 337 338 *pHandle = (effect_handle_t)fx; 339 340 ALOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name); 341 342 exit: 343 pthread_mutex_unlock(&gLibLock); 344 return ret; 345 } 346 347 int EffectRelease(effect_handle_t handle) 348 { 349 effect_entry_t *fx; 350 list_elem_t *e1; 351 list_elem_t *e2; 352 353 int ret = init(); 354 if (ret < 0) { 355 return ret; 356 } 357 358 // remove effect from effect list 359 pthread_mutex_lock(&gLibLock); 360 e1 = gEffectList; 361 e2 = NULL; 362 while (e1) { 363 if (e1->object == handle) { 364 if (e2) { 365 e2->next = e1->next; 366 } else { 367 gEffectList = e1->next; 368 } 369 fx = (effect_entry_t *)e1->object; 370 free(e1); 371 break; 372 } 373 e2 = e1; 374 e1 = e1->next; 375 } 376 if (e1 == NULL) { 377 ret = -ENOENT; 378 goto exit; 379 } 380 381 // release effect in library 382 if (fx->lib == NULL) { 383 ALOGW("EffectRelease() fx %p library already unloaded", handle); 384 } else { 385 pthread_mutex_lock(&fx->lib->lock); 386 fx->lib->desc->release_effect(fx->subItfe); 387 pthread_mutex_unlock(&fx->lib->lock); 388 } 389 free(fx); 390 391 exit: 392 pthread_mutex_unlock(&gLibLock); 393 return ret; 394 } 395 396 int EffectIsNullUuid(const effect_uuid_t *uuid) 397 { 398 if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) { 399 return 0; 400 } 401 return 1; 402 } 403 404 // Function to get the sub effect descriptors of the effect whose uuid 405 // is pointed by the first argument. It searches the gSubEffectList for the 406 // matching uuid and then copies the corresponding sub effect descriptors 407 // to the inout param 408 int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube, 409 size_t size) 410 { 411 ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X" 412 "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, 413 uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], 414 uuid->node[3],uuid->node[4],uuid->node[5]); 415 416 // Check if the size of the desc buffer is large enough for 2 subeffects 417 if ((uuid == NULL) || (pSube == NULL) || (size < 2)) { 418 ALOGW("NULL pointer or insufficient memory. Cannot query subeffects"); 419 return -EINVAL; 420 } 421 int ret = init(); 422 if (ret < 0) 423 return ret; 424 list_sub_elem_t *e = gSubEffectList; 425 sub_effect_entry_t *subeffect; 426 effect_descriptor_t *d; 427 int count = 0; 428 while (e != NULL) { 429 d = (effect_descriptor_t*)e->object; 430 if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) { 431 ALOGV("EffectGetSubEffects: effect found in the list"); 432 list_elem_t *subefx = e->sub_elem; 433 while (subefx != NULL) { 434 subeffect = (sub_effect_entry_t*)subefx->object; 435 pSube[count++] = subeffect; 436 subefx = subefx->next; 437 } 438 ALOGV("EffectGetSubEffects end - copied the sub effect structures"); 439 return count; 440 } 441 e = e->next; 442 } 443 return -ENOENT; 444 } 445 ///////////////////////////////////////////////// 446 // Local functions 447 ///////////////////////////////////////////////// 448 449 int init() { 450 int hdl; 451 452 if (gInitDone) { 453 return 0; 454 } 455 456 // ignore effects or not? 457 const bool ignoreFxConfFiles = property_get_bool(PROPERTY_IGNORE_EFFECTS, false); 458 459 pthread_mutex_init(&gLibLock, NULL); 460 461 if (ignoreFxConfFiles) { 462 ALOGI("Audio effects in configuration files will be ignored"); 463 } else { 464 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { 465 loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE); 466 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { 467 loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); 468 } 469 } 470 471 updateNumEffects(); 472 gInitDone = 1; 473 ALOGV("init() done"); 474 return 0; 475 } 476 477 int loadEffectConfigFile(const char *path) 478 { 479 cnode *root; 480 char *data; 481 482 data = load_file(path, NULL); 483 if (data == NULL) { 484 return -ENODEV; 485 } 486 root = config_node("", ""); 487 config_load(root, data); 488 loadLibraries(root); 489 loadEffects(root); 490 config_free(root); 491 free(root); 492 free(data); 493 494 return 0; 495 } 496 497 int loadLibraries(cnode *root) 498 { 499 cnode *node; 500 501 node = config_find(root, LIBRARIES_TAG); 502 if (node == NULL) { 503 return -ENOENT; 504 } 505 node = node->first_child; 506 while (node) { 507 loadLibrary(node, node->name); 508 node = node->next; 509 } 510 return 0; 511 } 512 513 #ifdef __LP64__ 514 // audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed 515 static const char *kLibraryPathRoot[] = 516 {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"}; 517 #else 518 static const char *kLibraryPathRoot[] = 519 {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"}; 520 #endif 521 522 static const int kLibraryPathRootSize = 523 (sizeof(kLibraryPathRoot) / sizeof(kLibraryPathRoot[0])); 524 525 // Checks if the library path passed as lib_path_in can be opened and if not 526 // tries in standard effect library directories with just the library name and returns correct path 527 // in lib_path_out 528 int checkLibraryPath(const char *lib_path_in, char *lib_path_out) { 529 char *str; 530 const char *lib_name; 531 size_t len; 532 533 if (lib_path_in == NULL || lib_path_out == NULL) { 534 return -EINVAL; 535 } 536 537 strlcpy(lib_path_out, lib_path_in, PATH_MAX); 538 539 // Try exact path first 540 str = strstr(lib_path_out, "/lib/soundfx/"); 541 if (str == NULL) { 542 return -EINVAL; 543 } 544 545 // Extract library name from input path 546 len = str - lib_path_out; 547 lib_name = lib_path_in + len + strlen("/lib/soundfx/"); 548 549 // Then try with library name and standard path names in order of preference 550 for (int i = 0; i < kLibraryPathRootSize; i++) { 551 char path[PATH_MAX]; 552 553 snprintf(path, 554 PATH_MAX, 555 "%s/%s", 556 kLibraryPathRoot[i], 557 lib_name); 558 if (F_OK == access(path, 0)) { 559 strcpy(lib_path_out, path); 560 ALOGW_IF(strncmp(lib_path_out, lib_path_in, PATH_MAX) != 0, 561 "checkLibraryPath() corrected library path %s to %s", lib_path_in, lib_path_out); 562 return 0; 563 } 564 } 565 return -EINVAL; 566 } 567 568 569 570 int loadLibrary(cnode *root, const char *name) 571 { 572 cnode *node; 573 void *hdl = NULL; 574 audio_effect_library_t *desc; 575 list_elem_t *e; 576 lib_entry_t *l; 577 char path[PATH_MAX]; 578 579 node = config_find(root, PATH_TAG); 580 if (node == NULL) { 581 return -EINVAL; 582 } 583 584 if (checkLibraryPath((const char *)node->value, path) != 0) { 585 ALOGW("loadLibrary() could not find library %s", path); 586 goto error; 587 } 588 589 hdl = dlopen(path, RTLD_NOW); 590 if (hdl == NULL) { 591 ALOGW("loadLibrary() failed to open %s", path); 592 goto error; 593 } 594 595 desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 596 if (desc == NULL) { 597 ALOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 598 goto error; 599 } 600 601 if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) { 602 ALOGW("getLibrary() bad tag %08x in lib info struct", desc->tag); 603 goto error; 604 } 605 606 if (EFFECT_API_VERSION_MAJOR(desc->version) != 607 EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) { 608 ALOGW("loadLibrary() bad lib version %08x", desc->version); 609 goto error; 610 } 611 612 // add entry for library in gLibraryList 613 l = malloc(sizeof(lib_entry_t)); 614 l->name = strndup(name, PATH_MAX); 615 l->path = strndup(path, PATH_MAX); 616 l->handle = hdl; 617 l->desc = desc; 618 l->effects = NULL; 619 pthread_mutex_init(&l->lock, NULL); 620 621 e = malloc(sizeof(list_elem_t)); 622 e->object = l; 623 pthread_mutex_lock(&gLibLock); 624 e->next = gLibraryList; 625 gLibraryList = e; 626 pthread_mutex_unlock(&gLibLock); 627 ALOGV("getLibrary() linked library %p for path %s", l, path); 628 629 return 0; 630 631 error: 632 if (hdl != NULL) { 633 dlclose(hdl); 634 } 635 //add entry for library errors in gLibraryFailedList 636 lib_failed_entry_t *fl = malloc(sizeof(lib_failed_entry_t)); 637 fl->name = strndup(name, PATH_MAX); 638 fl->path = strndup(path, PATH_MAX); 639 640 list_elem_t *fe = malloc(sizeof(list_elem_t)); 641 fe->object = fl; 642 fe->next = gLibraryFailedList; 643 gLibraryFailedList = fe; 644 ALOGV("getLibrary() linked error in library %p for path %s", fl, path); 645 646 return -EINVAL; 647 } 648 649 // This will find the library and UUID tags of the sub effect pointed by the 650 // node, gets the effect descriptor and lib_entry_t and adds the subeffect - 651 // sub_entry_t to the gSubEffectList 652 int addSubEffect(cnode *root) 653 { 654 ALOGV("addSubEffect"); 655 cnode *node; 656 effect_uuid_t uuid; 657 effect_descriptor_t *d; 658 lib_entry_t *l; 659 list_elem_t *e; 660 node = config_find(root, LIBRARY_TAG); 661 if (node == NULL) { 662 return -EINVAL; 663 } 664 l = getLibrary(node->value); 665 if (l == NULL) { 666 ALOGW("addSubEffect() could not get library %s", node->value); 667 return -EINVAL; 668 } 669 node = config_find(root, UUID_TAG); 670 if (node == NULL) { 671 return -EINVAL; 672 } 673 if (stringToUuid(node->value, &uuid) != 0) { 674 ALOGW("addSubEffect() invalid uuid %s", node->value); 675 return -EINVAL; 676 } 677 d = malloc(sizeof(effect_descriptor_t)); 678 if (l->desc->get_descriptor(&uuid, d) != 0) { 679 char s[40]; 680 uuidToString(&uuid, s, 40); 681 ALOGW("Error querying effect %s on lib %s", s, l->name); 682 free(d); 683 return -EINVAL; 684 } 685 #if (LOG_NDEBUG==0) 686 char s[512]; 687 dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */); 688 ALOGV("addSubEffect() read descriptor %p:%s",d, s); 689 #endif 690 if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != 691 EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { 692 ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); 693 free(d); 694 return -EINVAL; 695 } 696 sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t)); 697 sub_effect->object = d; 698 // lib_entry_t is stored since the sub effects are not linked to the library 699 sub_effect->lib = l; 700 e = malloc(sizeof(list_elem_t)); 701 e->object = sub_effect; 702 e->next = gSubEffectList->sub_elem; 703 gSubEffectList->sub_elem = e; 704 ALOGV("addSubEffect end"); 705 return 0; 706 } 707 708 int loadEffects(cnode *root) 709 { 710 cnode *node; 711 712 node = config_find(root, EFFECTS_TAG); 713 if (node == NULL) { 714 return -ENOENT; 715 } 716 node = node->first_child; 717 while (node) { 718 loadEffect(node); 719 node = node->next; 720 } 721 return 0; 722 } 723 724 int loadEffect(cnode *root) 725 { 726 cnode *node; 727 effect_uuid_t uuid; 728 lib_entry_t *l; 729 effect_descriptor_t *d; 730 list_elem_t *e; 731 732 node = config_find(root, LIBRARY_TAG); 733 if (node == NULL) { 734 return -EINVAL; 735 } 736 737 l = getLibrary(node->value); 738 if (l == NULL) { 739 ALOGW("loadEffect() could not get library %s", node->value); 740 return -EINVAL; 741 } 742 743 node = config_find(root, UUID_TAG); 744 if (node == NULL) { 745 return -EINVAL; 746 } 747 if (stringToUuid(node->value, &uuid) != 0) { 748 ALOGW("loadEffect() invalid uuid %s", node->value); 749 return -EINVAL; 750 } 751 lib_entry_t *tmp; 752 bool skip = false; 753 if (findEffect(NULL, &uuid, &tmp, NULL) == 0) { 754 ALOGW("skipping duplicate uuid %s %s", node->value, 755 node->next ? "and its sub-effects" : ""); 756 skip = true; 757 } 758 759 d = malloc(sizeof(effect_descriptor_t)); 760 if (l->desc->get_descriptor(&uuid, d) != 0) { 761 char s[40]; 762 uuidToString(&uuid, s, 40); 763 ALOGW("Error querying effect %s on lib %s", s, l->name); 764 free(d); 765 return -EINVAL; 766 } 767 #if (LOG_NDEBUG==0) 768 char s[512]; 769 dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */); 770 ALOGV("loadEffect() read descriptor %p:%s",d, s); 771 #endif 772 if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != 773 EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { 774 ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); 775 free(d); 776 return -EINVAL; 777 } 778 e = malloc(sizeof(list_elem_t)); 779 e->object = d; 780 if (skip) { 781 e->next = gSkippedEffects; 782 gSkippedEffects = e; 783 return -EINVAL; 784 } else { 785 e->next = l->effects; 786 l->effects = e; 787 } 788 789 // After the UUID node in the config_tree, if node->next is valid, 790 // that would be sub effect node. 791 // Find the sub effects and add them to the gSubEffectList 792 node = node->next; 793 int count = 2; 794 bool hwSubefx = false, swSubefx = false; 795 list_sub_elem_t *sube = NULL; 796 if (node != NULL) { 797 ALOGV("Adding the effect to gEffectSubList as there are sub effects"); 798 sube = malloc(sizeof(list_sub_elem_t)); 799 sube->object = d; 800 sube->sub_elem = NULL; 801 sube->next = gSubEffectList; 802 gSubEffectList = sube; 803 } 804 while (node != NULL && count) { 805 if (addSubEffect(node)) { 806 ALOGW("loadEffect() could not add subEffect %s", node->value); 807 // Change the gSubEffectList to point to older list; 808 gSubEffectList = sube->next; 809 free(sube->sub_elem);// Free an already added sub effect 810 sube->sub_elem = NULL; 811 free(sube); 812 return -ENOENT; 813 } 814 sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object; 815 effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object); 816 // Since we return a dummy descriptor for the proxy during 817 // get_descriptor call,we replace it with the correspoding 818 // sw effect descriptor, but with Proxy UUID 819 // check for Sw desc 820 if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) == 821 EFFECT_FLAG_HW_ACC_TUNNEL)) { 822 swSubefx = true; 823 *d = *subEffectDesc; 824 d->uuid = uuid; 825 ALOGV("loadEffect() Changed the Proxy desc"); 826 } else 827 hwSubefx = true; 828 count--; 829 node = node->next; 830 } 831 // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc 832 if (hwSubefx && swSubefx) { 833 d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; 834 } 835 return 0; 836 } 837 838 // Searches the sub effect matching to the specified uuid 839 // in the gSubEffectList. It gets the lib_entry_t for 840 // the matched sub_effect . Used in EffectCreate of sub effects 841 int findSubEffect(const effect_uuid_t *uuid, 842 lib_entry_t **lib, 843 effect_descriptor_t **desc) 844 { 845 list_sub_elem_t *e = gSubEffectList; 846 list_elem_t *subefx; 847 sub_effect_entry_t *effect; 848 lib_entry_t *l = NULL; 849 effect_descriptor_t *d = NULL; 850 int found = 0; 851 int ret = 0; 852 853 if (uuid == NULL) 854 return -EINVAL; 855 856 while (e != NULL && !found) { 857 subefx = (list_elem_t*)(e->sub_elem); 858 while (subefx != NULL) { 859 effect = (sub_effect_entry_t*)subefx->object; 860 l = (lib_entry_t *)effect->lib; 861 d = (effect_descriptor_t *)effect->object; 862 if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { 863 ALOGV("uuid matched"); 864 found = 1; 865 break; 866 } 867 subefx = subefx->next; 868 } 869 e = e->next; 870 } 871 if (!found) { 872 ALOGV("findSubEffect() effect not found"); 873 ret = -ENOENT; 874 } else { 875 ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name); 876 *lib = l; 877 if (desc != NULL) { 878 *desc = d; 879 } 880 } 881 return ret; 882 } 883 884 lib_entry_t *getLibrary(const char *name) 885 { 886 list_elem_t *e; 887 888 if (gCachedLibrary && 889 !strncmp(gCachedLibrary->name, name, PATH_MAX)) { 890 return gCachedLibrary; 891 } 892 893 e = gLibraryList; 894 while (e) { 895 lib_entry_t *l = (lib_entry_t *)e->object; 896 if (!strcmp(l->name, name)) { 897 gCachedLibrary = l; 898 return l; 899 } 900 e = e->next; 901 } 902 903 return NULL; 904 } 905 906 907 void resetEffectEnumeration() 908 { 909 gCurLib = gLibraryList; 910 gCurEffect = NULL; 911 if (gCurLib) { 912 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; 913 } 914 gCurEffectIdx = 0; 915 } 916 917 uint32_t updateNumEffects() { 918 list_elem_t *e; 919 uint32_t cnt = 0; 920 921 resetEffectEnumeration(); 922 923 e = gLibraryList; 924 while (e) { 925 lib_entry_t *l = (lib_entry_t *)e->object; 926 list_elem_t *efx = l->effects; 927 while (efx) { 928 cnt++; 929 efx = efx->next; 930 } 931 e = e->next; 932 } 933 gNumEffects = cnt; 934 gCanQueryEffect = 0; 935 return cnt; 936 } 937 938 int findEffect(const effect_uuid_t *type, 939 const effect_uuid_t *uuid, 940 lib_entry_t **lib, 941 effect_descriptor_t **desc) 942 { 943 list_elem_t *e = gLibraryList; 944 lib_entry_t *l = NULL; 945 effect_descriptor_t *d = NULL; 946 int found = 0; 947 int ret = 0; 948 949 while (e && !found) { 950 l = (lib_entry_t *)e->object; 951 list_elem_t *efx = l->effects; 952 while (efx) { 953 d = (effect_descriptor_t *)efx->object; 954 if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) { 955 found = 1; 956 break; 957 } 958 if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { 959 found = 1; 960 break; 961 } 962 efx = efx->next; 963 } 964 e = e->next; 965 } 966 if (!found) { 967 ALOGV("findEffect() effect not found"); 968 ret = -ENOENT; 969 } else { 970 ALOGV("findEffect() found effect: %s in lib %s", d->name, l->name); 971 *lib = l; 972 if (desc) { 973 *desc = d; 974 } 975 } 976 977 return ret; 978 } 979 980 void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent) { 981 char s[256]; 982 char ss[256]; 983 char idt[indent + 1]; 984 985 memset(idt, ' ', indent); 986 idt[indent] = 0; 987 988 str[0] = 0; 989 990 snprintf(s, sizeof(s), "%s%s / %s\n", idt, desc->name, desc->implementor); 991 strlcat(str, s, len); 992 993 uuidToString(&desc->uuid, s, sizeof(s)); 994 snprintf(ss, sizeof(ss), "%s UUID: %s\n", idt, s); 995 strlcat(str, ss, len); 996 997 uuidToString(&desc->type, s, sizeof(s)); 998 snprintf(ss, sizeof(ss), "%s TYPE: %s\n", idt, s); 999 strlcat(str, ss, len); 1000 1001 sprintf(s, "%s apiVersion: %08X\n%s flags: %08X\n", idt, 1002 desc->apiVersion, idt, desc->flags); 1003 strlcat(str, s, len); 1004 } 1005 1006 int stringToUuid(const char *str, effect_uuid_t *uuid) 1007 { 1008 int tmp[10]; 1009 1010 if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 1011 tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { 1012 return -EINVAL; 1013 } 1014 uuid->timeLow = (uint32_t)tmp[0]; 1015 uuid->timeMid = (uint16_t)tmp[1]; 1016 uuid->timeHiAndVersion = (uint16_t)tmp[2]; 1017 uuid->clockSeq = (uint16_t)tmp[3]; 1018 uuid->node[0] = (uint8_t)tmp[4]; 1019 uuid->node[1] = (uint8_t)tmp[5]; 1020 uuid->node[2] = (uint8_t)tmp[6]; 1021 uuid->node[3] = (uint8_t)tmp[7]; 1022 uuid->node[4] = (uint8_t)tmp[8]; 1023 uuid->node[5] = (uint8_t)tmp[9]; 1024 1025 return 0; 1026 } 1027 1028 int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen) 1029 { 1030 1031 snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 1032 uuid->timeLow, 1033 uuid->timeMid, 1034 uuid->timeHiAndVersion, 1035 uuid->clockSeq, 1036 uuid->node[0], 1037 uuid->node[1], 1038 uuid->node[2], 1039 uuid->node[3], 1040 uuid->node[4], 1041 uuid->node[5]); 1042 1043 return 0; 1044 } 1045 1046 int EffectDumpEffects(int fd) { 1047 char s[512]; 1048 1049 list_elem_t *fe = gLibraryFailedList; 1050 lib_failed_entry_t *fl = NULL; 1051 1052 dprintf(fd, "Libraries NOT loaded:\n"); 1053 1054 while (fe) { 1055 fl = (lib_failed_entry_t *)fe->object; 1056 dprintf(fd, " Library %s\n", fl->name); 1057 dprintf(fd, " path: %s\n", fl->path); 1058 fe = fe->next; 1059 } 1060 1061 list_elem_t *e = gLibraryList; 1062 lib_entry_t *l = NULL; 1063 effect_descriptor_t *d = NULL; 1064 int found = 0; 1065 int ret = 0; 1066 1067 dprintf(fd, "Libraries loaded:\n"); 1068 while (e) { 1069 l = (lib_entry_t *)e->object; 1070 list_elem_t *efx = l->effects; 1071 dprintf(fd, " Library %s\n", l->name); 1072 dprintf(fd, " path: %s\n", l->path); 1073 if (!efx) { 1074 dprintf(fd, " (no effects)\n"); 1075 } 1076 while (efx) { 1077 d = (effect_descriptor_t *)efx->object; 1078 dumpEffectDescriptor(d, s, sizeof(s), 2); 1079 dprintf(fd, "%s", s); 1080 efx = efx->next; 1081 } 1082 e = e->next; 1083 } 1084 1085 e = gSkippedEffects; 1086 if (e) { 1087 dprintf(fd, "Skipped effects\n"); 1088 while(e) { 1089 d = (effect_descriptor_t *)e->object; 1090 dumpEffectDescriptor(d, s, sizeof(s), 2 /* indent */); 1091 dprintf(fd, "%s", s); 1092 e = e->next; 1093 } 1094 } 1095 return ret; 1096 } 1097 1098