1 /* 2 * Copyright (C) 2014 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 "offload_effect_bundle" 18 //#define LOG_NDEBUG 0 19 20 #include <cutils/list.h> 21 #include <cutils/log.h> 22 #include <system/thread_defs.h> 23 #include <tinyalsa/asoundlib.h> 24 #include <hardware/audio_effect.h> 25 26 #include "bundle.h" 27 #include "equalizer.h" 28 #include "bass_boost.h" 29 #include "virtualizer.h" 30 #include "reverb.h" 31 32 enum { 33 EFFECT_STATE_UNINITIALIZED, 34 EFFECT_STATE_INITIALIZED, 35 EFFECT_STATE_ACTIVE, 36 }; 37 38 const effect_descriptor_t *descriptors[] = { 39 &equalizer_descriptor, 40 &bassboost_descriptor, 41 &virtualizer_descriptor, 42 &aux_env_reverb_descriptor, 43 &ins_env_reverb_descriptor, 44 &aux_preset_reverb_descriptor, 45 &ins_preset_reverb_descriptor, 46 NULL, 47 }; 48 49 pthread_once_t once = PTHREAD_ONCE_INIT; 50 int init_status; 51 /* 52 * list of created effects. 53 * Updated by offload_effects_bundle_hal_start_output() 54 * and offload_effects_bundle_hal_stop_output() 55 */ 56 struct listnode created_effects_list; 57 /* 58 * list of active output streams. 59 * Updated by offload_effects_bundle_hal_start_output() 60 * and offload_effects_bundle_hal_stop_output() 61 */ 62 struct listnode active_outputs_list; 63 /* 64 * lock must be held when modifying or accessing 65 * created_effects_list or active_outputs_list 66 */ 67 pthread_mutex_t lock; 68 69 70 /* 71 * Local functions 72 */ 73 static void init_once() { 74 list_init(&created_effects_list); 75 list_init(&active_outputs_list); 76 77 pthread_mutex_init(&lock, NULL); 78 79 init_status = 0; 80 } 81 82 int lib_init() 83 { 84 pthread_once(&once, init_once); 85 return init_status; 86 } 87 88 bool effect_exists(effect_context_t *context) 89 { 90 struct listnode *node; 91 92 list_for_each(node, &created_effects_list) { 93 effect_context_t *fx_ctxt = node_to_item(node, 94 effect_context_t, 95 effects_list_node); 96 if (fx_ctxt == context) { 97 return true; 98 } 99 } 100 return false; 101 } 102 103 output_context_t *get_output(audio_io_handle_t output) 104 { 105 struct listnode *node; 106 107 list_for_each(node, &active_outputs_list) { 108 output_context_t *out_ctxt = node_to_item(node, 109 output_context_t, 110 outputs_list_node); 111 if (out_ctxt->handle == output) 112 return out_ctxt; 113 } 114 return NULL; 115 } 116 117 void add_effect_to_output(output_context_t * output, effect_context_t *context) 118 { 119 struct listnode *fx_node; 120 121 list_for_each(fx_node, &output->effects_list) { 122 effect_context_t *fx_ctxt = node_to_item(fx_node, 123 effect_context_t, 124 output_node); 125 if (fx_ctxt == context) 126 return; 127 } 128 list_add_tail(&output->effects_list, &context->output_node); 129 if (context->ops.start) 130 context->ops.start(context, output); 131 132 } 133 134 void remove_effect_from_output(output_context_t * output, 135 effect_context_t *context) 136 { 137 struct listnode *fx_node; 138 139 list_for_each(fx_node, &output->effects_list) { 140 effect_context_t *fx_ctxt = node_to_item(fx_node, 141 effect_context_t, 142 output_node); 143 if (fx_ctxt == context) { 144 if (context->ops.stop) 145 context->ops.stop(context, output); 146 list_remove(&context->output_node); 147 return; 148 } 149 } 150 } 151 152 bool effects_enabled() 153 { 154 struct listnode *out_node; 155 156 list_for_each(out_node, &active_outputs_list) { 157 struct listnode *fx_node; 158 output_context_t *out_ctxt = node_to_item(out_node, 159 output_context_t, 160 outputs_list_node); 161 162 list_for_each(fx_node, &out_ctxt->effects_list) { 163 effect_context_t *fx_ctxt = node_to_item(fx_node, 164 effect_context_t, 165 output_node); 166 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) && 167 (fx_ctxt->ops.process != NULL)) 168 return true; 169 } 170 } 171 return false; 172 } 173 174 175 /* 176 * Interface from audio HAL 177 */ 178 __attribute__ ((visibility ("default"))) 179 int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id) 180 { 181 int ret = 0; 182 struct listnode *node; 183 char mixer_string[128]; 184 output_context_t * out_ctxt = NULL; 185 186 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); 187 188 if (lib_init() != 0) 189 return init_status; 190 191 pthread_mutex_lock(&lock); 192 if (get_output(output) != NULL) { 193 ALOGW("%s output already started", __func__); 194 ret = -ENOSYS; 195 goto exit; 196 } 197 198 out_ctxt = (output_context_t *) 199 malloc(sizeof(output_context_t)); 200 out_ctxt->handle = output; 201 out_ctxt->pcm_device_id = pcm_id; 202 203 /* populate the mixer control to send offload parameters */ 204 snprintf(mixer_string, sizeof(mixer_string), 205 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id); 206 out_ctxt->mixer = mixer_open(MIXER_CARD); 207 if (!out_ctxt->mixer) { 208 ALOGE("Failed to open mixer"); 209 out_ctxt->ctl = NULL; 210 ret = -EINVAL; 211 free(out_ctxt); 212 goto exit; 213 } else { 214 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string); 215 if (!out_ctxt->ctl) { 216 ALOGE("mixer_get_ctl_by_name failed"); 217 mixer_close(out_ctxt->mixer); 218 out_ctxt->mixer = NULL; 219 ret = -EINVAL; 220 free(out_ctxt); 221 goto exit; 222 } 223 } 224 225 list_init(&out_ctxt->effects_list); 226 227 list_for_each(node, &created_effects_list) { 228 effect_context_t *fx_ctxt = node_to_item(node, 229 effect_context_t, 230 effects_list_node); 231 if (fx_ctxt->out_handle == output) { 232 if (fx_ctxt->ops.start) 233 fx_ctxt->ops.start(fx_ctxt, out_ctxt); 234 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node); 235 } 236 } 237 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node); 238 exit: 239 pthread_mutex_unlock(&lock); 240 return ret; 241 } 242 243 __attribute__ ((visibility ("default"))) 244 int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id) 245 { 246 int ret; 247 struct listnode *node; 248 struct listnode *fx_node; 249 output_context_t *out_ctxt; 250 251 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); 252 253 if (lib_init() != 0) 254 return init_status; 255 256 pthread_mutex_lock(&lock); 257 258 out_ctxt = get_output(output); 259 if (out_ctxt == NULL) { 260 ALOGW("%s output not started", __func__); 261 ret = -ENOSYS; 262 goto exit; 263 } 264 265 if (out_ctxt->mixer) 266 mixer_close(out_ctxt->mixer); 267 268 list_for_each(fx_node, &out_ctxt->effects_list) { 269 effect_context_t *fx_ctxt = node_to_item(fx_node, 270 effect_context_t, 271 output_node); 272 if (fx_ctxt->ops.stop) 273 fx_ctxt->ops.stop(fx_ctxt, out_ctxt); 274 } 275 276 list_remove(&out_ctxt->outputs_list_node); 277 278 free(out_ctxt); 279 280 exit: 281 pthread_mutex_unlock(&lock); 282 return ret; 283 } 284 285 286 /* 287 * Effect operations 288 */ 289 int set_config(effect_context_t *context, effect_config_t *config) 290 { 291 context->config = *config; 292 293 if (context->ops.reset) 294 context->ops.reset(context); 295 296 return 0; 297 } 298 299 void get_config(effect_context_t *context, effect_config_t *config) 300 { 301 *config = context->config; 302 } 303 304 305 /* 306 * Effect Library Interface Implementation 307 */ 308 int effect_lib_create(const effect_uuid_t *uuid, 309 int32_t sessionId, 310 int32_t ioId, 311 effect_handle_t *pHandle) { 312 int ret; 313 int i; 314 315 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId); 316 if (lib_init() != 0) 317 return init_status; 318 319 if (pHandle == NULL || uuid == NULL) 320 return -EINVAL; 321 322 for (i = 0; descriptors[i] != NULL; i++) { 323 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) 324 break; 325 } 326 327 if (descriptors[i] == NULL) 328 return -EINVAL; 329 330 effect_context_t *context; 331 if (memcmp(uuid, &equalizer_descriptor.uuid, 332 sizeof(effect_uuid_t)) == 0) { 333 equalizer_context_t *eq_ctxt = (equalizer_context_t *) 334 calloc(1, sizeof(equalizer_context_t)); 335 context = (effect_context_t *)eq_ctxt; 336 context->ops.init = equalizer_init; 337 context->ops.reset = equalizer_reset; 338 context->ops.set_parameter = equalizer_set_parameter; 339 context->ops.get_parameter = equalizer_get_parameter; 340 context->ops.set_device = equalizer_set_device; 341 context->ops.enable = equalizer_enable; 342 context->ops.disable = equalizer_disable; 343 context->ops.start = equalizer_start; 344 context->ops.stop = equalizer_stop; 345 346 context->desc = &equalizer_descriptor; 347 eq_ctxt->ctl = NULL; 348 } else if (memcmp(uuid, &bassboost_descriptor.uuid, 349 sizeof(effect_uuid_t)) == 0) { 350 bassboost_context_t *bass_ctxt = (bassboost_context_t *) 351 calloc(1, sizeof(bassboost_context_t)); 352 context = (effect_context_t *)bass_ctxt; 353 context->ops.init = bassboost_init; 354 context->ops.reset = bassboost_reset; 355 context->ops.set_parameter = bassboost_set_parameter; 356 context->ops.get_parameter = bassboost_get_parameter; 357 context->ops.set_device = bassboost_set_device; 358 context->ops.enable = bassboost_enable; 359 context->ops.disable = bassboost_disable; 360 context->ops.start = bassboost_start; 361 context->ops.stop = bassboost_stop; 362 363 context->desc = &bassboost_descriptor; 364 bass_ctxt->ctl = NULL; 365 } else if (memcmp(uuid, &virtualizer_descriptor.uuid, 366 sizeof(effect_uuid_t)) == 0) { 367 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *) 368 calloc(1, sizeof(virtualizer_context_t)); 369 context = (effect_context_t *)virt_ctxt; 370 context->ops.init = virtualizer_init; 371 context->ops.reset = virtualizer_reset; 372 context->ops.set_parameter = virtualizer_set_parameter; 373 context->ops.get_parameter = virtualizer_get_parameter; 374 context->ops.set_device = virtualizer_set_device; 375 context->ops.enable = virtualizer_enable; 376 context->ops.disable = virtualizer_disable; 377 context->ops.start = virtualizer_start; 378 context->ops.stop = virtualizer_stop; 379 380 context->desc = &virtualizer_descriptor; 381 virt_ctxt->ctl = NULL; 382 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid, 383 sizeof(effect_uuid_t)) == 0) || 384 (memcmp(uuid, &ins_env_reverb_descriptor.uuid, 385 sizeof(effect_uuid_t)) == 0) || 386 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, 387 sizeof(effect_uuid_t)) == 0) || 388 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, 389 sizeof(effect_uuid_t)) == 0)) { 390 reverb_context_t *reverb_ctxt = (reverb_context_t *) 391 calloc(1, sizeof(reverb_context_t)); 392 context = (effect_context_t *)reverb_ctxt; 393 context->ops.init = reverb_init; 394 context->ops.reset = reverb_reset; 395 context->ops.set_parameter = reverb_set_parameter; 396 context->ops.get_parameter = reverb_get_parameter; 397 context->ops.set_device = reverb_set_device; 398 context->ops.enable = reverb_enable; 399 context->ops.disable = reverb_disable; 400 context->ops.start = reverb_start; 401 context->ops.stop = reverb_stop; 402 403 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid, 404 sizeof(effect_uuid_t)) == 0) { 405 context->desc = &aux_env_reverb_descriptor; 406 reverb_auxiliary_init(reverb_ctxt); 407 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid, 408 sizeof(effect_uuid_t)) == 0) { 409 context->desc = &ins_env_reverb_descriptor; 410 reverb_insert_init(reverb_ctxt); 411 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, 412 sizeof(effect_uuid_t)) == 0) { 413 context->desc = &aux_preset_reverb_descriptor; 414 reverb_auxiliary_init(reverb_ctxt); 415 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, 416 sizeof(effect_uuid_t)) == 0) { 417 context->desc = &ins_preset_reverb_descriptor; 418 reverb_preset_init(reverb_ctxt); 419 } 420 reverb_ctxt->ctl = NULL; 421 } else { 422 return -EINVAL; 423 } 424 425 context->itfe = &effect_interface; 426 context->state = EFFECT_STATE_UNINITIALIZED; 427 context->out_handle = (audio_io_handle_t)ioId; 428 429 ret = context->ops.init(context); 430 if (ret < 0) { 431 ALOGW("%s init failed", __func__); 432 free(context); 433 return ret; 434 } 435 436 context->state = EFFECT_STATE_INITIALIZED; 437 438 pthread_mutex_lock(&lock); 439 list_add_tail(&created_effects_list, &context->effects_list_node); 440 output_context_t *out_ctxt = get_output(ioId); 441 if (out_ctxt != NULL) 442 add_effect_to_output(out_ctxt, context); 443 pthread_mutex_unlock(&lock); 444 445 *pHandle = (effect_handle_t)context; 446 447 ALOGV("%s created context %p", __func__, context); 448 449 return 0; 450 451 } 452 453 int effect_lib_release(effect_handle_t handle) 454 { 455 effect_context_t *context = (effect_context_t *)handle; 456 int status; 457 458 if (lib_init() != 0) 459 return init_status; 460 461 ALOGV("%s context %p", __func__, handle); 462 pthread_mutex_lock(&lock); 463 status = -EINVAL; 464 if (effect_exists(context)) { 465 output_context_t *out_ctxt = get_output(context->out_handle); 466 if (out_ctxt != NULL) 467 remove_effect_from_output(out_ctxt, context); 468 list_remove(&context->effects_list_node); 469 if (context->ops.release) 470 context->ops.release(context); 471 free(context); 472 status = 0; 473 } 474 pthread_mutex_unlock(&lock); 475 476 return status; 477 } 478 479 int effect_lib_get_descriptor(const effect_uuid_t *uuid, 480 effect_descriptor_t *descriptor) 481 { 482 int i; 483 484 if (lib_init() != 0) 485 return init_status; 486 487 if (descriptor == NULL || uuid == NULL) { 488 ALOGV("%s called with NULL pointer", __func__); 489 return -EINVAL; 490 } 491 492 for (i = 0; descriptors[i] != NULL; i++) { 493 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) { 494 *descriptor = *descriptors[i]; 495 return 0; 496 } 497 } 498 499 return -EINVAL; 500 } 501 502 503 /* 504 * Effect Control Interface Implementation 505 */ 506 507 /* Stub function for effect interface: never called for offloaded effects */ 508 int effect_process(effect_handle_t self, 509 audio_buffer_t *inBuffer __unused, 510 audio_buffer_t *outBuffer __unused) 511 { 512 effect_context_t * context = (effect_context_t *)self; 513 int status = 0; 514 515 ALOGW("%s Called ?????", __func__); 516 517 pthread_mutex_lock(&lock); 518 if (!effect_exists(context)) { 519 status = -ENOSYS; 520 goto exit; 521 } 522 523 if (context->state != EFFECT_STATE_ACTIVE) { 524 status = -ENODATA; 525 goto exit; 526 } 527 528 exit: 529 pthread_mutex_unlock(&lock); 530 return status; 531 } 532 533 int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, 534 void *pCmdData, uint32_t *replySize, void *pReplyData) 535 { 536 537 effect_context_t * context = (effect_context_t *)self; 538 int retsize; 539 int status = 0; 540 541 pthread_mutex_lock(&lock); 542 543 if (!effect_exists(context)) { 544 status = -ENOSYS; 545 goto exit; 546 } 547 548 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) { 549 status = -ENOSYS; 550 goto exit; 551 } 552 553 switch (cmdCode) { 554 case EFFECT_CMD_INIT: 555 if (pReplyData == NULL || *replySize != sizeof(int)) { 556 status = -EINVAL; 557 goto exit; 558 } 559 if (context->ops.init) 560 *(int *) pReplyData = context->ops.init(context); 561 else 562 *(int *) pReplyData = 0; 563 break; 564 case EFFECT_CMD_SET_CONFIG: 565 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) 566 || pReplyData == NULL || *replySize != sizeof(int)) { 567 status = -EINVAL; 568 goto exit; 569 } 570 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData); 571 break; 572 case EFFECT_CMD_GET_CONFIG: 573 if (pReplyData == NULL || 574 *replySize != sizeof(effect_config_t)) { 575 status = -EINVAL; 576 goto exit; 577 } 578 if (!context->offload_enabled) { 579 status = -EINVAL; 580 goto exit; 581 } 582 583 get_config(context, (effect_config_t *)pReplyData); 584 break; 585 case EFFECT_CMD_RESET: 586 if (context->ops.reset) 587 context->ops.reset(context); 588 break; 589 case EFFECT_CMD_ENABLE: 590 if (pReplyData == NULL || *replySize != sizeof(int)) { 591 status = -EINVAL; 592 goto exit; 593 } 594 if (context->state != EFFECT_STATE_INITIALIZED) { 595 status = -ENOSYS; 596 goto exit; 597 } 598 context->state = EFFECT_STATE_ACTIVE; 599 if (context->ops.enable) 600 context->ops.enable(context); 601 ALOGV("%s EFFECT_CMD_ENABLE", __func__); 602 *(int *)pReplyData = 0; 603 break; 604 case EFFECT_CMD_DISABLE: 605 if (pReplyData == NULL || *replySize != sizeof(int)) { 606 status = -EINVAL; 607 goto exit; 608 } 609 if (context->state != EFFECT_STATE_ACTIVE) { 610 status = -ENOSYS; 611 goto exit; 612 } 613 context->state = EFFECT_STATE_INITIALIZED; 614 if (context->ops.disable) 615 context->ops.disable(context); 616 ALOGV("%s EFFECT_CMD_DISABLE", __func__); 617 *(int *)pReplyData = 0; 618 break; 619 case EFFECT_CMD_GET_PARAM: { 620 if (pCmdData == NULL || 621 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || 622 pReplyData == NULL || 623 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + 624 sizeof(uint16_t))) { 625 status = -EINVAL; 626 ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", 627 cmdSize, *replySize); 628 goto exit; 629 } 630 if (!context->offload_enabled) { 631 status = -EINVAL; 632 goto exit; 633 } 634 effect_param_t *q = (effect_param_t *)pCmdData; 635 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize); 636 effect_param_t *p = (effect_param_t *)pReplyData; 637 if (context->ops.get_parameter) 638 context->ops.get_parameter(context, p, replySize); 639 } break; 640 case EFFECT_CMD_SET_PARAM: { 641 if (pCmdData == NULL || 642 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + 643 sizeof(uint16_t)) || 644 pReplyData == NULL || *replySize != sizeof(int32_t)) { 645 status = -EINVAL; 646 ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d", 647 cmdSize, *replySize); 648 goto exit; 649 } 650 *(int32_t *)pReplyData = 0; 651 effect_param_t *p = (effect_param_t *)pCmdData; 652 if (context->ops.set_parameter) 653 *(int32_t *)pReplyData = context->ops.set_parameter(context, p, 654 *replySize); 655 656 } break; 657 case EFFECT_CMD_SET_DEVICE: { 658 uint32_t device; 659 ALOGV("\t EFFECT_CMD_SET_DEVICE start"); 660 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) { 661 status = -EINVAL; 662 ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize); 663 goto exit; 664 } 665 device = *(uint32_t *)pCmdData; 666 if (context->ops.set_device) 667 context->ops.set_device(context, device); 668 } break; 669 case EFFECT_CMD_SET_VOLUME: 670 case EFFECT_CMD_SET_AUDIO_MODE: 671 break; 672 673 case EFFECT_CMD_OFFLOAD: { 674 output_context_t *out_ctxt; 675 676 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL 677 || pReplyData == NULL || *replySize != sizeof(int)) { 678 ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__); 679 status = -EINVAL; 680 break; 681 } 682 683 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData; 684 685 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__, 686 offload_param->isOffload, offload_param->ioHandle); 687 688 *(int *)pReplyData = 0; 689 690 context->offload_enabled = offload_param->isOffload; 691 if (context->out_handle == offload_param->ioHandle) 692 break; 693 694 out_ctxt = get_output(context->out_handle); 695 if (out_ctxt != NULL) 696 remove_effect_from_output(out_ctxt, context); 697 698 context->out_handle = offload_param->ioHandle; 699 out_ctxt = get_output(context->out_handle); 700 if (out_ctxt != NULL) 701 add_effect_to_output(out_ctxt, context); 702 703 } break; 704 705 706 default: 707 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command) 708 status = context->ops.command(context, cmdCode, cmdSize, 709 pCmdData, replySize, pReplyData); 710 else { 711 ALOGW("%s invalid command %d", __func__, cmdCode); 712 status = -EINVAL; 713 } 714 break; 715 } 716 717 exit: 718 pthread_mutex_unlock(&lock); 719 720 return status; 721 } 722 723 /* Effect Control Interface Implementation: get_descriptor */ 724 int effect_get_descriptor(effect_handle_t self, 725 effect_descriptor_t *descriptor) 726 { 727 effect_context_t *context = (effect_context_t *)self; 728 729 if (!effect_exists(context) || (descriptor == NULL)) 730 return -EINVAL; 731 732 *descriptor = *context->desc; 733 734 return 0; 735 } 736 737 bool effect_is_active(effect_context_t * ctxt) { 738 return ctxt->state == EFFECT_STATE_ACTIVE; 739 } 740 741 /* effect_handle_t interface implementation for offload effects */ 742 const struct effect_interface_s effect_interface = { 743 effect_process, 744 effect_command, 745 effect_get_descriptor, 746 NULL, 747 }; 748 749 __attribute__ ((visibility ("default"))) 750 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 751 tag : AUDIO_EFFECT_LIBRARY_TAG, 752 version : EFFECT_LIBRARY_API_VERSION, 753 name : "Offload Effects Bundle Library", 754 implementor : "The Android Open Source Project", 755 create_effect : effect_lib_create, 756 release_effect : effect_lib_release, 757 get_descriptor : effect_lib_get_descriptor, 758 }; 759