blob: 37e78b16b925e095f4f16190c03277f87980be2a [file] [log] [blame]
Uday Kishore Pasupuleti582e0a52016-01-06 19:12:41 -08001/*
2 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#define LOG_TAG "offload_effect_bundle"
21#define LOG_NDEBUG 0
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#include <stdlib.h>
29
30#include "bundle.h"
31#include "equalizer.h"
32#include "bass_boost.h"
33#include "virtualizer.h"
34#include "reverb.h"
35
36enum {
37 EFFECT_STATE_UNINITIALIZED,
38 EFFECT_STATE_INITIALIZED,
39 EFFECT_STATE_ACTIVE,
40};
41
42const effect_descriptor_t *descriptors[] = {
43 &equalizer_descriptor,
44 &bassboost_descriptor,
45 &virtualizer_descriptor,
46 &aux_env_reverb_descriptor,
47 &ins_env_reverb_descriptor,
48 &aux_preset_reverb_descriptor,
49 &ins_preset_reverb_descriptor,
50 NULL,
51};
52
53pthread_once_t once = PTHREAD_ONCE_INIT;
54int init_status;
55/*
56 * list of created effects.
57 * Updated by offload_effects_bundle_hal_start_output()
58 * and offload_effects_bundle_hal_stop_output()
59 */
60struct listnode created_effects_list;
61/*
62 * list of active output streams.
63 * Updated by offload_effects_bundle_hal_start_output()
64 * and offload_effects_bundle_hal_stop_output()
65 */
66struct listnode active_outputs_list;
67/*
68 * lock must be held when modifying or accessing
69 * created_effects_list or active_outputs_list
70 */
71pthread_mutex_t lock;
72
73
74/*
75 * Local functions
76 */
77static void init_once() {
78 list_init(&created_effects_list);
79 list_init(&active_outputs_list);
80
81 pthread_mutex_init(&lock, NULL);
82
83 init_status = 0;
84}
85
86int lib_init()
87{
88 pthread_once(&once, init_once);
89 return init_status;
90}
91
92bool effect_exists(effect_context_t *context)
93{
94 struct listnode *node;
95
96 list_for_each(node, &created_effects_list) {
97 effect_context_t *fx_ctxt = node_to_item(node,
98 effect_context_t,
99 effects_list_node);
100 if (fx_ctxt == context) {
101 return true;
102 }
103 }
104 return false;
105}
106
107output_context_t *get_output(audio_io_handle_t output)
108{
109 struct listnode *node;
110
111 list_for_each(node, &active_outputs_list) {
112 output_context_t *out_ctxt = node_to_item(node,
113 output_context_t,
114 outputs_list_node);
115 if (out_ctxt->handle == output)
116 return out_ctxt;
117 }
118 return NULL;
119}
120
121void add_effect_to_output(output_context_t * output, effect_context_t *context)
122{
123 struct listnode *fx_node;
124
125 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
126 list_for_each(fx_node, &output->effects_list) {
127 effect_context_t *fx_ctxt = node_to_item(fx_node,
128 effect_context_t,
129 output_node);
130 if (fx_ctxt == context)
131 return;
132 }
133 list_add_tail(&output->effects_list, &context->output_node);
134 if (context->ops.start)
135 context->ops.start(context, output);
136
137}
138
139void remove_effect_from_output(output_context_t * output,
140 effect_context_t *context)
141{
142 struct listnode *fx_node;
143
144 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
145 list_for_each(fx_node, &output->effects_list) {
146 effect_context_t *fx_ctxt = node_to_item(fx_node,
147 effect_context_t,
148 output_node);
149 if (fx_ctxt == context) {
150 if (context->ops.stop)
151 context->ops.stop(context, output);
152 list_remove(&context->output_node);
153 return;
154 }
155 }
156}
157
158bool effects_enabled()
159{
160 struct listnode *out_node;
161
162 list_for_each(out_node, &active_outputs_list) {
163 struct listnode *fx_node;
164 output_context_t *out_ctxt = node_to_item(out_node,
165 output_context_t,
166 outputs_list_node);
167
168 list_for_each(fx_node, &out_ctxt->effects_list) {
169 effect_context_t *fx_ctxt = node_to_item(fx_node,
170 effect_context_t,
171 output_node);
172 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
173 (fx_ctxt->ops.process != NULL))
174 return true;
175 }
176 }
177 return false;
178}
179
180
181/*
182 * Interface from audio HAL
183 */
184__attribute__ ((visibility ("default")))
185int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
186{
187 int ret = 0;
188 struct listnode *node;
189 char mixer_string[128];
190 output_context_t * out_ctxt = NULL;
191
192 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
193
194 if (lib_init() != 0)
195 return init_status;
196
197 pthread_mutex_lock(&lock);
198 if (get_output(output) != NULL) {
199 ALOGW("%s output already started", __func__);
200 ret = -ENOSYS;
201 goto exit;
202 }
203
204 out_ctxt = (output_context_t *)
205 malloc(sizeof(output_context_t));
206 if (!out_ctxt) {
207 ALOGE("%s fail to allocate for output context", __func__);
208 ret = -ENOMEM;
209 goto exit;
210 }
211 out_ctxt->handle = output;
212 out_ctxt->pcm_device_id = pcm_id;
213
214 /* populate the mixer control to send offload parameters */
215 snprintf(mixer_string, sizeof(mixer_string),
216 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
217 out_ctxt->mixer = mixer_open(MIXER_CARD);
218 if (!out_ctxt->mixer) {
219 ALOGE("Failed to open mixer");
220 out_ctxt->ctl = NULL;
221 ret = -EINVAL;
222 free(out_ctxt);
223 goto exit;
224 } else {
225 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
226 if (!out_ctxt->ctl) {
227 ALOGE("mixer_get_ctl_by_name failed");
228 mixer_close(out_ctxt->mixer);
229 out_ctxt->mixer = NULL;
230 ret = -EINVAL;
231 free(out_ctxt);
232 goto exit;
233 }
234 }
235
236 list_init(&out_ctxt->effects_list);
237
238 list_for_each(node, &created_effects_list) {
239 effect_context_t *fx_ctxt = node_to_item(node,
240 effect_context_t,
241 effects_list_node);
242 if (fx_ctxt->out_handle == output) {
243 if (fx_ctxt->ops.start)
244 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
245 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
246 }
247 }
248 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
249exit:
250 pthread_mutex_unlock(&lock);
251 return ret;
252}
253
254__attribute__ ((visibility ("default")))
255int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
256{
257 int ret;
258 struct listnode *node;
259 struct listnode *fx_node;
260 output_context_t *out_ctxt;
261
262 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
263
264 if (lib_init() != 0)
265 return init_status;
266
267 pthread_mutex_lock(&lock);
268
269 out_ctxt = get_output(output);
270 if (out_ctxt == NULL) {
271 ALOGW("%s output not started", __func__);
272 ret = -ENOSYS;
273 goto exit;
274 }
275
276 if (out_ctxt->mixer)
277 mixer_close(out_ctxt->mixer);
278
279 list_for_each(fx_node, &out_ctxt->effects_list) {
280 effect_context_t *fx_ctxt = node_to_item(fx_node,
281 effect_context_t,
282 output_node);
283 if (fx_ctxt->ops.stop)
284 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
285 }
286
287 list_remove(&out_ctxt->outputs_list_node);
288
289 free(out_ctxt);
290
291exit:
292 pthread_mutex_unlock(&lock);
293 return ret;
294}
295
296
297/*
298 * Effect operations
299 */
300int set_config(effect_context_t *context, effect_config_t *config)
301{
302 context->config = *config;
303
304 if (context->ops.reset)
305 context->ops.reset(context);
306
307 return 0;
308}
309
310void get_config(effect_context_t *context, effect_config_t *config)
311{
312 *config = context->config;
313}
314
315
316/*
317 * Effect Library Interface Implementation
318 */
319int effect_lib_create(const effect_uuid_t *uuid,
320 int32_t sessionId,
321 int32_t ioId,
322 effect_handle_t *pHandle) {
323 int ret;
324 int i;
325
326 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
327 if (lib_init() != 0)
328 return init_status;
329
330 if (pHandle == NULL || uuid == NULL)
331 return -EINVAL;
332
333 for (i = 0; descriptors[i] != NULL; i++) {
334 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
335 break;
336 }
337
338 if (descriptors[i] == NULL)
339 return -EINVAL;
340
341 effect_context_t *context;
342 if (memcmp(uuid, &equalizer_descriptor.uuid,
343 sizeof(effect_uuid_t)) == 0) {
344 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
345 calloc(1, sizeof(equalizer_context_t));
346 if (eq_ctxt == NULL) {
347 return -ENOMEM;
348 }
349 context = (effect_context_t *)eq_ctxt;
350 context->ops.init = equalizer_init;
351 context->ops.reset = equalizer_reset;
352 context->ops.set_parameter = equalizer_set_parameter;
353 context->ops.get_parameter = equalizer_get_parameter;
354 context->ops.set_device = equalizer_set_device;
355 context->ops.enable = equalizer_enable;
356 context->ops.disable = equalizer_disable;
357 context->ops.start = equalizer_start;
358 context->ops.stop = equalizer_stop;
359
360 context->desc = &equalizer_descriptor;
361 eq_ctxt->ctl = NULL;
362 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
363 sizeof(effect_uuid_t)) == 0) {
364 bassboost_context_t *bass_ctxt = (bassboost_context_t *)
365 calloc(1, sizeof(bassboost_context_t));
366 if (bass_ctxt == NULL) {
367 return -ENOMEM;
368 }
369 context = (effect_context_t *)bass_ctxt;
370 context->ops.init = bassboost_init;
371 context->ops.reset = bassboost_reset;
372 context->ops.set_parameter = bassboost_set_parameter;
373 context->ops.get_parameter = bassboost_get_parameter;
374 context->ops.set_device = bassboost_set_device;
375 context->ops.enable = bassboost_enable;
376 context->ops.disable = bassboost_disable;
377 context->ops.start = bassboost_start;
378 context->ops.stop = bassboost_stop;
379
380 context->desc = &bassboost_descriptor;
381 bass_ctxt->ctl = NULL;
382 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
383 sizeof(effect_uuid_t)) == 0) {
384 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
385 calloc(1, sizeof(virtualizer_context_t));
386 if (virt_ctxt == NULL) {
387 return -ENOMEM;
388 }
389 context = (effect_context_t *)virt_ctxt;
390 context->ops.init = virtualizer_init;
391 context->ops.reset = virtualizer_reset;
392 context->ops.set_parameter = virtualizer_set_parameter;
393 context->ops.get_parameter = virtualizer_get_parameter;
394 context->ops.set_device = virtualizer_set_device;
395 context->ops.enable = virtualizer_enable;
396 context->ops.disable = virtualizer_disable;
397 context->ops.start = virtualizer_start;
398 context->ops.stop = virtualizer_stop;
399
400 context->desc = &virtualizer_descriptor;
401 virt_ctxt->ctl = NULL;
402 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
403 sizeof(effect_uuid_t)) == 0) ||
404 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
405 sizeof(effect_uuid_t)) == 0) ||
406 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
407 sizeof(effect_uuid_t)) == 0) ||
408 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
409 sizeof(effect_uuid_t)) == 0)) {
410 reverb_context_t *reverb_ctxt = (reverb_context_t *)
411 calloc(1, sizeof(reverb_context_t));
412 if (reverb_ctxt == NULL) {
413 return -ENOMEM;
414 }
415 context = (effect_context_t *)reverb_ctxt;
416 context->ops.init = reverb_init;
417 context->ops.reset = reverb_reset;
418 context->ops.set_parameter = reverb_set_parameter;
419 context->ops.get_parameter = reverb_get_parameter;
420 context->ops.set_device = reverb_set_device;
421 context->ops.enable = reverb_enable;
422 context->ops.disable = reverb_disable;
423 context->ops.start = reverb_start;
424 context->ops.stop = reverb_stop;
425
426 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
427 sizeof(effect_uuid_t)) == 0) {
428 context->desc = &aux_env_reverb_descriptor;
429 reverb_auxiliary_init(reverb_ctxt);
430 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
431 sizeof(effect_uuid_t)) == 0) {
432 context->desc = &ins_env_reverb_descriptor;
433 reverb_preset_init(reverb_ctxt);
434 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
435 sizeof(effect_uuid_t)) == 0) {
436 context->desc = &aux_preset_reverb_descriptor;
437 reverb_auxiliary_init(reverb_ctxt);
438 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
439 sizeof(effect_uuid_t)) == 0) {
440 context->desc = &ins_preset_reverb_descriptor;
441 reverb_preset_init(reverb_ctxt);
442 }
443 reverb_ctxt->ctl = NULL;
444 } else {
445 return -EINVAL;
446 }
447
448 context->itfe = &effect_interface;
449 context->state = EFFECT_STATE_UNINITIALIZED;
450 context->out_handle = (audio_io_handle_t)ioId;
451
452 ret = context->ops.init(context);
453 if (ret < 0) {
454 ALOGW("%s init failed", __func__);
455 free(context);
456 return ret;
457 }
458
459 context->state = EFFECT_STATE_INITIALIZED;
460
461 pthread_mutex_lock(&lock);
462 list_add_tail(&created_effects_list, &context->effects_list_node);
463 output_context_t *out_ctxt = get_output(ioId);
464 if (out_ctxt != NULL)
465 add_effect_to_output(out_ctxt, context);
466 pthread_mutex_unlock(&lock);
467
468 *pHandle = (effect_handle_t)context;
469
470 ALOGV("%s created context %p", __func__, context);
471
472 return 0;
473
474}
475
476int effect_lib_release(effect_handle_t handle)
477{
478 effect_context_t *context = (effect_context_t *)handle;
479 int status;
480
481 if (lib_init() != 0)
482 return init_status;
483
484 ALOGV("%s context %p", __func__, handle);
485 pthread_mutex_lock(&lock);
486 status = -EINVAL;
487 if (effect_exists(context)) {
488 output_context_t *out_ctxt = get_output(context->out_handle);
489 if (out_ctxt != NULL)
490 remove_effect_from_output(out_ctxt, context);
491 list_remove(&context->effects_list_node);
492 if (context->ops.release)
493 context->ops.release(context);
494 free(context);
495 status = 0;
496 }
497 pthread_mutex_unlock(&lock);
498
499 return status;
500}
501
502int effect_lib_get_descriptor(const effect_uuid_t *uuid,
503 effect_descriptor_t *descriptor)
504{
505 int i;
506
507 if (lib_init() != 0)
508 return init_status;
509
510 if (descriptor == NULL || uuid == NULL) {
511 ALOGV("%s called with NULL pointer", __func__);
512 return -EINVAL;
513 }
514
515 for (i = 0; descriptors[i] != NULL; i++) {
516 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
517 *descriptor = *descriptors[i];
518 return 0;
519 }
520 }
521
522 return -EINVAL;
523}
524
525
526/*
527 * Effect Control Interface Implementation
528 */
529
530/* Stub function for effect interface: never called for offloaded effects */
531int effect_process(effect_handle_t self,
532 audio_buffer_t *inBuffer __unused,
533 audio_buffer_t *outBuffer __unused)
534{
535 effect_context_t * context = (effect_context_t *)self;
536 int status = 0;
537
538 ALOGW("%s: ctxt %p, Called ?????", __func__, context);
539
540 pthread_mutex_lock(&lock);
541 if (!effect_exists(context)) {
542 status = -ENOSYS;
543 goto exit;
544 }
545
546 if (context->state != EFFECT_STATE_ACTIVE) {
547 status = -ENODATA;
548 goto exit;
549 }
550
551exit:
552 pthread_mutex_unlock(&lock);
553 return status;
554}
555
556int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
557 void *pCmdData, uint32_t *replySize, void *pReplyData)
558{
559
560 effect_context_t * context = (effect_context_t *)self;
561 int retsize;
562 int status = 0;
563
564 pthread_mutex_lock(&lock);
565
566 if (!effect_exists(context)) {
567 status = -ENOSYS;
568 goto exit;
569 }
570
571 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
572 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
573 status = -ENOSYS;
574 goto exit;
575 }
576
577 switch (cmdCode) {
578 case EFFECT_CMD_INIT:
579 if (pReplyData == NULL || *replySize != sizeof(int)) {
580 status = -EINVAL;
581 goto exit;
582 }
583 if (context->ops.init)
584 *(int *) pReplyData = context->ops.init(context);
585 else
586 *(int *) pReplyData = 0;
587 break;
588 case EFFECT_CMD_SET_CONFIG:
589 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
590 || pReplyData == NULL || *replySize != sizeof(int)) {
591 status = -EINVAL;
592 goto exit;
593 }
594 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
595 break;
596 case EFFECT_CMD_GET_CONFIG:
597 if (pReplyData == NULL ||
598 *replySize != sizeof(effect_config_t)) {
599 status = -EINVAL;
600 goto exit;
601 }
602 if (!context->offload_enabled) {
603 status = -EINVAL;
604 goto exit;
605 }
606
607 get_config(context, (effect_config_t *)pReplyData);
608 break;
609 case EFFECT_CMD_RESET:
610 if (context->ops.reset)
611 context->ops.reset(context);
612 break;
613 case EFFECT_CMD_ENABLE:
614 if (pReplyData == NULL || *replySize != sizeof(int)) {
615 status = -EINVAL;
616 goto exit;
617 }
618 if (context->state != EFFECT_STATE_INITIALIZED) {
619 status = -ENOSYS;
620 goto exit;
621 }
622 context->state = EFFECT_STATE_ACTIVE;
623 if (context->ops.enable)
624 context->ops.enable(context);
625 *(int *)pReplyData = 0;
626 break;
627 case EFFECT_CMD_DISABLE:
628 if (pReplyData == NULL || *replySize != sizeof(int)) {
629 status = -EINVAL;
630 goto exit;
631 }
632 if (context->state != EFFECT_STATE_ACTIVE) {
633 status = -ENOSYS;
634 goto exit;
635 }
636 context->state = EFFECT_STATE_INITIALIZED;
637 if (context->ops.disable)
638 context->ops.disable(context);
639 *(int *)pReplyData = 0;
640 break;
641 case EFFECT_CMD_GET_PARAM: {
642 if (pCmdData == NULL ||
643 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
644 pReplyData == NULL ||
645 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
646 sizeof(uint16_t))) {
647 status = -EINVAL;
648 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
649 cmdSize, *replySize);
650 goto exit;
651 }
652 if (!context->offload_enabled) {
653 status = -EINVAL;
654 goto exit;
655 }
656 effect_param_t *q = (effect_param_t *)pCmdData;
657 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
658 effect_param_t *p = (effect_param_t *)pReplyData;
659 if (context->ops.get_parameter)
660 context->ops.get_parameter(context, p, replySize);
661 } break;
662 case EFFECT_CMD_SET_PARAM: {
663 if (pCmdData == NULL ||
664 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
665 sizeof(uint16_t)) ||
666 pReplyData == NULL || *replySize != sizeof(int32_t)) {
667 status = -EINVAL;
668 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
669 cmdSize, *replySize);
670 goto exit;
671 }
672 *(int32_t *)pReplyData = 0;
673 effect_param_t *p = (effect_param_t *)pCmdData;
674 if (context->ops.set_parameter)
675 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
676 *replySize);
677
678 } break;
679 case EFFECT_CMD_SET_DEVICE: {
680 uint32_t device;
681 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
682 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
683 status = -EINVAL;
684 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
685 goto exit;
686 }
687 device = *(uint32_t *)pCmdData;
688 if (context->ops.set_device)
689 context->ops.set_device(context, device);
690 } break;
691 case EFFECT_CMD_SET_VOLUME:
692 case EFFECT_CMD_SET_AUDIO_MODE:
693 break;
694
695 case EFFECT_CMD_OFFLOAD: {
696 output_context_t *out_ctxt;
697
698 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
699 || pReplyData == NULL || *replySize != sizeof(int)) {
700 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
701 status = -EINVAL;
702 break;
703 }
704
705 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
706
707 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
708 offload_param->isOffload, offload_param->ioHandle);
709
710 *(int *)pReplyData = 0;
711
712 context->offload_enabled = offload_param->isOffload;
713 if (context->out_handle == offload_param->ioHandle)
714 break;
715
716 out_ctxt = get_output(context->out_handle);
717 if (out_ctxt != NULL)
718 remove_effect_from_output(out_ctxt, context);
719
720 context->out_handle = offload_param->ioHandle;
721 out_ctxt = get_output(context->out_handle);
722 if (out_ctxt != NULL)
723 add_effect_to_output(out_ctxt, context);
724
725 } break;
726
727
728 default:
729 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
730 status = context->ops.command(context, cmdCode, cmdSize,
731 pCmdData, replySize, pReplyData);
732 else {
733 ALOGW("%s invalid command %d", __func__, cmdCode);
734 status = -EINVAL;
735 }
736 break;
737 }
738
739exit:
740 pthread_mutex_unlock(&lock);
741
742 return status;
743}
744
745/* Effect Control Interface Implementation: get_descriptor */
746int effect_get_descriptor(effect_handle_t self,
747 effect_descriptor_t *descriptor)
748{
749 effect_context_t *context = (effect_context_t *)self;
750
751 if (!effect_exists(context) || (descriptor == NULL))
752 return -EINVAL;
753
754 *descriptor = *context->desc;
755
756 return 0;
757}
758
759bool effect_is_active(effect_context_t * ctxt) {
760 return ctxt->state == EFFECT_STATE_ACTIVE;
761}
762
763/* effect_handle_t interface implementation for offload effects */
764const struct effect_interface_s effect_interface = {
765 effect_process,
766 effect_command,
767 effect_get_descriptor,
768 NULL,
769};
770
771__attribute__ ((visibility ("default")))
772audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
773 tag : AUDIO_EFFECT_LIBRARY_TAG,
774 version : EFFECT_LIBRARY_API_VERSION,
775 name : "Offload Effects Bundle Library",
776 implementor : "The Linux Foundation",
777 create_effect : effect_lib_create,
778 release_effect : effect_lib_release,
779 get_descriptor : effect_lib_get_descriptor,
780};