blob: 8e2bce8de407dd178905689b7728cf701d5db867 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#define LOG_TAG "offload_effect_bundle"
21#define LOG_NDEBUG 0
22
23#include <cutils/list.h>
24#include <cutils/log.h>
25#include <system/thread_defs.h>
26#include <tinyalsa/asoundlib.h>
27#include <hardware/audio_effect.h>
28
29#include "bundle.h"
30#include "equalizer.h"
31#include "bass_boost.h"
32#include "virtualizer.h"
33#include "reverb.h"
34
35enum {
36 EFFECT_STATE_UNINITIALIZED,
37 EFFECT_STATE_INITIALIZED,
38 EFFECT_STATE_ACTIVE,
39};
40
41const effect_descriptor_t *descriptors[] = {
42 &equalizer_descriptor,
43 &bassboost_descriptor,
44 &virtualizer_descriptor,
45 &aux_env_reverb_descriptor,
46 &ins_env_reverb_descriptor,
47 &aux_preset_reverb_descriptor,
48 &ins_preset_reverb_descriptor,
49 NULL,
50};
51
52pthread_once_t once = PTHREAD_ONCE_INIT;
53int init_status;
54/*
55 * list of created effects.
56 * Updated by offload_effects_bundle_hal_start_output()
57 * and offload_effects_bundle_hal_stop_output()
58 */
59struct listnode created_effects_list;
60/*
61 * list of active output streams.
62 * Updated by offload_effects_bundle_hal_start_output()
63 * and offload_effects_bundle_hal_stop_output()
64 */
65struct listnode active_outputs_list;
66/*
67 * lock must be held when modifying or accessing
68 * created_effects_list or active_outputs_list
69 */
70pthread_mutex_t lock;
71
72
73/*
74 * Local functions
75 */
76static void init_once() {
77 list_init(&created_effects_list);
78 list_init(&active_outputs_list);
79
80 pthread_mutex_init(&lock, NULL);
81
82 init_status = 0;
83}
84
85int lib_init()
86{
87 pthread_once(&once, init_once);
88 return init_status;
89}
90
91bool effect_exists(effect_context_t *context)
92{
93 struct listnode *node;
94
95 list_for_each(node, &created_effects_list) {
96 effect_context_t *fx_ctxt = node_to_item(node,
97 effect_context_t,
98 effects_list_node);
99 if (fx_ctxt == context) {
100 return true;
101 }
102 }
103 return false;
104}
105
106output_context_t *get_output(audio_io_handle_t output)
107{
108 struct listnode *node;
109
110 list_for_each(node, &active_outputs_list) {
111 output_context_t *out_ctxt = node_to_item(node,
112 output_context_t,
113 outputs_list_node);
114 if (out_ctxt->handle == output)
115 return out_ctxt;
116 }
117 return NULL;
118}
119
120void add_effect_to_output(output_context_t * output, effect_context_t *context)
121{
122 struct listnode *fx_node;
123
124 list_for_each(fx_node, &output->effects_list) {
125 effect_context_t *fx_ctxt = node_to_item(fx_node,
126 effect_context_t,
127 output_node);
128 if (fx_ctxt == context)
129 return;
130 }
131 list_add_tail(&output->effects_list, &context->output_node);
132 if (context->ops.start)
133 context->ops.start(context, output);
134
135}
136
137void remove_effect_from_output(output_context_t * output,
138 effect_context_t *context)
139{
140 struct listnode *fx_node;
141
142 list_for_each(fx_node, &output->effects_list) {
143 effect_context_t *fx_ctxt = node_to_item(fx_node,
144 effect_context_t,
145 output_node);
146 if (fx_ctxt == context) {
147 if (context->ops.stop)
148 context->ops.stop(context, output);
149 list_remove(&context->output_node);
150 return;
151 }
152 }
153}
154
155bool effects_enabled()
156{
157 struct listnode *out_node;
158
159 list_for_each(out_node, &active_outputs_list) {
160 struct listnode *fx_node;
161 output_context_t *out_ctxt = node_to_item(out_node,
162 output_context_t,
163 outputs_list_node);
164
165 list_for_each(fx_node, &out_ctxt->effects_list) {
166 effect_context_t *fx_ctxt = node_to_item(fx_node,
167 effect_context_t,
168 output_node);
169 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
170 (fx_ctxt->ops.process != NULL))
171 return true;
172 }
173 }
174 return false;
175}
176
177
178/*
179 * Interface from audio HAL
180 */
181__attribute__ ((visibility ("default")))
182int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
183{
184 int ret = 0;
185 struct listnode *node;
186 char mixer_string[128];
187
188 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
189
190 if (lib_init() != 0)
191 return init_status;
192
193 pthread_mutex_lock(&lock);
194 if (get_output(output) != NULL) {
195 ALOGW("%s output already started", __func__);
196 ret = -ENOSYS;
197 goto exit;
198 }
199
200 output_context_t *out_ctxt = (output_context_t *)
201 malloc(sizeof(output_context_t));
202 out_ctxt->handle = output;
203 out_ctxt->pcm_device_id = pcm_id;
204
205 /* populate the mixer control to send offload parameters */
206 snprintf(mixer_string, sizeof(mixer_string),
207 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
208 out_ctxt->mixer = mixer_open(MIXER_CARD);
209 if (!out_ctxt->mixer) {
210 ALOGE("Failed to open mixer");
211 out_ctxt->ctl = NULL;
212 ret = -EINVAL;
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 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_preset_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,
509 audio_buffer_t *inBuffer,
510 audio_buffer_t *outBuffer)
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 = -EINVAL;
520 goto exit;
521 }
522
523 if (context->state != EFFECT_STATE_ACTIVE) {
524 status = -EINVAL;
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 = -EINVAL;
545 goto exit;
546 }
547
548 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
549 status = -EINVAL;
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
737
738/* effect_handle_t interface implementation for offload effects */
739const struct effect_interface_s effect_interface = {
740 effect_process,
741 effect_command,
742 effect_get_descriptor,
743 NULL,
744};
745
746__attribute__ ((visibility ("default")))
747audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
748 tag : AUDIO_EFFECT_LIBRARY_TAG,
749 version : EFFECT_LIBRARY_API_VERSION,
750 name : "Offload Effects Bundle Library",
751 implementor : "The Linux Foundation",
752 create_effect : effect_lib_create,
753 release_effect : effect_lib_release,
754 get_descriptor : effect_lib_get_descriptor,
755};