blob: ce0d0eccf3404cb078b39384ce1ecbebdf29b598 [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>
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 *node;
294 struct listnode *fx_node;
295 output_context_t *out_ctxt;
296
297 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
298
299 if (lib_init() != 0)
300 return init_status;
301
302 pthread_mutex_lock(&lock);
303
304 out_ctxt = get_output(output);
305 if (out_ctxt == NULL) {
306 ALOGW("%s output not started", __func__);
307 ret = -ENOSYS;
308 goto exit;
309 }
310
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800311 list_for_each(fx_node, &out_ctxt->effects_list) {
312 effect_context_t *fx_ctxt = node_to_item(fx_node,
313 effect_context_t,
314 output_node);
315 if (fx_ctxt->ops.stop)
316 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
317 }
318
319 list_remove(&out_ctxt->outputs_list_node);
320
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800321#ifdef DTS_EAGLE
322 remove_effect_state_node(pcm_id);
323#endif
324
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800325 free(out_ctxt);
326
327exit:
328 pthread_mutex_unlock(&lock);
329 return ret;
330}
331
Alexy Josephd464f3b2014-11-18 16:14:41 -0800332__attribute__ ((visibility ("default")))
333int offload_effects_bundle_set_hpx_state(bool hpx_state)
334{
335 int ret = 0;
336 struct listnode *node;
337
338 ALOGV("%s hpx state: %d", __func__, hpx_state);
339
340 if (lib_init() != 0)
341 return init_status;
342
343 pthread_mutex_lock(&lock);
344
345 if (hpx_state) {
346 /* set ramp down */
347 list_for_each(node, &active_outputs_list) {
348 output_context_t *out_ctxt = node_to_item(node,
349 output_context_t,
350 outputs_list_node);
351 struct soft_volume_params vol;
352 vol.master_gain = 0x0;
353 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
354 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
355 }
356 /* wait for ramp down duration - 30msec */
357 usleep(30000);
358 /* disable effects modules */
359 list_for_each(node, &active_outputs_list) {
360 struct listnode *fx_node;
361 output_context_t *out_ctxt = node_to_item(node,
362 output_context_t,
363 outputs_list_node);
364 list_for_each(fx_node, &out_ctxt->effects_list) {
365 effect_context_t *fx_ctxt = node_to_item(fx_node,
366 effect_context_t,
367 output_node);
368 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
369 (fx_ctxt->ops.stop != NULL))
370 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
371 }
372 out_ctxt->ctl = NULL;
373 }
374 /* set the channel mixer */
375 list_for_each(node, &active_outputs_list) {
376 /* send command to set channel mixer */
377 }
378 /* enable hpx modules */
379 list_for_each(node, &active_outputs_list) {
380 output_context_t *out_ctxt = node_to_item(node,
381 output_context_t,
382 outputs_list_node);
383 offload_hpx_send_params(out_ctxt->ref_ctl,
384 OFFLOAD_SEND_HPX_STATE_ON);
385 }
386 /* wait for transition state - 50msec */
387 usleep(50000);
388 /* set ramp up */
389 list_for_each(node, &active_outputs_list) {
390 output_context_t *out_ctxt = node_to_item(node,
391 output_context_t,
392 outputs_list_node);
393 struct soft_volume_params vol;
394 vol.master_gain = 0x2000;
395 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
396 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
397 }
398 } else {
399 /* set ramp down */
400 list_for_each(node, &active_outputs_list) {
401 output_context_t *out_ctxt = node_to_item(node,
402 output_context_t,
403 outputs_list_node);
404 struct soft_volume_params vol;
405 vol.master_gain = 0x0;
406 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
407 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
408 }
409 /* wait for ramp down duration - 30msec */
410 usleep(30000);
411 /* disable effects modules */
412 list_for_each(node, &active_outputs_list) {
413 output_context_t *out_ctxt = node_to_item(node,
414 output_context_t,
415 outputs_list_node);
416 offload_hpx_send_params(out_ctxt->ref_ctl,
417 OFFLOAD_SEND_HPX_STATE_OFF);
418 }
419 /* set the channel mixer */
420 list_for_each(node, &active_outputs_list) {
421 /* send command to set channel mixer */
422 }
423 /* enable effects modules */
424 list_for_each(node, &active_outputs_list) {
425 struct listnode *fx_node;
426 output_context_t *out_ctxt = node_to_item(node,
427 output_context_t,
428 outputs_list_node);
429 out_ctxt->ctl = out_ctxt->ref_ctl;
430 list_for_each(fx_node, &out_ctxt->effects_list) {
431 effect_context_t *fx_ctxt = node_to_item(fx_node,
432 effect_context_t,
433 output_node);
434 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
435 (fx_ctxt->ops.start != NULL))
436 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
437 }
438 }
439 /* wait for transition state - 50msec */
440 usleep(50000);
441 /* set ramp up */
442 list_for_each(node, &active_outputs_list) {
443 output_context_t *out_ctxt = node_to_item(node,
444 output_context_t,
445 outputs_list_node);
446 struct soft_volume_params vol;
447 vol.master_gain = 0x2000;
448 offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
449 OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
450 }
451 }
452
453exit:
454 pthread_mutex_unlock(&lock);
455 return ret;
456}
457
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800458/*
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530459 * Effect Bundle Set and get param operations.
460 * currently only handles audio sphere scenario,
461 * but the interface itself can be utilized for any effect.
462 */
463__attribute__ ((visibility ("default")))
464void offload_effects_bundle_get_parameters(struct str_parms *query,
465 struct str_parms *reply)
466{
467 asphere_get_parameters(query, reply);
468}
469
470__attribute__ ((visibility ("default")))
471void offload_effects_bundle_set_parameters(struct str_parms *parms)
472{
473 asphere_set_parameters(parms);
474}
475
476/*
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800477 * Effect operations
478 */
479int set_config(effect_context_t *context, effect_config_t *config)
480{
481 context->config = *config;
482
483 if (context->ops.reset)
484 context->ops.reset(context);
485
486 return 0;
487}
488
489void get_config(effect_context_t *context, effect_config_t *config)
490{
491 *config = context->config;
492}
493
494
495/*
496 * Effect Library Interface Implementation
497 */
498int effect_lib_create(const effect_uuid_t *uuid,
499 int32_t sessionId,
500 int32_t ioId,
501 effect_handle_t *pHandle) {
502 int ret;
503 int i;
504
505 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
506 if (lib_init() != 0)
507 return init_status;
508
509 if (pHandle == NULL || uuid == NULL)
510 return -EINVAL;
511
512 for (i = 0; descriptors[i] != NULL; i++) {
513 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
514 break;
515 }
516
517 if (descriptors[i] == NULL)
518 return -EINVAL;
519
520 effect_context_t *context;
521 if (memcmp(uuid, &equalizer_descriptor.uuid,
522 sizeof(effect_uuid_t)) == 0) {
523 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
524 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800525 if (eq_ctxt == NULL) {
526 return -ENOMEM;
527 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800528 context = (effect_context_t *)eq_ctxt;
529 context->ops.init = equalizer_init;
530 context->ops.reset = equalizer_reset;
531 context->ops.set_parameter = equalizer_set_parameter;
532 context->ops.get_parameter = equalizer_get_parameter;
533 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700534 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800535 context->ops.enable = equalizer_enable;
536 context->ops.disable = equalizer_disable;
537 context->ops.start = equalizer_start;
538 context->ops.stop = equalizer_stop;
539
540 context->desc = &equalizer_descriptor;
541 eq_ctxt->ctl = NULL;
542 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
543 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800544 bass_context_t *bass_ctxt = (bass_context_t *)
545 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800546 if (bass_ctxt == NULL) {
547 return -ENOMEM;
548 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800549 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800550 context->ops.init = bass_init;
551 context->ops.reset = bass_reset;
552 context->ops.set_parameter = bass_set_parameter;
553 context->ops.get_parameter = bass_get_parameter;
554 context->ops.set_device = bass_set_device;
555 context->ops.set_hw_acc_mode = bass_set_mode;
556 context->ops.enable = bass_enable;
557 context->ops.disable = bass_disable;
558 context->ops.start = bass_start;
559 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800560
561 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800562 bass_ctxt->bassboost_ctxt.ctl = NULL;
563 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800564 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
565 sizeof(effect_uuid_t)) == 0) {
566 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
567 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800568 if (virt_ctxt == NULL) {
569 return -ENOMEM;
570 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800571 context = (effect_context_t *)virt_ctxt;
572 context->ops.init = virtualizer_init;
573 context->ops.reset = virtualizer_reset;
574 context->ops.set_parameter = virtualizer_set_parameter;
575 context->ops.get_parameter = virtualizer_get_parameter;
576 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700577 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800578 context->ops.enable = virtualizer_enable;
579 context->ops.disable = virtualizer_disable;
580 context->ops.start = virtualizer_start;
581 context->ops.stop = virtualizer_stop;
582
583 context->desc = &virtualizer_descriptor;
584 virt_ctxt->ctl = NULL;
585 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
586 sizeof(effect_uuid_t)) == 0) ||
587 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
588 sizeof(effect_uuid_t)) == 0) ||
589 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
590 sizeof(effect_uuid_t)) == 0) ||
591 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
592 sizeof(effect_uuid_t)) == 0)) {
593 reverb_context_t *reverb_ctxt = (reverb_context_t *)
594 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800595 if (reverb_ctxt == NULL) {
596 return -ENOMEM;
597 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800598 context = (effect_context_t *)reverb_ctxt;
599 context->ops.init = reverb_init;
600 context->ops.reset = reverb_reset;
601 context->ops.set_parameter = reverb_set_parameter;
602 context->ops.get_parameter = reverb_get_parameter;
603 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700604 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800605 context->ops.enable = reverb_enable;
606 context->ops.disable = reverb_disable;
607 context->ops.start = reverb_start;
608 context->ops.stop = reverb_stop;
609
610 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
611 sizeof(effect_uuid_t)) == 0) {
612 context->desc = &aux_env_reverb_descriptor;
613 reverb_auxiliary_init(reverb_ctxt);
614 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
615 sizeof(effect_uuid_t)) == 0) {
616 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700617 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800618 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
619 sizeof(effect_uuid_t)) == 0) {
620 context->desc = &aux_preset_reverb_descriptor;
621 reverb_auxiliary_init(reverb_ctxt);
622 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
623 sizeof(effect_uuid_t)) == 0) {
624 context->desc = &ins_preset_reverb_descriptor;
625 reverb_preset_init(reverb_ctxt);
626 }
627 reverb_ctxt->ctl = NULL;
Mingming Yin497419f2015-07-01 16:57:32 -0700628#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700629 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
630 sizeof(effect_uuid_t)) == 0) {
631 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
632 calloc(1, sizeof(hw_accelerator_context_t));
633 if (hw_acc_ctxt == NULL) {
634 ALOGE("h/w acc context allocation failed");
635 return -ENOMEM;
636 }
637 context = (effect_context_t *)hw_acc_ctxt;
638 context->ops.init = hw_accelerator_init;
639 context->ops.reset = hw_accelerator_reset;
640 context->ops.set_parameter = hw_accelerator_set_parameter;
641 context->ops.get_parameter = hw_accelerator_get_parameter;
642 context->ops.set_device = hw_accelerator_set_device;
643 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
644 context->ops.enable = hw_accelerator_enable;
645 context->ops.disable = hw_accelerator_disable;
646 context->ops.release = hw_accelerator_release;
647 context->ops.process = hw_accelerator_process;
648
649 context->desc = &hw_accelerator_descriptor;
Mingming Yin497419f2015-07-01 16:57:32 -0700650#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800651 } else {
652 return -EINVAL;
653 }
654
655 context->itfe = &effect_interface;
656 context->state = EFFECT_STATE_UNINITIALIZED;
657 context->out_handle = (audio_io_handle_t)ioId;
658
659 ret = context->ops.init(context);
660 if (ret < 0) {
661 ALOGW("%s init failed", __func__);
662 free(context);
663 return ret;
664 }
665
666 context->state = EFFECT_STATE_INITIALIZED;
667
668 pthread_mutex_lock(&lock);
669 list_add_tail(&created_effects_list, &context->effects_list_node);
670 output_context_t *out_ctxt = get_output(ioId);
671 if (out_ctxt != NULL)
672 add_effect_to_output(out_ctxt, context);
673 pthread_mutex_unlock(&lock);
674
675 *pHandle = (effect_handle_t)context;
676
677 ALOGV("%s created context %p", __func__, context);
678
679 return 0;
680
681}
682
683int effect_lib_release(effect_handle_t handle)
684{
685 effect_context_t *context = (effect_context_t *)handle;
686 int status;
687
688 if (lib_init() != 0)
689 return init_status;
690
691 ALOGV("%s context %p", __func__, handle);
692 pthread_mutex_lock(&lock);
693 status = -EINVAL;
694 if (effect_exists(context)) {
695 output_context_t *out_ctxt = get_output(context->out_handle);
696 if (out_ctxt != NULL)
697 remove_effect_from_output(out_ctxt, context);
698 list_remove(&context->effects_list_node);
699 if (context->ops.release)
700 context->ops.release(context);
701 free(context);
702 status = 0;
703 }
704 pthread_mutex_unlock(&lock);
705
706 return status;
707}
708
709int effect_lib_get_descriptor(const effect_uuid_t *uuid,
710 effect_descriptor_t *descriptor)
711{
712 int i;
713
714 if (lib_init() != 0)
715 return init_status;
716
717 if (descriptor == NULL || uuid == NULL) {
718 ALOGV("%s called with NULL pointer", __func__);
719 return -EINVAL;
720 }
721
722 for (i = 0; descriptors[i] != NULL; i++) {
723 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
724 *descriptor = *descriptors[i];
725 return 0;
726 }
727 }
728
729 return -EINVAL;
730}
731
732
733/*
734 * Effect Control Interface Implementation
735 */
736
737/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700738/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800739int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800740 audio_buffer_t *inBuffer __unused,
741 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800742{
743 effect_context_t * context = (effect_context_t *)self;
744 int status = 0;
745
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700746 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800747
748 pthread_mutex_lock(&lock);
749 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800750 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800751 goto exit;
752 }
753
754 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800755 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800756 goto exit;
757 }
758
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700759 if (context->ops.process)
760 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800761exit:
762 pthread_mutex_unlock(&lock);
763 return status;
764}
765
766int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
767 void *pCmdData, uint32_t *replySize, void *pReplyData)
768{
769
770 effect_context_t * context = (effect_context_t *)self;
771 int retsize;
772 int status = 0;
773
774 pthread_mutex_lock(&lock);
775
776 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800777 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800778 goto exit;
779 }
780
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530781 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800782 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800783 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800784 goto exit;
785 }
786
787 switch (cmdCode) {
788 case EFFECT_CMD_INIT:
789 if (pReplyData == NULL || *replySize != sizeof(int)) {
790 status = -EINVAL;
791 goto exit;
792 }
793 if (context->ops.init)
794 *(int *) pReplyData = context->ops.init(context);
795 else
796 *(int *) pReplyData = 0;
797 break;
798 case EFFECT_CMD_SET_CONFIG:
799 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
800 || pReplyData == NULL || *replySize != sizeof(int)) {
801 status = -EINVAL;
802 goto exit;
803 }
804 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
805 break;
806 case EFFECT_CMD_GET_CONFIG:
807 if (pReplyData == NULL ||
808 *replySize != sizeof(effect_config_t)) {
809 status = -EINVAL;
810 goto exit;
811 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700812 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800813 status = -EINVAL;
814 goto exit;
815 }
816
817 get_config(context, (effect_config_t *)pReplyData);
818 break;
819 case EFFECT_CMD_RESET:
820 if (context->ops.reset)
821 context->ops.reset(context);
822 break;
823 case EFFECT_CMD_ENABLE:
824 if (pReplyData == NULL || *replySize != sizeof(int)) {
825 status = -EINVAL;
826 goto exit;
827 }
828 if (context->state != EFFECT_STATE_INITIALIZED) {
829 status = -ENOSYS;
830 goto exit;
831 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530832 handle_asphere_on_effect_enabled(true, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800833 context->state = EFFECT_STATE_ACTIVE;
834 if (context->ops.enable)
835 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800836 *(int *)pReplyData = 0;
837 break;
838 case EFFECT_CMD_DISABLE:
839 if (pReplyData == NULL || *replySize != sizeof(int)) {
840 status = -EINVAL;
841 goto exit;
842 }
843 if (context->state != EFFECT_STATE_ACTIVE) {
844 status = -ENOSYS;
845 goto exit;
846 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530847 handle_asphere_on_effect_enabled(false, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800848 context->state = EFFECT_STATE_INITIALIZED;
849 if (context->ops.disable)
850 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800851 *(int *)pReplyData = 0;
852 break;
853 case EFFECT_CMD_GET_PARAM: {
854 if (pCmdData == NULL ||
855 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
856 pReplyData == NULL ||
Andy Hungeae4d562016-04-28 13:43:44 -0700857 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) ||
858 // constrain memcpy below
859 ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800860 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530861 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800862 cmdSize, *replySize);
863 goto exit;
864 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700865 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800866 status = -EINVAL;
867 goto exit;
868 }
869 effect_param_t *q = (effect_param_t *)pCmdData;
870 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
871 effect_param_t *p = (effect_param_t *)pReplyData;
872 if (context->ops.get_parameter)
873 context->ops.get_parameter(context, p, replySize);
874 } break;
875 case EFFECT_CMD_SET_PARAM: {
876 if (pCmdData == NULL ||
877 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
878 sizeof(uint16_t)) ||
879 pReplyData == NULL || *replySize != sizeof(int32_t)) {
880 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530881 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800882 cmdSize, *replySize);
883 goto exit;
884 }
885 *(int32_t *)pReplyData = 0;
886 effect_param_t *p = (effect_param_t *)pCmdData;
887 if (context->ops.set_parameter)
888 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
889 *replySize);
890
891 } break;
892 case EFFECT_CMD_SET_DEVICE: {
893 uint32_t device;
894 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
895 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
896 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530897 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800898 goto exit;
899 }
900 device = *(uint32_t *)pCmdData;
901 if (context->ops.set_device)
902 context->ops.set_device(context, device);
903 } break;
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +0800904 case EFFECT_CMD_SET_VOLUME: {
905 // if pReplyData is NULL, VOL_CTRL is delegated to another effect
906 if (pReplyData == NULL) {
907 break;
908 }
909 if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
910 replySize == NULL || *replySize < 2*sizeof(int32_t)) {
911 return -EINVAL;
912 }
913 memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
914 } break;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800915 case EFFECT_CMD_SET_AUDIO_MODE:
916 break;
917
918 case EFFECT_CMD_OFFLOAD: {
919 output_context_t *out_ctxt;
920
921 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
922 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530923 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800924 status = -EINVAL;
925 break;
926 }
927
928 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
929
930 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
931 offload_param->isOffload, offload_param->ioHandle);
932
933 *(int *)pReplyData = 0;
934
935 context->offload_enabled = offload_param->isOffload;
936 if (context->out_handle == offload_param->ioHandle)
937 break;
938
939 out_ctxt = get_output(context->out_handle);
940 if (out_ctxt != NULL)
941 remove_effect_from_output(out_ctxt, context);
942
943 context->out_handle = offload_param->ioHandle;
944 out_ctxt = get_output(context->out_handle);
945 if (out_ctxt != NULL)
946 add_effect_to_output(out_ctxt, context);
947
948 } break;
Mingming Yin497419f2015-07-01 16:57:32 -0700949#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700950 case EFFECT_CMD_HW_ACC: {
951 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
952 cmdSize, pCmdData, *replySize, pReplyData);
953 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
954 || pReplyData == NULL || *replySize != sizeof(int)) {
955 return -EINVAL;
956 }
957 uint32_t value = *(uint32_t *)pCmdData;
958 if (context->ops.set_hw_acc_mode)
959 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800960
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700961 context->hw_acc_enabled = (value > 0) ? true : false;
962 break;
963 }
Mingming Yin497419f2015-07-01 16:57:32 -0700964#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800965 default:
966 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
967 status = context->ops.command(context, cmdCode, cmdSize,
968 pCmdData, replySize, pReplyData);
969 else {
970 ALOGW("%s invalid command %d", __func__, cmdCode);
971 status = -EINVAL;
972 }
973 break;
974 }
975
976exit:
977 pthread_mutex_unlock(&lock);
978
979 return status;
980}
981
982/* Effect Control Interface Implementation: get_descriptor */
983int effect_get_descriptor(effect_handle_t self,
984 effect_descriptor_t *descriptor)
985{
986 effect_context_t *context = (effect_context_t *)self;
987
988 if (!effect_exists(context) || (descriptor == NULL))
989 return -EINVAL;
990
991 *descriptor = *context->desc;
992
993 return 0;
994}
995
wjiang50b81f42014-08-06 08:03:14 +0800996bool effect_is_active(effect_context_t * ctxt) {
997 return ctxt->state == EFFECT_STATE_ACTIVE;
998}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800999
1000/* effect_handle_t interface implementation for offload effects */
1001const struct effect_interface_s effect_interface = {
1002 effect_process,
1003 effect_command,
1004 effect_get_descriptor,
1005 NULL,
1006};
1007
1008__attribute__ ((visibility ("default")))
1009audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
Weiyin Jiang90ac1ea2017-04-13 14:18:23 +08001010 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1011 .version = EFFECT_LIBRARY_API_VERSION,
1012 .name = "Offload Effects Bundle Library",
1013 .implementor = "The Linux Foundation",
1014 .create_effect = effect_lib_create,
1015 .release_effect = effect_lib_release,
1016 .get_descriptor = effect_lib_get_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001017};