blob: 6f1bdfaa7af02f5177e1345d7877c8d790a9b569 [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
Mingming Yin497419f2015-07-01 16:57:32 -070041#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080042#include <cutils/list.h>
43#include <cutils/log.h>
44#include <system/thread_defs.h>
45#include <tinyalsa/asoundlib.h>
46#include <hardware/audio_effect.h>
47
48#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070049#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080050#include "equalizer.h"
51#include "bass_boost.h"
52#include "virtualizer.h"
53#include "reverb.h"
54
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080055#ifdef DTS_EAGLE
56#include "effect_util.h"
57#endif
58
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080059enum {
60 EFFECT_STATE_UNINITIALIZED,
61 EFFECT_STATE_INITIALIZED,
62 EFFECT_STATE_ACTIVE,
63};
64
65const effect_descriptor_t *descriptors[] = {
66 &equalizer_descriptor,
67 &bassboost_descriptor,
68 &virtualizer_descriptor,
69 &aux_env_reverb_descriptor,
70 &ins_env_reverb_descriptor,
71 &aux_preset_reverb_descriptor,
72 &ins_preset_reverb_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070073#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070074 &hw_accelerator_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070075#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080076 NULL,
77};
78
79pthread_once_t once = PTHREAD_ONCE_INIT;
80int init_status;
81/*
82 * list of created effects.
83 * Updated by offload_effects_bundle_hal_start_output()
84 * and offload_effects_bundle_hal_stop_output()
85 */
86struct listnode created_effects_list;
87/*
88 * list of active output streams.
89 * Updated by offload_effects_bundle_hal_start_output()
90 * and offload_effects_bundle_hal_stop_output()
91 */
92struct listnode active_outputs_list;
93/*
94 * lock must be held when modifying or accessing
95 * created_effects_list or active_outputs_list
96 */
97pthread_mutex_t lock;
98
99
100/*
101 * Local functions
102 */
103static void init_once() {
104 list_init(&created_effects_list);
105 list_init(&active_outputs_list);
106
107 pthread_mutex_init(&lock, NULL);
108
109 init_status = 0;
110}
111
112int lib_init()
113{
114 pthread_once(&once, init_once);
115 return init_status;
116}
117
118bool effect_exists(effect_context_t *context)
119{
120 struct listnode *node;
121
122 list_for_each(node, &created_effects_list) {
123 effect_context_t *fx_ctxt = node_to_item(node,
124 effect_context_t,
125 effects_list_node);
126 if (fx_ctxt == context) {
127 return true;
128 }
129 }
130 return false;
131}
132
133output_context_t *get_output(audio_io_handle_t output)
134{
135 struct listnode *node;
136
137 list_for_each(node, &active_outputs_list) {
138 output_context_t *out_ctxt = node_to_item(node,
139 output_context_t,
140 outputs_list_node);
141 if (out_ctxt->handle == output)
142 return out_ctxt;
143 }
144 return NULL;
145}
146
147void add_effect_to_output(output_context_t * output, effect_context_t *context)
148{
149 struct listnode *fx_node;
150
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530151 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800152 list_for_each(fx_node, &output->effects_list) {
153 effect_context_t *fx_ctxt = node_to_item(fx_node,
154 effect_context_t,
155 output_node);
156 if (fx_ctxt == context)
157 return;
158 }
159 list_add_tail(&output->effects_list, &context->output_node);
160 if (context->ops.start)
161 context->ops.start(context, output);
162
163}
164
165void remove_effect_from_output(output_context_t * output,
166 effect_context_t *context)
167{
168 struct listnode *fx_node;
169
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530170 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800171 list_for_each(fx_node, &output->effects_list) {
172 effect_context_t *fx_ctxt = node_to_item(fx_node,
173 effect_context_t,
174 output_node);
175 if (fx_ctxt == context) {
176 if (context->ops.stop)
177 context->ops.stop(context, output);
178 list_remove(&context->output_node);
179 return;
180 }
181 }
182}
183
184bool effects_enabled()
185{
186 struct listnode *out_node;
187
188 list_for_each(out_node, &active_outputs_list) {
189 struct listnode *fx_node;
190 output_context_t *out_ctxt = node_to_item(out_node,
191 output_context_t,
192 outputs_list_node);
193
194 list_for_each(fx_node, &out_ctxt->effects_list) {
195 effect_context_t *fx_ctxt = node_to_item(fx_node,
196 effect_context_t,
197 output_node);
198 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
199 (fx_ctxt->ops.process != NULL))
200 return true;
201 }
202 }
203 return false;
204}
205
206
207/*
208 * Interface from audio HAL
209 */
210__attribute__ ((visibility ("default")))
211int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
212{
213 int ret = 0;
214 struct listnode *node;
215 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800216 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800217
218 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
219
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800220#ifdef DTS_EAGLE
221 create_effect_state_node(pcm_id);
222#endif
223
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800224 if (lib_init() != 0)
225 return init_status;
226
227 pthread_mutex_lock(&lock);
228 if (get_output(output) != NULL) {
229 ALOGW("%s output already started", __func__);
230 ret = -ENOSYS;
231 goto exit;
232 }
233
wjiang50b81f42014-08-06 08:03:14 +0800234 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800235 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800236 if (!out_ctxt) {
237 ALOGE("%s fail to allocate for output context", __func__);
238 ret = -ENOMEM;
239 goto exit;
240 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800241 out_ctxt->handle = output;
242 out_ctxt->pcm_device_id = pcm_id;
243
244 /* populate the mixer control to send offload parameters */
245 snprintf(mixer_string, sizeof(mixer_string),
246 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
247 out_ctxt->mixer = mixer_open(MIXER_CARD);
248 if (!out_ctxt->mixer) {
249 ALOGE("Failed to open mixer");
250 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700251 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800252 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800253 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800254 goto exit;
255 } else {
256 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
257 if (!out_ctxt->ctl) {
258 ALOGE("mixer_get_ctl_by_name failed");
259 mixer_close(out_ctxt->mixer);
260 out_ctxt->mixer = NULL;
261 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800262 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800263 goto exit;
264 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700265 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800266 }
267
268 list_init(&out_ctxt->effects_list);
269
270 list_for_each(node, &created_effects_list) {
271 effect_context_t *fx_ctxt = node_to_item(node,
272 effect_context_t,
273 effects_list_node);
274 if (fx_ctxt->out_handle == output) {
275 if (fx_ctxt->ops.start)
276 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
277 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
278 }
279 }
280 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
281exit:
282 pthread_mutex_unlock(&lock);
283 return ret;
284}
285
286__attribute__ ((visibility ("default")))
287int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
288{
289 int ret;
290 struct listnode *node;
291 struct listnode *fx_node;
292 output_context_t *out_ctxt;
293
294 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
295
296 if (lib_init() != 0)
297 return init_status;
298
299 pthread_mutex_lock(&lock);
300
301 out_ctxt = get_output(output);
302 if (out_ctxt == NULL) {
303 ALOGW("%s output not started", __func__);
304 ret = -ENOSYS;
305 goto exit;
306 }
307
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800308 list_for_each(fx_node, &out_ctxt->effects_list) {
309 effect_context_t *fx_ctxt = node_to_item(fx_node,
310 effect_context_t,
311 output_node);
312 if (fx_ctxt->ops.stop)
313 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
314 }
315
Dhananjay Kumar30410f62015-06-29 01:05:12 +0530316 if (out_ctxt->mixer)
317 mixer_close(out_ctxt->mixer);
318
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800319 list_remove(&out_ctxt->outputs_list_node);
320
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800321#ifdef DTS_EAGLE
322 remove_effect_state_node(pcm_id);
323#endif
324
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800325 free(out_ctxt);
326
327exit:
328 pthread_mutex_unlock(&lock);
329 return ret;
330}
331
Alexy Josephd464f3b2014-11-18 16:14:41 -0800332__attribute__ ((visibility ("default")))
333int offload_effects_bundle_set_hpx_state(bool hpx_state)
334{
335 int ret = 0;
336 struct listnode *node;
337
338 ALOGV("%s hpx state: %d", __func__, hpx_state);
339
340 if (lib_init() != 0)
341 return init_status;
342
343 pthread_mutex_lock(&lock);
344
345 if (hpx_state) {
346 /* set ramp down */
347 list_for_each(node, &active_outputs_list) {
348 output_context_t *out_ctxt = node_to_item(node,
349 output_context_t,
350 outputs_list_node);
351 struct soft_volume_params vol;
352 vol.master_gain = 0x0;
353 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
354 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
355 }
356 /* wait for ramp down duration - 30msec */
357 usleep(30000);
358 /* disable effects modules */
359 list_for_each(node, &active_outputs_list) {
360 struct listnode *fx_node;
361 output_context_t *out_ctxt = node_to_item(node,
362 output_context_t,
363 outputs_list_node);
364 list_for_each(fx_node, &out_ctxt->effects_list) {
365 effect_context_t *fx_ctxt = node_to_item(fx_node,
366 effect_context_t,
367 output_node);
368 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
369 (fx_ctxt->ops.stop != NULL))
370 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
371 }
372 out_ctxt->ctl = NULL;
373 }
374 /* set the channel mixer */
375 list_for_each(node, &active_outputs_list) {
376 /* send command to set channel mixer */
377 }
378 /* enable hpx modules */
379 list_for_each(node, &active_outputs_list) {
380 output_context_t *out_ctxt = node_to_item(node,
381 output_context_t,
382 outputs_list_node);
383 offload_hpx_send_params(out_ctxt->ref_ctl,
384 OFFLOAD_SEND_HPX_STATE_ON);
385 }
386 /* wait for transition state - 50msec */
387 usleep(50000);
388 /* set ramp up */
389 list_for_each(node, &active_outputs_list) {
390 output_context_t *out_ctxt = node_to_item(node,
391 output_context_t,
392 outputs_list_node);
393 struct soft_volume_params vol;
394 vol.master_gain = 0x2000;
395 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
396 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
397 }
398 } else {
399 /* set ramp down */
400 list_for_each(node, &active_outputs_list) {
401 output_context_t *out_ctxt = node_to_item(node,
402 output_context_t,
403 outputs_list_node);
404 struct soft_volume_params vol;
405 vol.master_gain = 0x0;
406 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
407 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
408 }
409 /* wait for ramp down duration - 30msec */
410 usleep(30000);
411 /* disable effects modules */
412 list_for_each(node, &active_outputs_list) {
413 output_context_t *out_ctxt = node_to_item(node,
414 output_context_t,
415 outputs_list_node);
416 offload_hpx_send_params(out_ctxt->ref_ctl,
417 OFFLOAD_SEND_HPX_STATE_OFF);
418 }
419 /* set the channel mixer */
420 list_for_each(node, &active_outputs_list) {
421 /* send command to set channel mixer */
422 }
423 /* enable effects modules */
424 list_for_each(node, &active_outputs_list) {
425 struct listnode *fx_node;
426 output_context_t *out_ctxt = node_to_item(node,
427 output_context_t,
428 outputs_list_node);
429 out_ctxt->ctl = out_ctxt->ref_ctl;
430 list_for_each(fx_node, &out_ctxt->effects_list) {
431 effect_context_t *fx_ctxt = node_to_item(fx_node,
432 effect_context_t,
433 output_node);
434 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
435 (fx_ctxt->ops.start != NULL))
436 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
437 }
438 }
439 /* wait for transition state - 50msec */
440 usleep(50000);
441 /* set ramp up */
442 list_for_each(node, &active_outputs_list) {
443 output_context_t *out_ctxt = node_to_item(node,
444 output_context_t,
445 outputs_list_node);
446 struct soft_volume_params vol;
447 vol.master_gain = 0x2000;
448 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
449 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
450 }
451 }
452
453exit:
454 pthread_mutex_unlock(&lock);
455 return ret;
456}
457
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800458/*
459 * Effect operations
460 */
461int set_config(effect_context_t *context, effect_config_t *config)
462{
463 context->config = *config;
464
465 if (context->ops.reset)
466 context->ops.reset(context);
467
468 return 0;
469}
470
471void get_config(effect_context_t *context, effect_config_t *config)
472{
473 *config = context->config;
474}
475
476
477/*
478 * Effect Library Interface Implementation
479 */
480int effect_lib_create(const effect_uuid_t *uuid,
481 int32_t sessionId,
482 int32_t ioId,
483 effect_handle_t *pHandle) {
484 int ret;
485 int i;
486
487 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
488 if (lib_init() != 0)
489 return init_status;
490
491 if (pHandle == NULL || uuid == NULL)
492 return -EINVAL;
493
494 for (i = 0; descriptors[i] != NULL; i++) {
495 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
496 break;
497 }
498
499 if (descriptors[i] == NULL)
500 return -EINVAL;
501
502 effect_context_t *context;
503 if (memcmp(uuid, &equalizer_descriptor.uuid,
504 sizeof(effect_uuid_t)) == 0) {
505 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
506 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800507 if (eq_ctxt == NULL) {
508 return -ENOMEM;
509 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800510 context = (effect_context_t *)eq_ctxt;
511 context->ops.init = equalizer_init;
512 context->ops.reset = equalizer_reset;
513 context->ops.set_parameter = equalizer_set_parameter;
514 context->ops.get_parameter = equalizer_get_parameter;
515 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700516 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800517 context->ops.enable = equalizer_enable;
518 context->ops.disable = equalizer_disable;
519 context->ops.start = equalizer_start;
520 context->ops.stop = equalizer_stop;
521
522 context->desc = &equalizer_descriptor;
523 eq_ctxt->ctl = NULL;
524 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
525 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800526 bass_context_t *bass_ctxt = (bass_context_t *)
527 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800528 if (bass_ctxt == NULL) {
529 return -ENOMEM;
530 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800531 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800532 context->ops.init = bass_init;
533 context->ops.reset = bass_reset;
534 context->ops.set_parameter = bass_set_parameter;
535 context->ops.get_parameter = bass_get_parameter;
536 context->ops.set_device = bass_set_device;
537 context->ops.set_hw_acc_mode = bass_set_mode;
538 context->ops.enable = bass_enable;
539 context->ops.disable = bass_disable;
540 context->ops.start = bass_start;
541 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800542
543 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800544 bass_ctxt->bassboost_ctxt.ctl = NULL;
545 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800546 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
547 sizeof(effect_uuid_t)) == 0) {
548 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
549 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800550 if (virt_ctxt == NULL) {
551 return -ENOMEM;
552 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800553 context = (effect_context_t *)virt_ctxt;
554 context->ops.init = virtualizer_init;
555 context->ops.reset = virtualizer_reset;
556 context->ops.set_parameter = virtualizer_set_parameter;
557 context->ops.get_parameter = virtualizer_get_parameter;
558 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700559 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800560 context->ops.enable = virtualizer_enable;
561 context->ops.disable = virtualizer_disable;
562 context->ops.start = virtualizer_start;
563 context->ops.stop = virtualizer_stop;
564
565 context->desc = &virtualizer_descriptor;
566 virt_ctxt->ctl = NULL;
567 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
568 sizeof(effect_uuid_t)) == 0) ||
569 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
570 sizeof(effect_uuid_t)) == 0) ||
571 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
572 sizeof(effect_uuid_t)) == 0) ||
573 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
574 sizeof(effect_uuid_t)) == 0)) {
575 reverb_context_t *reverb_ctxt = (reverb_context_t *)
576 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800577 if (reverb_ctxt == NULL) {
578 return -ENOMEM;
579 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800580 context = (effect_context_t *)reverb_ctxt;
581 context->ops.init = reverb_init;
582 context->ops.reset = reverb_reset;
583 context->ops.set_parameter = reverb_set_parameter;
584 context->ops.get_parameter = reverb_get_parameter;
585 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700586 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800587 context->ops.enable = reverb_enable;
588 context->ops.disable = reverb_disable;
589 context->ops.start = reverb_start;
590 context->ops.stop = reverb_stop;
591
592 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
593 sizeof(effect_uuid_t)) == 0) {
594 context->desc = &aux_env_reverb_descriptor;
595 reverb_auxiliary_init(reverb_ctxt);
596 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
597 sizeof(effect_uuid_t)) == 0) {
598 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700599 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800600 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
601 sizeof(effect_uuid_t)) == 0) {
602 context->desc = &aux_preset_reverb_descriptor;
603 reverb_auxiliary_init(reverb_ctxt);
604 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
605 sizeof(effect_uuid_t)) == 0) {
606 context->desc = &ins_preset_reverb_descriptor;
607 reverb_preset_init(reverb_ctxt);
608 }
609 reverb_ctxt->ctl = NULL;
Mingming Yin497419f2015-07-01 16:57:32 -0700610#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700611 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
612 sizeof(effect_uuid_t)) == 0) {
613 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
614 calloc(1, sizeof(hw_accelerator_context_t));
615 if (hw_acc_ctxt == NULL) {
616 ALOGE("h/w acc context allocation failed");
617 return -ENOMEM;
618 }
619 context = (effect_context_t *)hw_acc_ctxt;
620 context->ops.init = hw_accelerator_init;
621 context->ops.reset = hw_accelerator_reset;
622 context->ops.set_parameter = hw_accelerator_set_parameter;
623 context->ops.get_parameter = hw_accelerator_get_parameter;
624 context->ops.set_device = hw_accelerator_set_device;
625 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
626 context->ops.enable = hw_accelerator_enable;
627 context->ops.disable = hw_accelerator_disable;
628 context->ops.release = hw_accelerator_release;
629 context->ops.process = hw_accelerator_process;
630
631 context->desc = &hw_accelerator_descriptor;
Mingming Yin497419f2015-07-01 16:57:32 -0700632#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800633 } else {
634 return -EINVAL;
635 }
636
637 context->itfe = &effect_interface;
638 context->state = EFFECT_STATE_UNINITIALIZED;
639 context->out_handle = (audio_io_handle_t)ioId;
640
641 ret = context->ops.init(context);
642 if (ret < 0) {
643 ALOGW("%s init failed", __func__);
644 free(context);
645 return ret;
646 }
647
648 context->state = EFFECT_STATE_INITIALIZED;
649
650 pthread_mutex_lock(&lock);
651 list_add_tail(&created_effects_list, &context->effects_list_node);
652 output_context_t *out_ctxt = get_output(ioId);
653 if (out_ctxt != NULL)
654 add_effect_to_output(out_ctxt, context);
655 pthread_mutex_unlock(&lock);
656
657 *pHandle = (effect_handle_t)context;
658
659 ALOGV("%s created context %p", __func__, context);
660
661 return 0;
662
663}
664
665int effect_lib_release(effect_handle_t handle)
666{
667 effect_context_t *context = (effect_context_t *)handle;
668 int status;
669
670 if (lib_init() != 0)
671 return init_status;
672
673 ALOGV("%s context %p", __func__, handle);
674 pthread_mutex_lock(&lock);
675 status = -EINVAL;
676 if (effect_exists(context)) {
677 output_context_t *out_ctxt = get_output(context->out_handle);
678 if (out_ctxt != NULL)
679 remove_effect_from_output(out_ctxt, context);
680 list_remove(&context->effects_list_node);
681 if (context->ops.release)
682 context->ops.release(context);
683 free(context);
684 status = 0;
685 }
686 pthread_mutex_unlock(&lock);
687
688 return status;
689}
690
691int effect_lib_get_descriptor(const effect_uuid_t *uuid,
692 effect_descriptor_t *descriptor)
693{
694 int i;
695
696 if (lib_init() != 0)
697 return init_status;
698
699 if (descriptor == NULL || uuid == NULL) {
700 ALOGV("%s called with NULL pointer", __func__);
701 return -EINVAL;
702 }
703
704 for (i = 0; descriptors[i] != NULL; i++) {
705 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
706 *descriptor = *descriptors[i];
707 return 0;
708 }
709 }
710
711 return -EINVAL;
712}
713
714
715/*
716 * Effect Control Interface Implementation
717 */
718
719/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700720/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800721int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800722 audio_buffer_t *inBuffer __unused,
723 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800724{
725 effect_context_t * context = (effect_context_t *)self;
726 int status = 0;
727
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700728 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800729
730 pthread_mutex_lock(&lock);
731 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800732 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800733 goto exit;
734 }
735
736 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800737 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800738 goto exit;
739 }
740
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700741 if (context->ops.process)
742 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800743exit:
744 pthread_mutex_unlock(&lock);
745 return status;
746}
747
748int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
749 void *pCmdData, uint32_t *replySize, void *pReplyData)
750{
751
752 effect_context_t * context = (effect_context_t *)self;
753 int retsize;
754 int status = 0;
755
756 pthread_mutex_lock(&lock);
757
758 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800759 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800760 goto exit;
761 }
762
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530763 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800764 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800765 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800766 goto exit;
767 }
768
769 switch (cmdCode) {
770 case EFFECT_CMD_INIT:
771 if (pReplyData == NULL || *replySize != sizeof(int)) {
772 status = -EINVAL;
773 goto exit;
774 }
775 if (context->ops.init)
776 *(int *) pReplyData = context->ops.init(context);
777 else
778 *(int *) pReplyData = 0;
779 break;
780 case EFFECT_CMD_SET_CONFIG:
781 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
782 || pReplyData == NULL || *replySize != sizeof(int)) {
783 status = -EINVAL;
784 goto exit;
785 }
786 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
787 break;
788 case EFFECT_CMD_GET_CONFIG:
789 if (pReplyData == NULL ||
790 *replySize != sizeof(effect_config_t)) {
791 status = -EINVAL;
792 goto exit;
793 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700794 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800795 status = -EINVAL;
796 goto exit;
797 }
798
799 get_config(context, (effect_config_t *)pReplyData);
800 break;
801 case EFFECT_CMD_RESET:
802 if (context->ops.reset)
803 context->ops.reset(context);
804 break;
805 case EFFECT_CMD_ENABLE:
806 if (pReplyData == NULL || *replySize != sizeof(int)) {
807 status = -EINVAL;
808 goto exit;
809 }
810 if (context->state != EFFECT_STATE_INITIALIZED) {
811 status = -ENOSYS;
812 goto exit;
813 }
814 context->state = EFFECT_STATE_ACTIVE;
815 if (context->ops.enable)
816 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800817 *(int *)pReplyData = 0;
818 break;
819 case EFFECT_CMD_DISABLE:
820 if (pReplyData == NULL || *replySize != sizeof(int)) {
821 status = -EINVAL;
822 goto exit;
823 }
824 if (context->state != EFFECT_STATE_ACTIVE) {
825 status = -ENOSYS;
826 goto exit;
827 }
828 context->state = EFFECT_STATE_INITIALIZED;
829 if (context->ops.disable)
830 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800831 *(int *)pReplyData = 0;
832 break;
833 case EFFECT_CMD_GET_PARAM: {
834 if (pCmdData == NULL ||
835 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
836 pReplyData == NULL ||
837 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
838 sizeof(uint16_t))) {
839 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530840 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800841 cmdSize, *replySize);
842 goto exit;
843 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700844 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800845 status = -EINVAL;
846 goto exit;
847 }
848 effect_param_t *q = (effect_param_t *)pCmdData;
849 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
850 effect_param_t *p = (effect_param_t *)pReplyData;
851 if (context->ops.get_parameter)
852 context->ops.get_parameter(context, p, replySize);
853 } break;
854 case EFFECT_CMD_SET_PARAM: {
855 if (pCmdData == NULL ||
856 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
857 sizeof(uint16_t)) ||
858 pReplyData == NULL || *replySize != sizeof(int32_t)) {
859 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530860 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800861 cmdSize, *replySize);
862 goto exit;
863 }
864 *(int32_t *)pReplyData = 0;
865 effect_param_t *p = (effect_param_t *)pCmdData;
866 if (context->ops.set_parameter)
867 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
868 *replySize);
869
870 } break;
871 case EFFECT_CMD_SET_DEVICE: {
872 uint32_t device;
873 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
874 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
875 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530876 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800877 goto exit;
878 }
879 device = *(uint32_t *)pCmdData;
880 if (context->ops.set_device)
881 context->ops.set_device(context, device);
882 } break;
883 case EFFECT_CMD_SET_VOLUME:
884 case EFFECT_CMD_SET_AUDIO_MODE:
885 break;
886
887 case EFFECT_CMD_OFFLOAD: {
888 output_context_t *out_ctxt;
889
890 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
891 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530892 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800893 status = -EINVAL;
894 break;
895 }
896
897 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
898
899 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
900 offload_param->isOffload, offload_param->ioHandle);
901
902 *(int *)pReplyData = 0;
903
904 context->offload_enabled = offload_param->isOffload;
905 if (context->out_handle == offload_param->ioHandle)
906 break;
907
908 out_ctxt = get_output(context->out_handle);
909 if (out_ctxt != NULL)
910 remove_effect_from_output(out_ctxt, context);
911
912 context->out_handle = offload_param->ioHandle;
913 out_ctxt = get_output(context->out_handle);
914 if (out_ctxt != NULL)
915 add_effect_to_output(out_ctxt, context);
916
917 } break;
918
Mingming Yin497419f2015-07-01 16:57:32 -0700919#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700920 case EFFECT_CMD_HW_ACC: {
921 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
922 cmdSize, pCmdData, *replySize, pReplyData);
923 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
924 || pReplyData == NULL || *replySize != sizeof(int)) {
925 return -EINVAL;
926 }
927 uint32_t value = *(uint32_t *)pCmdData;
928 if (context->ops.set_hw_acc_mode)
929 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800930
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700931 context->hw_acc_enabled = (value > 0) ? true : false;
932 break;
933 }
Mingming Yin497419f2015-07-01 16:57:32 -0700934#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800935 default:
936 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
937 status = context->ops.command(context, cmdCode, cmdSize,
938 pCmdData, replySize, pReplyData);
939 else {
940 ALOGW("%s invalid command %d", __func__, cmdCode);
941 status = -EINVAL;
942 }
943 break;
944 }
945
946exit:
947 pthread_mutex_unlock(&lock);
948
949 return status;
950}
951
952/* Effect Control Interface Implementation: get_descriptor */
953int effect_get_descriptor(effect_handle_t self,
954 effect_descriptor_t *descriptor)
955{
956 effect_context_t *context = (effect_context_t *)self;
957
958 if (!effect_exists(context) || (descriptor == NULL))
959 return -EINVAL;
960
961 *descriptor = *context->desc;
962
963 return 0;
964}
965
wjiang50b81f42014-08-06 08:03:14 +0800966bool effect_is_active(effect_context_t * ctxt) {
967 return ctxt->state == EFFECT_STATE_ACTIVE;
968}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800969
970/* effect_handle_t interface implementation for offload effects */
971const struct effect_interface_s effect_interface = {
972 effect_process,
973 effect_command,
974 effect_get_descriptor,
975 NULL,
976};
977
978__attribute__ ((visibility ("default")))
979audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
980 tag : AUDIO_EFFECT_LIBRARY_TAG,
981 version : EFFECT_LIBRARY_API_VERSION,
982 name : "Offload Effects Bundle Library",
983 implementor : "The Linux Foundation",
984 create_effect : effect_lib_create,
985 release_effect : effect_lib_release,
986 get_descriptor : effect_lib_get_descriptor,
987};