blob: a9f95b976f31dd3dc00782e857e647e7c3655cea [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Aalique Grahame22e49102018-12-18 14:23:57 -08002 * Copyright (c) 2013-2017, 2019, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08003 * Not a Contribution.
4 *
Lakshman Chaluvaraju9b508a72022-09-09 10:59:41 +05305 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
6 *
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08007 * Copyright (C) 2013 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080020 *
21 * This file was modified by DTS, Inc. The portions of the
22 * code modified by DTS, Inc are copyrighted and
23 * licensed separately, as follows:
24 *
25 * (C) 2014 DTS, Inc.
26 *
27 * Licensed under the Apache License, Version 2.0 (the "License");
28 * you may not use this file except in compliance with the License.
29 * You may obtain a copy of the License at
30 *
31 * http://www.apache.org/licenses/LICENSE-2.0
32 *
33 * Unless required by applicable law or agreed to in writing, software
34 * distributed under the License is distributed on an "AS IS" BASIS,
35 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36 * See the License for the specific language governing permissions and
37 * limitations under the License.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080038 */
39
40#define LOG_TAG "offload_effect_bundle"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070041//#define LOG_NDEBUG 0
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080042
Mingming Yin497419f2015-07-01 16:57:32 -070043#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080044#include <cutils/list.h>
Weiyin Jiangfd19e982019-07-05 11:20:28 +080045#include <cutils/str_parms.h>
Aalique Grahame22e49102018-12-18 14:23:57 -080046#include <log/log.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080047#include <system/thread_defs.h>
48#include <tinyalsa/asoundlib.h>
49#include <hardware/audio_effect.h>
Vinay Vermaaddfa4a2018-04-29 14:03:38 +053050#include <pthread.h>
51#include <unistd.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080052
53#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070054#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080055#include "equalizer.h"
56#include "bass_boost.h"
57#include "virtualizer.h"
58#include "reverb.h"
59
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080060#ifdef DTS_EAGLE
61#include "effect_util.h"
62#endif
63
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080064enum {
65 EFFECT_STATE_UNINITIALIZED,
66 EFFECT_STATE_INITIALIZED,
67 EFFECT_STATE_ACTIVE,
68};
69
70const effect_descriptor_t *descriptors[] = {
71 &equalizer_descriptor,
72 &bassboost_descriptor,
73 &virtualizer_descriptor,
74 &aux_env_reverb_descriptor,
75 &ins_env_reverb_descriptor,
76 &aux_preset_reverb_descriptor,
77 &ins_preset_reverb_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070078#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070079 &hw_accelerator_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070080#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080081 NULL,
82};
83
84pthread_once_t once = PTHREAD_ONCE_INIT;
85int init_status;
86/*
87 * list of created effects.
88 * Updated by offload_effects_bundle_hal_start_output()
89 * and offload_effects_bundle_hal_stop_output()
90 */
91struct listnode created_effects_list;
92/*
93 * list of active output streams.
94 * Updated by offload_effects_bundle_hal_start_output()
95 * and offload_effects_bundle_hal_stop_output()
96 */
97struct listnode active_outputs_list;
98/*
99 * lock must be held when modifying or accessing
100 * created_effects_list or active_outputs_list
101 */
102pthread_mutex_t lock;
103
104
105/*
106 * Local functions
107 */
108static void init_once() {
109 list_init(&created_effects_list);
110 list_init(&active_outputs_list);
111
112 pthread_mutex_init(&lock, NULL);
113
114 init_status = 0;
115}
116
117int lib_init()
118{
119 pthread_once(&once, init_once);
120 return init_status;
121}
122
123bool effect_exists(effect_context_t *context)
124{
125 struct listnode *node;
126
127 list_for_each(node, &created_effects_list) {
128 effect_context_t *fx_ctxt = node_to_item(node,
129 effect_context_t,
130 effects_list_node);
131 if (fx_ctxt == context) {
132 return true;
133 }
134 }
135 return false;
136}
137
138output_context_t *get_output(audio_io_handle_t output)
139{
140 struct listnode *node;
141
142 list_for_each(node, &active_outputs_list) {
143 output_context_t *out_ctxt = node_to_item(node,
144 output_context_t,
145 outputs_list_node);
146 if (out_ctxt->handle == output)
147 return out_ctxt;
148 }
149 return NULL;
150}
151
152void add_effect_to_output(output_context_t * output, effect_context_t *context)
153{
154 struct listnode *fx_node;
155
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530156 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800157 list_for_each(fx_node, &output->effects_list) {
158 effect_context_t *fx_ctxt = node_to_item(fx_node,
159 effect_context_t,
160 output_node);
161 if (fx_ctxt == context)
162 return;
163 }
164 list_add_tail(&output->effects_list, &context->output_node);
165 if (context->ops.start)
166 context->ops.start(context, output);
167
168}
169
170void remove_effect_from_output(output_context_t * output,
171 effect_context_t *context)
172{
173 struct listnode *fx_node;
174
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530175 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800176 list_for_each(fx_node, &output->effects_list) {
177 effect_context_t *fx_ctxt = node_to_item(fx_node,
178 effect_context_t,
179 output_node);
180 if (fx_ctxt == context) {
181 if (context->ops.stop)
182 context->ops.stop(context, output);
183 list_remove(&context->output_node);
184 return;
185 }
186 }
187}
188
189bool effects_enabled()
190{
191 struct listnode *out_node;
192
193 list_for_each(out_node, &active_outputs_list) {
194 struct listnode *fx_node;
195 output_context_t *out_ctxt = node_to_item(out_node,
196 output_context_t,
197 outputs_list_node);
198
199 list_for_each(fx_node, &out_ctxt->effects_list) {
200 effect_context_t *fx_ctxt = node_to_item(fx_node,
201 effect_context_t,
202 output_node);
203 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
204 (fx_ctxt->ops.process != NULL))
205 return true;
206 }
207 }
208 return false;
209}
210
211
212/*
213 * Interface from audio HAL
214 */
215__attribute__ ((visibility ("default")))
Ashish Jain5106d362016-05-11 19:23:33 +0530216int 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 -0800217{
218 int ret = 0;
219 struct listnode *node;
220 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800221 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800222
223 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
224
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800225#ifdef DTS_EAGLE
226 create_effect_state_node(pcm_id);
227#endif
228
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800229 if (lib_init() != 0)
230 return init_status;
231
232 pthread_mutex_lock(&lock);
233 if (get_output(output) != NULL) {
234 ALOGW("%s output already started", __func__);
235 ret = -ENOSYS;
236 goto exit;
237 }
238
wjiang50b81f42014-08-06 08:03:14 +0800239 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800240 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800241 if (!out_ctxt) {
242 ALOGE("%s fail to allocate for output context", __func__);
243 ret = -ENOMEM;
244 goto exit;
245 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800246 out_ctxt->handle = output;
247 out_ctxt->pcm_device_id = pcm_id;
248
249 /* populate the mixer control to send offload parameters */
250 snprintf(mixer_string, sizeof(mixer_string),
251 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
Ashish Jain5106d362016-05-11 19:23:33 +0530252
253 if (!mixer) {
254 ALOGE("Invalid mixer");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800255 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700256 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800257 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800258 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800259 goto exit;
260 } else {
Ashish Jain5106d362016-05-11 19:23:33 +0530261 out_ctxt->mixer = mixer;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800262 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
263 if (!out_ctxt->ctl) {
264 ALOGE("mixer_get_ctl_by_name failed");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800265 out_ctxt->mixer = NULL;
266 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800267 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800268 goto exit;
269 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700270 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800271 }
272
273 list_init(&out_ctxt->effects_list);
274
275 list_for_each(node, &created_effects_list) {
276 effect_context_t *fx_ctxt = node_to_item(node,
277 effect_context_t,
278 effects_list_node);
279 if (fx_ctxt->out_handle == output) {
280 if (fx_ctxt->ops.start)
281 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
282 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
283 }
284 }
285 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
286exit:
287 pthread_mutex_unlock(&lock);
288 return ret;
289}
290
291__attribute__ ((visibility ("default")))
292int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
293{
Preetam Singh Ranawat53194302016-03-15 16:37:42 +0530294 int ret = -1;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800295 struct listnode *fx_node;
296 output_context_t *out_ctxt;
297
298 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
299
300 if (lib_init() != 0)
301 return init_status;
302
303 pthread_mutex_lock(&lock);
304
305 out_ctxt = get_output(output);
306 if (out_ctxt == NULL) {
307 ALOGW("%s output not started", __func__);
308 ret = -ENOSYS;
309 goto exit;
310 }
311
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800312 list_for_each(fx_node, &out_ctxt->effects_list) {
313 effect_context_t *fx_ctxt = node_to_item(fx_node,
314 effect_context_t,
315 output_node);
316 if (fx_ctxt->ops.stop)
317 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
318 }
319
320 list_remove(&out_ctxt->outputs_list_node);
321
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800322#ifdef DTS_EAGLE
323 remove_effect_state_node(pcm_id);
324#endif
325
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800326 free(out_ctxt);
327
328exit:
329 pthread_mutex_unlock(&lock);
330 return ret;
331}
332
Alexy Josephd464f3b2014-11-18 16:14:41 -0800333__attribute__ ((visibility ("default")))
334int offload_effects_bundle_set_hpx_state(bool hpx_state)
335{
336 int ret = 0;
337 struct listnode *node;
338
339 ALOGV("%s hpx state: %d", __func__, hpx_state);
340
341 if (lib_init() != 0)
342 return init_status;
343
344 pthread_mutex_lock(&lock);
345
346 if (hpx_state) {
347 /* set ramp down */
348 list_for_each(node, &active_outputs_list) {
349 output_context_t *out_ctxt = node_to_item(node,
350 output_context_t,
351 outputs_list_node);
352 struct soft_volume_params vol;
353 vol.master_gain = 0x0;
354 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
355 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
356 }
357 /* wait for ramp down duration - 30msec */
358 usleep(30000);
359 /* disable effects modules */
360 list_for_each(node, &active_outputs_list) {
361 struct listnode *fx_node;
362 output_context_t *out_ctxt = node_to_item(node,
363 output_context_t,
364 outputs_list_node);
365 list_for_each(fx_node, &out_ctxt->effects_list) {
366 effect_context_t *fx_ctxt = node_to_item(fx_node,
367 effect_context_t,
368 output_node);
369 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
370 (fx_ctxt->ops.stop != NULL))
371 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
372 }
373 out_ctxt->ctl = NULL;
374 }
375 /* set the channel mixer */
376 list_for_each(node, &active_outputs_list) {
377 /* send command to set channel mixer */
378 }
379 /* enable hpx modules */
380 list_for_each(node, &active_outputs_list) {
381 output_context_t *out_ctxt = node_to_item(node,
382 output_context_t,
383 outputs_list_node);
384 offload_hpx_send_params(out_ctxt->ref_ctl,
385 OFFLOAD_SEND_HPX_STATE_ON);
386 }
387 /* wait for transition state - 50msec */
388 usleep(50000);
389 /* set ramp up */
390 list_for_each(node, &active_outputs_list) {
391 output_context_t *out_ctxt = node_to_item(node,
392 output_context_t,
393 outputs_list_node);
394 struct soft_volume_params vol;
395 vol.master_gain = 0x2000;
396 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
397 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
398 }
399 } else {
400 /* set ramp down */
401 list_for_each(node, &active_outputs_list) {
402 output_context_t *out_ctxt = node_to_item(node,
403 output_context_t,
404 outputs_list_node);
405 struct soft_volume_params vol;
406 vol.master_gain = 0x0;
407 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
408 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
409 }
410 /* wait for ramp down duration - 30msec */
411 usleep(30000);
412 /* disable effects modules */
413 list_for_each(node, &active_outputs_list) {
414 output_context_t *out_ctxt = node_to_item(node,
415 output_context_t,
416 outputs_list_node);
417 offload_hpx_send_params(out_ctxt->ref_ctl,
418 OFFLOAD_SEND_HPX_STATE_OFF);
419 }
420 /* set the channel mixer */
421 list_for_each(node, &active_outputs_list) {
422 /* send command to set channel mixer */
423 }
424 /* enable effects modules */
425 list_for_each(node, &active_outputs_list) {
426 struct listnode *fx_node;
427 output_context_t *out_ctxt = node_to_item(node,
428 output_context_t,
429 outputs_list_node);
430 out_ctxt->ctl = out_ctxt->ref_ctl;
431 list_for_each(fx_node, &out_ctxt->effects_list) {
432 effect_context_t *fx_ctxt = node_to_item(fx_node,
433 effect_context_t,
434 output_node);
435 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
436 (fx_ctxt->ops.start != NULL))
437 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
438 }
439 }
440 /* wait for transition state - 50msec */
441 usleep(50000);
442 /* set ramp up */
443 list_for_each(node, &active_outputs_list) {
444 output_context_t *out_ctxt = node_to_item(node,
445 output_context_t,
446 outputs_list_node);
447 struct soft_volume_params vol;
448 vol.master_gain = 0x2000;
449 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
450 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
451 }
452 }
453
Alexy Josephd464f3b2014-11-18 16:14:41 -0800454 pthread_mutex_unlock(&lock);
455 return ret;
456}
457
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800458/*
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530459 * Effect Bundle Set and get param operations.
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530460 */
461__attribute__ ((visibility ("default")))
Weiyin Jiangfd19e982019-07-05 11:20:28 +0800462void offload_effects_bundle_get_parameters(struct str_parms *query __unused,
463 struct str_parms *reply __unused)
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530464{
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530465}
466
467__attribute__ ((visibility ("default")))
Weiyin Jiangfd19e982019-07-05 11:20:28 +0800468void offload_effects_bundle_set_parameters(struct str_parms *parms __unused)
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530469{
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530470}
471
472/*
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800473 * Effect operations
474 */
475int set_config(effect_context_t *context, effect_config_t *config)
476{
477 context->config = *config;
478
479 if (context->ops.reset)
480 context->ops.reset(context);
481
482 return 0;
483}
484
485void get_config(effect_context_t *context, effect_config_t *config)
486{
487 *config = context->config;
488}
489
490
491/*
492 * Effect Library Interface Implementation
493 */
494int effect_lib_create(const effect_uuid_t *uuid,
495 int32_t sessionId,
496 int32_t ioId,
497 effect_handle_t *pHandle) {
498 int ret;
499 int i;
500
501 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
502 if (lib_init() != 0)
503 return init_status;
504
505 if (pHandle == NULL || uuid == NULL)
506 return -EINVAL;
507
508 for (i = 0; descriptors[i] != NULL; i++) {
509 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
510 break;
511 }
512
513 if (descriptors[i] == NULL)
514 return -EINVAL;
515
516 effect_context_t *context;
517 if (memcmp(uuid, &equalizer_descriptor.uuid,
518 sizeof(effect_uuid_t)) == 0) {
519 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
520 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800521 if (eq_ctxt == NULL) {
522 return -ENOMEM;
523 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800524 context = (effect_context_t *)eq_ctxt;
525 context->ops.init = equalizer_init;
526 context->ops.reset = equalizer_reset;
527 context->ops.set_parameter = equalizer_set_parameter;
528 context->ops.get_parameter = equalizer_get_parameter;
529 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700530 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800531 context->ops.enable = equalizer_enable;
532 context->ops.disable = equalizer_disable;
533 context->ops.start = equalizer_start;
534 context->ops.stop = equalizer_stop;
535
536 context->desc = &equalizer_descriptor;
537 eq_ctxt->ctl = NULL;
538 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
539 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800540 bass_context_t *bass_ctxt = (bass_context_t *)
541 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800542 if (bass_ctxt == NULL) {
543 return -ENOMEM;
544 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800545 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800546 context->ops.init = bass_init;
547 context->ops.reset = bass_reset;
548 context->ops.set_parameter = bass_set_parameter;
549 context->ops.get_parameter = bass_get_parameter;
550 context->ops.set_device = bass_set_device;
551 context->ops.set_hw_acc_mode = bass_set_mode;
552 context->ops.enable = bass_enable;
553 context->ops.disable = bass_disable;
554 context->ops.start = bass_start;
555 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800556
557 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800558 bass_ctxt->bassboost_ctxt.ctl = NULL;
559 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800560 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
561 sizeof(effect_uuid_t)) == 0) {
562 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
563 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800564 if (virt_ctxt == NULL) {
565 return -ENOMEM;
566 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800567 context = (effect_context_t *)virt_ctxt;
568 context->ops.init = virtualizer_init;
569 context->ops.reset = virtualizer_reset;
570 context->ops.set_parameter = virtualizer_set_parameter;
571 context->ops.get_parameter = virtualizer_get_parameter;
572 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700573 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800574 context->ops.enable = virtualizer_enable;
575 context->ops.disable = virtualizer_disable;
576 context->ops.start = virtualizer_start;
577 context->ops.stop = virtualizer_stop;
578
579 context->desc = &virtualizer_descriptor;
580 virt_ctxt->ctl = NULL;
581 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
582 sizeof(effect_uuid_t)) == 0) ||
583 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
584 sizeof(effect_uuid_t)) == 0) ||
585 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
586 sizeof(effect_uuid_t)) == 0) ||
587 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
588 sizeof(effect_uuid_t)) == 0)) {
589 reverb_context_t *reverb_ctxt = (reverb_context_t *)
590 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800591 if (reverb_ctxt == NULL) {
592 return -ENOMEM;
593 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800594 context = (effect_context_t *)reverb_ctxt;
595 context->ops.init = reverb_init;
596 context->ops.reset = reverb_reset;
597 context->ops.set_parameter = reverb_set_parameter;
598 context->ops.get_parameter = reverb_get_parameter;
599 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700600 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800601 context->ops.enable = reverb_enable;
602 context->ops.disable = reverb_disable;
603 context->ops.start = reverb_start;
604 context->ops.stop = reverb_stop;
605
606 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
607 sizeof(effect_uuid_t)) == 0) {
608 context->desc = &aux_env_reverb_descriptor;
609 reverb_auxiliary_init(reverb_ctxt);
610 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
611 sizeof(effect_uuid_t)) == 0) {
612 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700613 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800614 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
615 sizeof(effect_uuid_t)) == 0) {
616 context->desc = &aux_preset_reverb_descriptor;
617 reverb_auxiliary_init(reverb_ctxt);
618 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
619 sizeof(effect_uuid_t)) == 0) {
620 context->desc = &ins_preset_reverb_descriptor;
621 reverb_preset_init(reverb_ctxt);
622 }
623 reverb_ctxt->ctl = NULL;
Mingming Yin497419f2015-07-01 16:57:32 -0700624#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700625 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
626 sizeof(effect_uuid_t)) == 0) {
627 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
628 calloc(1, sizeof(hw_accelerator_context_t));
629 if (hw_acc_ctxt == NULL) {
630 ALOGE("h/w acc context allocation failed");
631 return -ENOMEM;
632 }
633 context = (effect_context_t *)hw_acc_ctxt;
634 context->ops.init = hw_accelerator_init;
635 context->ops.reset = hw_accelerator_reset;
636 context->ops.set_parameter = hw_accelerator_set_parameter;
637 context->ops.get_parameter = hw_accelerator_get_parameter;
638 context->ops.set_device = hw_accelerator_set_device;
639 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
640 context->ops.enable = hw_accelerator_enable;
641 context->ops.disable = hw_accelerator_disable;
642 context->ops.release = hw_accelerator_release;
643 context->ops.process = hw_accelerator_process;
644
645 context->desc = &hw_accelerator_descriptor;
Mingming Yin497419f2015-07-01 16:57:32 -0700646#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800647 } else {
648 return -EINVAL;
649 }
650
651 context->itfe = &effect_interface;
652 context->state = EFFECT_STATE_UNINITIALIZED;
653 context->out_handle = (audio_io_handle_t)ioId;
654
655 ret = context->ops.init(context);
656 if (ret < 0) {
657 ALOGW("%s init failed", __func__);
658 free(context);
659 return ret;
660 }
661
662 context->state = EFFECT_STATE_INITIALIZED;
663
664 pthread_mutex_lock(&lock);
665 list_add_tail(&created_effects_list, &context->effects_list_node);
666 output_context_t *out_ctxt = get_output(ioId);
667 if (out_ctxt != NULL)
668 add_effect_to_output(out_ctxt, context);
669 pthread_mutex_unlock(&lock);
670
671 *pHandle = (effect_handle_t)context;
672
673 ALOGV("%s created context %p", __func__, context);
674
675 return 0;
676
677}
678
679int effect_lib_release(effect_handle_t handle)
680{
681 effect_context_t *context = (effect_context_t *)handle;
682 int status;
683
684 if (lib_init() != 0)
685 return init_status;
686
687 ALOGV("%s context %p", __func__, handle);
688 pthread_mutex_lock(&lock);
689 status = -EINVAL;
690 if (effect_exists(context)) {
691 output_context_t *out_ctxt = get_output(context->out_handle);
692 if (out_ctxt != NULL)
693 remove_effect_from_output(out_ctxt, context);
694 list_remove(&context->effects_list_node);
695 if (context->ops.release)
696 context->ops.release(context);
697 free(context);
698 status = 0;
699 }
700 pthread_mutex_unlock(&lock);
701
702 return status;
703}
704
705int effect_lib_get_descriptor(const effect_uuid_t *uuid,
706 effect_descriptor_t *descriptor)
707{
708 int i;
709
710 if (lib_init() != 0)
711 return init_status;
712
713 if (descriptor == NULL || uuid == NULL) {
714 ALOGV("%s called with NULL pointer", __func__);
715 return -EINVAL;
716 }
717
718 for (i = 0; descriptors[i] != NULL; i++) {
719 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
720 *descriptor = *descriptors[i];
721 return 0;
722 }
723 }
724
725 return -EINVAL;
726}
727
728
729/*
730 * Effect Control Interface Implementation
731 */
732
733/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700734/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800735int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800736 audio_buffer_t *inBuffer __unused,
737 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800738{
739 effect_context_t * context = (effect_context_t *)self;
740 int status = 0;
741
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700742 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800743
744 pthread_mutex_lock(&lock);
745 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800746 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800747 goto exit;
748 }
749
750 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800751 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800752 goto exit;
753 }
754
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700755 if (context->ops.process)
756 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800757exit:
758 pthread_mutex_unlock(&lock);
759 return status;
760}
761
762int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
763 void *pCmdData, uint32_t *replySize, void *pReplyData)
764{
765
766 effect_context_t * context = (effect_context_t *)self;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800767 int status = 0;
768
769 pthread_mutex_lock(&lock);
770
771 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800772 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800773 goto exit;
774 }
775
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530776 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800777 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800778 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800779 goto exit;
780 }
781
782 switch (cmdCode) {
783 case EFFECT_CMD_INIT:
784 if (pReplyData == NULL || *replySize != sizeof(int)) {
785 status = -EINVAL;
786 goto exit;
787 }
788 if (context->ops.init)
789 *(int *) pReplyData = context->ops.init(context);
790 else
791 *(int *) pReplyData = 0;
792 break;
793 case EFFECT_CMD_SET_CONFIG:
794 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
795 || pReplyData == NULL || *replySize != sizeof(int)) {
796 status = -EINVAL;
797 goto exit;
798 }
799 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
800 break;
801 case EFFECT_CMD_GET_CONFIG:
802 if (pReplyData == NULL ||
803 *replySize != sizeof(effect_config_t)) {
804 status = -EINVAL;
805 goto exit;
806 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700807 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800808 status = -EINVAL;
809 goto exit;
810 }
811
812 get_config(context, (effect_config_t *)pReplyData);
813 break;
814 case EFFECT_CMD_RESET:
815 if (context->ops.reset)
816 context->ops.reset(context);
817 break;
818 case EFFECT_CMD_ENABLE:
819 if (pReplyData == NULL || *replySize != sizeof(int)) {
820 status = -EINVAL;
821 goto exit;
822 }
823 if (context->state != EFFECT_STATE_INITIALIZED) {
824 status = -ENOSYS;
825 goto exit;
826 }
827 context->state = EFFECT_STATE_ACTIVE;
828 if (context->ops.enable)
829 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800830 *(int *)pReplyData = 0;
831 break;
832 case EFFECT_CMD_DISABLE:
833 if (pReplyData == NULL || *replySize != sizeof(int)) {
834 status = -EINVAL;
835 goto exit;
836 }
837 if (context->state != EFFECT_STATE_ACTIVE) {
838 status = -ENOSYS;
839 goto exit;
840 }
841 context->state = EFFECT_STATE_INITIALIZED;
842 if (context->ops.disable)
843 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800844 *(int *)pReplyData = 0;
845 break;
846 case EFFECT_CMD_GET_PARAM: {
847 if (pCmdData == NULL ||
848 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
849 pReplyData == NULL ||
Andy Hungeae4d562016-04-28 13:43:44 -0700850 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
851 // constrain memcpy below
Lakshman Chaluvaraju9b508a72022-09-09 10:59:41 +0530852 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t) ||
853 ((effect_param_t *)pCmdData)->psize > cmdSize - sizeof(effect_param_t)) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800854 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530855 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800856 cmdSize, *replySize);
857 goto exit;
858 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700859 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800860 status = -EINVAL;
861 goto exit;
862 }
863 effect_param_t *q = (effect_param_t *)pCmdData;
864 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
865 effect_param_t *p = (effect_param_t *)pReplyData;
866 if (context->ops.get_parameter)
867 context->ops.get_parameter(context, p, replySize);
868 } break;
869 case EFFECT_CMD_SET_PARAM: {
870 if (pCmdData == NULL ||
871 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
872 sizeof(uint16_t)) ||
873 pReplyData == NULL || *replySize != sizeof(int32_t)) {
874 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530875 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800876 cmdSize, *replySize);
877 goto exit;
878 }
879 *(int32_t *)pReplyData = 0;
880 effect_param_t *p = (effect_param_t *)pCmdData;
881 if (context->ops.set_parameter)
882 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
883 *replySize);
884
885 } break;
886 case EFFECT_CMD_SET_DEVICE: {
887 uint32_t device;
888 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
889 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
890 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530891 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800892 goto exit;
893 }
894 device = *(uint32_t *)pCmdData;
895 if (context->ops.set_device)
896 context->ops.set_device(context, device);
897 } break;
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +0800898 case EFFECT_CMD_SET_VOLUME: {
899 // if pReplyData is NULL, VOL_CTRL is delegated to another effect
900 if (pReplyData == NULL) {
901 break;
902 }
903 if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
904 replySize == NULL || *replySize < 2*sizeof(int32_t)) {
905 return -EINVAL;
906 }
907 memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
908 } break;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800909 case EFFECT_CMD_SET_AUDIO_MODE:
910 break;
911
912 case EFFECT_CMD_OFFLOAD: {
913 output_context_t *out_ctxt;
914
915 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
916 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530917 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800918 status = -EINVAL;
919 break;
920 }
921
922 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
923
924 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
925 offload_param->isOffload, offload_param->ioHandle);
926
927 *(int *)pReplyData = 0;
928
929 context->offload_enabled = offload_param->isOffload;
930 if (context->out_handle == offload_param->ioHandle)
931 break;
932
933 out_ctxt = get_output(context->out_handle);
934 if (out_ctxt != NULL)
935 remove_effect_from_output(out_ctxt, context);
936
937 context->out_handle = offload_param->ioHandle;
938 out_ctxt = get_output(context->out_handle);
939 if (out_ctxt != NULL)
940 add_effect_to_output(out_ctxt, context);
941
942 } break;
Mingming Yin497419f2015-07-01 16:57:32 -0700943#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700944 case EFFECT_CMD_HW_ACC: {
945 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
946 cmdSize, pCmdData, *replySize, pReplyData);
947 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
948 || pReplyData == NULL || *replySize != sizeof(int)) {
949 return -EINVAL;
950 }
951 uint32_t value = *(uint32_t *)pCmdData;
952 if (context->ops.set_hw_acc_mode)
953 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800954
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700955 context->hw_acc_enabled = (value > 0) ? true : false;
956 break;
957 }
Mingming Yin497419f2015-07-01 16:57:32 -0700958#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800959 default:
960 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
961 status = context->ops.command(context, cmdCode, cmdSize,
962 pCmdData, replySize, pReplyData);
963 else {
964 ALOGW("%s invalid command %d", __func__, cmdCode);
965 status = -EINVAL;
966 }
967 break;
968 }
969
970exit:
971 pthread_mutex_unlock(&lock);
972
973 return status;
974}
975
976/* Effect Control Interface Implementation: get_descriptor */
977int effect_get_descriptor(effect_handle_t self,
978 effect_descriptor_t *descriptor)
979{
980 effect_context_t *context = (effect_context_t *)self;
981
982 if (!effect_exists(context) || (descriptor == NULL))
983 return -EINVAL;
984
985 *descriptor = *context->desc;
986
987 return 0;
988}
989
wjiang50b81f42014-08-06 08:03:14 +0800990bool effect_is_active(effect_context_t * ctxt) {
991 return ctxt->state == EFFECT_STATE_ACTIVE;
992}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800993
994/* effect_handle_t interface implementation for offload effects */
995const struct effect_interface_s effect_interface = {
996 effect_process,
997 effect_command,
998 effect_get_descriptor,
999 NULL,
1000};
1001
1002__attribute__ ((visibility ("default")))
1003audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +08001004 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1005 .version = EFFECT_LIBRARY_API_VERSION,
1006 .name = "Offload Effects Bundle Library",
1007 .implementor = "The Linux Foundation",
1008 .create_effect = effect_lib_create,
1009 .release_effect = effect_lib_release,
1010 .get_descriptor = effect_lib_get_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001011};