blob: d7fa2aa466e9824800ea18233481102bb11a1302 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Weiyin Jiang80fcb3d2015-03-23 00:54:14 +08002 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08003 * 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];
wjiang91a333d2014-08-06 08:03:14 +0800189 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800190
191 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
192
193 if (lib_init() != 0)
194 return init_status;
195
196 pthread_mutex_lock(&lock);
197 if (get_output(output) != NULL) {
198 ALOGW("%s output already started", __func__);
199 ret = -ENOSYS;
200 goto exit;
201 }
202
wjiang91a333d2014-08-06 08:03:14 +0800203 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800204 malloc(sizeof(output_context_t));
wjiang74ff5952014-05-15 19:38:26 +0800205 if (!out_ctxt) {
206 ALOGE("%s fail to allocate for output context", __func__);
207 ret = -ENOMEM;
208 goto exit;
209 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800210 out_ctxt->handle = output;
211 out_ctxt->pcm_device_id = pcm_id;
212
213 /* populate the mixer control to send offload parameters */
214 snprintf(mixer_string, sizeof(mixer_string),
215 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
216 out_ctxt->mixer = mixer_open(MIXER_CARD);
217 if (!out_ctxt->mixer) {
218 ALOGE("Failed to open mixer");
219 out_ctxt->ctl = NULL;
220 ret = -EINVAL;
wjiang91a333d2014-08-06 08:03:14 +0800221 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800222 goto exit;
223 } else {
224 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
225 if (!out_ctxt->ctl) {
226 ALOGE("mixer_get_ctl_by_name failed");
227 mixer_close(out_ctxt->mixer);
228 out_ctxt->mixer = NULL;
229 ret = -EINVAL;
wjiang91a333d2014-08-06 08:03:14 +0800230 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800231 goto exit;
232 }
233 }
234
235 list_init(&out_ctxt->effects_list);
236
237 list_for_each(node, &created_effects_list) {
238 effect_context_t *fx_ctxt = node_to_item(node,
239 effect_context_t,
240 effects_list_node);
241 if (fx_ctxt->out_handle == output) {
242 if (fx_ctxt->ops.start)
243 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
244 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
245 }
246 }
247 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
248exit:
249 pthread_mutex_unlock(&lock);
250 return ret;
251}
252
253__attribute__ ((visibility ("default")))
254int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
255{
256 int ret;
257 struct listnode *node;
258 struct listnode *fx_node;
259 output_context_t *out_ctxt;
260
261 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
262
263 if (lib_init() != 0)
264 return init_status;
265
266 pthread_mutex_lock(&lock);
267
268 out_ctxt = get_output(output);
269 if (out_ctxt == NULL) {
270 ALOGW("%s output not started", __func__);
271 ret = -ENOSYS;
272 goto exit;
273 }
274
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800275 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
Dhananjay Kumar9fddcb22015-06-29 01:05:12 +0530283 if (out_ctxt->mixer)
284 mixer_close(out_ctxt->mixer);
285
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800286 list_remove(&out_ctxt->outputs_list_node);
287
288 free(out_ctxt);
289
290exit:
291 pthread_mutex_unlock(&lock);
292 return ret;
293}
294
295
296/*
297 * Effect operations
298 */
299int set_config(effect_context_t *context, effect_config_t *config)
300{
301 context->config = *config;
302
303 if (context->ops.reset)
304 context->ops.reset(context);
305
306 return 0;
307}
308
309void get_config(effect_context_t *context, effect_config_t *config)
310{
311 *config = context->config;
312}
313
314
315/*
316 * Effect Library Interface Implementation
317 */
318int effect_lib_create(const effect_uuid_t *uuid,
319 int32_t sessionId,
320 int32_t ioId,
321 effect_handle_t *pHandle) {
322 int ret;
323 int i;
324
325 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
326 if (lib_init() != 0)
327 return init_status;
328
329 if (pHandle == NULL || uuid == NULL)
330 return -EINVAL;
331
332 for (i = 0; descriptors[i] != NULL; i++) {
333 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
334 break;
335 }
336
337 if (descriptors[i] == NULL)
338 return -EINVAL;
339
340 effect_context_t *context;
341 if (memcmp(uuid, &equalizer_descriptor.uuid,
342 sizeof(effect_uuid_t)) == 0) {
343 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
344 calloc(1, sizeof(equalizer_context_t));
wjiang74ff5952014-05-15 19:38:26 +0800345 if (eq_ctxt == NULL) {
346 return -ENOMEM;
347 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800348 context = (effect_context_t *)eq_ctxt;
349 context->ops.init = equalizer_init;
350 context->ops.reset = equalizer_reset;
351 context->ops.set_parameter = equalizer_set_parameter;
352 context->ops.get_parameter = equalizer_get_parameter;
353 context->ops.set_device = equalizer_set_device;
354 context->ops.enable = equalizer_enable;
355 context->ops.disable = equalizer_disable;
356 context->ops.start = equalizer_start;
357 context->ops.stop = equalizer_stop;
358
359 context->desc = &equalizer_descriptor;
360 eq_ctxt->ctl = NULL;
361 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
362 sizeof(effect_uuid_t)) == 0) {
363 bassboost_context_t *bass_ctxt = (bassboost_context_t *)
364 calloc(1, sizeof(bassboost_context_t));
wjiang74ff5952014-05-15 19:38:26 +0800365 if (bass_ctxt == NULL) {
366 return -ENOMEM;
367 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800368 context = (effect_context_t *)bass_ctxt;
369 context->ops.init = bassboost_init;
370 context->ops.reset = bassboost_reset;
371 context->ops.set_parameter = bassboost_set_parameter;
372 context->ops.get_parameter = bassboost_get_parameter;
373 context->ops.set_device = bassboost_set_device;
374 context->ops.enable = bassboost_enable;
375 context->ops.disable = bassboost_disable;
376 context->ops.start = bassboost_start;
377 context->ops.stop = bassboost_stop;
378
379 context->desc = &bassboost_descriptor;
380 bass_ctxt->ctl = NULL;
381 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
382 sizeof(effect_uuid_t)) == 0) {
383 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
384 calloc(1, sizeof(virtualizer_context_t));
wjiang74ff5952014-05-15 19:38:26 +0800385 if (virt_ctxt == NULL) {
386 return -ENOMEM;
387 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800388 context = (effect_context_t *)virt_ctxt;
389 context->ops.init = virtualizer_init;
390 context->ops.reset = virtualizer_reset;
391 context->ops.set_parameter = virtualizer_set_parameter;
392 context->ops.get_parameter = virtualizer_get_parameter;
393 context->ops.set_device = virtualizer_set_device;
394 context->ops.enable = virtualizer_enable;
395 context->ops.disable = virtualizer_disable;
396 context->ops.start = virtualizer_start;
397 context->ops.stop = virtualizer_stop;
398
399 context->desc = &virtualizer_descriptor;
400 virt_ctxt->ctl = NULL;
401 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
402 sizeof(effect_uuid_t)) == 0) ||
403 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
404 sizeof(effect_uuid_t)) == 0) ||
405 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
406 sizeof(effect_uuid_t)) == 0) ||
407 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
408 sizeof(effect_uuid_t)) == 0)) {
409 reverb_context_t *reverb_ctxt = (reverb_context_t *)
410 calloc(1, sizeof(reverb_context_t));
wjiang74ff5952014-05-15 19:38:26 +0800411 if (reverb_ctxt == NULL) {
412 return -ENOMEM;
413 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800414 context = (effect_context_t *)reverb_ctxt;
415 context->ops.init = reverb_init;
416 context->ops.reset = reverb_reset;
417 context->ops.set_parameter = reverb_set_parameter;
418 context->ops.get_parameter = reverb_get_parameter;
419 context->ops.set_device = reverb_set_device;
420 context->ops.enable = reverb_enable;
421 context->ops.disable = reverb_disable;
422 context->ops.start = reverb_start;
423 context->ops.stop = reverb_stop;
424
425 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
426 sizeof(effect_uuid_t)) == 0) {
427 context->desc = &aux_env_reverb_descriptor;
428 reverb_auxiliary_init(reverb_ctxt);
429 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
430 sizeof(effect_uuid_t)) == 0) {
431 context->desc = &ins_env_reverb_descriptor;
432 reverb_preset_init(reverb_ctxt);
433 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
434 sizeof(effect_uuid_t)) == 0) {
435 context->desc = &aux_preset_reverb_descriptor;
436 reverb_auxiliary_init(reverb_ctxt);
437 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
438 sizeof(effect_uuid_t)) == 0) {
439 context->desc = &ins_preset_reverb_descriptor;
440 reverb_preset_init(reverb_ctxt);
441 }
442 reverb_ctxt->ctl = NULL;
443 } else {
444 return -EINVAL;
445 }
446
447 context->itfe = &effect_interface;
448 context->state = EFFECT_STATE_UNINITIALIZED;
449 context->out_handle = (audio_io_handle_t)ioId;
450
451 ret = context->ops.init(context);
452 if (ret < 0) {
453 ALOGW("%s init failed", __func__);
454 free(context);
455 return ret;
456 }
457
458 context->state = EFFECT_STATE_INITIALIZED;
459
460 pthread_mutex_lock(&lock);
461 list_add_tail(&created_effects_list, &context->effects_list_node);
462 output_context_t *out_ctxt = get_output(ioId);
463 if (out_ctxt != NULL)
464 add_effect_to_output(out_ctxt, context);
465 pthread_mutex_unlock(&lock);
466
467 *pHandle = (effect_handle_t)context;
468
469 ALOGV("%s created context %p", __func__, context);
470
471 return 0;
472
473}
474
475int effect_lib_release(effect_handle_t handle)
476{
477 effect_context_t *context = (effect_context_t *)handle;
478 int status;
479
480 if (lib_init() != 0)
481 return init_status;
482
483 ALOGV("%s context %p", __func__, handle);
484 pthread_mutex_lock(&lock);
485 status = -EINVAL;
486 if (effect_exists(context)) {
487 output_context_t *out_ctxt = get_output(context->out_handle);
488 if (out_ctxt != NULL)
489 remove_effect_from_output(out_ctxt, context);
490 list_remove(&context->effects_list_node);
491 if (context->ops.release)
492 context->ops.release(context);
493 free(context);
494 status = 0;
495 }
496 pthread_mutex_unlock(&lock);
497
498 return status;
499}
500
501int effect_lib_get_descriptor(const effect_uuid_t *uuid,
502 effect_descriptor_t *descriptor)
503{
504 int i;
505
506 if (lib_init() != 0)
507 return init_status;
508
509 if (descriptor == NULL || uuid == NULL) {
510 ALOGV("%s called with NULL pointer", __func__);
511 return -EINVAL;
512 }
513
514 for (i = 0; descriptors[i] != NULL; i++) {
515 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
516 *descriptor = *descriptors[i];
517 return 0;
518 }
519 }
520
521 return -EINVAL;
522}
523
524
525/*
526 * Effect Control Interface Implementation
527 */
528
529/* Stub function for effect interface: never called for offloaded effects */
530int effect_process(effect_handle_t self,
Steve Kondik231bd9d2014-12-06 13:02:51 -0800531 audio_buffer_t *inBuffer __unused,
532 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800533{
534 effect_context_t * context = (effect_context_t *)self;
535 int status = 0;
536
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530537 ALOGW("%s: ctxt %p, Called ?????", __func__, context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800538
539 pthread_mutex_lock(&lock);
540 if (!effect_exists(context)) {
wjiang91a333d2014-08-06 08:03:14 +0800541 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800542 goto exit;
543 }
544
545 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang91a333d2014-08-06 08:03:14 +0800546 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800547 goto exit;
548 }
549
550exit:
551 pthread_mutex_unlock(&lock);
552 return status;
553}
554
555int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
556 void *pCmdData, uint32_t *replySize, void *pReplyData)
557{
558
559 effect_context_t * context = (effect_context_t *)self;
560 int retsize;
561 int status = 0;
562
563 pthread_mutex_lock(&lock);
564
565 if (!effect_exists(context)) {
wjiang91a333d2014-08-06 08:03:14 +0800566 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800567 goto exit;
568 }
569
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530570 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800571 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang91a333d2014-08-06 08:03:14 +0800572 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800573 goto exit;
574 }
575
576 switch (cmdCode) {
577 case EFFECT_CMD_INIT:
578 if (pReplyData == NULL || *replySize != sizeof(int)) {
579 status = -EINVAL;
580 goto exit;
581 }
582 if (context->ops.init)
583 *(int *) pReplyData = context->ops.init(context);
584 else
585 *(int *) pReplyData = 0;
586 break;
587 case EFFECT_CMD_SET_CONFIG:
588 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
589 || pReplyData == NULL || *replySize != sizeof(int)) {
590 status = -EINVAL;
591 goto exit;
592 }
593 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
594 break;
595 case EFFECT_CMD_GET_CONFIG:
596 if (pReplyData == NULL ||
597 *replySize != sizeof(effect_config_t)) {
598 status = -EINVAL;
599 goto exit;
600 }
601 if (!context->offload_enabled) {
602 status = -EINVAL;
603 goto exit;
604 }
605
606 get_config(context, (effect_config_t *)pReplyData);
607 break;
608 case EFFECT_CMD_RESET:
609 if (context->ops.reset)
610 context->ops.reset(context);
611 break;
612 case EFFECT_CMD_ENABLE:
613 if (pReplyData == NULL || *replySize != sizeof(int)) {
614 status = -EINVAL;
615 goto exit;
616 }
617 if (context->state != EFFECT_STATE_INITIALIZED) {
618 status = -ENOSYS;
619 goto exit;
620 }
621 context->state = EFFECT_STATE_ACTIVE;
622 if (context->ops.enable)
623 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800624 *(int *)pReplyData = 0;
625 break;
626 case EFFECT_CMD_DISABLE:
627 if (pReplyData == NULL || *replySize != sizeof(int)) {
628 status = -EINVAL;
629 goto exit;
630 }
631 if (context->state != EFFECT_STATE_ACTIVE) {
632 status = -ENOSYS;
633 goto exit;
634 }
635 context->state = EFFECT_STATE_INITIALIZED;
636 if (context->ops.disable)
637 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800638 *(int *)pReplyData = 0;
639 break;
640 case EFFECT_CMD_GET_PARAM: {
641 if (pCmdData == NULL ||
642 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
643 pReplyData == NULL ||
Andy Hung8c1ea0f2016-06-07 17:51:48 -0700644 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
645 // constrain memcpy below
646 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800647 status = -EINVAL;
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530648 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800649 cmdSize, *replySize);
650 goto exit;
651 }
652 if (!context->offload_enabled) {
653 status = -EINVAL;
654 goto exit;
655 }
656 effect_param_t *q = (effect_param_t *)pCmdData;
657 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
658 effect_param_t *p = (effect_param_t *)pReplyData;
659 if (context->ops.get_parameter)
660 context->ops.get_parameter(context, p, replySize);
661 } break;
662 case EFFECT_CMD_SET_PARAM: {
663 if (pCmdData == NULL ||
664 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
665 sizeof(uint16_t)) ||
666 pReplyData == NULL || *replySize != sizeof(int32_t)) {
667 status = -EINVAL;
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530668 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800669 cmdSize, *replySize);
670 goto exit;
671 }
672 *(int32_t *)pReplyData = 0;
673 effect_param_t *p = (effect_param_t *)pCmdData;
674 if (context->ops.set_parameter)
675 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
676 *replySize);
677
678 } break;
679 case EFFECT_CMD_SET_DEVICE: {
680 uint32_t device;
681 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
682 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
683 status = -EINVAL;
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530684 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800685 goto exit;
686 }
687 device = *(uint32_t *)pCmdData;
688 if (context->ops.set_device)
689 context->ops.set_device(context, device);
690 } break;
691 case EFFECT_CMD_SET_VOLUME:
692 case EFFECT_CMD_SET_AUDIO_MODE:
693 break;
694
695 case EFFECT_CMD_OFFLOAD: {
696 output_context_t *out_ctxt;
697
698 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
699 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumarb2c7ac12014-03-25 17:41:44 +0530700 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800701 status = -EINVAL;
702 break;
703 }
704
705 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
706
707 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
708 offload_param->isOffload, offload_param->ioHandle);
709
710 *(int *)pReplyData = 0;
711
712 context->offload_enabled = offload_param->isOffload;
713 if (context->out_handle == offload_param->ioHandle)
714 break;
715
716 out_ctxt = get_output(context->out_handle);
717 if (out_ctxt != NULL)
718 remove_effect_from_output(out_ctxt, context);
719
720 context->out_handle = offload_param->ioHandle;
721 out_ctxt = get_output(context->out_handle);
722 if (out_ctxt != NULL)
723 add_effect_to_output(out_ctxt, context);
724
725 } break;
726
727
728 default:
729 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
730 status = context->ops.command(context, cmdCode, cmdSize,
731 pCmdData, replySize, pReplyData);
732 else {
733 ALOGW("%s invalid command %d", __func__, cmdCode);
734 status = -EINVAL;
735 }
736 break;
737 }
738
739exit:
740 pthread_mutex_unlock(&lock);
741
742 return status;
743}
744
745/* Effect Control Interface Implementation: get_descriptor */
746int effect_get_descriptor(effect_handle_t self,
747 effect_descriptor_t *descriptor)
748{
749 effect_context_t *context = (effect_context_t *)self;
750
751 if (!effect_exists(context) || (descriptor == NULL))
752 return -EINVAL;
753
754 *descriptor = *context->desc;
755
756 return 0;
757}
758
wjiang91a333d2014-08-06 08:03:14 +0800759bool effect_is_active(effect_context_t * ctxt) {
760 return ctxt->state == EFFECT_STATE_ACTIVE;
761}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800762
763/* effect_handle_t interface implementation for offload effects */
764const struct effect_interface_s effect_interface = {
765 effect_process,
766 effect_command,
767 effect_get_descriptor,
768 NULL,
769};
770
771__attribute__ ((visibility ("default")))
772audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
773 tag : AUDIO_EFFECT_LIBRARY_TAG,
774 version : EFFECT_LIBRARY_API_VERSION,
775 name : "Offload Effects Bundle Library",
776 implementor : "The Linux Foundation",
777 create_effect : effect_lib_create,
778 release_effect : effect_lib_release,
779 get_descriptor : effect_lib_get_descriptor,
780};