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