• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 enum {
33     EFFECT_STATE_UNINITIALIZED,
34     EFFECT_STATE_INITIALIZED,
35     EFFECT_STATE_ACTIVE,
36 };
37 
38 const 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 
49 pthread_once_t once = PTHREAD_ONCE_INIT;
50 int 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  */
56 struct 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  */
62 struct listnode active_outputs_list;
63 /*
64  * lock must be held when modifying or accessing
65  * created_effects_list or active_outputs_list
66  */
67 pthread_mutex_t lock;
68 
69 
70 /*
71  *  Local functions
72  */
init_once()73 static 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 
lib_init()82 int lib_init()
83 {
84     pthread_once(&once, init_once);
85     return init_status;
86 }
87 
effect_exists(effect_context_t * context)88 bool 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 
get_output(audio_io_handle_t output)103 output_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 
add_effect_to_output(output_context_t * output,effect_context_t * context)117 void 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 
remove_effect_from_output(output_context_t * output,effect_context_t * context)134 void 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 
effects_enabled()152 bool 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")))
offload_effects_bundle_hal_start_output(audio_io_handle_t output,int pcm_id)179 int 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);
238 exit:
239     pthread_mutex_unlock(&lock);
240     return ret;
241 }
242 
243 __attribute__ ((visibility ("default")))
offload_effects_bundle_hal_stop_output(audio_io_handle_t output,int pcm_id)244 int 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 
280 exit:
281     pthread_mutex_unlock(&lock);
282     return ret;
283 }
284 
285 
286 /*
287  * Effect operations
288  */
set_config(effect_context_t * context,effect_config_t * config)289 int 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 
get_config(effect_context_t * context,effect_config_t * config)299 void 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  */
effect_lib_create(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)308 int 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 
effect_lib_release(effect_handle_t handle)453 int 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 
effect_lib_get_descriptor(const effect_uuid_t * uuid,effect_descriptor_t * descriptor)479 int 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 */
effect_process(effect_handle_t self,audio_buffer_t * inBuffer __unused,audio_buffer_t * outBuffer __unused)508 int effect_process(effect_handle_t self,
509                        audio_buffer_t *inBuffer __unused,
510                        audio_buffer_t *outBuffer __unused)
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 
528 exit:
529     pthread_mutex_unlock(&lock);
530     return status;
531 }
532 
effect_command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)533 int 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 
717 exit:
718     pthread_mutex_unlock(&lock);
719 
720     return status;
721 }
722 
723 /* Effect Control Interface Implementation: get_descriptor */
effect_get_descriptor(effect_handle_t self,effect_descriptor_t * descriptor)724 int 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 
effect_is_active(effect_context_t * ctxt)737 bool 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 */
742 const struct effect_interface_s effect_interface = {
743     effect_process,
744     effect_command,
745     effect_get_descriptor,
746     NULL,
747 };
748 
749 __attribute__ ((visibility ("default")))
750 audio_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