1 /*
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
36 enum {
37 EFFECT_STATE_UNINITIALIZED,
38 EFFECT_STATE_INITIALIZED,
39 EFFECT_STATE_ACTIVE,
40 };
41
42 const 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
53 pthread_once_t once = PTHREAD_ONCE_INIT;
54 int 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 */
60 struct 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 */
66 struct listnode active_outputs_list;
67 /*
68 * lock must be held when modifying or accessing
69 * created_effects_list or active_outputs_list
70 */
71 pthread_mutex_t lock;
72
73
74 /*
75 * Local functions
76 */
init_once()77 static 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
lib_init()86 int lib_init()
87 {
88 pthread_once(&once, init_once);
89 return init_status;
90 }
91
effect_exists(effect_context_t * context)92 bool 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
get_output(audio_io_handle_t output)107 output_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
add_effect_to_output(output_context_t * output,effect_context_t * context)121 void 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
remove_effect_from_output(output_context_t * output,effect_context_t * context)139 void 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
effects_enabled()158 bool 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")))
offload_effects_bundle_hal_start_output(audio_io_handle_t output,int pcm_id)185 int 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);
249 exit:
250 pthread_mutex_unlock(&lock);
251 return ret;
252 }
253
254 __attribute__ ((visibility ("default")))
offload_effects_bundle_hal_stop_output(audio_io_handle_t output,int pcm_id)255 int 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
291 exit:
292 pthread_mutex_unlock(&lock);
293 return ret;
294 }
295
296
297 /*
298 * Effect operations
299 */
set_config(effect_context_t * context,effect_config_t * config)300 int 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
get_config(effect_context_t * context,effect_config_t * config)310 void 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 */
effect_lib_create(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)319 int 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 bass_context_t *bass_ctxt = (bass_context_t *)
365 calloc(1, sizeof(bass_context_t));
366 if (bass_ctxt == NULL) {
367 return -ENOMEM;
368 }
369 context = (effect_context_t *)bass_ctxt;
370 context->ops.init = bass_init;
371 context->ops.reset = bass_reset;
372 context->ops.set_parameter = bass_set_parameter;
373 context->ops.get_parameter = bass_get_parameter;
374 context->ops.set_device = bass_set_device;
375 context->ops.enable = bass_enable;
376 context->ops.disable = bass_disable;
377 context->ops.start = bass_start;
378 context->ops.stop = bass_stop;
379
380 context->desc = &bassboost_descriptor;
381 bass_ctxt->bassboost_ctxt.ctl = NULL;
382 bass_ctxt->pbe_ctxt.ctl = NULL;
383 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
384 sizeof(effect_uuid_t)) == 0) {
385 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
386 calloc(1, sizeof(virtualizer_context_t));
387 if (virt_ctxt == NULL) {
388 return -ENOMEM;
389 }
390 context = (effect_context_t *)virt_ctxt;
391 context->ops.init = virtualizer_init;
392 context->ops.reset = virtualizer_reset;
393 context->ops.set_parameter = virtualizer_set_parameter;
394 context->ops.get_parameter = virtualizer_get_parameter;
395 context->ops.set_device = virtualizer_set_device;
396 context->ops.enable = virtualizer_enable;
397 context->ops.disable = virtualizer_disable;
398 context->ops.start = virtualizer_start;
399 context->ops.stop = virtualizer_stop;
400
401 context->desc = &virtualizer_descriptor;
402 virt_ctxt->ctl = NULL;
403 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
404 sizeof(effect_uuid_t)) == 0) ||
405 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
406 sizeof(effect_uuid_t)) == 0) ||
407 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
408 sizeof(effect_uuid_t)) == 0) ||
409 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
410 sizeof(effect_uuid_t)) == 0)) {
411 reverb_context_t *reverb_ctxt = (reverb_context_t *)
412 calloc(1, sizeof(reverb_context_t));
413 if (reverb_ctxt == NULL) {
414 return -ENOMEM;
415 }
416 context = (effect_context_t *)reverb_ctxt;
417 context->ops.init = reverb_init;
418 context->ops.reset = reverb_reset;
419 context->ops.set_parameter = reverb_set_parameter;
420 context->ops.get_parameter = reverb_get_parameter;
421 context->ops.set_device = reverb_set_device;
422 context->ops.enable = reverb_enable;
423 context->ops.disable = reverb_disable;
424 context->ops.start = reverb_start;
425 context->ops.stop = reverb_stop;
426
427 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
428 sizeof(effect_uuid_t)) == 0) {
429 context->desc = &aux_env_reverb_descriptor;
430 reverb_auxiliary_init(reverb_ctxt);
431 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
432 sizeof(effect_uuid_t)) == 0) {
433 context->desc = &ins_env_reverb_descriptor;
434 reverb_preset_init(reverb_ctxt);
435 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
436 sizeof(effect_uuid_t)) == 0) {
437 context->desc = &aux_preset_reverb_descriptor;
438 reverb_auxiliary_init(reverb_ctxt);
439 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
440 sizeof(effect_uuid_t)) == 0) {
441 context->desc = &ins_preset_reverb_descriptor;
442 reverb_preset_init(reverb_ctxt);
443 }
444 reverb_ctxt->ctl = NULL;
445 } else {
446 return -EINVAL;
447 }
448
449 context->itfe = &effect_interface;
450 context->state = EFFECT_STATE_UNINITIALIZED;
451 context->out_handle = (audio_io_handle_t)ioId;
452
453 ret = context->ops.init(context);
454 if (ret < 0) {
455 ALOGW("%s init failed", __func__);
456 free(context);
457 return ret;
458 }
459
460 context->state = EFFECT_STATE_INITIALIZED;
461
462 pthread_mutex_lock(&lock);
463 list_add_tail(&created_effects_list, &context->effects_list_node);
464 output_context_t *out_ctxt = get_output(ioId);
465 if (out_ctxt != NULL)
466 add_effect_to_output(out_ctxt, context);
467 pthread_mutex_unlock(&lock);
468
469 *pHandle = (effect_handle_t)context;
470
471 ALOGV("%s created context %p", __func__, context);
472
473 return 0;
474
475 }
476
effect_lib_release(effect_handle_t handle)477 int effect_lib_release(effect_handle_t handle)
478 {
479 effect_context_t *context = (effect_context_t *)handle;
480 int status;
481
482 if (lib_init() != 0)
483 return init_status;
484
485 ALOGV("%s context %p", __func__, handle);
486 pthread_mutex_lock(&lock);
487 status = -EINVAL;
488 if (effect_exists(context)) {
489 output_context_t *out_ctxt = get_output(context->out_handle);
490 if (out_ctxt != NULL)
491 remove_effect_from_output(out_ctxt, context);
492 list_remove(&context->effects_list_node);
493 if (context->ops.release)
494 context->ops.release(context);
495 free(context);
496 status = 0;
497 }
498 pthread_mutex_unlock(&lock);
499
500 return status;
501 }
502
effect_lib_get_descriptor(const effect_uuid_t * uuid,effect_descriptor_t * descriptor)503 int effect_lib_get_descriptor(const effect_uuid_t *uuid,
504 effect_descriptor_t *descriptor)
505 {
506 int i;
507
508 if (lib_init() != 0)
509 return init_status;
510
511 if (descriptor == NULL || uuid == NULL) {
512 ALOGV("%s called with NULL pointer", __func__);
513 return -EINVAL;
514 }
515
516 for (i = 0; descriptors[i] != NULL; i++) {
517 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
518 *descriptor = *descriptors[i];
519 return 0;
520 }
521 }
522
523 return -EINVAL;
524 }
525
526
527 /*
528 * Effect Control Interface Implementation
529 */
530
531 /* 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)532 int effect_process(effect_handle_t self,
533 audio_buffer_t *inBuffer __unused,
534 audio_buffer_t *outBuffer __unused)
535 {
536 effect_context_t * context = (effect_context_t *)self;
537 int status = 0;
538
539 ALOGW("%s: ctxt %p, Called ?????", __func__, context);
540
541 pthread_mutex_lock(&lock);
542 if (!effect_exists(context)) {
543 status = -ENOSYS;
544 goto exit;
545 }
546
547 if (context->state != EFFECT_STATE_ACTIVE) {
548 status = -ENODATA;
549 goto exit;
550 }
551
552 exit:
553 pthread_mutex_unlock(&lock);
554 return status;
555 }
556
effect_command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)557 int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
558 void *pCmdData, uint32_t *replySize, void *pReplyData)
559 {
560
561 effect_context_t * context = (effect_context_t *)self;
562 int retsize;
563 int status = 0;
564
565 pthread_mutex_lock(&lock);
566
567 if (!effect_exists(context)) {
568 status = -ENOSYS;
569 goto exit;
570 }
571
572 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
573 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
574 status = -ENOSYS;
575 goto exit;
576 }
577
578 switch (cmdCode) {
579 case EFFECT_CMD_INIT:
580 if (pReplyData == NULL || *replySize != sizeof(int)) {
581 status = -EINVAL;
582 goto exit;
583 }
584 if (context->ops.init)
585 *(int *) pReplyData = context->ops.init(context);
586 else
587 *(int *) pReplyData = 0;
588 break;
589 case EFFECT_CMD_SET_CONFIG:
590 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
591 || pReplyData == NULL || *replySize != sizeof(int)) {
592 status = -EINVAL;
593 goto exit;
594 }
595 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
596 break;
597 case EFFECT_CMD_GET_CONFIG:
598 if (pReplyData == NULL ||
599 *replySize != sizeof(effect_config_t)) {
600 status = -EINVAL;
601 goto exit;
602 }
603 if (!context->offload_enabled) {
604 status = -EINVAL;
605 goto exit;
606 }
607
608 get_config(context, (effect_config_t *)pReplyData);
609 break;
610 case EFFECT_CMD_RESET:
611 if (context->ops.reset)
612 context->ops.reset(context);
613 break;
614 case EFFECT_CMD_ENABLE:
615 if (pReplyData == NULL || *replySize != sizeof(int)) {
616 status = -EINVAL;
617 goto exit;
618 }
619 if (context->state != EFFECT_STATE_INITIALIZED) {
620 status = -ENOSYS;
621 goto exit;
622 }
623 context->state = EFFECT_STATE_ACTIVE;
624 if (context->ops.enable)
625 context->ops.enable(context);
626 *(int *)pReplyData = 0;
627 break;
628 case EFFECT_CMD_DISABLE:
629 if (pReplyData == NULL || *replySize != sizeof(int)) {
630 status = -EINVAL;
631 goto exit;
632 }
633 if (context->state != EFFECT_STATE_ACTIVE) {
634 status = -ENOSYS;
635 goto exit;
636 }
637 context->state = EFFECT_STATE_INITIALIZED;
638 if (context->ops.disable)
639 context->ops.disable(context);
640 *(int *)pReplyData = 0;
641 break;
642 case EFFECT_CMD_GET_PARAM: {
643 if (pCmdData == NULL ||
644 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
645 pReplyData == NULL ||
646 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
647 // constrain memcpy below
648 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
649 status = -EINVAL;
650 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
651 cmdSize, *replySize);
652 goto exit;
653 }
654 if (!context->offload_enabled) {
655 status = -EINVAL;
656 goto exit;
657 }
658 effect_param_t *q = (effect_param_t *)pCmdData;
659 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
660 effect_param_t *p = (effect_param_t *)pReplyData;
661 if (context->ops.get_parameter)
662 context->ops.get_parameter(context, p, replySize);
663 } break;
664 case EFFECT_CMD_SET_PARAM: {
665 if (pCmdData == NULL ||
666 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
667 sizeof(uint16_t)) ||
668 pReplyData == NULL || *replySize != sizeof(int32_t)) {
669 status = -EINVAL;
670 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
671 cmdSize, *replySize);
672 goto exit;
673 }
674 *(int32_t *)pReplyData = 0;
675 effect_param_t *p = (effect_param_t *)pCmdData;
676 if (context->ops.set_parameter)
677 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
678 *replySize);
679
680 } break;
681 case EFFECT_CMD_SET_DEVICE: {
682 uint32_t device;
683 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
684 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
685 status = -EINVAL;
686 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
687 goto exit;
688 }
689 device = *(uint32_t *)pCmdData;
690 if (context->ops.set_device)
691 context->ops.set_device(context, device);
692 } break;
693 case EFFECT_CMD_SET_VOLUME:
694 case EFFECT_CMD_SET_AUDIO_MODE:
695 break;
696
697 case EFFECT_CMD_OFFLOAD: {
698 output_context_t *out_ctxt;
699
700 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
701 || pReplyData == NULL || *replySize != sizeof(int)) {
702 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
703 status = -EINVAL;
704 break;
705 }
706
707 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
708
709 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
710 offload_param->isOffload, offload_param->ioHandle);
711
712 *(int *)pReplyData = 0;
713
714 context->offload_enabled = offload_param->isOffload;
715 if (context->out_handle == offload_param->ioHandle)
716 break;
717
718 out_ctxt = get_output(context->out_handle);
719 if (out_ctxt != NULL)
720 remove_effect_from_output(out_ctxt, context);
721
722 context->out_handle = offload_param->ioHandle;
723 out_ctxt = get_output(context->out_handle);
724 if (out_ctxt != NULL)
725 add_effect_to_output(out_ctxt, context);
726
727 } break;
728
729
730 default:
731 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
732 status = context->ops.command(context, cmdCode, cmdSize,
733 pCmdData, replySize, pReplyData);
734 else {
735 ALOGW("%s invalid command %d", __func__, cmdCode);
736 status = -EINVAL;
737 }
738 break;
739 }
740
741 exit:
742 pthread_mutex_unlock(&lock);
743
744 return status;
745 }
746
747 /* Effect Control Interface Implementation: get_descriptor */
effect_get_descriptor(effect_handle_t self,effect_descriptor_t * descriptor)748 int effect_get_descriptor(effect_handle_t self,
749 effect_descriptor_t *descriptor)
750 {
751 effect_context_t *context = (effect_context_t *)self;
752
753 if (!effect_exists(context) || (descriptor == NULL))
754 return -EINVAL;
755
756 *descriptor = *context->desc;
757
758 return 0;
759 }
760
effect_is_active(effect_context_t * ctxt)761 bool effect_is_active(effect_context_t * ctxt) {
762 return ctxt->state == EFFECT_STATE_ACTIVE;
763 }
764
765 /* effect_handle_t interface implementation for offload effects */
766 const struct effect_interface_s effect_interface = {
767 effect_process,
768 effect_command,
769 effect_get_descriptor,
770 NULL,
771 };
772
773 __attribute__ ((visibility ("default")))
774 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
775 tag : AUDIO_EFFECT_LIBRARY_TAG,
776 version : EFFECT_LIBRARY_API_VERSION,
777 name : "Offload Effects Bundle Library",
778 implementor : "The Linux Foundation",
779 create_effect : effect_lib_create,
780 release_effect : effect_lib_release,
781 get_descriptor : effect_lib_get_descriptor,
782 };
783