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