blob: 410e17b0747fee8000fa114307130eb715610e91 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -07002 * Copyright (c) 2013-2014, 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) {
523 bassboost_context_t *bass_ctxt = (bassboost_context_t *)
524 calloc(1, sizeof(bassboost_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;
529 context->ops.init = bassboost_init;
530 context->ops.reset = bassboost_reset;
531 context->ops.set_parameter = bassboost_set_parameter;
532 context->ops.get_parameter = bassboost_get_parameter;
533 context->ops.set_device = bassboost_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700534 context->ops.set_hw_acc_mode = bassboost_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800535 context->ops.enable = bassboost_enable;
536 context->ops.disable = bassboost_disable;
537 context->ops.start = bassboost_start;
538 context->ops.stop = bassboost_stop;
539
540 context->desc = &bassboost_descriptor;
541 bass_ctxt->ctl = NULL;
542 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
543 sizeof(effect_uuid_t)) == 0) {
544 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
545 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800546 if (virt_ctxt == NULL) {
547 return -ENOMEM;
548 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800549 context = (effect_context_t *)virt_ctxt;
550 context->ops.init = virtualizer_init;
551 context->ops.reset = virtualizer_reset;
552 context->ops.set_parameter = virtualizer_set_parameter;
553 context->ops.get_parameter = virtualizer_get_parameter;
554 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700555 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800556 context->ops.enable = virtualizer_enable;
557 context->ops.disable = virtualizer_disable;
558 context->ops.start = virtualizer_start;
559 context->ops.stop = virtualizer_stop;
560
561 context->desc = &virtualizer_descriptor;
562 virt_ctxt->ctl = NULL;
563 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
564 sizeof(effect_uuid_t)) == 0) ||
565 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
566 sizeof(effect_uuid_t)) == 0) ||
567 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
568 sizeof(effect_uuid_t)) == 0) ||
569 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
570 sizeof(effect_uuid_t)) == 0)) {
571 reverb_context_t *reverb_ctxt = (reverb_context_t *)
572 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800573 if (reverb_ctxt == NULL) {
574 return -ENOMEM;
575 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800576 context = (effect_context_t *)reverb_ctxt;
577 context->ops.init = reverb_init;
578 context->ops.reset = reverb_reset;
579 context->ops.set_parameter = reverb_set_parameter;
580 context->ops.get_parameter = reverb_get_parameter;
581 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700582 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800583 context->ops.enable = reverb_enable;
584 context->ops.disable = reverb_disable;
585 context->ops.start = reverb_start;
586 context->ops.stop = reverb_stop;
587
588 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
589 sizeof(effect_uuid_t)) == 0) {
590 context->desc = &aux_env_reverb_descriptor;
591 reverb_auxiliary_init(reverb_ctxt);
592 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
593 sizeof(effect_uuid_t)) == 0) {
594 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700595 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800596 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
597 sizeof(effect_uuid_t)) == 0) {
598 context->desc = &aux_preset_reverb_descriptor;
599 reverb_auxiliary_init(reverb_ctxt);
600 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
601 sizeof(effect_uuid_t)) == 0) {
602 context->desc = &ins_preset_reverb_descriptor;
603 reverb_preset_init(reverb_ctxt);
604 }
605 reverb_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700606 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
607 sizeof(effect_uuid_t)) == 0) {
608 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
609 calloc(1, sizeof(hw_accelerator_context_t));
610 if (hw_acc_ctxt == NULL) {
611 ALOGE("h/w acc context allocation failed");
612 return -ENOMEM;
613 }
614 context = (effect_context_t *)hw_acc_ctxt;
615 context->ops.init = hw_accelerator_init;
616 context->ops.reset = hw_accelerator_reset;
617 context->ops.set_parameter = hw_accelerator_set_parameter;
618 context->ops.get_parameter = hw_accelerator_get_parameter;
619 context->ops.set_device = hw_accelerator_set_device;
620 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
621 context->ops.enable = hw_accelerator_enable;
622 context->ops.disable = hw_accelerator_disable;
623 context->ops.release = hw_accelerator_release;
624 context->ops.process = hw_accelerator_process;
625
626 context->desc = &hw_accelerator_descriptor;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800627 } else {
628 return -EINVAL;
629 }
630
631 context->itfe = &effect_interface;
632 context->state = EFFECT_STATE_UNINITIALIZED;
633 context->out_handle = (audio_io_handle_t)ioId;
634
635 ret = context->ops.init(context);
636 if (ret < 0) {
637 ALOGW("%s init failed", __func__);
638 free(context);
639 return ret;
640 }
641
642 context->state = EFFECT_STATE_INITIALIZED;
643
644 pthread_mutex_lock(&lock);
645 list_add_tail(&created_effects_list, &context->effects_list_node);
646 output_context_t *out_ctxt = get_output(ioId);
647 if (out_ctxt != NULL)
648 add_effect_to_output(out_ctxt, context);
649 pthread_mutex_unlock(&lock);
650
651 *pHandle = (effect_handle_t)context;
652
653 ALOGV("%s created context %p", __func__, context);
654
655 return 0;
656
657}
658
659int effect_lib_release(effect_handle_t handle)
660{
661 effect_context_t *context = (effect_context_t *)handle;
662 int status;
663
664 if (lib_init() != 0)
665 return init_status;
666
667 ALOGV("%s context %p", __func__, handle);
668 pthread_mutex_lock(&lock);
669 status = -EINVAL;
670 if (effect_exists(context)) {
671 output_context_t *out_ctxt = get_output(context->out_handle);
672 if (out_ctxt != NULL)
673 remove_effect_from_output(out_ctxt, context);
674 list_remove(&context->effects_list_node);
675 if (context->ops.release)
676 context->ops.release(context);
677 free(context);
678 status = 0;
679 }
680 pthread_mutex_unlock(&lock);
681
682 return status;
683}
684
685int effect_lib_get_descriptor(const effect_uuid_t *uuid,
686 effect_descriptor_t *descriptor)
687{
688 int i;
689
690 if (lib_init() != 0)
691 return init_status;
692
693 if (descriptor == NULL || uuid == NULL) {
694 ALOGV("%s called with NULL pointer", __func__);
695 return -EINVAL;
696 }
697
698 for (i = 0; descriptors[i] != NULL; i++) {
699 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
700 *descriptor = *descriptors[i];
701 return 0;
702 }
703 }
704
705 return -EINVAL;
706}
707
708
709/*
710 * Effect Control Interface Implementation
711 */
712
713/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700714/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800715int effect_process(effect_handle_t self,
716 audio_buffer_t *inBuffer,
717 audio_buffer_t *outBuffer)
718{
719 effect_context_t * context = (effect_context_t *)self;
720 int status = 0;
721
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700722 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800723
724 pthread_mutex_lock(&lock);
725 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800726 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800727 goto exit;
728 }
729
730 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800731 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800732 goto exit;
733 }
734
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700735 if (context->ops.process)
736 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800737exit:
738 pthread_mutex_unlock(&lock);
739 return status;
740}
741
742int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
743 void *pCmdData, uint32_t *replySize, void *pReplyData)
744{
745
746 effect_context_t * context = (effect_context_t *)self;
747 int retsize;
748 int status = 0;
749
750 pthread_mutex_lock(&lock);
751
752 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800753 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800754 goto exit;
755 }
756
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530757 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800758 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800759 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800760 goto exit;
761 }
762
763 switch (cmdCode) {
764 case EFFECT_CMD_INIT:
765 if (pReplyData == NULL || *replySize != sizeof(int)) {
766 status = -EINVAL;
767 goto exit;
768 }
769 if (context->ops.init)
770 *(int *) pReplyData = context->ops.init(context);
771 else
772 *(int *) pReplyData = 0;
773 break;
774 case EFFECT_CMD_SET_CONFIG:
775 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
776 || pReplyData == NULL || *replySize != sizeof(int)) {
777 status = -EINVAL;
778 goto exit;
779 }
780 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
781 break;
782 case EFFECT_CMD_GET_CONFIG:
783 if (pReplyData == NULL ||
784 *replySize != sizeof(effect_config_t)) {
785 status = -EINVAL;
786 goto exit;
787 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700788 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800789 status = -EINVAL;
790 goto exit;
791 }
792
793 get_config(context, (effect_config_t *)pReplyData);
794 break;
795 case EFFECT_CMD_RESET:
796 if (context->ops.reset)
797 context->ops.reset(context);
798 break;
799 case EFFECT_CMD_ENABLE:
800 if (pReplyData == NULL || *replySize != sizeof(int)) {
801 status = -EINVAL;
802 goto exit;
803 }
804 if (context->state != EFFECT_STATE_INITIALIZED) {
805 status = -ENOSYS;
806 goto exit;
807 }
808 context->state = EFFECT_STATE_ACTIVE;
809 if (context->ops.enable)
810 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800811 *(int *)pReplyData = 0;
812 break;
813 case EFFECT_CMD_DISABLE:
814 if (pReplyData == NULL || *replySize != sizeof(int)) {
815 status = -EINVAL;
816 goto exit;
817 }
818 if (context->state != EFFECT_STATE_ACTIVE) {
819 status = -ENOSYS;
820 goto exit;
821 }
822 context->state = EFFECT_STATE_INITIALIZED;
823 if (context->ops.disable)
824 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800825 *(int *)pReplyData = 0;
826 break;
827 case EFFECT_CMD_GET_PARAM: {
828 if (pCmdData == NULL ||
829 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
830 pReplyData == NULL ||
831 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
832 sizeof(uint16_t))) {
833 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530834 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800835 cmdSize, *replySize);
836 goto exit;
837 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700838 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800839 status = -EINVAL;
840 goto exit;
841 }
842 effect_param_t *q = (effect_param_t *)pCmdData;
843 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
844 effect_param_t *p = (effect_param_t *)pReplyData;
845 if (context->ops.get_parameter)
846 context->ops.get_parameter(context, p, replySize);
847 } break;
848 case EFFECT_CMD_SET_PARAM: {
849 if (pCmdData == NULL ||
850 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
851 sizeof(uint16_t)) ||
852 pReplyData == NULL || *replySize != sizeof(int32_t)) {
853 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530854 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800855 cmdSize, *replySize);
856 goto exit;
857 }
858 *(int32_t *)pReplyData = 0;
859 effect_param_t *p = (effect_param_t *)pCmdData;
860 if (context->ops.set_parameter)
861 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
862 *replySize);
863
864 } break;
865 case EFFECT_CMD_SET_DEVICE: {
866 uint32_t device;
867 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
868 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
869 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530870 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800871 goto exit;
872 }
873 device = *(uint32_t *)pCmdData;
874 if (context->ops.set_device)
875 context->ops.set_device(context, device);
876 } break;
877 case EFFECT_CMD_SET_VOLUME:
878 case EFFECT_CMD_SET_AUDIO_MODE:
879 break;
880
881 case EFFECT_CMD_OFFLOAD: {
882 output_context_t *out_ctxt;
883
884 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
885 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530886 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800887 status = -EINVAL;
888 break;
889 }
890
891 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
892
893 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
894 offload_param->isOffload, offload_param->ioHandle);
895
896 *(int *)pReplyData = 0;
897
898 context->offload_enabled = offload_param->isOffload;
899 if (context->out_handle == offload_param->ioHandle)
900 break;
901
902 out_ctxt = get_output(context->out_handle);
903 if (out_ctxt != NULL)
904 remove_effect_from_output(out_ctxt, context);
905
906 context->out_handle = offload_param->ioHandle;
907 out_ctxt = get_output(context->out_handle);
908 if (out_ctxt != NULL)
909 add_effect_to_output(out_ctxt, context);
910
911 } break;
912
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700913 case EFFECT_CMD_HW_ACC: {
914 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
915 cmdSize, pCmdData, *replySize, pReplyData);
916 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
917 || pReplyData == NULL || *replySize != sizeof(int)) {
918 return -EINVAL;
919 }
920 uint32_t value = *(uint32_t *)pCmdData;
921 if (context->ops.set_hw_acc_mode)
922 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800923
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700924 context->hw_acc_enabled = (value > 0) ? true : false;
925 break;
926 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800927 default:
928 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
929 status = context->ops.command(context, cmdCode, cmdSize,
930 pCmdData, replySize, pReplyData);
931 else {
932 ALOGW("%s invalid command %d", __func__, cmdCode);
933 status = -EINVAL;
934 }
935 break;
936 }
937
938exit:
939 pthread_mutex_unlock(&lock);
940
941 return status;
942}
943
944/* Effect Control Interface Implementation: get_descriptor */
945int effect_get_descriptor(effect_handle_t self,
946 effect_descriptor_t *descriptor)
947{
948 effect_context_t *context = (effect_context_t *)self;
949
950 if (!effect_exists(context) || (descriptor == NULL))
951 return -EINVAL;
952
953 *descriptor = *context->desc;
954
955 return 0;
956}
957
wjiang50b81f42014-08-06 08:03:14 +0800958bool effect_is_active(effect_context_t * ctxt) {
959 return ctxt->state == EFFECT_STATE_ACTIVE;
960}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800961
962/* effect_handle_t interface implementation for offload effects */
963const struct effect_interface_s effect_interface = {
964 effect_process,
965 effect_command,
966 effect_get_descriptor,
967 NULL,
968};
969
970__attribute__ ((visibility ("default")))
971audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
972 tag : AUDIO_EFFECT_LIBRARY_TAG,
973 version : EFFECT_LIBRARY_API_VERSION,
974 name : "Offload Effects Bundle Library",
975 implementor : "The Linux Foundation",
976 create_effect : effect_lib_create,
977 release_effect : effect_lib_release,
978 get_descriptor : effect_lib_get_descriptor,
979};