1 /* 2 * Copyright (C) 2013 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 "voice_processing" 18 /*#define LOG_NDEBUG 0*/ 19 #include <dlfcn.h> 20 #include <cutils/log.h> 21 #include <cutils/list.h> 22 #include <hardware/audio_effect.h> 23 #include <audio_effects/effect_aec.h> 24 #include <audio_effects/effect_agc.h> 25 #include <audio_effects/effect_ns.h> 26 27 28 //------------------------------------------------------------------------------ 29 // local definitions 30 //------------------------------------------------------------------------------ 31 32 #define EFFECTS_DESCRIPTOR_LIBRARY_PATH "/system/lib/soundfx/libqcomvoiceprocessingdescriptors.so" 33 34 // types of pre processing modules 35 enum effect_id 36 { 37 AEC_ID, // Acoustic Echo Canceler 38 NS_ID, // Noise Suppressor 39 //ENABLE_AGC AGC_ID, // Automatic Gain Control 40 NUM_ID 41 }; 42 43 // Session state 44 enum session_state { 45 SESSION_STATE_INIT, // initialized 46 SESSION_STATE_CONFIG // configuration received 47 }; 48 49 // Effect/Preprocessor state 50 enum effect_state { 51 EFFECT_STATE_INIT, // initialized 52 EFFECT_STATE_CREATED, // webRTC engine created 53 EFFECT_STATE_CONFIG, // configuration received/disabled 54 EFFECT_STATE_ACTIVE // active/enabled 55 }; 56 57 // Effect context 58 struct effect_s { 59 const struct effect_interface_s *itfe; 60 uint32_t id; // type of pre processor (enum effect_id) 61 uint32_t state; // current state (enum effect_state) 62 struct session_s *session; // session the effect is on 63 }; 64 65 // Session context 66 struct session_s { 67 struct listnode node; 68 effect_config_t config; 69 struct effect_s effects[NUM_ID]; // effects in this session 70 uint32_t state; // current state (enum session_state) 71 int id; // audio session ID 72 int io; // handle of input stream this session is on 73 uint32_t created_msk; // bit field containing IDs of crested pre processors 74 uint32_t enabled_msk; // bit field containing IDs of enabled pre processors 75 uint32_t processed_msk; // bit field containing IDs of pre processors already 76 }; 77 78 79 //------------------------------------------------------------------------------ 80 // Default Effect descriptors. Device specific descriptors should be defined in 81 // libqcomvoiceprocessing.<product_name>.so if needed. 82 //------------------------------------------------------------------------------ 83 84 // UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html 85 // as the pre processing effects are not defined by OpenSL ES 86 87 // Acoustic Echo Cancellation 88 static const effect_descriptor_t qcom_default_aec_descriptor = { 89 { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type 90 { 0x0f8d0d2a, 0x59e5, 0x45fe, 0xb6e4, { 0x24, 0x8c, 0x8a, 0x79, 0x91, 0x09 } }, // uuid 91 EFFECT_CONTROL_API_VERSION, 92 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), 93 0, 94 0, 95 "Acoustic Echo Canceler", 96 "Qualcomm Fluence" 97 }; 98 99 // Noise suppression 100 static const effect_descriptor_t qcom_default_ns_descriptor = { 101 { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type 102 { 0x1d97bb0b, 0x9e2f, 0x4403, 0x9ae3, { 0x58, 0xc2, 0x55, 0x43, 0x06, 0xf8 } }, // uuid 103 EFFECT_CONTROL_API_VERSION, 104 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), 105 0, 106 0, 107 "Noise Suppression", 108 "Qualcomm Fluence" 109 }; 110 111 //ENABLE_AGC 112 // Automatic Gain Control 113 //static const effect_descriptor_t qcom_default_agc_descriptor = { 114 // { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type 115 // { 0x0dd49521, 0x8c59, 0x40b1, 0xb403, { 0xe0, 0x8d, 0x5f, 0x01, 0x87, 0x5e } }, // uuid 116 // EFFECT_CONTROL_API_VERSION, 117 // (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), 118 // 0, 119 // 0, 120 // "Automatic Gain Control", 121 // "Qualcomm Fluence" 122 //}; 123 124 const effect_descriptor_t *descriptors[NUM_ID] = { 125 &qcom_default_aec_descriptor, 126 &qcom_default_ns_descriptor, 127 //ENABLE_AGC &qcom_default_agc_descriptor, 128 }; 129 130 131 static int init_status = 1; 132 struct listnode session_list; 133 static const struct effect_interface_s effect_interface; 134 static const effect_uuid_t * uuid_to_id_table[NUM_ID]; 135 136 //------------------------------------------------------------------------------ 137 // Helper functions 138 //------------------------------------------------------------------------------ 139 140 static const effect_uuid_t * id_to_uuid(int id) 141 { 142 if (id >= NUM_ID) 143 return EFFECT_UUID_NULL; 144 145 return uuid_to_id_table[id]; 146 } 147 148 static uint32_t uuid_to_id(const effect_uuid_t * uuid) 149 { 150 size_t i; 151 for (i = 0; i < NUM_ID; i++) 152 if (memcmp(uuid, uuid_to_id_table[i], sizeof(*uuid)) == 0) 153 break; 154 155 return i; 156 } 157 158 //------------------------------------------------------------------------------ 159 // Effect functions 160 //------------------------------------------------------------------------------ 161 162 static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled); 163 164 #define BAD_STATE_ABORT(from, to) \ 165 LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to); 166 167 static int effect_set_state(struct effect_s *effect, uint32_t state) 168 { 169 int status = 0; 170 ALOGV("effect_set_state() id %d, new %d old %d", effect->id, state, effect->state); 171 switch(state) { 172 case EFFECT_STATE_INIT: 173 switch(effect->state) { 174 case EFFECT_STATE_ACTIVE: 175 session_set_fx_enabled(effect->session, effect->id, false); 176 case EFFECT_STATE_CONFIG: 177 case EFFECT_STATE_CREATED: 178 case EFFECT_STATE_INIT: 179 break; 180 default: 181 BAD_STATE_ABORT(effect->state, state); 182 } 183 break; 184 case EFFECT_STATE_CREATED: 185 switch(effect->state) { 186 case EFFECT_STATE_INIT: 187 break; 188 case EFFECT_STATE_CREATED: 189 case EFFECT_STATE_ACTIVE: 190 case EFFECT_STATE_CONFIG: 191 ALOGE("effect_set_state() invalid transition"); 192 status = -ENOSYS; 193 break; 194 default: 195 BAD_STATE_ABORT(effect->state, state); 196 } 197 break; 198 case EFFECT_STATE_CONFIG: 199 switch(effect->state) { 200 case EFFECT_STATE_INIT: 201 ALOGE("effect_set_state() invalid transition"); 202 status = -ENOSYS; 203 break; 204 case EFFECT_STATE_ACTIVE: 205 session_set_fx_enabled(effect->session, effect->id, false); 206 break; 207 case EFFECT_STATE_CREATED: 208 case EFFECT_STATE_CONFIG: 209 break; 210 default: 211 BAD_STATE_ABORT(effect->state, state); 212 } 213 break; 214 case EFFECT_STATE_ACTIVE: 215 switch(effect->state) { 216 case EFFECT_STATE_INIT: 217 case EFFECT_STATE_CREATED: 218 ALOGE("effect_set_state() invalid transition"); 219 status = -ENOSYS; 220 break; 221 case EFFECT_STATE_ACTIVE: 222 // enabling an already enabled effect is just ignored 223 break; 224 case EFFECT_STATE_CONFIG: 225 session_set_fx_enabled(effect->session, effect->id, true); 226 break; 227 default: 228 BAD_STATE_ABORT(effect->state, state); 229 } 230 break; 231 default: 232 BAD_STATE_ABORT(effect->state, state); 233 } 234 235 if (status == 0) 236 effect->state = state; 237 238 return status; 239 } 240 241 static int effect_init(struct effect_s *effect, uint32_t id) 242 { 243 effect->itfe = &effect_interface; 244 effect->id = id; 245 effect->state = EFFECT_STATE_INIT; 246 return 0; 247 } 248 249 static int effect_create(struct effect_s *effect, 250 struct session_s *session, 251 effect_handle_t *interface) 252 { 253 effect->session = session; 254 *interface = (effect_handle_t)&effect->itfe; 255 return effect_set_state(effect, EFFECT_STATE_CREATED); 256 } 257 258 static int effect_release(struct effect_s *effect) 259 { 260 return effect_set_state(effect, EFFECT_STATE_INIT); 261 } 262 263 264 //------------------------------------------------------------------------------ 265 // Session functions 266 //------------------------------------------------------------------------------ 267 268 static int session_init(struct session_s *session) 269 { 270 size_t i; 271 int status = 0; 272 273 session->state = SESSION_STATE_INIT; 274 session->id = 0; 275 session->io = 0; 276 session->created_msk = 0; 277 for (i = 0; i < NUM_ID && status == 0; i++) 278 status = effect_init(&session->effects[i], i); 279 280 return status; 281 } 282 283 284 static int session_create_effect(struct session_s *session, 285 int32_t id, 286 effect_handle_t *interface) 287 { 288 int status = -ENOMEM; 289 290 ALOGV("session_create_effect() %s, created_msk %08x", 291 id == AEC_ID ? "AEC" : id == NS_ID ? "NS" : "?", session->created_msk); 292 293 if (session->created_msk == 0) { 294 session->config.inputCfg.samplingRate = 16000; 295 session->config.inputCfg.channels = AUDIO_CHANNEL_IN_MONO; 296 session->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 297 session->config.outputCfg.samplingRate = 16000; 298 session->config.outputCfg.channels = AUDIO_CHANNEL_IN_MONO; 299 session->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 300 session->enabled_msk = 0; 301 session->processed_msk = 0; 302 } 303 status = effect_create(&session->effects[id], session, interface); 304 if (status < 0) 305 goto error; 306 307 ALOGV("session_create_effect() OK"); 308 session->created_msk |= (1<<id); 309 return status; 310 311 error: 312 return status; 313 } 314 315 static int session_release_effect(struct session_s *session, 316 struct effect_s *fx) 317 { 318 ALOGW_IF(effect_release(fx) != 0, " session_release_effect() failed for id %d", fx->id); 319 320 session->created_msk &= ~(1<<fx->id); 321 if (session->created_msk == 0) 322 { 323 ALOGV("session_release_effect() last effect: removing session"); 324 list_remove(&session->node); 325 free(session); 326 } 327 328 return 0; 329 } 330 331 332 static int session_set_config(struct session_s *session, effect_config_t *config) 333 { 334 int status; 335 336 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate || 337 config->inputCfg.format != config->outputCfg.format || 338 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) 339 return -EINVAL; 340 341 ALOGV("session_set_config() sampling rate %d channels %08x", 342 config->inputCfg.samplingRate, config->inputCfg.channels); 343 344 // if at least one process is enabled, do not accept configuration changes 345 if (session->enabled_msk) { 346 if (session->config.inputCfg.samplingRate != config->inputCfg.samplingRate || 347 session->config.inputCfg.channels != config->inputCfg.channels || 348 session->config.outputCfg.channels != config->outputCfg.channels) 349 return -ENOSYS; 350 else 351 return 0; 352 } 353 354 memcpy(&session->config, config, sizeof(effect_config_t)); 355 356 session->state = SESSION_STATE_CONFIG; 357 return 0; 358 } 359 360 static void session_get_config(struct session_s *session, effect_config_t *config) 361 { 362 memcpy(config, &session->config, sizeof(effect_config_t)); 363 364 config->inputCfg.mask = config->outputCfg.mask = 365 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT); 366 } 367 368 369 static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled) 370 { 371 if (enabled) { 372 if(session->enabled_msk == 0) { 373 /* do first enable here */ 374 } 375 session->enabled_msk |= (1 << id); 376 } else { 377 session->enabled_msk &= ~(1 << id); 378 if(session->enabled_msk == 0) { 379 /* do last enable here */ 380 } 381 } 382 ALOGV("session_set_fx_enabled() id %d, enabled %d enabled_msk %08x", 383 id, enabled, session->enabled_msk); 384 session->processed_msk = 0; 385 } 386 387 //------------------------------------------------------------------------------ 388 // Global functions 389 //------------------------------------------------------------------------------ 390 391 static struct session_s *get_session(int32_t id, int32_t sessionId, int32_t ioId) 392 { 393 size_t i; 394 int free = -1; 395 struct listnode *node; 396 struct session_s *session; 397 398 list_for_each(node, &session_list) { 399 session = node_to_item(node, struct session_s, node); 400 if (session->io == ioId) { 401 if (session->created_msk & (1 << id)) { 402 ALOGV("get_session() effect %d already created", id); 403 return NULL; 404 } 405 ALOGV("get_session() found session %p", session); 406 return session; 407 } 408 } 409 410 session = (struct session_s *)calloc(1, sizeof(struct session_s)); 411 session_init(session); 412 session->id = sessionId; 413 session->io = ioId; 414 list_add_tail(&session_list, &session->node); 415 416 ALOGV("get_session() created session %p", session); 417 418 return session; 419 } 420 421 static int init() { 422 void *lib_handle; 423 const effect_descriptor_t *desc; 424 425 if (init_status <= 0) 426 return init_status; 427 428 if (access(EFFECTS_DESCRIPTOR_LIBRARY_PATH, R_OK) == 0) { 429 lib_handle = dlopen(EFFECTS_DESCRIPTOR_LIBRARY_PATH, RTLD_NOW); 430 if (lib_handle == NULL) { 431 ALOGE("%s: DLOPEN failed for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH); 432 } else { 433 ALOGV("%s: DLOPEN successful for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH); 434 desc = (const effect_descriptor_t *)dlsym(lib_handle, 435 "qcom_product_aec_descriptor"); 436 if (desc) 437 descriptors[AEC_ID] = desc; 438 439 desc = (const effect_descriptor_t *)dlsym(lib_handle, 440 "qcom_product_ns_descriptor"); 441 if (desc) 442 descriptors[NS_ID] = desc; 443 444 //ENABLE_AGC 445 // desc = (const effect_descriptor_t *)dlsym(lib_handle, 446 // "qcom_product_agc_descriptor"); 447 // if (desc) 448 // descriptors[AGC_ID] = desc; 449 } 450 } 451 452 uuid_to_id_table[AEC_ID] = FX_IID_AEC; 453 uuid_to_id_table[NS_ID] = FX_IID_NS; 454 //ENABLE_AGC uuid_to_id_table[AGC_ID] = FX_IID_AGC; 455 456 list_init(&session_list); 457 458 init_status = 0; 459 return init_status; 460 } 461 462 static const effect_descriptor_t *get_descriptor(const effect_uuid_t *uuid) 463 { 464 size_t i; 465 for (i = 0; i < NUM_ID; i++) 466 if (memcmp(&descriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) 467 return descriptors[i]; 468 469 return NULL; 470 } 471 472 473 //------------------------------------------------------------------------------ 474 // Effect Control Interface Implementation 475 //------------------------------------------------------------------------------ 476 477 static int fx_process(effect_handle_t self, 478 audio_buffer_t *inBuffer, 479 audio_buffer_t *outBuffer) 480 { 481 struct effect_s *effect = (struct effect_s *)self; 482 struct session_s *session; 483 484 if (effect == NULL) { 485 ALOGV("fx_process() ERROR effect == NULL"); 486 return -EINVAL; 487 } 488 489 if (inBuffer == NULL || inBuffer->raw == NULL || 490 outBuffer == NULL || outBuffer->raw == NULL) { 491 ALOGW("fx_process() ERROR bad pointer"); 492 return -EINVAL; 493 } 494 495 session = (struct session_s *)effect->session; 496 497 session->processed_msk |= (1<<effect->id); 498 499 if ((session->processed_msk & session->enabled_msk) == session->enabled_msk) { 500 effect->session->processed_msk = 0; 501 return 0; 502 } else 503 return -ENODATA; 504 } 505 506 static int fx_command(effect_handle_t self, 507 uint32_t cmdCode, 508 uint32_t cmdSize, 509 void *pCmdData, 510 uint32_t *replySize, 511 void *pReplyData) 512 { 513 struct effect_s *effect = (struct effect_s *)self; 514 515 if (effect == NULL) 516 return -EINVAL; 517 518 //ALOGV("fx_command: command %d cmdSize %d",cmdCode, cmdSize); 519 520 switch (cmdCode) { 521 case EFFECT_CMD_INIT: 522 if (pReplyData == NULL || *replySize != sizeof(int)) 523 return -EINVAL; 524 525 *(int *)pReplyData = 0; 526 break; 527 528 case EFFECT_CMD_SET_CONFIG: { 529 if (pCmdData == NULL|| 530 cmdSize != sizeof(effect_config_t)|| 531 pReplyData == NULL|| 532 *replySize != sizeof(int)) { 533 ALOGV("fx_command() EFFECT_CMD_SET_CONFIG invalid args"); 534 return -EINVAL; 535 } 536 *(int *)pReplyData = session_set_config(effect->session, (effect_config_t *)pCmdData); 537 if (*(int *)pReplyData != 0) 538 break; 539 540 if (effect->state != EFFECT_STATE_ACTIVE) 541 *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_CONFIG); 542 543 } break; 544 545 case EFFECT_CMD_GET_CONFIG: 546 if (pReplyData == NULL || 547 *replySize != sizeof(effect_config_t)) { 548 ALOGV("fx_command() EFFECT_CMD_GET_CONFIG invalid args"); 549 return -EINVAL; 550 } 551 552 session_get_config(effect->session, (effect_config_t *)pReplyData); 553 break; 554 555 case EFFECT_CMD_RESET: 556 break; 557 558 case EFFECT_CMD_GET_PARAM: { 559 if (pCmdData == NULL || 560 cmdSize < (int)sizeof(effect_param_t) || 561 pReplyData == NULL || 562 *replySize < (int)sizeof(effect_param_t)) { 563 ALOGV("fx_command() EFFECT_CMD_GET_PARAM invalid args"); 564 return -EINVAL; 565 } 566 effect_param_t *p = (effect_param_t *)pCmdData; 567 568 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); 569 p = (effect_param_t *)pReplyData; 570 p->status = -ENOSYS; 571 572 } break; 573 574 case EFFECT_CMD_SET_PARAM: { 575 if (pCmdData == NULL|| 576 cmdSize < (int)sizeof(effect_param_t) || 577 pReplyData == NULL || 578 *replySize != sizeof(int32_t)) { 579 ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid args"); 580 return -EINVAL; 581 } 582 effect_param_t *p = (effect_param_t *) pCmdData; 583 584 if (p->psize != sizeof(int32_t)) { 585 ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid param format"); 586 return -EINVAL; 587 } 588 *(int *)pReplyData = -ENOSYS; 589 } break; 590 591 case EFFECT_CMD_ENABLE: 592 if (pReplyData == NULL || *replySize != sizeof(int)) { 593 ALOGV("fx_command() EFFECT_CMD_ENABLE invalid args"); 594 return -EINVAL; 595 } 596 *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_ACTIVE); 597 break; 598 599 case EFFECT_CMD_DISABLE: 600 if (pReplyData == NULL || *replySize != sizeof(int)) { 601 ALOGV("fx_command() EFFECT_CMD_DISABLE invalid args"); 602 return -EINVAL; 603 } 604 *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_CONFIG); 605 break; 606 607 case EFFECT_CMD_SET_DEVICE: 608 case EFFECT_CMD_SET_INPUT_DEVICE: 609 case EFFECT_CMD_SET_VOLUME: 610 case EFFECT_CMD_SET_AUDIO_MODE: 611 if (pCmdData == NULL || 612 cmdSize != sizeof(uint32_t)) { 613 ALOGV("fx_command() %s invalid args", 614 cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" : 615 cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" : 616 cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" : 617 cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE" : 618 ""); 619 return -EINVAL; 620 } 621 ALOGV("fx_command() %s value %08x", 622 cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" : 623 cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" : 624 cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" : 625 cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE": 626 "", 627 *(int *)pCmdData); 628 break; 629 630 default: 631 return -EINVAL; 632 } 633 return 0; 634 } 635 636 637 static int fx_get_descriptor(effect_handle_t self, 638 effect_descriptor_t *pDescriptor) 639 { 640 struct effect_s *effect = (struct effect_s *)self; 641 642 if (effect == NULL || pDescriptor == NULL) 643 return -EINVAL; 644 645 *pDescriptor = *descriptors[effect->id]; 646 647 return 0; 648 } 649 650 651 // effect_handle_t interface implementation for effect 652 static const struct effect_interface_s effect_interface = { 653 fx_process, 654 fx_command, 655 fx_get_descriptor, 656 NULL 657 }; 658 659 //------------------------------------------------------------------------------ 660 // Effect Library Interface Implementation 661 //------------------------------------------------------------------------------ 662 663 static int lib_create(const effect_uuid_t *uuid, 664 int32_t sessionId, 665 int32_t ioId, 666 effect_handle_t *pInterface) 667 { 668 ALOGV("lib_create: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId); 669 670 int status; 671 const effect_descriptor_t *desc; 672 struct session_s *session; 673 uint32_t id; 674 675 if (init() != 0) 676 return init_status; 677 678 desc = get_descriptor(uuid); 679 680 if (desc == NULL) { 681 ALOGW("lib_create: fx not found uuid: %08x", uuid->timeLow); 682 return -EINVAL; 683 } 684 id = uuid_to_id(&desc->type); 685 686 session = get_session(id, sessionId, ioId); 687 688 if (session == NULL) { 689 ALOGW("lib_create: no more session available"); 690 return -EINVAL; 691 } 692 693 status = session_create_effect(session, id, pInterface); 694 695 if (status < 0 && session->created_msk == 0) { 696 list_remove(&session->node); 697 free(session); 698 } 699 return status; 700 } 701 702 static int lib_release(effect_handle_t interface) 703 { 704 struct listnode *node; 705 struct session_s *session; 706 707 ALOGV("lib_release %p", interface); 708 if (init() != 0) 709 return init_status; 710 711 struct effect_s *fx = (struct effect_s *)interface; 712 713 list_for_each(node, &session_list) { 714 session = node_to_item(node, struct session_s, node); 715 if (session == fx->session) { 716 session_release_effect(fx->session, fx); 717 return 0; 718 } 719 } 720 721 return -EINVAL; 722 } 723 724 static int lib_get_descriptor(const effect_uuid_t *uuid, 725 effect_descriptor_t *pDescriptor) 726 { 727 const effect_descriptor_t *desc; 728 729 if (pDescriptor == NULL || uuid == NULL) 730 return -EINVAL; 731 732 if (init() != 0) 733 return init_status; 734 735 desc = get_descriptor(uuid); 736 if (desc == NULL) { 737 ALOGV("lib_get_descriptor() not found"); 738 return -EINVAL; 739 } 740 741 ALOGV("lib_get_descriptor() got fx %s", desc->name); 742 743 *pDescriptor = *desc; 744 return 0; 745 } 746 747 // This is the only symbol that needs to be exported 748 __attribute__ ((visibility ("default"))) 749 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 750 .tag = AUDIO_EFFECT_LIBRARY_TAG, 751 .version = EFFECT_LIBRARY_API_VERSION, 752 .name = "MSM8960 Audio Preprocessing Library", 753 .implementor = "The Android Open Source Project", 754 .create_effect = lib_create, 755 .release_effect = lib_release, 756 .get_descriptor = lib_get_descriptor 757 }; 758