blob: 8518e54b5fa02b626e9ac136ebc9351af194f97c [file] [log] [blame]
Haynes Mathew George41f86652014-06-17 14:22:15 -07001/*
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
32enum {
33 EFFECT_STATE_UNINITIALIZED,
34 EFFECT_STATE_INITIALIZED,
35 EFFECT_STATE_ACTIVE,
36};
37
38const 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
49pthread_once_t once = PTHREAD_ONCE_INIT;
50int 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 */
56struct 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 */
62struct listnode active_outputs_list;
63/*
64 * lock must be held when modifying or accessing
65 * created_effects_list or active_outputs_list
66 */
67pthread_mutex_t lock;
68
69
70/*
71 * Local functions
72 */
73static 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
82int lib_init()
83{
84 pthread_once(&once, init_once);
85 return init_status;
86}
87
88bool 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
103output_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
117void 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
134void 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
152bool 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")))
179int 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);
238exit:
239 pthread_mutex_unlock(&lock);
240 return ret;
241}
242
243__attribute__ ((visibility ("default")))
244int 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
280exit:
281 pthread_mutex_unlock(&lock);
282 return ret;
283}
284
285
286/*
287 * Effect operations
288 */
289int 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
299void 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 */
308int 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
453int 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
479int 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 */
508int effect_process(effect_handle_t self,
Haynes Mathew George97a10592014-06-17 14:18:20 -0700509 audio_buffer_t *inBuffer __unused,
510 audio_buffer_t *outBuffer __unused)
Haynes Mathew George41f86652014-06-17 14:22:15 -0700511{
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
528exit:
529 pthread_mutex_unlock(&lock);
530 return status;
531}
532
533int 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
717exit:
718 pthread_mutex_unlock(&lock);
719
720 return status;
721}
722
723/* Effect Control Interface Implementation: get_descriptor */
724int 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
737bool 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 */
742const struct effect_interface_s effect_interface = {
743 effect_process,
744 effect_command,
745 effect_get_descriptor,
746 NULL,
747};
748
749__attribute__ ((visibility ("default")))
750audio_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};