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