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