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