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