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 <pthread.h>
21 #include <stdlib.h>
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 
35 enum {
36     EFFECT_STATE_UNINITIALIZED,
37     EFFECT_STATE_INITIALIZED,
38     EFFECT_STATE_ACTIVE,
39 };
40 
41 const 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 
52 pthread_once_t once = PTHREAD_ONCE_INIT;
53 int 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  */
59 struct 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  */
65 struct listnode active_outputs_list;
66 /*
67  * lock must be held when modifying or accessing
68  * created_effects_list or active_outputs_list
69  */
70 pthread_mutex_t lock;
71 
72 
73 /*
74  *  Local functions
75  */
init_once()76 static 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 
lib_init()85 int lib_init()
86 {
87     pthread_once(&once, init_once);
88     return init_status;
89 }
90 
effect_exists(effect_context_t * context)91 bool 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 
get_output(audio_io_handle_t output)106 output_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 
add_effect_to_output(output_context_t * output,effect_context_t * context)120 void 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 
remove_effect_from_output(output_context_t * output,effect_context_t * context)137 void 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 
effects_enabled()155 bool 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")))
offload_effects_bundle_hal_start_output(audio_io_handle_t output,int pcm_id)182 int 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     output_context_t * out_ctxt = NULL;
188 
189     ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
190 
191     if (lib_init() != 0)
192         return init_status;
193 
194     pthread_mutex_lock(&lock);
195     if (get_output(output) != NULL) {
196         ALOGW("%s output already started", __func__);
197         ret = -ENOSYS;
198         goto exit;
199     }
200 
201     out_ctxt = (output_context_t *)
202                                  malloc(sizeof(output_context_t));
203     out_ctxt->handle = output;
204     out_ctxt->pcm_device_id = pcm_id;
205 
206     /* populate the mixer control to send offload parameters */
207     snprintf(mixer_string, sizeof(mixer_string),
208              "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
209     out_ctxt->mixer = mixer_open(MIXER_CARD);
210     if (!out_ctxt->mixer) {
211         ALOGE("Failed to open mixer");
212         out_ctxt->ctl = NULL;
213         ret = -EINVAL;
214         free(out_ctxt);
215         goto exit;
216     } else {
217         out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
218         if (!out_ctxt->ctl) {
219             ALOGE("mixer_get_ctl_by_name failed");
220             mixer_close(out_ctxt->mixer);
221             out_ctxt->mixer = NULL;
222             ret = -EINVAL;
223             free(out_ctxt);
224             goto exit;
225         }
226     }
227 
228     list_init(&out_ctxt->effects_list);
229 
230     list_for_each(node, &created_effects_list) {
231         effect_context_t *fx_ctxt = node_to_item(node,
232                                                  effect_context_t,
233                                                  effects_list_node);
234         if (fx_ctxt->out_handle == output) {
235             if (fx_ctxt->ops.start)
236                 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
237             list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
238         }
239     }
240     list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
241 exit:
242     pthread_mutex_unlock(&lock);
243     return ret;
244 }
245 
246 __attribute__ ((visibility ("default")))
offload_effects_bundle_hal_stop_output(audio_io_handle_t output,int pcm_id)247 int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
248 {
249     int ret = 0;
250     struct listnode *node;
251     struct listnode *fx_node;
252     output_context_t *out_ctxt;
253 
254     ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
255 
256     if (lib_init() != 0)
257         return init_status;
258 
259     pthread_mutex_lock(&lock);
260 
261     out_ctxt = get_output(output);
262     if (out_ctxt == NULL) {
263         ALOGW("%s output not started", __func__);
264         ret = -ENOSYS;
265         goto exit;
266     }
267 
268     if (out_ctxt->mixer)
269         mixer_close(out_ctxt->mixer);
270 
271     list_for_each(fx_node, &out_ctxt->effects_list) {
272         effect_context_t *fx_ctxt = node_to_item(fx_node,
273                                                  effect_context_t,
274                                                  output_node);
275         if (fx_ctxt->ops.stop)
276             fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
277     }
278 
279     list_remove(&out_ctxt->outputs_list_node);
280 
281     free(out_ctxt);
282 
283 exit:
284     pthread_mutex_unlock(&lock);
285     return ret;
286 }
287 
288 
289 /*
290  * Effect operations
291  */
set_config(effect_context_t * context,effect_config_t * config)292 int set_config(effect_context_t *context, effect_config_t *config)
293 {
294     context->config = *config;
295 
296     if (context->ops.reset)
297         context->ops.reset(context);
298 
299     return 0;
300 }
301 
get_config(effect_context_t * context,effect_config_t * config)302 void get_config(effect_context_t *context, effect_config_t *config)
303 {
304     *config = context->config;
305 }
306 
307 
308 /*
309  * Effect Library Interface Implementation
310  */
effect_lib_create(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)311 int effect_lib_create(const effect_uuid_t *uuid,
312                          int32_t sessionId,
313                          int32_t ioId,
314                          effect_handle_t *pHandle) {
315     int ret;
316     int i;
317 
318     ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
319     if (lib_init() != 0)
320         return init_status;
321 
322     if (pHandle == NULL || uuid == NULL)
323         return -EINVAL;
324 
325     for (i = 0; descriptors[i] != NULL; i++) {
326         if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
327             break;
328     }
329 
330     if (descriptors[i] == NULL)
331         return -EINVAL;
332 
333     effect_context_t *context;
334     if (memcmp(uuid, &equalizer_descriptor.uuid,
335         sizeof(effect_uuid_t)) == 0) {
336         equalizer_context_t *eq_ctxt = (equalizer_context_t *)
337                                        calloc(1, sizeof(equalizer_context_t));
338         context = (effect_context_t *)eq_ctxt;
339         context->ops.init = equalizer_init;
340         context->ops.reset = equalizer_reset;
341         context->ops.set_parameter = equalizer_set_parameter;
342         context->ops.get_parameter = equalizer_get_parameter;
343         context->ops.set_device = equalizer_set_device;
344         context->ops.enable = equalizer_enable;
345         context->ops.disable = equalizer_disable;
346         context->ops.start = equalizer_start;
347         context->ops.stop = equalizer_stop;
348 
349         context->desc = &equalizer_descriptor;
350         eq_ctxt->ctl = NULL;
351     } else if (memcmp(uuid, &bassboost_descriptor.uuid,
352                sizeof(effect_uuid_t)) == 0) {
353         bassboost_context_t *bass_ctxt = (bassboost_context_t *)
354                                          calloc(1, sizeof(bassboost_context_t));
355         context = (effect_context_t *)bass_ctxt;
356         context->ops.init = bassboost_init;
357         context->ops.reset = bassboost_reset;
358         context->ops.set_parameter = bassboost_set_parameter;
359         context->ops.get_parameter = bassboost_get_parameter;
360         context->ops.set_device = bassboost_set_device;
361         context->ops.enable = bassboost_enable;
362         context->ops.disable = bassboost_disable;
363         context->ops.start = bassboost_start;
364         context->ops.stop = bassboost_stop;
365 
366         context->desc = &bassboost_descriptor;
367         bass_ctxt->ctl = NULL;
368     } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
369                sizeof(effect_uuid_t)) == 0) {
370         virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
371                                            calloc(1, sizeof(virtualizer_context_t));
372         context = (effect_context_t *)virt_ctxt;
373         context->ops.init = virtualizer_init;
374         context->ops.reset = virtualizer_reset;
375         context->ops.set_parameter = virtualizer_set_parameter;
376         context->ops.get_parameter = virtualizer_get_parameter;
377         context->ops.set_device = virtualizer_set_device;
378         context->ops.enable = virtualizer_enable;
379         context->ops.disable = virtualizer_disable;
380         context->ops.start = virtualizer_start;
381         context->ops.stop = virtualizer_stop;
382 
383         context->desc = &virtualizer_descriptor;
384         virt_ctxt->ctl = NULL;
385     } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
386                 sizeof(effect_uuid_t)) == 0) ||
387                (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
388                 sizeof(effect_uuid_t)) == 0) ||
389                (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
390                 sizeof(effect_uuid_t)) == 0) ||
391                (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
392                 sizeof(effect_uuid_t)) == 0)) {
393         reverb_context_t *reverb_ctxt = (reverb_context_t *)
394                                         calloc(1, sizeof(reverb_context_t));
395         context = (effect_context_t *)reverb_ctxt;
396         context->ops.init = reverb_init;
397         context->ops.reset = reverb_reset;
398         context->ops.set_parameter = reverb_set_parameter;
399         context->ops.get_parameter = reverb_get_parameter;
400         context->ops.set_device = reverb_set_device;
401         context->ops.enable = reverb_enable;
402         context->ops.disable = reverb_disable;
403         context->ops.start = reverb_start;
404         context->ops.stop = reverb_stop;
405 
406         if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
407                    sizeof(effect_uuid_t)) == 0) {
408             context->desc = &aux_env_reverb_descriptor;
409             reverb_auxiliary_init(reverb_ctxt);
410         } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
411                    sizeof(effect_uuid_t)) == 0) {
412             context->desc = &ins_env_reverb_descriptor;
413             reverb_insert_init(reverb_ctxt);
414         } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
415                    sizeof(effect_uuid_t)) == 0) {
416             context->desc = &aux_preset_reverb_descriptor;
417             reverb_auxiliary_init(reverb_ctxt);
418         } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
419                    sizeof(effect_uuid_t)) == 0) {
420             context->desc = &ins_preset_reverb_descriptor;
421             reverb_preset_init(reverb_ctxt);
422         }
423         reverb_ctxt->ctl = NULL;
424     } else {
425         return -EINVAL;
426     }
427 
428     context->itfe = &effect_interface;
429     context->state = EFFECT_STATE_UNINITIALIZED;
430     context->out_handle = (audio_io_handle_t)ioId;
431 
432     ret = context->ops.init(context);
433     if (ret < 0) {
434         ALOGW("%s init failed", __func__);
435         free(context);
436         return ret;
437     }
438 
439     context->state = EFFECT_STATE_INITIALIZED;
440 
441     pthread_mutex_lock(&lock);
442     list_add_tail(&created_effects_list, &context->effects_list_node);
443     output_context_t *out_ctxt = get_output(ioId);
444     if (out_ctxt != NULL)
445         add_effect_to_output(out_ctxt, context);
446     pthread_mutex_unlock(&lock);
447 
448     *pHandle = (effect_handle_t)context;
449 
450     ALOGV("%s created context %p", __func__, context);
451 
452     return 0;
453 
454 }
455 
effect_lib_release(effect_handle_t handle)456 int effect_lib_release(effect_handle_t handle)
457 {
458     effect_context_t *context = (effect_context_t *)handle;
459     int status;
460 
461     if (lib_init() != 0)
462         return init_status;
463 
464     ALOGV("%s context %p", __func__, handle);
465     pthread_mutex_lock(&lock);
466     status = -EINVAL;
467     if (effect_exists(context)) {
468         output_context_t *out_ctxt = get_output(context->out_handle);
469         if (out_ctxt != NULL)
470             remove_effect_from_output(out_ctxt, context);
471         list_remove(&context->effects_list_node);
472         if (context->ops.release)
473             context->ops.release(context);
474         free(context);
475         status = 0;
476     }
477     pthread_mutex_unlock(&lock);
478 
479     return status;
480 }
481 
effect_lib_get_descriptor(const effect_uuid_t * uuid,effect_descriptor_t * descriptor)482 int effect_lib_get_descriptor(const effect_uuid_t *uuid,
483                               effect_descriptor_t *descriptor)
484 {
485     int i;
486 
487     if (lib_init() != 0)
488         return init_status;
489 
490     if (descriptor == NULL || uuid == NULL) {
491         ALOGV("%s called with NULL pointer", __func__);
492         return -EINVAL;
493     }
494 
495     for (i = 0; descriptors[i] != NULL; i++) {
496         if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
497             *descriptor = *descriptors[i];
498             return 0;
499         }
500     }
501 
502     return  -EINVAL;
503 }
504 
505 
506 /*
507  * Effect Control Interface Implementation
508  */
509 
510 /* 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)511 int effect_process(effect_handle_t self,
512                        audio_buffer_t *inBuffer __unused,
513                        audio_buffer_t *outBuffer __unused)
514 {
515     effect_context_t * context = (effect_context_t *)self;
516     int status = 0;
517 
518     ALOGW("%s Called ?????", __func__);
519 
520     pthread_mutex_lock(&lock);
521     if (!effect_exists(context)) {
522         status = -ENOSYS;
523         goto exit;
524     }
525 
526     if (context->state != EFFECT_STATE_ACTIVE) {
527         status = -ENODATA;
528         goto exit;
529     }
530 
531 exit:
532     pthread_mutex_unlock(&lock);
533     return status;
534 }
535 
effect_command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)536 int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
537                    void *pCmdData, uint32_t *replySize, void *pReplyData)
538 {
539 
540     effect_context_t * context = (effect_context_t *)self;
541     int retsize;
542     int status = 0;
543 
544     pthread_mutex_lock(&lock);
545 
546     if (!effect_exists(context)) {
547         status = -ENOSYS;
548         goto exit;
549     }
550 
551     if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
552         status = -ENOSYS;
553         goto exit;
554     }
555 
556     switch (cmdCode) {
557     case EFFECT_CMD_INIT:
558         if (pReplyData == NULL || *replySize != sizeof(int)) {
559             status = -EINVAL;
560             goto exit;
561         }
562         if (context->ops.init)
563             *(int *) pReplyData = context->ops.init(context);
564         else
565             *(int *) pReplyData = 0;
566         break;
567     case EFFECT_CMD_SET_CONFIG:
568         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
569                 || pReplyData == NULL || *replySize != sizeof(int)) {
570             status = -EINVAL;
571             goto exit;
572         }
573         *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
574         break;
575     case EFFECT_CMD_GET_CONFIG:
576         if (pReplyData == NULL ||
577             *replySize != sizeof(effect_config_t)) {
578             status = -EINVAL;
579             goto exit;
580         }
581         if (!context->offload_enabled) {
582             status = -EINVAL;
583             goto exit;
584         }
585 
586         get_config(context, (effect_config_t *)pReplyData);
587         break;
588     case EFFECT_CMD_RESET:
589         if (context->ops.reset)
590             context->ops.reset(context);
591         break;
592     case EFFECT_CMD_ENABLE:
593         if (pReplyData == NULL || *replySize != sizeof(int)) {
594             status = -EINVAL;
595             goto exit;
596         }
597         if (context->state != EFFECT_STATE_INITIALIZED) {
598             status = -ENOSYS;
599             goto exit;
600         }
601         context->state = EFFECT_STATE_ACTIVE;
602         if (context->ops.enable)
603             context->ops.enable(context);
604         ALOGV("%s EFFECT_CMD_ENABLE", __func__);
605         *(int *)pReplyData = 0;
606         break;
607     case EFFECT_CMD_DISABLE:
608         if (pReplyData == NULL || *replySize != sizeof(int)) {
609             status = -EINVAL;
610             goto exit;
611         }
612         if (context->state != EFFECT_STATE_ACTIVE) {
613             status = -ENOSYS;
614             goto exit;
615         }
616         context->state = EFFECT_STATE_INITIALIZED;
617         if (context->ops.disable)
618             context->ops.disable(context);
619         ALOGV("%s EFFECT_CMD_DISABLE", __func__);
620         *(int *)pReplyData = 0;
621         break;
622     case EFFECT_CMD_GET_PARAM: {
623         if (pCmdData == NULL ||
624             cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
625             pReplyData == NULL ||
626             *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
627             // constrain memcpy below
628             ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
629             status = -EINVAL;
630             ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
631                   cmdSize, *replySize);
632             goto exit;
633         }
634         if (!context->offload_enabled) {
635             status = -EINVAL;
636             goto exit;
637         }
638         effect_param_t *q = (effect_param_t *)pCmdData;
639         memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
640         effect_param_t *p = (effect_param_t *)pReplyData;
641         if (context->ops.get_parameter)
642             context->ops.get_parameter(context, p, replySize);
643         } break;
644     case EFFECT_CMD_SET_PARAM: {
645         if (pCmdData == NULL ||
646             cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
647                             sizeof(uint16_t)) ||
648             pReplyData == NULL || *replySize != sizeof(int32_t)) {
649             status = -EINVAL;
650             ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
651                   cmdSize, *replySize);
652             goto exit;
653         }
654         *(int32_t *)pReplyData = 0;
655         effect_param_t *p = (effect_param_t *)pCmdData;
656         if (context->ops.set_parameter)
657             *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
658                                                                 *replySize);
659 
660         } break;
661     case EFFECT_CMD_SET_DEVICE: {
662         uint32_t device;
663         ALOGV("\t EFFECT_CMD_SET_DEVICE start");
664         if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
665             status = -EINVAL;
666             ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
667             goto exit;
668         }
669         device = *(uint32_t *)pCmdData;
670         if (context->ops.set_device)
671             context->ops.set_device(context, device);
672         } break;
673     case EFFECT_CMD_SET_VOLUME: {
674         // if pReplyData is NULL, VOL_CTRL is delegated to another effect
675         if (pReplyData == NULL) {
676             break;
677         }
678         if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
679                 replySize == NULL || *replySize < 2*sizeof(int32_t)) {
680             return -EINVAL;
681         }
682         memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
683         } break;
684     case EFFECT_CMD_SET_AUDIO_MODE:
685         break;
686     case EFFECT_CMD_OFFLOAD: {
687         output_context_t *out_ctxt;
688 
689         if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
690                 || pReplyData == NULL || *replySize != sizeof(int)) {
691             ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__);
692             status = -EINVAL;
693             break;
694         }
695 
696         effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
697 
698         ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
699               offload_param->isOffload, offload_param->ioHandle);
700 
701         *(int *)pReplyData = 0;
702 
703         context->offload_enabled = offload_param->isOffload;
704         if (context->out_handle == offload_param->ioHandle)
705             break;
706 
707         out_ctxt = get_output(context->out_handle);
708         if (out_ctxt != NULL)
709             remove_effect_from_output(out_ctxt, context);
710 
711         context->out_handle = offload_param->ioHandle;
712         out_ctxt = get_output(context->out_handle);
713         if (out_ctxt != NULL)
714             add_effect_to_output(out_ctxt, context);
715 
716         } break;
717     default:
718         if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
719             status = context->ops.command(context, cmdCode, cmdSize,
720                                           pCmdData, replySize, pReplyData);
721         else {
722             ALOGW("%s invalid command %d", __func__, cmdCode);
723             status = -EINVAL;
724         }
725         break;
726     }
727 
728 exit:
729     pthread_mutex_unlock(&lock);
730 
731     return status;
732 }
733 
734 /* Effect Control Interface Implementation: get_descriptor */
effect_get_descriptor(effect_handle_t self,effect_descriptor_t * descriptor)735 int effect_get_descriptor(effect_handle_t   self,
736                           effect_descriptor_t *descriptor)
737 {
738     effect_context_t *context = (effect_context_t *)self;
739 
740     if (!effect_exists(context) || (descriptor == NULL))
741         return -EINVAL;
742 
743     *descriptor = *context->desc;
744 
745     return 0;
746 }
747 
effect_is_active(effect_context_t * ctxt)748 bool effect_is_active(effect_context_t * ctxt) {
749     return ctxt->state == EFFECT_STATE_ACTIVE;
750 }
751 
752 /* effect_handle_t interface implementation for offload effects */
753 const struct effect_interface_s effect_interface = {
754     effect_process,
755     effect_command,
756     effect_get_descriptor,
757     NULL,
758 };
759 
760 __attribute__ ((visibility ("default")))
761 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
762     .tag = AUDIO_EFFECT_LIBRARY_TAG,
763     .version = EFFECT_LIBRARY_API_VERSION,
764     .name = "Offload Effects Bundle Library",
765     .implementor = "The Android Open Source Project",
766     .create_effect = effect_lib_create,
767     .release_effect = effect_lib_release,
768     .get_descriptor = effect_lib_get_descriptor,
769 };
770