blob: 000020da349fb572845ea95ae5d186281da4a826 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +08002 * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08003 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080018 *
19 * This file was modified by DTS, Inc. The portions of the
20 * code modified by DTS, Inc are copyrighted and
21 * licensed separately, as follows:
22 *
23 * (C) 2014 DTS, Inc.
24 *
25 * Licensed under the Apache License, Version 2.0 (the "License");
26 * you may not use this file except in compliance with the License.
27 * You may obtain a copy of the License at
28 *
29 * http://www.apache.org/licenses/LICENSE-2.0
30 *
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080036 */
37
38#define LOG_TAG "offload_effect_bundle"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070039//#define LOG_NDEBUG 0
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080040
Mingming Yin497419f2015-07-01 16:57:32 -070041#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080042#include <cutils/list.h>
43#include <cutils/log.h>
44#include <system/thread_defs.h>
45#include <tinyalsa/asoundlib.h>
46#include <hardware/audio_effect.h>
47
48#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070049#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080050#include "equalizer.h"
51#include "bass_boost.h"
52#include "virtualizer.h"
53#include "reverb.h"
Dhananjay Kumar1c978df2015-09-04 13:44:59 +053054#include "asphere.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080055
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080056#ifdef DTS_EAGLE
57#include "effect_util.h"
58#endif
59
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080060enum {
61 EFFECT_STATE_UNINITIALIZED,
62 EFFECT_STATE_INITIALIZED,
63 EFFECT_STATE_ACTIVE,
64};
65
66const effect_descriptor_t *descriptors[] = {
67 &equalizer_descriptor,
68 &bassboost_descriptor,
69 &virtualizer_descriptor,
70 &aux_env_reverb_descriptor,
71 &ins_env_reverb_descriptor,
72 &aux_preset_reverb_descriptor,
73 &ins_preset_reverb_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070074#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070075 &hw_accelerator_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070076#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080077 NULL,
78};
79
80pthread_once_t once = PTHREAD_ONCE_INIT;
81int init_status;
82/*
83 * list of created effects.
84 * Updated by offload_effects_bundle_hal_start_output()
85 * and offload_effects_bundle_hal_stop_output()
86 */
87struct listnode created_effects_list;
88/*
89 * list of active output streams.
90 * Updated by offload_effects_bundle_hal_start_output()
91 * and offload_effects_bundle_hal_stop_output()
92 */
93struct listnode active_outputs_list;
94/*
95 * lock must be held when modifying or accessing
96 * created_effects_list or active_outputs_list
97 */
98pthread_mutex_t lock;
99
100
101/*
102 * Local functions
103 */
104static void init_once() {
105 list_init(&created_effects_list);
106 list_init(&active_outputs_list);
107
108 pthread_mutex_init(&lock, NULL);
109
110 init_status = 0;
111}
112
113int lib_init()
114{
115 pthread_once(&once, init_once);
116 return init_status;
117}
118
119bool effect_exists(effect_context_t *context)
120{
121 struct listnode *node;
122
123 list_for_each(node, &created_effects_list) {
124 effect_context_t *fx_ctxt = node_to_item(node,
125 effect_context_t,
126 effects_list_node);
127 if (fx_ctxt == context) {
128 return true;
129 }
130 }
131 return false;
132}
133
134output_context_t *get_output(audio_io_handle_t output)
135{
136 struct listnode *node;
137
138 list_for_each(node, &active_outputs_list) {
139 output_context_t *out_ctxt = node_to_item(node,
140 output_context_t,
141 outputs_list_node);
142 if (out_ctxt->handle == output)
143 return out_ctxt;
144 }
145 return NULL;
146}
147
148void add_effect_to_output(output_context_t * output, effect_context_t *context)
149{
150 struct listnode *fx_node;
151
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530152 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800153 list_for_each(fx_node, &output->effects_list) {
154 effect_context_t *fx_ctxt = node_to_item(fx_node,
155 effect_context_t,
156 output_node);
157 if (fx_ctxt == context)
158 return;
159 }
160 list_add_tail(&output->effects_list, &context->output_node);
161 if (context->ops.start)
162 context->ops.start(context, output);
163
164}
165
166void remove_effect_from_output(output_context_t * output,
167 effect_context_t *context)
168{
169 struct listnode *fx_node;
170
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530171 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800172 list_for_each(fx_node, &output->effects_list) {
173 effect_context_t *fx_ctxt = node_to_item(fx_node,
174 effect_context_t,
175 output_node);
176 if (fx_ctxt == context) {
177 if (context->ops.stop)
178 context->ops.stop(context, output);
179 list_remove(&context->output_node);
180 return;
181 }
182 }
183}
184
185bool effects_enabled()
186{
187 struct listnode *out_node;
188
189 list_for_each(out_node, &active_outputs_list) {
190 struct listnode *fx_node;
191 output_context_t *out_ctxt = node_to_item(out_node,
192 output_context_t,
193 outputs_list_node);
194
195 list_for_each(fx_node, &out_ctxt->effects_list) {
196 effect_context_t *fx_ctxt = node_to_item(fx_node,
197 effect_context_t,
198 output_node);
199 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
200 (fx_ctxt->ops.process != NULL))
201 return true;
202 }
203 }
204 return false;
205}
206
207
208/*
209 * Interface from audio HAL
210 */
211__attribute__ ((visibility ("default")))
Ashish Jain5106d362016-05-11 19:23:33 +0530212int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id, struct mixer *mixer)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800213{
214 int ret = 0;
215 struct listnode *node;
216 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800217 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800218
219 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
220
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800221#ifdef DTS_EAGLE
222 create_effect_state_node(pcm_id);
223#endif
224
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800225 if (lib_init() != 0)
226 return init_status;
227
228 pthread_mutex_lock(&lock);
229 if (get_output(output) != NULL) {
230 ALOGW("%s output already started", __func__);
231 ret = -ENOSYS;
232 goto exit;
233 }
234
wjiang50b81f42014-08-06 08:03:14 +0800235 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800236 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800237 if (!out_ctxt) {
238 ALOGE("%s fail to allocate for output context", __func__);
239 ret = -ENOMEM;
240 goto exit;
241 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800242 out_ctxt->handle = output;
243 out_ctxt->pcm_device_id = pcm_id;
244
245 /* populate the mixer control to send offload parameters */
246 snprintf(mixer_string, sizeof(mixer_string),
247 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
Ashish Jain5106d362016-05-11 19:23:33 +0530248
249 if (!mixer) {
250 ALOGE("Invalid mixer");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800251 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700252 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800253 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800254 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800255 goto exit;
256 } else {
Ashish Jain5106d362016-05-11 19:23:33 +0530257 out_ctxt->mixer = mixer;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800258 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
259 if (!out_ctxt->ctl) {
260 ALOGE("mixer_get_ctl_by_name failed");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800261 out_ctxt->mixer = NULL;
262 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800263 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800264 goto exit;
265 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700266 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800267 }
268
269 list_init(&out_ctxt->effects_list);
270
271 list_for_each(node, &created_effects_list) {
272 effect_context_t *fx_ctxt = node_to_item(node,
273 effect_context_t,
274 effects_list_node);
275 if (fx_ctxt->out_handle == output) {
276 if (fx_ctxt->ops.start)
277 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
278 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
279 }
280 }
281 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
282exit:
283 pthread_mutex_unlock(&lock);
284 return ret;
285}
286
287__attribute__ ((visibility ("default")))
288int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
289{
Preetam Singh Ranawat53194302016-03-15 16:37:42 +0530290 int ret = -1;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800291 struct listnode *node;
292 struct listnode *fx_node;
293 output_context_t *out_ctxt;
294
295 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
296
297 if (lib_init() != 0)
298 return init_status;
299
300 pthread_mutex_lock(&lock);
301
302 out_ctxt = get_output(output);
303 if (out_ctxt == NULL) {
304 ALOGW("%s output not started", __func__);
305 ret = -ENOSYS;
306 goto exit;
307 }
308
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800309 list_for_each(fx_node, &out_ctxt->effects_list) {
310 effect_context_t *fx_ctxt = node_to_item(fx_node,
311 effect_context_t,
312 output_node);
313 if (fx_ctxt->ops.stop)
314 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
315 }
316
317 list_remove(&out_ctxt->outputs_list_node);
318
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800319#ifdef DTS_EAGLE
320 remove_effect_state_node(pcm_id);
321#endif
322
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800323 free(out_ctxt);
324
325exit:
326 pthread_mutex_unlock(&lock);
327 return ret;
328}
329
Alexy Josephd464f3b2014-11-18 16:14:41 -0800330__attribute__ ((visibility ("default")))
331int offload_effects_bundle_set_hpx_state(bool hpx_state)
332{
333 int ret = 0;
334 struct listnode *node;
335
336 ALOGV("%s hpx state: %d", __func__, hpx_state);
337
338 if (lib_init() != 0)
339 return init_status;
340
341 pthread_mutex_lock(&lock);
342
343 if (hpx_state) {
344 /* set ramp down */
345 list_for_each(node, &active_outputs_list) {
346 output_context_t *out_ctxt = node_to_item(node,
347 output_context_t,
348 outputs_list_node);
349 struct soft_volume_params vol;
350 vol.master_gain = 0x0;
351 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
352 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
353 }
354 /* wait for ramp down duration - 30msec */
355 usleep(30000);
356 /* disable effects modules */
357 list_for_each(node, &active_outputs_list) {
358 struct listnode *fx_node;
359 output_context_t *out_ctxt = node_to_item(node,
360 output_context_t,
361 outputs_list_node);
362 list_for_each(fx_node, &out_ctxt->effects_list) {
363 effect_context_t *fx_ctxt = node_to_item(fx_node,
364 effect_context_t,
365 output_node);
366 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
367 (fx_ctxt->ops.stop != NULL))
368 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
369 }
370 out_ctxt->ctl = NULL;
371 }
372 /* set the channel mixer */
373 list_for_each(node, &active_outputs_list) {
374 /* send command to set channel mixer */
375 }
376 /* enable hpx modules */
377 list_for_each(node, &active_outputs_list) {
378 output_context_t *out_ctxt = node_to_item(node,
379 output_context_t,
380 outputs_list_node);
381 offload_hpx_send_params(out_ctxt->ref_ctl,
382 OFFLOAD_SEND_HPX_STATE_ON);
383 }
384 /* wait for transition state - 50msec */
385 usleep(50000);
386 /* set ramp up */
387 list_for_each(node, &active_outputs_list) {
388 output_context_t *out_ctxt = node_to_item(node,
389 output_context_t,
390 outputs_list_node);
391 struct soft_volume_params vol;
392 vol.master_gain = 0x2000;
393 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
394 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
395 }
396 } else {
397 /* set ramp down */
398 list_for_each(node, &active_outputs_list) {
399 output_context_t *out_ctxt = node_to_item(node,
400 output_context_t,
401 outputs_list_node);
402 struct soft_volume_params vol;
403 vol.master_gain = 0x0;
404 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
405 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
406 }
407 /* wait for ramp down duration - 30msec */
408 usleep(30000);
409 /* disable effects modules */
410 list_for_each(node, &active_outputs_list) {
411 output_context_t *out_ctxt = node_to_item(node,
412 output_context_t,
413 outputs_list_node);
414 offload_hpx_send_params(out_ctxt->ref_ctl,
415 OFFLOAD_SEND_HPX_STATE_OFF);
416 }
417 /* set the channel mixer */
418 list_for_each(node, &active_outputs_list) {
419 /* send command to set channel mixer */
420 }
421 /* enable effects modules */
422 list_for_each(node, &active_outputs_list) {
423 struct listnode *fx_node;
424 output_context_t *out_ctxt = node_to_item(node,
425 output_context_t,
426 outputs_list_node);
427 out_ctxt->ctl = out_ctxt->ref_ctl;
428 list_for_each(fx_node, &out_ctxt->effects_list) {
429 effect_context_t *fx_ctxt = node_to_item(fx_node,
430 effect_context_t,
431 output_node);
432 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
433 (fx_ctxt->ops.start != NULL))
434 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
435 }
436 }
437 /* wait for transition state - 50msec */
438 usleep(50000);
439 /* set ramp up */
440 list_for_each(node, &active_outputs_list) {
441 output_context_t *out_ctxt = node_to_item(node,
442 output_context_t,
443 outputs_list_node);
444 struct soft_volume_params vol;
445 vol.master_gain = 0x2000;
446 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
447 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
448 }
449 }
450
451exit:
452 pthread_mutex_unlock(&lock);
453 return ret;
454}
455
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800456/*
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530457 * Effect Bundle Set and get param operations.
458 * currently only handles audio sphere scenario,
459 * but the interface itself can be utilized for any effect.
460 */
461__attribute__ ((visibility ("default")))
462void offload_effects_bundle_get_parameters(struct str_parms *query,
463 struct str_parms *reply)
464{
465 asphere_get_parameters(query, reply);
466}
467
468__attribute__ ((visibility ("default")))
469void offload_effects_bundle_set_parameters(struct str_parms *parms)
470{
471 asphere_set_parameters(parms);
472}
473
474/*
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800475 * Effect operations
476 */
477int set_config(effect_context_t *context, effect_config_t *config)
478{
479 context->config = *config;
480
481 if (context->ops.reset)
482 context->ops.reset(context);
483
484 return 0;
485}
486
487void get_config(effect_context_t *context, effect_config_t *config)
488{
489 *config = context->config;
490}
491
492
493/*
494 * Effect Library Interface Implementation
495 */
496int effect_lib_create(const effect_uuid_t *uuid,
497 int32_t sessionId,
498 int32_t ioId,
499 effect_handle_t *pHandle) {
500 int ret;
501 int i;
502
503 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
504 if (lib_init() != 0)
505 return init_status;
506
507 if (pHandle == NULL || uuid == NULL)
508 return -EINVAL;
509
510 for (i = 0; descriptors[i] != NULL; i++) {
511 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
512 break;
513 }
514
515 if (descriptors[i] == NULL)
516 return -EINVAL;
517
518 effect_context_t *context;
519 if (memcmp(uuid, &equalizer_descriptor.uuid,
520 sizeof(effect_uuid_t)) == 0) {
521 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
522 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800523 if (eq_ctxt == NULL) {
524 return -ENOMEM;
525 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800526 context = (effect_context_t *)eq_ctxt;
527 context->ops.init = equalizer_init;
528 context->ops.reset = equalizer_reset;
529 context->ops.set_parameter = equalizer_set_parameter;
530 context->ops.get_parameter = equalizer_get_parameter;
531 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700532 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800533 context->ops.enable = equalizer_enable;
534 context->ops.disable = equalizer_disable;
535 context->ops.start = equalizer_start;
536 context->ops.stop = equalizer_stop;
537
538 context->desc = &equalizer_descriptor;
539 eq_ctxt->ctl = NULL;
540 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
541 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800542 bass_context_t *bass_ctxt = (bass_context_t *)
543 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800544 if (bass_ctxt == NULL) {
545 return -ENOMEM;
546 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800547 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800548 context->ops.init = bass_init;
549 context->ops.reset = bass_reset;
550 context->ops.set_parameter = bass_set_parameter;
551 context->ops.get_parameter = bass_get_parameter;
552 context->ops.set_device = bass_set_device;
553 context->ops.set_hw_acc_mode = bass_set_mode;
554 context->ops.enable = bass_enable;
555 context->ops.disable = bass_disable;
556 context->ops.start = bass_start;
557 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800558
559 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800560 bass_ctxt->bassboost_ctxt.ctl = NULL;
561 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800562 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
563 sizeof(effect_uuid_t)) == 0) {
564 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
565 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800566 if (virt_ctxt == NULL) {
567 return -ENOMEM;
568 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800569 context = (effect_context_t *)virt_ctxt;
570 context->ops.init = virtualizer_init;
571 context->ops.reset = virtualizer_reset;
572 context->ops.set_parameter = virtualizer_set_parameter;
573 context->ops.get_parameter = virtualizer_get_parameter;
574 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700575 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800576 context->ops.enable = virtualizer_enable;
577 context->ops.disable = virtualizer_disable;
578 context->ops.start = virtualizer_start;
579 context->ops.stop = virtualizer_stop;
580
581 context->desc = &virtualizer_descriptor;
582 virt_ctxt->ctl = NULL;
583 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
584 sizeof(effect_uuid_t)) == 0) ||
585 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
586 sizeof(effect_uuid_t)) == 0) ||
587 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
588 sizeof(effect_uuid_t)) == 0) ||
589 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
590 sizeof(effect_uuid_t)) == 0)) {
591 reverb_context_t *reverb_ctxt = (reverb_context_t *)
592 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800593 if (reverb_ctxt == NULL) {
594 return -ENOMEM;
595 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800596 context = (effect_context_t *)reverb_ctxt;
597 context->ops.init = reverb_init;
598 context->ops.reset = reverb_reset;
599 context->ops.set_parameter = reverb_set_parameter;
600 context->ops.get_parameter = reverb_get_parameter;
601 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700602 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800603 context->ops.enable = reverb_enable;
604 context->ops.disable = reverb_disable;
605 context->ops.start = reverb_start;
606 context->ops.stop = reverb_stop;
607
608 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
609 sizeof(effect_uuid_t)) == 0) {
610 context->desc = &aux_env_reverb_descriptor;
611 reverb_auxiliary_init(reverb_ctxt);
612 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
613 sizeof(effect_uuid_t)) == 0) {
614 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700615 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800616 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
617 sizeof(effect_uuid_t)) == 0) {
618 context->desc = &aux_preset_reverb_descriptor;
619 reverb_auxiliary_init(reverb_ctxt);
620 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
621 sizeof(effect_uuid_t)) == 0) {
622 context->desc = &ins_preset_reverb_descriptor;
623 reverb_preset_init(reverb_ctxt);
624 }
625 reverb_ctxt->ctl = NULL;
Mingming Yin497419f2015-07-01 16:57:32 -0700626#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700627 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
628 sizeof(effect_uuid_t)) == 0) {
629 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
630 calloc(1, sizeof(hw_accelerator_context_t));
631 if (hw_acc_ctxt == NULL) {
632 ALOGE("h/w acc context allocation failed");
633 return -ENOMEM;
634 }
635 context = (effect_context_t *)hw_acc_ctxt;
636 context->ops.init = hw_accelerator_init;
637 context->ops.reset = hw_accelerator_reset;
638 context->ops.set_parameter = hw_accelerator_set_parameter;
639 context->ops.get_parameter = hw_accelerator_get_parameter;
640 context->ops.set_device = hw_accelerator_set_device;
641 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
642 context->ops.enable = hw_accelerator_enable;
643 context->ops.disable = hw_accelerator_disable;
644 context->ops.release = hw_accelerator_release;
645 context->ops.process = hw_accelerator_process;
646
647 context->desc = &hw_accelerator_descriptor;
Mingming Yin497419f2015-07-01 16:57:32 -0700648#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800649 } else {
650 return -EINVAL;
651 }
652
653 context->itfe = &effect_interface;
654 context->state = EFFECT_STATE_UNINITIALIZED;
655 context->out_handle = (audio_io_handle_t)ioId;
656
657 ret = context->ops.init(context);
658 if (ret < 0) {
659 ALOGW("%s init failed", __func__);
660 free(context);
661 return ret;
662 }
663
664 context->state = EFFECT_STATE_INITIALIZED;
665
666 pthread_mutex_lock(&lock);
667 list_add_tail(&created_effects_list, &context->effects_list_node);
668 output_context_t *out_ctxt = get_output(ioId);
669 if (out_ctxt != NULL)
670 add_effect_to_output(out_ctxt, context);
671 pthread_mutex_unlock(&lock);
672
673 *pHandle = (effect_handle_t)context;
674
675 ALOGV("%s created context %p", __func__, context);
676
677 return 0;
678
679}
680
681int effect_lib_release(effect_handle_t handle)
682{
683 effect_context_t *context = (effect_context_t *)handle;
684 int status;
685
686 if (lib_init() != 0)
687 return init_status;
688
689 ALOGV("%s context %p", __func__, handle);
690 pthread_mutex_lock(&lock);
691 status = -EINVAL;
692 if (effect_exists(context)) {
693 output_context_t *out_ctxt = get_output(context->out_handle);
694 if (out_ctxt != NULL)
695 remove_effect_from_output(out_ctxt, context);
696 list_remove(&context->effects_list_node);
697 if (context->ops.release)
698 context->ops.release(context);
699 free(context);
700 status = 0;
701 }
702 pthread_mutex_unlock(&lock);
703
704 return status;
705}
706
707int effect_lib_get_descriptor(const effect_uuid_t *uuid,
708 effect_descriptor_t *descriptor)
709{
710 int i;
711
712 if (lib_init() != 0)
713 return init_status;
714
715 if (descriptor == NULL || uuid == NULL) {
716 ALOGV("%s called with NULL pointer", __func__);
717 return -EINVAL;
718 }
719
720 for (i = 0; descriptors[i] != NULL; i++) {
721 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
722 *descriptor = *descriptors[i];
723 return 0;
724 }
725 }
726
727 return -EINVAL;
728}
729
730
731/*
732 * Effect Control Interface Implementation
733 */
734
735/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700736/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800737int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800738 audio_buffer_t *inBuffer __unused,
739 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800740{
741 effect_context_t * context = (effect_context_t *)self;
742 int status = 0;
743
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700744 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800745
746 pthread_mutex_lock(&lock);
747 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800748 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800749 goto exit;
750 }
751
752 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800753 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800754 goto exit;
755 }
756
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700757 if (context->ops.process)
758 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800759exit:
760 pthread_mutex_unlock(&lock);
761 return status;
762}
763
764int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
765 void *pCmdData, uint32_t *replySize, void *pReplyData)
766{
767
768 effect_context_t * context = (effect_context_t *)self;
769 int retsize;
770 int status = 0;
771
772 pthread_mutex_lock(&lock);
773
774 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800775 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800776 goto exit;
777 }
778
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530779 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800780 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800781 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800782 goto exit;
783 }
784
785 switch (cmdCode) {
786 case EFFECT_CMD_INIT:
787 if (pReplyData == NULL || *replySize != sizeof(int)) {
788 status = -EINVAL;
789 goto exit;
790 }
791 if (context->ops.init)
792 *(int *) pReplyData = context->ops.init(context);
793 else
794 *(int *) pReplyData = 0;
795 break;
796 case EFFECT_CMD_SET_CONFIG:
797 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
798 || pReplyData == NULL || *replySize != sizeof(int)) {
799 status = -EINVAL;
800 goto exit;
801 }
802 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
803 break;
804 case EFFECT_CMD_GET_CONFIG:
805 if (pReplyData == NULL ||
806 *replySize != sizeof(effect_config_t)) {
807 status = -EINVAL;
808 goto exit;
809 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700810 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800811 status = -EINVAL;
812 goto exit;
813 }
814
815 get_config(context, (effect_config_t *)pReplyData);
816 break;
817 case EFFECT_CMD_RESET:
818 if (context->ops.reset)
819 context->ops.reset(context);
820 break;
821 case EFFECT_CMD_ENABLE:
822 if (pReplyData == NULL || *replySize != sizeof(int)) {
823 status = -EINVAL;
824 goto exit;
825 }
826 if (context->state != EFFECT_STATE_INITIALIZED) {
827 status = -ENOSYS;
828 goto exit;
829 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530830 handle_asphere_on_effect_enabled(true, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800831 context->state = EFFECT_STATE_ACTIVE;
832 if (context->ops.enable)
833 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800834 *(int *)pReplyData = 0;
835 break;
836 case EFFECT_CMD_DISABLE:
837 if (pReplyData == NULL || *replySize != sizeof(int)) {
838 status = -EINVAL;
839 goto exit;
840 }
841 if (context->state != EFFECT_STATE_ACTIVE) {
842 status = -ENOSYS;
843 goto exit;
844 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530845 handle_asphere_on_effect_enabled(false, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800846 context->state = EFFECT_STATE_INITIALIZED;
847 if (context->ops.disable)
848 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800849 *(int *)pReplyData = 0;
850 break;
851 case EFFECT_CMD_GET_PARAM: {
852 if (pCmdData == NULL ||
853 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
854 pReplyData == NULL ||
Andy Hungeae4d562016-04-28 13:43:44 -0700855 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
856 // constrain memcpy below
857 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800858 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530859 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800860 cmdSize, *replySize);
861 goto exit;
862 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700863 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800864 status = -EINVAL;
865 goto exit;
866 }
867 effect_param_t *q = (effect_param_t *)pCmdData;
868 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
869 effect_param_t *p = (effect_param_t *)pReplyData;
870 if (context->ops.get_parameter)
871 context->ops.get_parameter(context, p, replySize);
872 } break;
873 case EFFECT_CMD_SET_PARAM: {
874 if (pCmdData == NULL ||
875 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
876 sizeof(uint16_t)) ||
877 pReplyData == NULL || *replySize != sizeof(int32_t)) {
878 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530879 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800880 cmdSize, *replySize);
881 goto exit;
882 }
883 *(int32_t *)pReplyData = 0;
884 effect_param_t *p = (effect_param_t *)pCmdData;
885 if (context->ops.set_parameter)
886 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
887 *replySize);
888
889 } break;
890 case EFFECT_CMD_SET_DEVICE: {
891 uint32_t device;
892 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
893 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
894 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530895 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800896 goto exit;
897 }
898 device = *(uint32_t *)pCmdData;
899 if (context->ops.set_device)
900 context->ops.set_device(context, device);
901 } break;
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +0800902 case EFFECT_CMD_SET_VOLUME: {
903 // if pReplyData is NULL, VOL_CTRL is delegated to another effect
904 if (pReplyData == NULL) {
905 break;
906 }
907 if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
908 replySize == NULL || *replySize < 2*sizeof(int32_t)) {
909 return -EINVAL;
910 }
911 memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
912 } break;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800913 case EFFECT_CMD_SET_AUDIO_MODE:
914 break;
915
916 case EFFECT_CMD_OFFLOAD: {
917 output_context_t *out_ctxt;
918
919 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
920 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530921 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800922 status = -EINVAL;
923 break;
924 }
925
926 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
927
928 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
929 offload_param->isOffload, offload_param->ioHandle);
930
931 *(int *)pReplyData = 0;
932
933 context->offload_enabled = offload_param->isOffload;
934 if (context->out_handle == offload_param->ioHandle)
935 break;
936
937 out_ctxt = get_output(context->out_handle);
938 if (out_ctxt != NULL)
939 remove_effect_from_output(out_ctxt, context);
940
941 context->out_handle = offload_param->ioHandle;
942 out_ctxt = get_output(context->out_handle);
943 if (out_ctxt != NULL)
944 add_effect_to_output(out_ctxt, context);
945
946 } break;
Mingming Yin497419f2015-07-01 16:57:32 -0700947#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700948 case EFFECT_CMD_HW_ACC: {
949 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
950 cmdSize, pCmdData, *replySize, pReplyData);
951 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
952 || pReplyData == NULL || *replySize != sizeof(int)) {
953 return -EINVAL;
954 }
955 uint32_t value = *(uint32_t *)pCmdData;
956 if (context->ops.set_hw_acc_mode)
957 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800958
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700959 context->hw_acc_enabled = (value > 0) ? true : false;
960 break;
961 }
Mingming Yin497419f2015-07-01 16:57:32 -0700962#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800963 default:
964 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
965 status = context->ops.command(context, cmdCode, cmdSize,
966 pCmdData, replySize, pReplyData);
967 else {
968 ALOGW("%s invalid command %d", __func__, cmdCode);
969 status = -EINVAL;
970 }
971 break;
972 }
973
974exit:
975 pthread_mutex_unlock(&lock);
976
977 return status;
978}
979
980/* Effect Control Interface Implementation: get_descriptor */
981int effect_get_descriptor(effect_handle_t self,
982 effect_descriptor_t *descriptor)
983{
984 effect_context_t *context = (effect_context_t *)self;
985
986 if (!effect_exists(context) || (descriptor == NULL))
987 return -EINVAL;
988
989 *descriptor = *context->desc;
990
991 return 0;
992}
993
wjiang50b81f42014-08-06 08:03:14 +0800994bool effect_is_active(effect_context_t * ctxt) {
995 return ctxt->state == EFFECT_STATE_ACTIVE;
996}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800997
998/* effect_handle_t interface implementation for offload effects */
999const struct effect_interface_s effect_interface = {
1000 effect_process,
1001 effect_command,
1002 effect_get_descriptor,
1003 NULL,
1004};
1005
1006__attribute__ ((visibility ("default")))
1007audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +08001008 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1009 .version = EFFECT_LIBRARY_API_VERSION,
1010 .name = "Offload Effects Bundle Library",
1011 .implementor = "The Linux Foundation",
1012 .create_effect = effect_lib_create,
1013 .release_effect = effect_lib_release,
1014 .get_descriptor = effect_lib_get_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001015};