blob: e38a41c810e31e6b7b967b32e767f5dffc33d6ac [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>
46
47#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,
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070072 &hw_accelerator_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080073 NULL,
74};
75
76pthread_once_t once = PTHREAD_ONCE_INIT;
77int init_status;
78/*
79 * list of created effects.
80 * Updated by offload_effects_bundle_hal_start_output()
81 * and offload_effects_bundle_hal_stop_output()
82 */
83struct listnode created_effects_list;
84/*
85 * list of active output streams.
86 * Updated by offload_effects_bundle_hal_start_output()
87 * and offload_effects_bundle_hal_stop_output()
88 */
89struct listnode active_outputs_list;
90/*
91 * lock must be held when modifying or accessing
92 * created_effects_list or active_outputs_list
93 */
94pthread_mutex_t lock;
95
96
97/*
98 * Local functions
99 */
100static void init_once() {
101 list_init(&created_effects_list);
102 list_init(&active_outputs_list);
103
104 pthread_mutex_init(&lock, NULL);
105
106 init_status = 0;
107}
108
109int lib_init()
110{
111 pthread_once(&once, init_once);
112 return init_status;
113}
114
115bool effect_exists(effect_context_t *context)
116{
117 struct listnode *node;
118
119 list_for_each(node, &created_effects_list) {
120 effect_context_t *fx_ctxt = node_to_item(node,
121 effect_context_t,
122 effects_list_node);
123 if (fx_ctxt == context) {
124 return true;
125 }
126 }
127 return false;
128}
129
130output_context_t *get_output(audio_io_handle_t output)
131{
132 struct listnode *node;
133
134 list_for_each(node, &active_outputs_list) {
135 output_context_t *out_ctxt = node_to_item(node,
136 output_context_t,
137 outputs_list_node);
138 if (out_ctxt->handle == output)
139 return out_ctxt;
140 }
141 return NULL;
142}
143
144void add_effect_to_output(output_context_t * output, effect_context_t *context)
145{
146 struct listnode *fx_node;
147
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530148 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800149 list_for_each(fx_node, &output->effects_list) {
150 effect_context_t *fx_ctxt = node_to_item(fx_node,
151 effect_context_t,
152 output_node);
153 if (fx_ctxt == context)
154 return;
155 }
156 list_add_tail(&output->effects_list, &context->output_node);
157 if (context->ops.start)
158 context->ops.start(context, output);
159
160}
161
162void remove_effect_from_output(output_context_t * output,
163 effect_context_t *context)
164{
165 struct listnode *fx_node;
166
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530167 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800168 list_for_each(fx_node, &output->effects_list) {
169 effect_context_t *fx_ctxt = node_to_item(fx_node,
170 effect_context_t,
171 output_node);
172 if (fx_ctxt == context) {
173 if (context->ops.stop)
174 context->ops.stop(context, output);
175 list_remove(&context->output_node);
176 return;
177 }
178 }
179}
180
181bool effects_enabled()
182{
183 struct listnode *out_node;
184
185 list_for_each(out_node, &active_outputs_list) {
186 struct listnode *fx_node;
187 output_context_t *out_ctxt = node_to_item(out_node,
188 output_context_t,
189 outputs_list_node);
190
191 list_for_each(fx_node, &out_ctxt->effects_list) {
192 effect_context_t *fx_ctxt = node_to_item(fx_node,
193 effect_context_t,
194 output_node);
195 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
196 (fx_ctxt->ops.process != NULL))
197 return true;
198 }
199 }
200 return false;
201}
202
203
204/*
205 * Interface from audio HAL
206 */
207__attribute__ ((visibility ("default")))
208int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
209{
210 int ret = 0;
211 struct listnode *node;
212 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800213 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800214
215 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
216
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800217#ifdef DTS_EAGLE
218 create_effect_state_node(pcm_id);
219#endif
220
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800221 if (lib_init() != 0)
222 return init_status;
223
224 pthread_mutex_lock(&lock);
225 if (get_output(output) != NULL) {
226 ALOGW("%s output already started", __func__);
227 ret = -ENOSYS;
228 goto exit;
229 }
230
wjiang50b81f42014-08-06 08:03:14 +0800231 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800232 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800233 if (!out_ctxt) {
234 ALOGE("%s fail to allocate for output context", __func__);
235 ret = -ENOMEM;
236 goto exit;
237 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800238 out_ctxt->handle = output;
239 out_ctxt->pcm_device_id = pcm_id;
240
241 /* populate the mixer control to send offload parameters */
242 snprintf(mixer_string, sizeof(mixer_string),
243 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
244 out_ctxt->mixer = mixer_open(MIXER_CARD);
245 if (!out_ctxt->mixer) {
246 ALOGE("Failed to open mixer");
247 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700248 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800249 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800250 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800251 goto exit;
252 } else {
253 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
254 if (!out_ctxt->ctl) {
255 ALOGE("mixer_get_ctl_by_name failed");
256 mixer_close(out_ctxt->mixer);
257 out_ctxt->mixer = NULL;
258 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800259 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800260 goto exit;
261 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700262 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800263 }
264
265 list_init(&out_ctxt->effects_list);
266
267 list_for_each(node, &created_effects_list) {
268 effect_context_t *fx_ctxt = node_to_item(node,
269 effect_context_t,
270 effects_list_node);
271 if (fx_ctxt->out_handle == output) {
272 if (fx_ctxt->ops.start)
273 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
274 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
275 }
276 }
277 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
278exit:
279 pthread_mutex_unlock(&lock);
280 return ret;
281}
282
283__attribute__ ((visibility ("default")))
284int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
285{
286 int ret;
287 struct listnode *node;
288 struct listnode *fx_node;
289 output_context_t *out_ctxt;
290
291 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
292
293 if (lib_init() != 0)
294 return init_status;
295
296 pthread_mutex_lock(&lock);
297
298 out_ctxt = get_output(output);
299 if (out_ctxt == NULL) {
300 ALOGW("%s output not started", __func__);
301 ret = -ENOSYS;
302 goto exit;
303 }
304
305 if (out_ctxt->mixer)
306 mixer_close(out_ctxt->mixer);
307
308 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
316 list_remove(&out_ctxt->outputs_list_node);
317
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800318#ifdef DTS_EAGLE
319 remove_effect_state_node(pcm_id);
320#endif
321
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800322 free(out_ctxt);
323
324exit:
325 pthread_mutex_unlock(&lock);
326 return ret;
327}
328
Alexy Josephd464f3b2014-11-18 16:14:41 -0800329__attribute__ ((visibility ("default")))
330int offload_effects_bundle_set_hpx_state(bool hpx_state)
331{
332 int ret = 0;
333 struct listnode *node;
334
335 ALOGV("%s hpx state: %d", __func__, hpx_state);
336
337 if (lib_init() != 0)
338 return init_status;
339
340 pthread_mutex_lock(&lock);
341
342 if (hpx_state) {
343 /* set ramp down */
344 list_for_each(node, &active_outputs_list) {
345 output_context_t *out_ctxt = node_to_item(node,
346 output_context_t,
347 outputs_list_node);
348 struct soft_volume_params vol;
349 vol.master_gain = 0x0;
350 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
351 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
352 }
353 /* wait for ramp down duration - 30msec */
354 usleep(30000);
355 /* disable effects modules */
356 list_for_each(node, &active_outputs_list) {
357 struct listnode *fx_node;
358 output_context_t *out_ctxt = node_to_item(node,
359 output_context_t,
360 outputs_list_node);
361 list_for_each(fx_node, &out_ctxt->effects_list) {
362 effect_context_t *fx_ctxt = node_to_item(fx_node,
363 effect_context_t,
364 output_node);
365 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
366 (fx_ctxt->ops.stop != NULL))
367 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
368 }
369 out_ctxt->ctl = NULL;
370 }
371 /* set the channel mixer */
372 list_for_each(node, &active_outputs_list) {
373 /* send command to set channel mixer */
374 }
375 /* enable hpx modules */
376 list_for_each(node, &active_outputs_list) {
377 output_context_t *out_ctxt = node_to_item(node,
378 output_context_t,
379 outputs_list_node);
380 offload_hpx_send_params(out_ctxt->ref_ctl,
381 OFFLOAD_SEND_HPX_STATE_ON);
382 }
383 /* wait for transition state - 50msec */
384 usleep(50000);
385 /* set ramp up */
386 list_for_each(node, &active_outputs_list) {
387 output_context_t *out_ctxt = node_to_item(node,
388 output_context_t,
389 outputs_list_node);
390 struct soft_volume_params vol;
391 vol.master_gain = 0x2000;
392 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
393 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
394 }
395 } else {
396 /* set ramp down */
397 list_for_each(node, &active_outputs_list) {
398 output_context_t *out_ctxt = node_to_item(node,
399 output_context_t,
400 outputs_list_node);
401 struct soft_volume_params vol;
402 vol.master_gain = 0x0;
403 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
404 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
405 }
406 /* wait for ramp down duration - 30msec */
407 usleep(30000);
408 /* disable effects modules */
409 list_for_each(node, &active_outputs_list) {
410 output_context_t *out_ctxt = node_to_item(node,
411 output_context_t,
412 outputs_list_node);
413 offload_hpx_send_params(out_ctxt->ref_ctl,
414 OFFLOAD_SEND_HPX_STATE_OFF);
415 }
416 /* set the channel mixer */
417 list_for_each(node, &active_outputs_list) {
418 /* send command to set channel mixer */
419 }
420 /* enable effects modules */
421 list_for_each(node, &active_outputs_list) {
422 struct listnode *fx_node;
423 output_context_t *out_ctxt = node_to_item(node,
424 output_context_t,
425 outputs_list_node);
426 out_ctxt->ctl = out_ctxt->ref_ctl;
427 list_for_each(fx_node, &out_ctxt->effects_list) {
428 effect_context_t *fx_ctxt = node_to_item(fx_node,
429 effect_context_t,
430 output_node);
431 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
432 (fx_ctxt->ops.start != NULL))
433 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
434 }
435 }
436 /* wait for transition state - 50msec */
437 usleep(50000);
438 /* set ramp up */
439 list_for_each(node, &active_outputs_list) {
440 output_context_t *out_ctxt = node_to_item(node,
441 output_context_t,
442 outputs_list_node);
443 struct soft_volume_params vol;
444 vol.master_gain = 0x2000;
445 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
446 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
447 }
448 }
449
450exit:
451 pthread_mutex_unlock(&lock);
452 return ret;
453}
454
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800455/*
456 * Effect operations
457 */
458int set_config(effect_context_t *context, effect_config_t *config)
459{
460 context->config = *config;
461
462 if (context->ops.reset)
463 context->ops.reset(context);
464
465 return 0;
466}
467
468void get_config(effect_context_t *context, effect_config_t *config)
469{
470 *config = context->config;
471}
472
473
474/*
475 * Effect Library Interface Implementation
476 */
477int effect_lib_create(const effect_uuid_t *uuid,
478 int32_t sessionId,
479 int32_t ioId,
480 effect_handle_t *pHandle) {
481 int ret;
482 int i;
483
484 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
485 if (lib_init() != 0)
486 return init_status;
487
488 if (pHandle == NULL || uuid == NULL)
489 return -EINVAL;
490
491 for (i = 0; descriptors[i] != NULL; i++) {
492 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
493 break;
494 }
495
496 if (descriptors[i] == NULL)
497 return -EINVAL;
498
499 effect_context_t *context;
500 if (memcmp(uuid, &equalizer_descriptor.uuid,
501 sizeof(effect_uuid_t)) == 0) {
502 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
503 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800504 if (eq_ctxt == NULL) {
505 return -ENOMEM;
506 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800507 context = (effect_context_t *)eq_ctxt;
508 context->ops.init = equalizer_init;
509 context->ops.reset = equalizer_reset;
510 context->ops.set_parameter = equalizer_set_parameter;
511 context->ops.get_parameter = equalizer_get_parameter;
512 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700513 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800514 context->ops.enable = equalizer_enable;
515 context->ops.disable = equalizer_disable;
516 context->ops.start = equalizer_start;
517 context->ops.stop = equalizer_stop;
518
519 context->desc = &equalizer_descriptor;
520 eq_ctxt->ctl = NULL;
521 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
522 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800523 bass_context_t *bass_ctxt = (bass_context_t *)
524 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800525 if (bass_ctxt == NULL) {
526 return -ENOMEM;
527 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800528 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800529 context->ops.init = bass_init;
530 context->ops.reset = bass_reset;
531 context->ops.set_parameter = bass_set_parameter;
532 context->ops.get_parameter = bass_get_parameter;
533 context->ops.set_device = bass_set_device;
534 context->ops.set_hw_acc_mode = bass_set_mode;
535 context->ops.enable = bass_enable;
536 context->ops.disable = bass_disable;
537 context->ops.start = bass_start;
538 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800539
540 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800541 bass_ctxt->bassboost_ctxt.ctl = NULL;
542 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800543 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
544 sizeof(effect_uuid_t)) == 0) {
545 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
546 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800547 if (virt_ctxt == NULL) {
548 return -ENOMEM;
549 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800550 context = (effect_context_t *)virt_ctxt;
551 context->ops.init = virtualizer_init;
552 context->ops.reset = virtualizer_reset;
553 context->ops.set_parameter = virtualizer_set_parameter;
554 context->ops.get_parameter = virtualizer_get_parameter;
555 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700556 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800557 context->ops.enable = virtualizer_enable;
558 context->ops.disable = virtualizer_disable;
559 context->ops.start = virtualizer_start;
560 context->ops.stop = virtualizer_stop;
561
562 context->desc = &virtualizer_descriptor;
563 virt_ctxt->ctl = NULL;
564 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
565 sizeof(effect_uuid_t)) == 0) ||
566 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
567 sizeof(effect_uuid_t)) == 0) ||
568 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
569 sizeof(effect_uuid_t)) == 0) ||
570 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
571 sizeof(effect_uuid_t)) == 0)) {
572 reverb_context_t *reverb_ctxt = (reverb_context_t *)
573 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800574 if (reverb_ctxt == NULL) {
575 return -ENOMEM;
576 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800577 context = (effect_context_t *)reverb_ctxt;
578 context->ops.init = reverb_init;
579 context->ops.reset = reverb_reset;
580 context->ops.set_parameter = reverb_set_parameter;
581 context->ops.get_parameter = reverb_get_parameter;
582 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700583 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800584 context->ops.enable = reverb_enable;
585 context->ops.disable = reverb_disable;
586 context->ops.start = reverb_start;
587 context->ops.stop = reverb_stop;
588
589 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
590 sizeof(effect_uuid_t)) == 0) {
591 context->desc = &aux_env_reverb_descriptor;
592 reverb_auxiliary_init(reverb_ctxt);
593 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
594 sizeof(effect_uuid_t)) == 0) {
595 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700596 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800597 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
598 sizeof(effect_uuid_t)) == 0) {
599 context->desc = &aux_preset_reverb_descriptor;
600 reverb_auxiliary_init(reverb_ctxt);
601 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
602 sizeof(effect_uuid_t)) == 0) {
603 context->desc = &ins_preset_reverb_descriptor;
604 reverb_preset_init(reverb_ctxt);
605 }
606 reverb_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700607 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
608 sizeof(effect_uuid_t)) == 0) {
609 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
610 calloc(1, sizeof(hw_accelerator_context_t));
611 if (hw_acc_ctxt == NULL) {
612 ALOGE("h/w acc context allocation failed");
613 return -ENOMEM;
614 }
615 context = (effect_context_t *)hw_acc_ctxt;
616 context->ops.init = hw_accelerator_init;
617 context->ops.reset = hw_accelerator_reset;
618 context->ops.set_parameter = hw_accelerator_set_parameter;
619 context->ops.get_parameter = hw_accelerator_get_parameter;
620 context->ops.set_device = hw_accelerator_set_device;
621 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
622 context->ops.enable = hw_accelerator_enable;
623 context->ops.disable = hw_accelerator_disable;
624 context->ops.release = hw_accelerator_release;
625 context->ops.process = hw_accelerator_process;
626
627 context->desc = &hw_accelerator_descriptor;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800628 } else {
629 return -EINVAL;
630 }
631
632 context->itfe = &effect_interface;
633 context->state = EFFECT_STATE_UNINITIALIZED;
634 context->out_handle = (audio_io_handle_t)ioId;
635
636 ret = context->ops.init(context);
637 if (ret < 0) {
638 ALOGW("%s init failed", __func__);
639 free(context);
640 return ret;
641 }
642
643 context->state = EFFECT_STATE_INITIALIZED;
644
645 pthread_mutex_lock(&lock);
646 list_add_tail(&created_effects_list, &context->effects_list_node);
647 output_context_t *out_ctxt = get_output(ioId);
648 if (out_ctxt != NULL)
649 add_effect_to_output(out_ctxt, context);
650 pthread_mutex_unlock(&lock);
651
652 *pHandle = (effect_handle_t)context;
653
654 ALOGV("%s created context %p", __func__, context);
655
656 return 0;
657
658}
659
660int effect_lib_release(effect_handle_t handle)
661{
662 effect_context_t *context = (effect_context_t *)handle;
663 int status;
664
665 if (lib_init() != 0)
666 return init_status;
667
668 ALOGV("%s context %p", __func__, handle);
669 pthread_mutex_lock(&lock);
670 status = -EINVAL;
671 if (effect_exists(context)) {
672 output_context_t *out_ctxt = get_output(context->out_handle);
673 if (out_ctxt != NULL)
674 remove_effect_from_output(out_ctxt, context);
675 list_remove(&context->effects_list_node);
676 if (context->ops.release)
677 context->ops.release(context);
678 free(context);
679 status = 0;
680 }
681 pthread_mutex_unlock(&lock);
682
683 return status;
684}
685
686int effect_lib_get_descriptor(const effect_uuid_t *uuid,
687 effect_descriptor_t *descriptor)
688{
689 int i;
690
691 if (lib_init() != 0)
692 return init_status;
693
694 if (descriptor == NULL || uuid == NULL) {
695 ALOGV("%s called with NULL pointer", __func__);
696 return -EINVAL;
697 }
698
699 for (i = 0; descriptors[i] != NULL; i++) {
700 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
701 *descriptor = *descriptors[i];
702 return 0;
703 }
704 }
705
706 return -EINVAL;
707}
708
709
710/*
711 * Effect Control Interface Implementation
712 */
713
714/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700715/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800716int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800717 audio_buffer_t *inBuffer __unused,
718 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800719{
720 effect_context_t * context = (effect_context_t *)self;
721 int status = 0;
722
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700723 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800724
725 pthread_mutex_lock(&lock);
726 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800727 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800728 goto exit;
729 }
730
731 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800732 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800733 goto exit;
734 }
735
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700736 if (context->ops.process)
737 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800738exit:
739 pthread_mutex_unlock(&lock);
740 return status;
741}
742
743int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
744 void *pCmdData, uint32_t *replySize, void *pReplyData)
745{
746
747 effect_context_t * context = (effect_context_t *)self;
748 int retsize;
749 int status = 0;
750
751 pthread_mutex_lock(&lock);
752
753 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800754 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800755 goto exit;
756 }
757
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530758 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800759 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800760 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800761 goto exit;
762 }
763
764 switch (cmdCode) {
765 case EFFECT_CMD_INIT:
766 if (pReplyData == NULL || *replySize != sizeof(int)) {
767 status = -EINVAL;
768 goto exit;
769 }
770 if (context->ops.init)
771 *(int *) pReplyData = context->ops.init(context);
772 else
773 *(int *) pReplyData = 0;
774 break;
775 case EFFECT_CMD_SET_CONFIG:
776 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
777 || pReplyData == NULL || *replySize != sizeof(int)) {
778 status = -EINVAL;
779 goto exit;
780 }
781 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
782 break;
783 case EFFECT_CMD_GET_CONFIG:
784 if (pReplyData == NULL ||
785 *replySize != sizeof(effect_config_t)) {
786 status = -EINVAL;
787 goto exit;
788 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700789 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800790 status = -EINVAL;
791 goto exit;
792 }
793
794 get_config(context, (effect_config_t *)pReplyData);
795 break;
796 case EFFECT_CMD_RESET:
797 if (context->ops.reset)
798 context->ops.reset(context);
799 break;
800 case EFFECT_CMD_ENABLE:
801 if (pReplyData == NULL || *replySize != sizeof(int)) {
802 status = -EINVAL;
803 goto exit;
804 }
805 if (context->state != EFFECT_STATE_INITIALIZED) {
806 status = -ENOSYS;
807 goto exit;
808 }
809 context->state = EFFECT_STATE_ACTIVE;
810 if (context->ops.enable)
811 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800812 *(int *)pReplyData = 0;
813 break;
814 case EFFECT_CMD_DISABLE:
815 if (pReplyData == NULL || *replySize != sizeof(int)) {
816 status = -EINVAL;
817 goto exit;
818 }
819 if (context->state != EFFECT_STATE_ACTIVE) {
820 status = -ENOSYS;
821 goto exit;
822 }
823 context->state = EFFECT_STATE_INITIALIZED;
824 if (context->ops.disable)
825 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800826 *(int *)pReplyData = 0;
827 break;
828 case EFFECT_CMD_GET_PARAM: {
829 if (pCmdData == NULL ||
830 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
831 pReplyData == NULL ||
832 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
833 sizeof(uint16_t))) {
834 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530835 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800836 cmdSize, *replySize);
837 goto exit;
838 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700839 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800840 status = -EINVAL;
841 goto exit;
842 }
843 effect_param_t *q = (effect_param_t *)pCmdData;
844 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
845 effect_param_t *p = (effect_param_t *)pReplyData;
846 if (context->ops.get_parameter)
847 context->ops.get_parameter(context, p, replySize);
848 } break;
849 case EFFECT_CMD_SET_PARAM: {
850 if (pCmdData == NULL ||
851 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
852 sizeof(uint16_t)) ||
853 pReplyData == NULL || *replySize != sizeof(int32_t)) {
854 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530855 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800856 cmdSize, *replySize);
857 goto exit;
858 }
859 *(int32_t *)pReplyData = 0;
860 effect_param_t *p = (effect_param_t *)pCmdData;
861 if (context->ops.set_parameter)
862 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
863 *replySize);
864
865 } break;
866 case EFFECT_CMD_SET_DEVICE: {
867 uint32_t device;
868 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
869 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
870 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530871 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800872 goto exit;
873 }
874 device = *(uint32_t *)pCmdData;
875 if (context->ops.set_device)
876 context->ops.set_device(context, device);
877 } break;
878 case EFFECT_CMD_SET_VOLUME:
879 case EFFECT_CMD_SET_AUDIO_MODE:
880 break;
881
882 case EFFECT_CMD_OFFLOAD: {
883 output_context_t *out_ctxt;
884
885 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
886 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530887 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800888 status = -EINVAL;
889 break;
890 }
891
892 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
893
894 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
895 offload_param->isOffload, offload_param->ioHandle);
896
897 *(int *)pReplyData = 0;
898
899 context->offload_enabled = offload_param->isOffload;
900 if (context->out_handle == offload_param->ioHandle)
901 break;
902
903 out_ctxt = get_output(context->out_handle);
904 if (out_ctxt != NULL)
905 remove_effect_from_output(out_ctxt, context);
906
907 context->out_handle = offload_param->ioHandle;
908 out_ctxt = get_output(context->out_handle);
909 if (out_ctxt != NULL)
910 add_effect_to_output(out_ctxt, context);
911
912 } break;
913
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700914 case EFFECT_CMD_HW_ACC: {
915 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
916 cmdSize, pCmdData, *replySize, pReplyData);
917 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
918 || pReplyData == NULL || *replySize != sizeof(int)) {
919 return -EINVAL;
920 }
921 uint32_t value = *(uint32_t *)pCmdData;
922 if (context->ops.set_hw_acc_mode)
923 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800924
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700925 context->hw_acc_enabled = (value > 0) ? true : false;
926 break;
927 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800928 default:
929 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
930 status = context->ops.command(context, cmdCode, cmdSize,
931 pCmdData, replySize, pReplyData);
932 else {
933 ALOGW("%s invalid command %d", __func__, cmdCode);
934 status = -EINVAL;
935 }
936 break;
937 }
938
939exit:
940 pthread_mutex_unlock(&lock);
941
942 return status;
943}
944
945/* Effect Control Interface Implementation: get_descriptor */
946int effect_get_descriptor(effect_handle_t self,
947 effect_descriptor_t *descriptor)
948{
949 effect_context_t *context = (effect_context_t *)self;
950
951 if (!effect_exists(context) || (descriptor == NULL))
952 return -EINVAL;
953
954 *descriptor = *context->desc;
955
956 return 0;
957}
958
wjiang50b81f42014-08-06 08:03:14 +0800959bool effect_is_active(effect_context_t * ctxt) {
960 return ctxt->state == EFFECT_STATE_ACTIVE;
961}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800962
963/* effect_handle_t interface implementation for offload effects */
964const struct effect_interface_s effect_interface = {
965 effect_process,
966 effect_command,
967 effect_get_descriptor,
968 NULL,
969};
970
971__attribute__ ((visibility ("default")))
972audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
973 tag : AUDIO_EFFECT_LIBRARY_TAG,
974 version : EFFECT_LIBRARY_API_VERSION,
975 name : "Offload Effects Bundle Library",
976 implementor : "The Linux Foundation",
977 create_effect : effect_lib_create,
978 release_effect : effect_lib_release,
979 get_descriptor : effect_lib_get_descriptor,
980};