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