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 
33 enum {
34     EFFECT_STATE_UNINITIALIZED,
35     EFFECT_STATE_INITIALIZED,
36     EFFECT_STATE_ACTIVE,
37 };
38 
39 const 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 
50 pthread_once_t once = PTHREAD_ONCE_INIT;
51 int 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  */
57 struct 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  */
63 struct listnode active_outputs_list;
64 /*
65  * lock must be held when modifying or accessing
66  * created_effects_list or active_outputs_list
67  */
68 pthread_mutex_t lock;
69 
70 
71 /*
72  *  Local functions
73  */
init_once()74 static 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 
lib_init()83 int lib_init()
84 {
85     pthread_once(&once, init_once);
86     return init_status;
87 }
88 
effect_exists(effect_context_t * context)89 bool 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 
get_output(audio_io_handle_t output)104 output_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 
add_effect_to_output(output_context_t * output,effect_context_t * context)118 void 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 
remove_effect_from_output(output_context_t * output,effect_context_t * context)135 void 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 
effects_enabled()153 bool 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")))
offload_effects_bundle_hal_start_output(audio_io_handle_t output,int pcm_id)180 int 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);
239 exit:
240     pthread_mutex_unlock(&lock);
241     return ret;
242 }
243 
244 __attribute__ ((visibility ("default")))
offload_effects_bundle_hal_stop_output(audio_io_handle_t output,int pcm_id)245 int 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 
281 exit:
282     pthread_mutex_unlock(&lock);
283     return ret;
284 }
285 
286 
287 /*
288  * Effect operations
289  */
set_config(effect_context_t * context,effect_config_t * config)290 int 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 
get_config(effect_context_t * context,effect_config_t * config)300 void 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  */
effect_lib_create(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)309 int 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 
effect_lib_release(effect_handle_t handle)454 int 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 
effect_lib_get_descriptor(const effect_uuid_t * uuid,effect_descriptor_t * descriptor)480 int 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 */
effect_process(effect_handle_t self,audio_buffer_t * inBuffer __unused,audio_buffer_t * outBuffer __unused)509 int 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 
529 exit:
530     pthread_mutex_unlock(&lock);
531     return status;
532 }
533 
effect_command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)534 int 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 
719 exit:
720     pthread_mutex_unlock(&lock);
721 
722     return status;
723 }
724 
725 /* Effect Control Interface Implementation: get_descriptor */
effect_get_descriptor(effect_handle_t self,effect_descriptor_t * descriptor)726 int 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 
effect_is_active(effect_context_t * ctxt)739 bool 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 */
744 const struct effect_interface_s effect_interface = {
745     effect_process,
746     effect_command,
747     effect_get_descriptor,
748     NULL,
749 };
750 
751 __attribute__ ((visibility ("default")))
752 audio_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