blob: 1e6b91dec8b04591243f025f036caf7efa8d8228 [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 *
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>
Aalique Grahame22e49102018-12-18 14:23:57 -080043#include <log/log.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080044#include <system/thread_defs.h>
45#include <tinyalsa/asoundlib.h>
46#include <hardware/audio_effect.h>
Vinay Vermaaddfa4a2018-04-29 14:03:38 +053047#include <pthread.h>
48#include <unistd.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080049
50#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070051#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080052#include "equalizer.h"
53#include "bass_boost.h"
54#include "virtualizer.h"
55#include "reverb.h"
Dhananjay Kumar1c978df2015-09-04 13:44:59 +053056#include "asphere.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080057
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080058#ifdef DTS_EAGLE
59#include "effect_util.h"
60#endif
61
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080062enum {
63 EFFECT_STATE_UNINITIALIZED,
64 EFFECT_STATE_INITIALIZED,
65 EFFECT_STATE_ACTIVE,
66};
67
68const effect_descriptor_t *descriptors[] = {
69 &equalizer_descriptor,
70 &bassboost_descriptor,
71 &virtualizer_descriptor,
72 &aux_env_reverb_descriptor,
73 &ins_env_reverb_descriptor,
74 &aux_preset_reverb_descriptor,
75 &ins_preset_reverb_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070076#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070077 &hw_accelerator_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070078#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080079 NULL,
80};
81
82pthread_once_t once = PTHREAD_ONCE_INIT;
83int init_status;
84/*
85 * list of created effects.
86 * Updated by offload_effects_bundle_hal_start_output()
87 * and offload_effects_bundle_hal_stop_output()
88 */
89struct listnode created_effects_list;
90/*
91 * list of active output streams.
92 * Updated by offload_effects_bundle_hal_start_output()
93 * and offload_effects_bundle_hal_stop_output()
94 */
95struct listnode active_outputs_list;
96/*
97 * lock must be held when modifying or accessing
98 * created_effects_list or active_outputs_list
99 */
100pthread_mutex_t lock;
101
102
103/*
104 * Local functions
105 */
106static void init_once() {
107 list_init(&created_effects_list);
108 list_init(&active_outputs_list);
109
110 pthread_mutex_init(&lock, NULL);
111
112 init_status = 0;
113}
114
115int lib_init()
116{
117 pthread_once(&once, init_once);
118 return init_status;
119}
120
121bool effect_exists(effect_context_t *context)
122{
123 struct listnode *node;
124
125 list_for_each(node, &created_effects_list) {
126 effect_context_t *fx_ctxt = node_to_item(node,
127 effect_context_t,
128 effects_list_node);
129 if (fx_ctxt == context) {
130 return true;
131 }
132 }
133 return false;
134}
135
136output_context_t *get_output(audio_io_handle_t output)
137{
138 struct listnode *node;
139
140 list_for_each(node, &active_outputs_list) {
141 output_context_t *out_ctxt = node_to_item(node,
142 output_context_t,
143 outputs_list_node);
144 if (out_ctxt->handle == output)
145 return out_ctxt;
146 }
147 return NULL;
148}
149
150void add_effect_to_output(output_context_t * output, effect_context_t *context)
151{
152 struct listnode *fx_node;
153
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530154 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800155 list_for_each(fx_node, &output->effects_list) {
156 effect_context_t *fx_ctxt = node_to_item(fx_node,
157 effect_context_t,
158 output_node);
159 if (fx_ctxt == context)
160 return;
161 }
162 list_add_tail(&output->effects_list, &context->output_node);
163 if (context->ops.start)
164 context->ops.start(context, output);
165
166}
167
168void remove_effect_from_output(output_context_t * output,
169 effect_context_t *context)
170{
171 struct listnode *fx_node;
172
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530173 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800174 list_for_each(fx_node, &output->effects_list) {
175 effect_context_t *fx_ctxt = node_to_item(fx_node,
176 effect_context_t,
177 output_node);
178 if (fx_ctxt == context) {
179 if (context->ops.stop)
180 context->ops.stop(context, output);
181 list_remove(&context->output_node);
182 return;
183 }
184 }
185}
186
187bool effects_enabled()
188{
189 struct listnode *out_node;
190
191 list_for_each(out_node, &active_outputs_list) {
192 struct listnode *fx_node;
193 output_context_t *out_ctxt = node_to_item(out_node,
194 output_context_t,
195 outputs_list_node);
196
197 list_for_each(fx_node, &out_ctxt->effects_list) {
198 effect_context_t *fx_ctxt = node_to_item(fx_node,
199 effect_context_t,
200 output_node);
201 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
202 (fx_ctxt->ops.process != NULL))
203 return true;
204 }
205 }
206 return false;
207}
208
209
210/*
211 * Interface from audio HAL
212 */
213__attribute__ ((visibility ("default")))
Ashish Jain5106d362016-05-11 19:23:33 +0530214int 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 -0800215{
216 int ret = 0;
217 struct listnode *node;
218 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800219 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800220
221 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
222
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800223#ifdef DTS_EAGLE
224 create_effect_state_node(pcm_id);
225#endif
226
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800227 if (lib_init() != 0)
228 return init_status;
229
230 pthread_mutex_lock(&lock);
231 if (get_output(output) != NULL) {
232 ALOGW("%s output already started", __func__);
233 ret = -ENOSYS;
234 goto exit;
235 }
236
wjiang50b81f42014-08-06 08:03:14 +0800237 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800238 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800239 if (!out_ctxt) {
240 ALOGE("%s fail to allocate for output context", __func__);
241 ret = -ENOMEM;
242 goto exit;
243 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800244 out_ctxt->handle = output;
245 out_ctxt->pcm_device_id = pcm_id;
246
247 /* populate the mixer control to send offload parameters */
248 snprintf(mixer_string, sizeof(mixer_string),
249 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
Ashish Jain5106d362016-05-11 19:23:33 +0530250
251 if (!mixer) {
252 ALOGE("Invalid mixer");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800253 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700254 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800255 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800256 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800257 goto exit;
258 } else {
Ashish Jain5106d362016-05-11 19:23:33 +0530259 out_ctxt->mixer = mixer;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800260 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
261 if (!out_ctxt->ctl) {
262 ALOGE("mixer_get_ctl_by_name failed");
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800263 out_ctxt->mixer = NULL;
264 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800265 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800266 goto exit;
267 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700268 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800269 }
270
271 list_init(&out_ctxt->effects_list);
272
273 list_for_each(node, &created_effects_list) {
274 effect_context_t *fx_ctxt = node_to_item(node,
275 effect_context_t,
276 effects_list_node);
277 if (fx_ctxt->out_handle == output) {
278 if (fx_ctxt->ops.start)
279 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
280 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
281 }
282 }
283 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
284exit:
285 pthread_mutex_unlock(&lock);
286 return ret;
287}
288
289__attribute__ ((visibility ("default")))
290int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
291{
Preetam Singh Ranawat53194302016-03-15 16:37:42 +0530292 int ret = -1;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800293 struct listnode *fx_node;
294 output_context_t *out_ctxt;
295
296 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
297
298 if (lib_init() != 0)
299 return init_status;
300
301 pthread_mutex_lock(&lock);
302
303 out_ctxt = get_output(output);
304 if (out_ctxt == NULL) {
305 ALOGW("%s output not started", __func__);
306 ret = -ENOSYS;
307 goto exit;
308 }
309
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800310 list_for_each(fx_node, &out_ctxt->effects_list) {
311 effect_context_t *fx_ctxt = node_to_item(fx_node,
312 effect_context_t,
313 output_node);
314 if (fx_ctxt->ops.stop)
315 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
316 }
317
318 list_remove(&out_ctxt->outputs_list_node);
319
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800320#ifdef DTS_EAGLE
321 remove_effect_state_node(pcm_id);
322#endif
323
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800324 free(out_ctxt);
325
326exit:
327 pthread_mutex_unlock(&lock);
328 return ret;
329}
330
Alexy Josephd464f3b2014-11-18 16:14:41 -0800331__attribute__ ((visibility ("default")))
332int offload_effects_bundle_set_hpx_state(bool hpx_state)
333{
334 int ret = 0;
335 struct listnode *node;
336
337 ALOGV("%s hpx state: %d", __func__, hpx_state);
338
339 if (lib_init() != 0)
340 return init_status;
341
342 pthread_mutex_lock(&lock);
343
344 if (hpx_state) {
345 /* set ramp down */
346 list_for_each(node, &active_outputs_list) {
347 output_context_t *out_ctxt = node_to_item(node,
348 output_context_t,
349 outputs_list_node);
350 struct soft_volume_params vol;
351 vol.master_gain = 0x0;
352 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
353 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
354 }
355 /* wait for ramp down duration - 30msec */
356 usleep(30000);
357 /* disable effects modules */
358 list_for_each(node, &active_outputs_list) {
359 struct listnode *fx_node;
360 output_context_t *out_ctxt = node_to_item(node,
361 output_context_t,
362 outputs_list_node);
363 list_for_each(fx_node, &out_ctxt->effects_list) {
364 effect_context_t *fx_ctxt = node_to_item(fx_node,
365 effect_context_t,
366 output_node);
367 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
368 (fx_ctxt->ops.stop != NULL))
369 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
370 }
371 out_ctxt->ctl = NULL;
372 }
373 /* set the channel mixer */
374 list_for_each(node, &active_outputs_list) {
375 /* send command to set channel mixer */
376 }
377 /* enable hpx modules */
378 list_for_each(node, &active_outputs_list) {
379 output_context_t *out_ctxt = node_to_item(node,
380 output_context_t,
381 outputs_list_node);
382 offload_hpx_send_params(out_ctxt->ref_ctl,
383 OFFLOAD_SEND_HPX_STATE_ON);
384 }
385 /* wait for transition state - 50msec */
386 usleep(50000);
387 /* set ramp up */
388 list_for_each(node, &active_outputs_list) {
389 output_context_t *out_ctxt = node_to_item(node,
390 output_context_t,
391 outputs_list_node);
392 struct soft_volume_params vol;
393 vol.master_gain = 0x2000;
394 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
395 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
396 }
397 } else {
398 /* set ramp down */
399 list_for_each(node, &active_outputs_list) {
400 output_context_t *out_ctxt = node_to_item(node,
401 output_context_t,
402 outputs_list_node);
403 struct soft_volume_params vol;
404 vol.master_gain = 0x0;
405 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
406 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
407 }
408 /* wait for ramp down duration - 30msec */
409 usleep(30000);
410 /* disable effects modules */
411 list_for_each(node, &active_outputs_list) {
412 output_context_t *out_ctxt = node_to_item(node,
413 output_context_t,
414 outputs_list_node);
415 offload_hpx_send_params(out_ctxt->ref_ctl,
416 OFFLOAD_SEND_HPX_STATE_OFF);
417 }
418 /* set the channel mixer */
419 list_for_each(node, &active_outputs_list) {
420 /* send command to set channel mixer */
421 }
422 /* enable effects modules */
423 list_for_each(node, &active_outputs_list) {
424 struct listnode *fx_node;
425 output_context_t *out_ctxt = node_to_item(node,
426 output_context_t,
427 outputs_list_node);
428 out_ctxt->ctl = out_ctxt->ref_ctl;
429 list_for_each(fx_node, &out_ctxt->effects_list) {
430 effect_context_t *fx_ctxt = node_to_item(fx_node,
431 effect_context_t,
432 output_node);
433 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
434 (fx_ctxt->ops.start != NULL))
435 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
436 }
437 }
438 /* wait for transition state - 50msec */
439 usleep(50000);
440 /* set ramp up */
441 list_for_each(node, &active_outputs_list) {
442 output_context_t *out_ctxt = node_to_item(node,
443 output_context_t,
444 outputs_list_node);
445 struct soft_volume_params vol;
446 vol.master_gain = 0x2000;
447 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
448 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
449 }
450 }
451
Alexy Josephd464f3b2014-11-18 16:14:41 -0800452 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;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800769 int status = 0;
770
771 pthread_mutex_lock(&lock);
772
773 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800774 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800775 goto exit;
776 }
777
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530778 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800779 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800780 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800781 goto exit;
782 }
783
784 switch (cmdCode) {
785 case EFFECT_CMD_INIT:
786 if (pReplyData == NULL || *replySize != sizeof(int)) {
787 status = -EINVAL;
788 goto exit;
789 }
790 if (context->ops.init)
791 *(int *) pReplyData = context->ops.init(context);
792 else
793 *(int *) pReplyData = 0;
794 break;
795 case EFFECT_CMD_SET_CONFIG:
796 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
797 || pReplyData == NULL || *replySize != sizeof(int)) {
798 status = -EINVAL;
799 goto exit;
800 }
801 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
802 break;
803 case EFFECT_CMD_GET_CONFIG:
804 if (pReplyData == NULL ||
805 *replySize != sizeof(effect_config_t)) {
806 status = -EINVAL;
807 goto exit;
808 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700809 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800810 status = -EINVAL;
811 goto exit;
812 }
813
814 get_config(context, (effect_config_t *)pReplyData);
815 break;
816 case EFFECT_CMD_RESET:
817 if (context->ops.reset)
818 context->ops.reset(context);
819 break;
820 case EFFECT_CMD_ENABLE:
821 if (pReplyData == NULL || *replySize != sizeof(int)) {
822 status = -EINVAL;
823 goto exit;
824 }
825 if (context->state != EFFECT_STATE_INITIALIZED) {
826 status = -ENOSYS;
827 goto exit;
828 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530829 handle_asphere_on_effect_enabled(true, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800830 context->state = EFFECT_STATE_ACTIVE;
831 if (context->ops.enable)
832 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800833 *(int *)pReplyData = 0;
834 break;
835 case EFFECT_CMD_DISABLE:
836 if (pReplyData == NULL || *replySize != sizeof(int)) {
837 status = -EINVAL;
838 goto exit;
839 }
840 if (context->state != EFFECT_STATE_ACTIVE) {
841 status = -ENOSYS;
842 goto exit;
843 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530844 handle_asphere_on_effect_enabled(false, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800845 context->state = EFFECT_STATE_INITIALIZED;
846 if (context->ops.disable)
847 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800848 *(int *)pReplyData = 0;
849 break;
850 case EFFECT_CMD_GET_PARAM: {
851 if (pCmdData == NULL ||
852 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
853 pReplyData == NULL ||
Andy Hungeae4d562016-04-28 13:43:44 -0700854 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
855 // constrain memcpy below
856 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800857 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530858 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800859 cmdSize, *replySize);
860 goto exit;
861 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700862 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800863 status = -EINVAL;
864 goto exit;
865 }
866 effect_param_t *q = (effect_param_t *)pCmdData;
867 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
868 effect_param_t *p = (effect_param_t *)pReplyData;
869 if (context->ops.get_parameter)
870 context->ops.get_parameter(context, p, replySize);
871 } break;
872 case EFFECT_CMD_SET_PARAM: {
873 if (pCmdData == NULL ||
874 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
875 sizeof(uint16_t)) ||
876 pReplyData == NULL || *replySize != sizeof(int32_t)) {
877 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530878 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800879 cmdSize, *replySize);
880 goto exit;
881 }
882 *(int32_t *)pReplyData = 0;
883 effect_param_t *p = (effect_param_t *)pCmdData;
884 if (context->ops.set_parameter)
885 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
886 *replySize);
887
888 } break;
889 case EFFECT_CMD_SET_DEVICE: {
890 uint32_t device;
891 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
892 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
893 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530894 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800895 goto exit;
896 }
897 device = *(uint32_t *)pCmdData;
898 if (context->ops.set_device)
899 context->ops.set_device(context, device);
900 } break;
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +0800901 case EFFECT_CMD_SET_VOLUME: {
902 // if pReplyData is NULL, VOL_CTRL is delegated to another effect
903 if (pReplyData == NULL) {
904 break;
905 }
906 if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
907 replySize == NULL || *replySize < 2*sizeof(int32_t)) {
908 return -EINVAL;
909 }
910 memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
911 } break;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800912 case EFFECT_CMD_SET_AUDIO_MODE:
913 break;
914
915 case EFFECT_CMD_OFFLOAD: {
916 output_context_t *out_ctxt;
917
918 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
919 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530920 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800921 status = -EINVAL;
922 break;
923 }
924
925 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
926
927 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
928 offload_param->isOffload, offload_param->ioHandle);
929
930 *(int *)pReplyData = 0;
931
932 context->offload_enabled = offload_param->isOffload;
933 if (context->out_handle == offload_param->ioHandle)
934 break;
935
936 out_ctxt = get_output(context->out_handle);
937 if (out_ctxt != NULL)
938 remove_effect_from_output(out_ctxt, context);
939
940 context->out_handle = offload_param->ioHandle;
941 out_ctxt = get_output(context->out_handle);
942 if (out_ctxt != NULL)
943 add_effect_to_output(out_ctxt, context);
944
945 } break;
Mingming Yin497419f2015-07-01 16:57:32 -0700946#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700947 case EFFECT_CMD_HW_ACC: {
948 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
949 cmdSize, pCmdData, *replySize, pReplyData);
950 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
951 || pReplyData == NULL || *replySize != sizeof(int)) {
952 return -EINVAL;
953 }
954 uint32_t value = *(uint32_t *)pCmdData;
955 if (context->ops.set_hw_acc_mode)
956 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800957
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700958 context->hw_acc_enabled = (value > 0) ? true : false;
959 break;
960 }
Mingming Yin497419f2015-07-01 16:57:32 -0700961#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800962 default:
963 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
964 status = context->ops.command(context, cmdCode, cmdSize,
965 pCmdData, replySize, pReplyData);
966 else {
967 ALOGW("%s invalid command %d", __func__, cmdCode);
968 status = -EINVAL;
969 }
970 break;
971 }
972
973exit:
974 pthread_mutex_unlock(&lock);
975
976 return status;
977}
978
979/* Effect Control Interface Implementation: get_descriptor */
980int effect_get_descriptor(effect_handle_t self,
981 effect_descriptor_t *descriptor)
982{
983 effect_context_t *context = (effect_context_t *)self;
984
985 if (!effect_exists(context) || (descriptor == NULL))
986 return -EINVAL;
987
988 *descriptor = *context->desc;
989
990 return 0;
991}
992
wjiang50b81f42014-08-06 08:03:14 +0800993bool effect_is_active(effect_context_t * ctxt) {
994 return ctxt->state == EFFECT_STATE_ACTIVE;
995}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800996
997/* effect_handle_t interface implementation for offload effects */
998const struct effect_interface_s effect_interface = {
999 effect_process,
1000 effect_command,
1001 effect_get_descriptor,
1002 NULL,
1003};
1004
1005__attribute__ ((visibility ("default")))
1006audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +08001007 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1008 .version = EFFECT_LIBRARY_API_VERSION,
1009 .name = "Offload Effects Bundle Library",
1010 .implementor = "The Linux Foundation",
1011 .create_effect = effect_lib_create,
1012 .release_effect = effect_lib_release,
1013 .get_descriptor = effect_lib_get_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001014};