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