bundle.c revision 41f86651e362abc62d9d03f5c612c986bf15298f
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
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,
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 = -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};
759