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