EffectsFactory.c revision e1315cf0b63b4c14a77046519e6b01f6f60d74b0
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 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 EffectLoadLibrary(const char *libPath, int *handle) 336{ 337 // TODO: see if this interface still makes sense with the use of config files 338 return -ENOSYS; 339} 340 341int EffectUnloadLibrary(int handle) 342{ 343 // TODO: see if this interface still makes sense with the use of config files 344 return -ENOSYS; 345} 346 347int EffectIsNullUuid(effect_uuid_t *uuid) 348{ 349 if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) { 350 return 0; 351 } 352 return 1; 353} 354 355///////////////////////////////////////////////// 356// Local functions 357///////////////////////////////////////////////// 358 359int init() { 360 int hdl; 361 362 if (gInitDone) { 363 return 0; 364 } 365 366 pthread_mutex_init(&gLibLock, NULL); 367 368 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { 369 loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE); 370 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { 371 loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); 372 } 373 374 updateNumEffects(); 375 gInitDone = 1; 376 LOGV("init() done"); 377 return 0; 378} 379 380int loadEffectConfigFile(const char *path) 381{ 382 cnode *root; 383 char *data; 384 385 data = load_file(path, NULL); 386 if (data == NULL) { 387 return -ENODEV; 388 } 389 root = config_node("", ""); 390 config_load(root, data); 391 loadLibraries(root); 392 loadEffects(root); 393 config_free(root); 394 free(root); 395 free(data); 396 397 return 0; 398} 399 400int loadLibraries(cnode *root) 401{ 402 cnode *node; 403 404 node = config_find(root, LIBRARIES_TAG); 405 if (node == NULL) { 406 return -ENOENT; 407 } 408 node = node->first_child; 409 while (node) { 410 loadLibrary(node, node->name); 411 node = node->next; 412 } 413 return 0; 414} 415 416int loadLibrary(cnode *root, const char *name) 417{ 418 cnode *node; 419 void *hdl; 420 audio_effect_library_t *desc; 421 list_elem_t *e; 422 lib_entry_t *l; 423 424 node = config_find(root, PATH_TAG); 425 if (node == NULL) { 426 return -EINVAL; 427 } 428 429 hdl = dlopen(node->value, RTLD_NOW); 430 if (hdl == NULL) { 431 LOGW("loadLibrary() failed to open %s", node->value); 432 goto error; 433 } 434 435 desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 436 if (desc == NULL) { 437 LOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); 438 goto error; 439 } 440 441 if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) { 442 LOGW("getLibrary() bad tag %08x in lib info struct", desc->tag); 443 goto error; 444 } 445 446 if (EFFECT_API_VERSION_MAJOR(desc->version) != 447 EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) { 448 LOGW("loadLibrary() bad lib version %08x", desc->version); 449 goto error; 450 } 451 452 // add entry for library in gLibraryList 453 l = malloc(sizeof(lib_entry_t)); 454 l->name = strndup(name, PATH_MAX); 455 l->path = strndup(node->value, PATH_MAX); 456 l->handle = hdl; 457 l->desc = desc; 458 l->effects = NULL; 459 pthread_mutex_init(&l->lock, NULL); 460 461 e = malloc(sizeof(list_elem_t)); 462 e->object = l; 463 pthread_mutex_lock(&gLibLock); 464 e->next = gLibraryList; 465 gLibraryList = e; 466 pthread_mutex_unlock(&gLibLock); 467 LOGV("getLibrary() linked library %p for path %s", l, node->value); 468 469 return 0; 470 471error: 472 if (hdl != NULL) { 473 dlclose(hdl); 474 } 475 return -EINVAL; 476} 477 478int loadEffects(cnode *root) 479{ 480 cnode *node; 481 482 node = config_find(root, EFFECTS_TAG); 483 if (node == NULL) { 484 return -ENOENT; 485 } 486 node = node->first_child; 487 while (node) { 488 loadEffect(node); 489 node = node->next; 490 } 491 return 0; 492} 493 494int loadEffect(cnode *root) 495{ 496 cnode *node; 497 effect_uuid_t uuid; 498 lib_entry_t *l; 499 effect_descriptor_t *d; 500 list_elem_t *e; 501 502 node = config_find(root, LIBRARY_TAG); 503 if (node == NULL) { 504 return -EINVAL; 505 } 506 507 l = getLibrary(node->value); 508 if (l == NULL) { 509 LOGW("loadEffect() could not get library %s", node->value); 510 return -EINVAL; 511 } 512 513 node = config_find(root, UUID_TAG); 514 if (node == NULL) { 515 return -EINVAL; 516 } 517 if (stringToUuid(node->value, &uuid) != 0) { 518 LOGW("loadEffect() invalid uuid %s", node->value); 519 return -EINVAL; 520 } 521 522 d = malloc(sizeof(effect_descriptor_t)); 523 if (l->desc->get_descriptor(&uuid, d) != 0) { 524 char s[40]; 525 uuidToString(&uuid, s, 40); 526 LOGW("Error querying effect %s on lib %s", s, l->name); 527 free(d); 528 return -EINVAL; 529 } 530#if (LOG_NDEBUG==0) 531 char s[256]; 532 dumpEffectDescriptor(d, s, 256); 533 LOGV("loadEffect() read descriptor %p:%s",d, s); 534#endif 535 if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != 536 EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { 537 LOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); 538 free(d); 539 return -EINVAL; 540 } 541 e = malloc(sizeof(list_elem_t)); 542 e->object = d; 543 e->next = l->effects; 544 l->effects = e; 545 546 return 0; 547} 548 549lib_entry_t *getLibrary(const char *name) 550{ 551 list_elem_t *e; 552 553 if (gCachedLibrary && 554 !strncmp(gCachedLibrary->name, name, PATH_MAX)) { 555 return gCachedLibrary; 556 } 557 558 e = gLibraryList; 559 while (e) { 560 lib_entry_t *l = (lib_entry_t *)e->object; 561 if (!strcmp(l->name, name)) { 562 gCachedLibrary = l; 563 return l; 564 } 565 e = e->next; 566 } 567 568 return NULL; 569} 570 571 572void resetEffectEnumeration() 573{ 574 gCurLib = gLibraryList; 575 gCurEffect = NULL; 576 if (gCurLib) { 577 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects; 578 } 579 gCurEffectIdx = 0; 580} 581 582uint32_t updateNumEffects() { 583 list_elem_t *e; 584 uint32_t cnt = 0; 585 586 resetEffectEnumeration(); 587 588 e = gLibraryList; 589 while (e) { 590 lib_entry_t *l = (lib_entry_t *)e->object; 591 list_elem_t *efx = l->effects; 592 while (efx) { 593 cnt++; 594 efx = efx->next; 595 } 596 e = e->next; 597 } 598 gNumEffects = cnt; 599 gCanQueryEffect = 0; 600 return cnt; 601} 602 603int findEffect(effect_uuid_t *type, 604 effect_uuid_t *uuid, 605 lib_entry_t **lib, 606 effect_descriptor_t **desc) 607{ 608 list_elem_t *e = gLibraryList; 609 lib_entry_t *l = NULL; 610 effect_descriptor_t *d = NULL; 611 int found = 0; 612 int ret = 0; 613 614 while (e && !found) { 615 l = (lib_entry_t *)e->object; 616 list_elem_t *efx = l->effects; 617 while (efx) { 618 d = (effect_descriptor_t *)efx->object; 619 if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) { 620 found = 1; 621 break; 622 } 623 if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { 624 found = 1; 625 break; 626 } 627 efx = efx->next; 628 } 629 e = e->next; 630 } 631 if (!found) { 632 LOGV("findEffect() effect not found"); 633 ret = -ENOENT; 634 } else { 635 LOGV("findEffect() found effect: %s in lib %s", d->name, l->name); 636 *lib = l; 637 if (desc) { 638 *desc = d; 639 } 640 } 641 642 return ret; 643} 644 645void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) { 646 char s[256]; 647 648 snprintf(str, len, "\nEffect Descriptor %p:\n", desc); 649 strncat(str, "- TYPE: ", len); 650 uuidToString(&desc->uuid, s, 256); 651 snprintf(str, len, "- UUID: %s\n", s); 652 uuidToString(&desc->type, s, 256); 653 snprintf(str, len, "- TYPE: %s\n", s); 654 sprintf(s, "- apiVersion: %08X\n- flags: %08X\n", 655 desc->apiVersion, desc->flags); 656 strncat(str, s, len); 657 sprintf(s, "- name: %s\n", desc->name); 658 strncat(str, s, len); 659 sprintf(s, "- implementor: %s\n", desc->implementor); 660 strncat(str, s, len); 661} 662 663int stringToUuid(const char *str, effect_uuid_t *uuid) 664{ 665 int tmp[10]; 666 667 if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 668 tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { 669 return -EINVAL; 670 } 671 uuid->timeLow = (uint32_t)tmp[0]; 672 uuid->timeMid = (uint16_t)tmp[1]; 673 uuid->timeHiAndVersion = (uint16_t)tmp[2]; 674 uuid->clockSeq = (uint16_t)tmp[3]; 675 uuid->node[0] = (uint8_t)tmp[4]; 676 uuid->node[1] = (uint8_t)tmp[5]; 677 uuid->node[2] = (uint8_t)tmp[6]; 678 uuid->node[3] = (uint8_t)tmp[7]; 679 uuid->node[4] = (uint8_t)tmp[8]; 680 uuid->node[5] = (uint8_t)tmp[9]; 681 682 return 0; 683} 684 685int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen) 686{ 687 688 snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 689 uuid->timeLow, 690 uuid->timeMid, 691 uuid->timeHiAndVersion, 692 uuid->clockSeq, 693 uuid->node[0], 694 uuid->node[1], 695 uuid->node[2], 696 uuid->node[3], 697 uuid->node[4], 698 uuid->node[5]); 699 700 return 0; 701} 702 703