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 <cutils/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 39enum 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 48enum session_state { 49 SESSION_STATE_INIT, // initialized 50 SESSION_STATE_CONFIG // configuration received 51}; 52 53// Effect/Preprocessor state 54enum 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 62struct 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 70struct 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 92static 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 104static 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 128const 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 135static int init_status = 1; 136struct listnode session_list; 137static const struct effect_interface_s effect_interface; 138static const effect_uuid_t * uuid_to_id_table[NUM_ID]; 139 140//------------------------------------------------------------------------------ 141// Helper functions 142//------------------------------------------------------------------------------ 143 144static 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 152static 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 166static 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 171static 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 245static 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 253static 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 262static 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 272static 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 288static 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 315error: 316 return status; 317} 318 319static 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 336static 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 364static 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 373static 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 395static 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->io == ioId) { 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 425static 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 476static 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 491static 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 520static 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 653static 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 668static 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 679static 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 718static 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 740static 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"))) 765audio_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