blob: 8df93cb5ff41e47c260fa7d6c055ed4786548a23 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +08002 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08003 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080018 *
19 * This file was modified by DTS, Inc. The portions of the
20 * code modified by DTS, Inc are copyrighted and
21 * licensed separately, as follows:
22 *
23 * (C) 2014 DTS, Inc.
24 *
25 * Licensed under the Apache License, Version 2.0 (the "License");
26 * you may not use this file except in compliance with the License.
27 * You may obtain a copy of the License at
28 *
29 * http://www.apache.org/licenses/LICENSE-2.0
30 *
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080036 */
37
38#define LOG_TAG "offload_effect_bundle"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070039//#define LOG_NDEBUG 0
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080040
41#include <cutils/list.h>
42#include <cutils/log.h>
43#include <system/thread_defs.h>
44#include <tinyalsa/asoundlib.h>
45#include <hardware/audio_effect.h>
Sharad Sangleb27354b2015-06-18 15:58:55 +053046#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080047#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070048#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080049#include "equalizer.h"
50#include "bass_boost.h"
51#include "virtualizer.h"
52#include "reverb.h"
Dhananjay Kumar1e4061e2015-09-04 13:44:59 +053053#include "asphere.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080054
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,
Sharad Sangleb27354b2015-06-18 15:58:55 +053073#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070074 &hw_accelerator_descriptor,
Sharad Sangleb27354b2015-06-18 15:58:55 +053075#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 Kumarb91d3d12015-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/*
Dhananjay Kumar1e4061e2015-09-04 13:44:59 +0530459 * Effect Bundle Set and get param operations.
460 * currently only handles audio sphere scenario,
461 * but the interface itself can be utilized for any effect.
462 */
463__attribute__ ((visibility ("default")))
464void offload_effects_bundle_get_parameters(struct str_parms *query,
465 struct str_parms *reply)
466{
467 asphere_get_parameters(query, reply);
468}
469
470__attribute__ ((visibility ("default")))
471void offload_effects_bundle_set_parameters(struct str_parms *parms)
472{
473 asphere_set_parameters(parms);
474}
475
476/*
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800477 * Effect operations
478 */
479int set_config(effect_context_t *context, effect_config_t *config)
480{
481 context->config = *config;
482
483 if (context->ops.reset)
484 context->ops.reset(context);
485
486 return 0;
487}
488
489void get_config(effect_context_t *context, effect_config_t *config)
490{
491 *config = context->config;
492}
493
494
495/*
496 * Effect Library Interface Implementation
497 */
498int effect_lib_create(const effect_uuid_t *uuid,
499 int32_t sessionId,
500 int32_t ioId,
501 effect_handle_t *pHandle) {
502 int ret;
503 int i;
504
505 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
506 if (lib_init() != 0)
507 return init_status;
508
509 if (pHandle == NULL || uuid == NULL)
510 return -EINVAL;
511
512 for (i = 0; descriptors[i] != NULL; i++) {
513 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
514 break;
515 }
516
517 if (descriptors[i] == NULL)
518 return -EINVAL;
519
520 effect_context_t *context;
521 if (memcmp(uuid, &equalizer_descriptor.uuid,
522 sizeof(effect_uuid_t)) == 0) {
523 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
524 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800525 if (eq_ctxt == NULL) {
526 return -ENOMEM;
527 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800528 context = (effect_context_t *)eq_ctxt;
529 context->ops.init = equalizer_init;
530 context->ops.reset = equalizer_reset;
531 context->ops.set_parameter = equalizer_set_parameter;
532 context->ops.get_parameter = equalizer_get_parameter;
533 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700534 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800535 context->ops.enable = equalizer_enable;
536 context->ops.disable = equalizer_disable;
537 context->ops.start = equalizer_start;
538 context->ops.stop = equalizer_stop;
539
540 context->desc = &equalizer_descriptor;
541 eq_ctxt->ctl = NULL;
542 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
543 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800544 bass_context_t *bass_ctxt = (bass_context_t *)
545 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800546 if (bass_ctxt == NULL) {
547 return -ENOMEM;
548 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800549 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800550 context->ops.init = bass_init;
551 context->ops.reset = bass_reset;
552 context->ops.set_parameter = bass_set_parameter;
553 context->ops.get_parameter = bass_get_parameter;
554 context->ops.set_device = bass_set_device;
555 context->ops.set_hw_acc_mode = bass_set_mode;
556 context->ops.enable = bass_enable;
557 context->ops.disable = bass_disable;
558 context->ops.start = bass_start;
559 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800560
561 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800562 bass_ctxt->bassboost_ctxt.ctl = NULL;
563 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800564 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
565 sizeof(effect_uuid_t)) == 0) {
566 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
567 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800568 if (virt_ctxt == NULL) {
569 return -ENOMEM;
570 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800571 context = (effect_context_t *)virt_ctxt;
572 context->ops.init = virtualizer_init;
573 context->ops.reset = virtualizer_reset;
574 context->ops.set_parameter = virtualizer_set_parameter;
575 context->ops.get_parameter = virtualizer_get_parameter;
576 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700577 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800578 context->ops.enable = virtualizer_enable;
579 context->ops.disable = virtualizer_disable;
580 context->ops.start = virtualizer_start;
581 context->ops.stop = virtualizer_stop;
582
583 context->desc = &virtualizer_descriptor;
584 virt_ctxt->ctl = NULL;
585 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
586 sizeof(effect_uuid_t)) == 0) ||
587 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
588 sizeof(effect_uuid_t)) == 0) ||
589 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
590 sizeof(effect_uuid_t)) == 0) ||
591 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
592 sizeof(effect_uuid_t)) == 0)) {
593 reverb_context_t *reverb_ctxt = (reverb_context_t *)
594 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800595 if (reverb_ctxt == NULL) {
596 return -ENOMEM;
597 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800598 context = (effect_context_t *)reverb_ctxt;
599 context->ops.init = reverb_init;
600 context->ops.reset = reverb_reset;
601 context->ops.set_parameter = reverb_set_parameter;
602 context->ops.get_parameter = reverb_get_parameter;
603 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700604 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800605 context->ops.enable = reverb_enable;
606 context->ops.disable = reverb_disable;
607 context->ops.start = reverb_start;
608 context->ops.stop = reverb_stop;
609
610 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
611 sizeof(effect_uuid_t)) == 0) {
612 context->desc = &aux_env_reverb_descriptor;
613 reverb_auxiliary_init(reverb_ctxt);
614 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
615 sizeof(effect_uuid_t)) == 0) {
616 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700617 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800618 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
619 sizeof(effect_uuid_t)) == 0) {
620 context->desc = &aux_preset_reverb_descriptor;
621 reverb_auxiliary_init(reverb_ctxt);
622 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
623 sizeof(effect_uuid_t)) == 0) {
624 context->desc = &ins_preset_reverb_descriptor;
625 reverb_preset_init(reverb_ctxt);
626 }
627 reverb_ctxt->ctl = NULL;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530628#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700629 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
630 sizeof(effect_uuid_t)) == 0) {
631 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
632 calloc(1, sizeof(hw_accelerator_context_t));
633 if (hw_acc_ctxt == NULL) {
634 ALOGE("h/w acc context allocation failed");
635 return -ENOMEM;
636 }
637 context = (effect_context_t *)hw_acc_ctxt;
638 context->ops.init = hw_accelerator_init;
639 context->ops.reset = hw_accelerator_reset;
640 context->ops.set_parameter = hw_accelerator_set_parameter;
641 context->ops.get_parameter = hw_accelerator_get_parameter;
642 context->ops.set_device = hw_accelerator_set_device;
643 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
644 context->ops.enable = hw_accelerator_enable;
645 context->ops.disable = hw_accelerator_disable;
646 context->ops.release = hw_accelerator_release;
647 context->ops.process = hw_accelerator_process;
648
649 context->desc = &hw_accelerator_descriptor;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530650#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800651 } else {
652 return -EINVAL;
653 }
654
655 context->itfe = &effect_interface;
656 context->state = EFFECT_STATE_UNINITIALIZED;
657 context->out_handle = (audio_io_handle_t)ioId;
658
659 ret = context->ops.init(context);
660 if (ret < 0) {
661 ALOGW("%s init failed", __func__);
662 free(context);
663 return ret;
664 }
665
666 context->state = EFFECT_STATE_INITIALIZED;
667
668 pthread_mutex_lock(&lock);
669 list_add_tail(&created_effects_list, &context->effects_list_node);
670 output_context_t *out_ctxt = get_output(ioId);
671 if (out_ctxt != NULL)
672 add_effect_to_output(out_ctxt, context);
673 pthread_mutex_unlock(&lock);
674
675 *pHandle = (effect_handle_t)context;
676
677 ALOGV("%s created context %p", __func__, context);
678
679 return 0;
680
681}
682
683int effect_lib_release(effect_handle_t handle)
684{
685 effect_context_t *context = (effect_context_t *)handle;
686 int status;
687
688 if (lib_init() != 0)
689 return init_status;
690
691 ALOGV("%s context %p", __func__, handle);
692 pthread_mutex_lock(&lock);
693 status = -EINVAL;
694 if (effect_exists(context)) {
695 output_context_t *out_ctxt = get_output(context->out_handle);
696 if (out_ctxt != NULL)
697 remove_effect_from_output(out_ctxt, context);
698 list_remove(&context->effects_list_node);
699 if (context->ops.release)
700 context->ops.release(context);
701 free(context);
702 status = 0;
703 }
704 pthread_mutex_unlock(&lock);
705
706 return status;
707}
708
709int effect_lib_get_descriptor(const effect_uuid_t *uuid,
710 effect_descriptor_t *descriptor)
711{
712 int i;
713
714 if (lib_init() != 0)
715 return init_status;
716
717 if (descriptor == NULL || uuid == NULL) {
718 ALOGV("%s called with NULL pointer", __func__);
719 return -EINVAL;
720 }
721
722 for (i = 0; descriptors[i] != NULL; i++) {
723 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
724 *descriptor = *descriptors[i];
725 return 0;
726 }
727 }
728
729 return -EINVAL;
730}
731
732
733/*
734 * Effect Control Interface Implementation
735 */
736
737/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700738/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800739int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800740 audio_buffer_t *inBuffer __unused,
741 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800742{
743 effect_context_t * context = (effect_context_t *)self;
744 int status = 0;
745
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700746 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800747
748 pthread_mutex_lock(&lock);
749 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800750 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800751 goto exit;
752 }
753
754 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800755 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800756 goto exit;
757 }
758
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700759 if (context->ops.process)
760 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800761exit:
762 pthread_mutex_unlock(&lock);
763 return status;
764}
765
766int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
767 void *pCmdData, uint32_t *replySize, void *pReplyData)
768{
769
770 effect_context_t * context = (effect_context_t *)self;
771 int retsize;
772 int status = 0;
773
774 pthread_mutex_lock(&lock);
775
776 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800777 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800778 goto exit;
779 }
780
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530781 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800782 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800783 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800784 goto exit;
785 }
786
787 switch (cmdCode) {
788 case EFFECT_CMD_INIT:
789 if (pReplyData == NULL || *replySize != sizeof(int)) {
790 status = -EINVAL;
791 goto exit;
792 }
793 if (context->ops.init)
794 *(int *) pReplyData = context->ops.init(context);
795 else
796 *(int *) pReplyData = 0;
797 break;
798 case EFFECT_CMD_SET_CONFIG:
799 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
800 || pReplyData == NULL || *replySize != sizeof(int)) {
801 status = -EINVAL;
802 goto exit;
803 }
804 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
805 break;
806 case EFFECT_CMD_GET_CONFIG:
807 if (pReplyData == NULL ||
808 *replySize != sizeof(effect_config_t)) {
809 status = -EINVAL;
810 goto exit;
811 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700812 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800813 status = -EINVAL;
814 goto exit;
815 }
816
817 get_config(context, (effect_config_t *)pReplyData);
818 break;
819 case EFFECT_CMD_RESET:
820 if (context->ops.reset)
821 context->ops.reset(context);
822 break;
823 case EFFECT_CMD_ENABLE:
824 if (pReplyData == NULL || *replySize != sizeof(int)) {
825 status = -EINVAL;
826 goto exit;
827 }
828 if (context->state != EFFECT_STATE_INITIALIZED) {
829 status = -ENOSYS;
830 goto exit;
831 }
Dhananjay Kumar1e4061e2015-09-04 13:44:59 +0530832 handle_asphere_on_effect_enabled(true, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800833 context->state = EFFECT_STATE_ACTIVE;
834 if (context->ops.enable)
835 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800836 *(int *)pReplyData = 0;
837 break;
838 case EFFECT_CMD_DISABLE:
839 if (pReplyData == NULL || *replySize != sizeof(int)) {
840 status = -EINVAL;
841 goto exit;
842 }
843 if (context->state != EFFECT_STATE_ACTIVE) {
844 status = -ENOSYS;
845 goto exit;
846 }
Dhananjay Kumar1e4061e2015-09-04 13:44:59 +0530847 handle_asphere_on_effect_enabled(false, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800848 context->state = EFFECT_STATE_INITIALIZED;
849 if (context->ops.disable)
850 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800851 *(int *)pReplyData = 0;
852 break;
853 case EFFECT_CMD_GET_PARAM: {
854 if (pCmdData == NULL ||
855 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
856 pReplyData == NULL ||
857 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
858 sizeof(uint16_t))) {
859 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530860 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800861 cmdSize, *replySize);
862 goto exit;
863 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700864 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800865 status = -EINVAL;
866 goto exit;
867 }
868 effect_param_t *q = (effect_param_t *)pCmdData;
869 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
870 effect_param_t *p = (effect_param_t *)pReplyData;
871 if (context->ops.get_parameter)
872 context->ops.get_parameter(context, p, replySize);
873 } break;
874 case EFFECT_CMD_SET_PARAM: {
875 if (pCmdData == NULL ||
876 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
877 sizeof(uint16_t)) ||
878 pReplyData == NULL || *replySize != sizeof(int32_t)) {
879 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530880 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800881 cmdSize, *replySize);
882 goto exit;
883 }
884 *(int32_t *)pReplyData = 0;
885 effect_param_t *p = (effect_param_t *)pCmdData;
886 if (context->ops.set_parameter)
887 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
888 *replySize);
889
890 } break;
891 case EFFECT_CMD_SET_DEVICE: {
892 uint32_t device;
893 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
894 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
895 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530896 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800897 goto exit;
898 }
899 device = *(uint32_t *)pCmdData;
900 if (context->ops.set_device)
901 context->ops.set_device(context, device);
902 } break;
903 case EFFECT_CMD_SET_VOLUME:
904 case EFFECT_CMD_SET_AUDIO_MODE:
905 break;
906
907 case EFFECT_CMD_OFFLOAD: {
908 output_context_t *out_ctxt;
909
910 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
911 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530912 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800913 status = -EINVAL;
914 break;
915 }
916
917 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
918
919 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
920 offload_param->isOffload, offload_param->ioHandle);
921
922 *(int *)pReplyData = 0;
923
924 context->offload_enabled = offload_param->isOffload;
925 if (context->out_handle == offload_param->ioHandle)
926 break;
927
928 out_ctxt = get_output(context->out_handle);
929 if (out_ctxt != NULL)
930 remove_effect_from_output(out_ctxt, context);
931
932 context->out_handle = offload_param->ioHandle;
933 out_ctxt = get_output(context->out_handle);
934 if (out_ctxt != NULL)
935 add_effect_to_output(out_ctxt, context);
936
937 } break;
Sharad Sangleb27354b2015-06-18 15:58:55 +0530938#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700939 case EFFECT_CMD_HW_ACC: {
940 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
941 cmdSize, pCmdData, *replySize, pReplyData);
942 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
943 || pReplyData == NULL || *replySize != sizeof(int)) {
944 return -EINVAL;
945 }
946 uint32_t value = *(uint32_t *)pCmdData;
947 if (context->ops.set_hw_acc_mode)
948 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800949
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700950 context->hw_acc_enabled = (value > 0) ? true : false;
951 break;
952 }
Sharad Sangleb27354b2015-06-18 15:58:55 +0530953#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800954 default:
955 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
956 status = context->ops.command(context, cmdCode, cmdSize,
957 pCmdData, replySize, pReplyData);
958 else {
959 ALOGW("%s invalid command %d", __func__, cmdCode);
960 status = -EINVAL;
961 }
962 break;
963 }
964
965exit:
966 pthread_mutex_unlock(&lock);
967
968 return status;
969}
970
971/* Effect Control Interface Implementation: get_descriptor */
972int effect_get_descriptor(effect_handle_t self,
973 effect_descriptor_t *descriptor)
974{
975 effect_context_t *context = (effect_context_t *)self;
976
977 if (!effect_exists(context) || (descriptor == NULL))
978 return -EINVAL;
979
980 *descriptor = *context->desc;
981
982 return 0;
983}
984
wjiang50b81f42014-08-06 08:03:14 +0800985bool effect_is_active(effect_context_t * ctxt) {
986 return ctxt->state == EFFECT_STATE_ACTIVE;
987}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800988
989/* effect_handle_t interface implementation for offload effects */
990const struct effect_interface_s effect_interface = {
991 effect_process,
992 effect_command,
993 effect_get_descriptor,
994 NULL,
995};
996
997__attribute__ ((visibility ("default")))
998audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
999 tag : AUDIO_EFFECT_LIBRARY_TAG,
1000 version : EFFECT_LIBRARY_API_VERSION,
1001 name : "Offload Effects Bundle Library",
1002 implementor : "The Linux Foundation",
1003 create_effect : effect_lib_create,
1004 release_effect : effect_lib_release,
1005 get_descriptor : effect_lib_get_descriptor,
1006};