blob: b33f2d1d623a5f0a5af72f8d53c528b0e95b276f [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Weiyin Jiangb64b7dd2015-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.
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"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070039//#define LOG_NDEBUG 0
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080040
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>
Sharad Sangleb27354b2015-06-18 15:58:55 +053046#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080047#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070048#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080049#include "equalizer.h"
50#include "bass_boost.h"
51#include "virtualizer.h"
52#include "reverb.h"
53
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080054#ifdef DTS_EAGLE
55#include "effect_util.h"
56#endif
57
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080058enum {
59 EFFECT_STATE_UNINITIALIZED,
60 EFFECT_STATE_INITIALIZED,
61 EFFECT_STATE_ACTIVE,
62};
63
64const effect_descriptor_t *descriptors[] = {
65 &equalizer_descriptor,
66 &bassboost_descriptor,
67 &virtualizer_descriptor,
68 &aux_env_reverb_descriptor,
69 &ins_env_reverb_descriptor,
70 &aux_preset_reverb_descriptor,
71 &ins_preset_reverb_descriptor,
Sharad Sangleb27354b2015-06-18 15:58:55 +053072#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070073 &hw_accelerator_descriptor,
Sharad Sangleb27354b2015-06-18 15:58:55 +053074#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080075 NULL,
76};
77
78pthread_once_t once = PTHREAD_ONCE_INIT;
79int init_status;
80/*
81 * list of created effects.
82 * Updated by offload_effects_bundle_hal_start_output()
83 * and offload_effects_bundle_hal_stop_output()
84 */
85struct listnode created_effects_list;
86/*
87 * list of active output streams.
88 * Updated by offload_effects_bundle_hal_start_output()
89 * and offload_effects_bundle_hal_stop_output()
90 */
91struct listnode active_outputs_list;
92/*
93 * lock must be held when modifying or accessing
94 * created_effects_list or active_outputs_list
95 */
96pthread_mutex_t lock;
97
98
99/*
100 * Local functions
101 */
102static void init_once() {
103 list_init(&created_effects_list);
104 list_init(&active_outputs_list);
105
106 pthread_mutex_init(&lock, NULL);
107
108 init_status = 0;
109}
110
111int lib_init()
112{
113 pthread_once(&once, init_once);
114 return init_status;
115}
116
117bool effect_exists(effect_context_t *context)
118{
119 struct listnode *node;
120
121 list_for_each(node, &created_effects_list) {
122 effect_context_t *fx_ctxt = node_to_item(node,
123 effect_context_t,
124 effects_list_node);
125 if (fx_ctxt == context) {
126 return true;
127 }
128 }
129 return false;
130}
131
132output_context_t *get_output(audio_io_handle_t output)
133{
134 struct listnode *node;
135
136 list_for_each(node, &active_outputs_list) {
137 output_context_t *out_ctxt = node_to_item(node,
138 output_context_t,
139 outputs_list_node);
140 if (out_ctxt->handle == output)
141 return out_ctxt;
142 }
143 return NULL;
144}
145
146void add_effect_to_output(output_context_t * output, effect_context_t *context)
147{
148 struct listnode *fx_node;
149
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530150 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800151 list_for_each(fx_node, &output->effects_list) {
152 effect_context_t *fx_ctxt = node_to_item(fx_node,
153 effect_context_t,
154 output_node);
155 if (fx_ctxt == context)
156 return;
157 }
158 list_add_tail(&output->effects_list, &context->output_node);
159 if (context->ops.start)
160 context->ops.start(context, output);
161
162}
163
164void remove_effect_from_output(output_context_t * output,
165 effect_context_t *context)
166{
167 struct listnode *fx_node;
168
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530169 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800170 list_for_each(fx_node, &output->effects_list) {
171 effect_context_t *fx_ctxt = node_to_item(fx_node,
172 effect_context_t,
173 output_node);
174 if (fx_ctxt == context) {
175 if (context->ops.stop)
176 context->ops.stop(context, output);
177 list_remove(&context->output_node);
178 return;
179 }
180 }
181}
182
183bool effects_enabled()
184{
185 struct listnode *out_node;
186
187 list_for_each(out_node, &active_outputs_list) {
188 struct listnode *fx_node;
189 output_context_t *out_ctxt = node_to_item(out_node,
190 output_context_t,
191 outputs_list_node);
192
193 list_for_each(fx_node, &out_ctxt->effects_list) {
194 effect_context_t *fx_ctxt = node_to_item(fx_node,
195 effect_context_t,
196 output_node);
197 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
198 (fx_ctxt->ops.process != NULL))
199 return true;
200 }
201 }
202 return false;
203}
204
205
206/*
207 * Interface from audio HAL
208 */
209__attribute__ ((visibility ("default")))
210int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
211{
212 int ret = 0;
213 struct listnode *node;
214 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800215 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800216
217 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
218
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800219#ifdef DTS_EAGLE
220 create_effect_state_node(pcm_id);
221#endif
222
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800223 if (lib_init() != 0)
224 return init_status;
225
226 pthread_mutex_lock(&lock);
227 if (get_output(output) != NULL) {
228 ALOGW("%s output already started", __func__);
229 ret = -ENOSYS;
230 goto exit;
231 }
232
wjiang50b81f42014-08-06 08:03:14 +0800233 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800234 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800235 if (!out_ctxt) {
236 ALOGE("%s fail to allocate for output context", __func__);
237 ret = -ENOMEM;
238 goto exit;
239 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800240 out_ctxt->handle = output;
241 out_ctxt->pcm_device_id = pcm_id;
242
243 /* populate the mixer control to send offload parameters */
244 snprintf(mixer_string, sizeof(mixer_string),
245 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
246 out_ctxt->mixer = mixer_open(MIXER_CARD);
247 if (!out_ctxt->mixer) {
248 ALOGE("Failed to open mixer");
249 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700250 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800251 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800252 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800253 goto exit;
254 } else {
255 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
256 if (!out_ctxt->ctl) {
257 ALOGE("mixer_get_ctl_by_name failed");
258 mixer_close(out_ctxt->mixer);
259 out_ctxt->mixer = NULL;
260 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800261 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800262 goto exit;
263 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700264 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800265 }
266
267 list_init(&out_ctxt->effects_list);
268
269 list_for_each(node, &created_effects_list) {
270 effect_context_t *fx_ctxt = node_to_item(node,
271 effect_context_t,
272 effects_list_node);
273 if (fx_ctxt->out_handle == output) {
274 if (fx_ctxt->ops.start)
275 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
276 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
277 }
278 }
279 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
280exit:
281 pthread_mutex_unlock(&lock);
282 return ret;
283}
284
285__attribute__ ((visibility ("default")))
286int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
287{
288 int ret;
289 struct listnode *node;
290 struct listnode *fx_node;
291 output_context_t *out_ctxt;
292
293 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
294
295 if (lib_init() != 0)
296 return init_status;
297
298 pthread_mutex_lock(&lock);
299
300 out_ctxt = get_output(output);
301 if (out_ctxt == NULL) {
302 ALOGW("%s output not started", __func__);
303 ret = -ENOSYS;
304 goto exit;
305 }
306
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800307 list_for_each(fx_node, &out_ctxt->effects_list) {
308 effect_context_t *fx_ctxt = node_to_item(fx_node,
309 effect_context_t,
310 output_node);
311 if (fx_ctxt->ops.stop)
312 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
313 }
314
Dhananjay Kumarb91d3d12015-06-29 01:05:12 +0530315 if (out_ctxt->mixer)
316 mixer_close(out_ctxt->mixer);
317
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800318 list_remove(&out_ctxt->outputs_list_node);
319
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800320#ifdef DTS_EAGLE
321 remove_effect_state_node(pcm_id);
322#endif
323
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800324 free(out_ctxt);
325
326exit:
327 pthread_mutex_unlock(&lock);
328 return ret;
329}
330
Alexy Josephd464f3b2014-11-18 16:14:41 -0800331__attribute__ ((visibility ("default")))
332int offload_effects_bundle_set_hpx_state(bool hpx_state)
333{
334 int ret = 0;
335 struct listnode *node;
336
337 ALOGV("%s hpx state: %d", __func__, hpx_state);
338
339 if (lib_init() != 0)
340 return init_status;
341
342 pthread_mutex_lock(&lock);
343
344 if (hpx_state) {
345 /* set ramp down */
346 list_for_each(node, &active_outputs_list) {
347 output_context_t *out_ctxt = node_to_item(node,
348 output_context_t,
349 outputs_list_node);
350 struct soft_volume_params vol;
351 vol.master_gain = 0x0;
352 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
353 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
354 }
355 /* wait for ramp down duration - 30msec */
356 usleep(30000);
357 /* disable effects modules */
358 list_for_each(node, &active_outputs_list) {
359 struct listnode *fx_node;
360 output_context_t *out_ctxt = node_to_item(node,
361 output_context_t,
362 outputs_list_node);
363 list_for_each(fx_node, &out_ctxt->effects_list) {
364 effect_context_t *fx_ctxt = node_to_item(fx_node,
365 effect_context_t,
366 output_node);
367 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
368 (fx_ctxt->ops.stop != NULL))
369 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
370 }
371 out_ctxt->ctl = NULL;
372 }
373 /* set the channel mixer */
374 list_for_each(node, &active_outputs_list) {
375 /* send command to set channel mixer */
376 }
377 /* enable hpx modules */
378 list_for_each(node, &active_outputs_list) {
379 output_context_t *out_ctxt = node_to_item(node,
380 output_context_t,
381 outputs_list_node);
382 offload_hpx_send_params(out_ctxt->ref_ctl,
383 OFFLOAD_SEND_HPX_STATE_ON);
384 }
385 /* wait for transition state - 50msec */
386 usleep(50000);
387 /* set ramp up */
388 list_for_each(node, &active_outputs_list) {
389 output_context_t *out_ctxt = node_to_item(node,
390 output_context_t,
391 outputs_list_node);
392 struct soft_volume_params vol;
393 vol.master_gain = 0x2000;
394 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
395 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
396 }
397 } else {
398 /* set ramp down */
399 list_for_each(node, &active_outputs_list) {
400 output_context_t *out_ctxt = node_to_item(node,
401 output_context_t,
402 outputs_list_node);
403 struct soft_volume_params vol;
404 vol.master_gain = 0x0;
405 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
406 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
407 }
408 /* wait for ramp down duration - 30msec */
409 usleep(30000);
410 /* disable effects modules */
411 list_for_each(node, &active_outputs_list) {
412 output_context_t *out_ctxt = node_to_item(node,
413 output_context_t,
414 outputs_list_node);
415 offload_hpx_send_params(out_ctxt->ref_ctl,
416 OFFLOAD_SEND_HPX_STATE_OFF);
417 }
418 /* set the channel mixer */
419 list_for_each(node, &active_outputs_list) {
420 /* send command to set channel mixer */
421 }
422 /* enable effects modules */
423 list_for_each(node, &active_outputs_list) {
424 struct listnode *fx_node;
425 output_context_t *out_ctxt = node_to_item(node,
426 output_context_t,
427 outputs_list_node);
428 out_ctxt->ctl = out_ctxt->ref_ctl;
429 list_for_each(fx_node, &out_ctxt->effects_list) {
430 effect_context_t *fx_ctxt = node_to_item(fx_node,
431 effect_context_t,
432 output_node);
433 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
434 (fx_ctxt->ops.start != NULL))
435 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
436 }
437 }
438 /* wait for transition state - 50msec */
439 usleep(50000);
440 /* set ramp up */
441 list_for_each(node, &active_outputs_list) {
442 output_context_t *out_ctxt = node_to_item(node,
443 output_context_t,
444 outputs_list_node);
445 struct soft_volume_params vol;
446 vol.master_gain = 0x2000;
447 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
448 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
449 }
450 }
451
452exit:
453 pthread_mutex_unlock(&lock);
454 return ret;
455}
456
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800457/*
458 * Effect operations
459 */
460int set_config(effect_context_t *context, effect_config_t *config)
461{
462 context->config = *config;
463
464 if (context->ops.reset)
465 context->ops.reset(context);
466
467 return 0;
468}
469
470void get_config(effect_context_t *context, effect_config_t *config)
471{
472 *config = context->config;
473}
474
475
476/*
477 * Effect Library Interface Implementation
478 */
479int effect_lib_create(const effect_uuid_t *uuid,
480 int32_t sessionId,
481 int32_t ioId,
482 effect_handle_t *pHandle) {
483 int ret;
484 int i;
485
486 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
487 if (lib_init() != 0)
488 return init_status;
489
490 if (pHandle == NULL || uuid == NULL)
491 return -EINVAL;
492
493 for (i = 0; descriptors[i] != NULL; i++) {
494 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
495 break;
496 }
497
498 if (descriptors[i] == NULL)
499 return -EINVAL;
500
501 effect_context_t *context;
502 if (memcmp(uuid, &equalizer_descriptor.uuid,
503 sizeof(effect_uuid_t)) == 0) {
504 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
505 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800506 if (eq_ctxt == NULL) {
507 return -ENOMEM;
508 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800509 context = (effect_context_t *)eq_ctxt;
510 context->ops.init = equalizer_init;
511 context->ops.reset = equalizer_reset;
512 context->ops.set_parameter = equalizer_set_parameter;
513 context->ops.get_parameter = equalizer_get_parameter;
514 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700515 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800516 context->ops.enable = equalizer_enable;
517 context->ops.disable = equalizer_disable;
518 context->ops.start = equalizer_start;
519 context->ops.stop = equalizer_stop;
520
521 context->desc = &equalizer_descriptor;
522 eq_ctxt->ctl = NULL;
523 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
524 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800525 bass_context_t *bass_ctxt = (bass_context_t *)
526 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800527 if (bass_ctxt == NULL) {
528 return -ENOMEM;
529 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800530 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800531 context->ops.init = bass_init;
532 context->ops.reset = bass_reset;
533 context->ops.set_parameter = bass_set_parameter;
534 context->ops.get_parameter = bass_get_parameter;
535 context->ops.set_device = bass_set_device;
536 context->ops.set_hw_acc_mode = bass_set_mode;
537 context->ops.enable = bass_enable;
538 context->ops.disable = bass_disable;
539 context->ops.start = bass_start;
540 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800541
542 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800543 bass_ctxt->bassboost_ctxt.ctl = NULL;
544 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800545 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
546 sizeof(effect_uuid_t)) == 0) {
547 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
548 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800549 if (virt_ctxt == NULL) {
550 return -ENOMEM;
551 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800552 context = (effect_context_t *)virt_ctxt;
553 context->ops.init = virtualizer_init;
554 context->ops.reset = virtualizer_reset;
555 context->ops.set_parameter = virtualizer_set_parameter;
556 context->ops.get_parameter = virtualizer_get_parameter;
557 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700558 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800559 context->ops.enable = virtualizer_enable;
560 context->ops.disable = virtualizer_disable;
561 context->ops.start = virtualizer_start;
562 context->ops.stop = virtualizer_stop;
563
564 context->desc = &virtualizer_descriptor;
565 virt_ctxt->ctl = NULL;
566 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
567 sizeof(effect_uuid_t)) == 0) ||
568 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
569 sizeof(effect_uuid_t)) == 0) ||
570 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
571 sizeof(effect_uuid_t)) == 0) ||
572 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
573 sizeof(effect_uuid_t)) == 0)) {
574 reverb_context_t *reverb_ctxt = (reverb_context_t *)
575 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800576 if (reverb_ctxt == NULL) {
577 return -ENOMEM;
578 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800579 context = (effect_context_t *)reverb_ctxt;
580 context->ops.init = reverb_init;
581 context->ops.reset = reverb_reset;
582 context->ops.set_parameter = reverb_set_parameter;
583 context->ops.get_parameter = reverb_get_parameter;
584 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700585 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800586 context->ops.enable = reverb_enable;
587 context->ops.disable = reverb_disable;
588 context->ops.start = reverb_start;
589 context->ops.stop = reverb_stop;
590
591 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
592 sizeof(effect_uuid_t)) == 0) {
593 context->desc = &aux_env_reverb_descriptor;
594 reverb_auxiliary_init(reverb_ctxt);
595 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
596 sizeof(effect_uuid_t)) == 0) {
597 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700598 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800599 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
600 sizeof(effect_uuid_t)) == 0) {
601 context->desc = &aux_preset_reverb_descriptor;
602 reverb_auxiliary_init(reverb_ctxt);
603 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
604 sizeof(effect_uuid_t)) == 0) {
605 context->desc = &ins_preset_reverb_descriptor;
606 reverb_preset_init(reverb_ctxt);
607 }
608 reverb_ctxt->ctl = NULL;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530609#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700610 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
611 sizeof(effect_uuid_t)) == 0) {
612 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
613 calloc(1, sizeof(hw_accelerator_context_t));
614 if (hw_acc_ctxt == NULL) {
615 ALOGE("h/w acc context allocation failed");
616 return -ENOMEM;
617 }
618 context = (effect_context_t *)hw_acc_ctxt;
619 context->ops.init = hw_accelerator_init;
620 context->ops.reset = hw_accelerator_reset;
621 context->ops.set_parameter = hw_accelerator_set_parameter;
622 context->ops.get_parameter = hw_accelerator_get_parameter;
623 context->ops.set_device = hw_accelerator_set_device;
624 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
625 context->ops.enable = hw_accelerator_enable;
626 context->ops.disable = hw_accelerator_disable;
627 context->ops.release = hw_accelerator_release;
628 context->ops.process = hw_accelerator_process;
629
630 context->desc = &hw_accelerator_descriptor;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530631#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800632 } else {
633 return -EINVAL;
634 }
635
636 context->itfe = &effect_interface;
637 context->state = EFFECT_STATE_UNINITIALIZED;
638 context->out_handle = (audio_io_handle_t)ioId;
639
640 ret = context->ops.init(context);
641 if (ret < 0) {
642 ALOGW("%s init failed", __func__);
643 free(context);
644 return ret;
645 }
646
647 context->state = EFFECT_STATE_INITIALIZED;
648
649 pthread_mutex_lock(&lock);
650 list_add_tail(&created_effects_list, &context->effects_list_node);
651 output_context_t *out_ctxt = get_output(ioId);
652 if (out_ctxt != NULL)
653 add_effect_to_output(out_ctxt, context);
654 pthread_mutex_unlock(&lock);
655
656 *pHandle = (effect_handle_t)context;
657
658 ALOGV("%s created context %p", __func__, context);
659
660 return 0;
661
662}
663
664int effect_lib_release(effect_handle_t handle)
665{
666 effect_context_t *context = (effect_context_t *)handle;
667 int status;
668
669 if (lib_init() != 0)
670 return init_status;
671
672 ALOGV("%s context %p", __func__, handle);
673 pthread_mutex_lock(&lock);
674 status = -EINVAL;
675 if (effect_exists(context)) {
676 output_context_t *out_ctxt = get_output(context->out_handle);
677 if (out_ctxt != NULL)
678 remove_effect_from_output(out_ctxt, context);
679 list_remove(&context->effects_list_node);
680 if (context->ops.release)
681 context->ops.release(context);
682 free(context);
683 status = 0;
684 }
685 pthread_mutex_unlock(&lock);
686
687 return status;
688}
689
690int effect_lib_get_descriptor(const effect_uuid_t *uuid,
691 effect_descriptor_t *descriptor)
692{
693 int i;
694
695 if (lib_init() != 0)
696 return init_status;
697
698 if (descriptor == NULL || uuid == NULL) {
699 ALOGV("%s called with NULL pointer", __func__);
700 return -EINVAL;
701 }
702
703 for (i = 0; descriptors[i] != NULL; i++) {
704 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
705 *descriptor = *descriptors[i];
706 return 0;
707 }
708 }
709
710 return -EINVAL;
711}
712
713
714/*
715 * Effect Control Interface Implementation
716 */
717
718/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700719/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800720int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800721 audio_buffer_t *inBuffer __unused,
722 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800723{
724 effect_context_t * context = (effect_context_t *)self;
725 int status = 0;
726
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700727 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800728
729 pthread_mutex_lock(&lock);
730 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800731 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800732 goto exit;
733 }
734
735 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800736 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800737 goto exit;
738 }
739
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700740 if (context->ops.process)
741 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800742exit:
743 pthread_mutex_unlock(&lock);
744 return status;
745}
746
747int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
748 void *pCmdData, uint32_t *replySize, void *pReplyData)
749{
750
751 effect_context_t * context = (effect_context_t *)self;
752 int retsize;
753 int status = 0;
754
755 pthread_mutex_lock(&lock);
756
757 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800758 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800759 goto exit;
760 }
761
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530762 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800763 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800764 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800765 goto exit;
766 }
767
768 switch (cmdCode) {
769 case EFFECT_CMD_INIT:
770 if (pReplyData == NULL || *replySize != sizeof(int)) {
771 status = -EINVAL;
772 goto exit;
773 }
774 if (context->ops.init)
775 *(int *) pReplyData = context->ops.init(context);
776 else
777 *(int *) pReplyData = 0;
778 break;
779 case EFFECT_CMD_SET_CONFIG:
780 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
781 || pReplyData == NULL || *replySize != sizeof(int)) {
782 status = -EINVAL;
783 goto exit;
784 }
785 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
786 break;
787 case EFFECT_CMD_GET_CONFIG:
788 if (pReplyData == NULL ||
789 *replySize != sizeof(effect_config_t)) {
790 status = -EINVAL;
791 goto exit;
792 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700793 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800794 status = -EINVAL;
795 goto exit;
796 }
797
798 get_config(context, (effect_config_t *)pReplyData);
799 break;
800 case EFFECT_CMD_RESET:
801 if (context->ops.reset)
802 context->ops.reset(context);
803 break;
804 case EFFECT_CMD_ENABLE:
805 if (pReplyData == NULL || *replySize != sizeof(int)) {
806 status = -EINVAL;
807 goto exit;
808 }
809 if (context->state != EFFECT_STATE_INITIALIZED) {
810 status = -ENOSYS;
811 goto exit;
812 }
813 context->state = EFFECT_STATE_ACTIVE;
814 if (context->ops.enable)
815 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800816 *(int *)pReplyData = 0;
817 break;
818 case EFFECT_CMD_DISABLE:
819 if (pReplyData == NULL || *replySize != sizeof(int)) {
820 status = -EINVAL;
821 goto exit;
822 }
823 if (context->state != EFFECT_STATE_ACTIVE) {
824 status = -ENOSYS;
825 goto exit;
826 }
827 context->state = EFFECT_STATE_INITIALIZED;
828 if (context->ops.disable)
829 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800830 *(int *)pReplyData = 0;
831 break;
832 case EFFECT_CMD_GET_PARAM: {
833 if (pCmdData == NULL ||
834 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
835 pReplyData == NULL ||
836 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
837 sizeof(uint16_t))) {
838 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530839 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800840 cmdSize, *replySize);
841 goto exit;
842 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700843 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800844 status = -EINVAL;
845 goto exit;
846 }
847 effect_param_t *q = (effect_param_t *)pCmdData;
848 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
849 effect_param_t *p = (effect_param_t *)pReplyData;
850 if (context->ops.get_parameter)
851 context->ops.get_parameter(context, p, replySize);
852 } break;
853 case EFFECT_CMD_SET_PARAM: {
854 if (pCmdData == NULL ||
855 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
856 sizeof(uint16_t)) ||
857 pReplyData == NULL || *replySize != sizeof(int32_t)) {
858 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530859 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800860 cmdSize, *replySize);
861 goto exit;
862 }
863 *(int32_t *)pReplyData = 0;
864 effect_param_t *p = (effect_param_t *)pCmdData;
865 if (context->ops.set_parameter)
866 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
867 *replySize);
868
869 } break;
870 case EFFECT_CMD_SET_DEVICE: {
871 uint32_t device;
872 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
873 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
874 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530875 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800876 goto exit;
877 }
878 device = *(uint32_t *)pCmdData;
879 if (context->ops.set_device)
880 context->ops.set_device(context, device);
881 } break;
882 case EFFECT_CMD_SET_VOLUME:
883 case EFFECT_CMD_SET_AUDIO_MODE:
884 break;
885
886 case EFFECT_CMD_OFFLOAD: {
887 output_context_t *out_ctxt;
888
889 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
890 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530891 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800892 status = -EINVAL;
893 break;
894 }
895
896 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
897
898 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
899 offload_param->isOffload, offload_param->ioHandle);
900
901 *(int *)pReplyData = 0;
902
903 context->offload_enabled = offload_param->isOffload;
904 if (context->out_handle == offload_param->ioHandle)
905 break;
906
907 out_ctxt = get_output(context->out_handle);
908 if (out_ctxt != NULL)
909 remove_effect_from_output(out_ctxt, context);
910
911 context->out_handle = offload_param->ioHandle;
912 out_ctxt = get_output(context->out_handle);
913 if (out_ctxt != NULL)
914 add_effect_to_output(out_ctxt, context);
915
916 } break;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530917#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700918 case EFFECT_CMD_HW_ACC: {
919 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
920 cmdSize, pCmdData, *replySize, pReplyData);
921 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
922 || pReplyData == NULL || *replySize != sizeof(int)) {
923 return -EINVAL;
924 }
925 uint32_t value = *(uint32_t *)pCmdData;
926 if (context->ops.set_hw_acc_mode)
927 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800928
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700929 context->hw_acc_enabled = (value > 0) ? true : false;
930 break;
931 }
Sharad Sangleb27354b2015-06-18 15:58:55 +0530932#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800933 default:
934 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
935 status = context->ops.command(context, cmdCode, cmdSize,
936 pCmdData, replySize, pReplyData);
937 else {
938 ALOGW("%s invalid command %d", __func__, cmdCode);
939 status = -EINVAL;
940 }
941 break;
942 }
943
944exit:
945 pthread_mutex_unlock(&lock);
946
947 return status;
948}
949
950/* Effect Control Interface Implementation: get_descriptor */
951int effect_get_descriptor(effect_handle_t self,
952 effect_descriptor_t *descriptor)
953{
954 effect_context_t *context = (effect_context_t *)self;
955
956 if (!effect_exists(context) || (descriptor == NULL))
957 return -EINVAL;
958
959 *descriptor = *context->desc;
960
961 return 0;
962}
963
wjiang50b81f42014-08-06 08:03:14 +0800964bool effect_is_active(effect_context_t * ctxt) {
965 return ctxt->state == EFFECT_STATE_ACTIVE;
966}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800967
968/* effect_handle_t interface implementation for offload effects */
969const struct effect_interface_s effect_interface = {
970 effect_process,
971 effect_command,
972 effect_get_descriptor,
973 NULL,
974};
975
976__attribute__ ((visibility ("default")))
977audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
978 tag : AUDIO_EFFECT_LIBRARY_TAG,
979 version : EFFECT_LIBRARY_API_VERSION,
980 name : "Offload Effects Bundle Library",
981 implementor : "The Linux Foundation",
982 create_effect : effect_lib_create,
983 release_effect : effect_lib_release,
984 get_descriptor : effect_lib_get_descriptor,
985};