blob: 2bc7fad1308653115f1e427706bbc74fa96c68e6 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +08002 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08003 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080018 *
19 * This file was modified by DTS, Inc. The portions of the
20 * code modified by DTS, Inc are copyrighted and
21 * licensed separately, as follows:
22 *
23 * (C) 2014 DTS, Inc.
24 *
25 * Licensed under the Apache License, Version 2.0 (the "License");
26 * you may not use this file except in compliance with the License.
27 * You may obtain a copy of the License at
28 *
29 * http://www.apache.org/licenses/LICENSE-2.0
30 *
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080036 */
37
38#define LOG_TAG "offload_effect_bundle"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070039//#define LOG_NDEBUG 0
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080040
Mingming Yin497419f2015-07-01 16:57:32 -070041#include <stdlib.h>
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080042#include <cutils/list.h>
43#include <cutils/log.h>
44#include <system/thread_defs.h>
45#include <tinyalsa/asoundlib.h>
46#include <hardware/audio_effect.h>
47
48#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070049#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080050#include "equalizer.h"
51#include "bass_boost.h"
52#include "virtualizer.h"
53#include "reverb.h"
Dhananjay Kumar1c978df2015-09-04 13:44:59 +053054#include "asphere.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080055
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080056#ifdef DTS_EAGLE
57#include "effect_util.h"
58#endif
59
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080060enum {
61 EFFECT_STATE_UNINITIALIZED,
62 EFFECT_STATE_INITIALIZED,
63 EFFECT_STATE_ACTIVE,
64};
65
66const effect_descriptor_t *descriptors[] = {
67 &equalizer_descriptor,
68 &bassboost_descriptor,
69 &virtualizer_descriptor,
70 &aux_env_reverb_descriptor,
71 &ins_env_reverb_descriptor,
72 &aux_preset_reverb_descriptor,
73 &ins_preset_reverb_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070074#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070075 &hw_accelerator_descriptor,
Mingming Yin497419f2015-07-01 16:57:32 -070076#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080077 NULL,
78};
79
80pthread_once_t once = PTHREAD_ONCE_INIT;
81int init_status;
82/*
83 * list of created effects.
84 * Updated by offload_effects_bundle_hal_start_output()
85 * and offload_effects_bundle_hal_stop_output()
86 */
87struct listnode created_effects_list;
88/*
89 * list of active output streams.
90 * Updated by offload_effects_bundle_hal_start_output()
91 * and offload_effects_bundle_hal_stop_output()
92 */
93struct listnode active_outputs_list;
94/*
95 * lock must be held when modifying or accessing
96 * created_effects_list or active_outputs_list
97 */
98pthread_mutex_t lock;
99
100
101/*
102 * Local functions
103 */
104static void init_once() {
105 list_init(&created_effects_list);
106 list_init(&active_outputs_list);
107
108 pthread_mutex_init(&lock, NULL);
109
110 init_status = 0;
111}
112
113int lib_init()
114{
115 pthread_once(&once, init_once);
116 return init_status;
117}
118
119bool effect_exists(effect_context_t *context)
120{
121 struct listnode *node;
122
123 list_for_each(node, &created_effects_list) {
124 effect_context_t *fx_ctxt = node_to_item(node,
125 effect_context_t,
126 effects_list_node);
127 if (fx_ctxt == context) {
128 return true;
129 }
130 }
131 return false;
132}
133
134output_context_t *get_output(audio_io_handle_t output)
135{
136 struct listnode *node;
137
138 list_for_each(node, &active_outputs_list) {
139 output_context_t *out_ctxt = node_to_item(node,
140 output_context_t,
141 outputs_list_node);
142 if (out_ctxt->handle == output)
143 return out_ctxt;
144 }
145 return NULL;
146}
147
148void add_effect_to_output(output_context_t * output, effect_context_t *context)
149{
150 struct listnode *fx_node;
151
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530152 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800153 list_for_each(fx_node, &output->effects_list) {
154 effect_context_t *fx_ctxt = node_to_item(fx_node,
155 effect_context_t,
156 output_node);
157 if (fx_ctxt == context)
158 return;
159 }
160 list_add_tail(&output->effects_list, &context->output_node);
161 if (context->ops.start)
162 context->ops.start(context, output);
163
164}
165
166void remove_effect_from_output(output_context_t * output,
167 effect_context_t *context)
168{
169 struct listnode *fx_node;
170
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530171 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800172 list_for_each(fx_node, &output->effects_list) {
173 effect_context_t *fx_ctxt = node_to_item(fx_node,
174 effect_context_t,
175 output_node);
176 if (fx_ctxt == context) {
177 if (context->ops.stop)
178 context->ops.stop(context, output);
179 list_remove(&context->output_node);
180 return;
181 }
182 }
183}
184
185bool effects_enabled()
186{
187 struct listnode *out_node;
188
189 list_for_each(out_node, &active_outputs_list) {
190 struct listnode *fx_node;
191 output_context_t *out_ctxt = node_to_item(out_node,
192 output_context_t,
193 outputs_list_node);
194
195 list_for_each(fx_node, &out_ctxt->effects_list) {
196 effect_context_t *fx_ctxt = node_to_item(fx_node,
197 effect_context_t,
198 output_node);
199 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
200 (fx_ctxt->ops.process != NULL))
201 return true;
202 }
203 }
204 return false;
205}
206
207
208/*
209 * Interface from audio HAL
210 */
211__attribute__ ((visibility ("default")))
212int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
213{
214 int ret = 0;
215 struct listnode *node;
216 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800217 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800218
219 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
220
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800221#ifdef DTS_EAGLE
222 create_effect_state_node(pcm_id);
223#endif
224
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800225 if (lib_init() != 0)
226 return init_status;
227
228 pthread_mutex_lock(&lock);
229 if (get_output(output) != NULL) {
230 ALOGW("%s output already started", __func__);
231 ret = -ENOSYS;
232 goto exit;
233 }
234
wjiang50b81f42014-08-06 08:03:14 +0800235 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800236 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800237 if (!out_ctxt) {
238 ALOGE("%s fail to allocate for output context", __func__);
239 ret = -ENOMEM;
240 goto exit;
241 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800242 out_ctxt->handle = output;
243 out_ctxt->pcm_device_id = pcm_id;
244
245 /* populate the mixer control to send offload parameters */
246 snprintf(mixer_string, sizeof(mixer_string),
247 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
248 out_ctxt->mixer = mixer_open(MIXER_CARD);
249 if (!out_ctxt->mixer) {
250 ALOGE("Failed to open mixer");
251 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700252 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800253 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800254 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800255 goto exit;
256 } else {
257 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
258 if (!out_ctxt->ctl) {
259 ALOGE("mixer_get_ctl_by_name failed");
260 mixer_close(out_ctxt->mixer);
261 out_ctxt->mixer = NULL;
262 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800263 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800264 goto exit;
265 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700266 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800267 }
268
269 list_init(&out_ctxt->effects_list);
270
271 list_for_each(node, &created_effects_list) {
272 effect_context_t *fx_ctxt = node_to_item(node,
273 effect_context_t,
274 effects_list_node);
275 if (fx_ctxt->out_handle == output) {
276 if (fx_ctxt->ops.start)
277 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
278 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
279 }
280 }
281 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
282exit:
283 pthread_mutex_unlock(&lock);
284 return ret;
285}
286
287__attribute__ ((visibility ("default")))
288int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
289{
290 int ret;
291 struct listnode *node;
292 struct listnode *fx_node;
293 output_context_t *out_ctxt;
294
295 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
296
297 if (lib_init() != 0)
298 return init_status;
299
300 pthread_mutex_lock(&lock);
301
302 out_ctxt = get_output(output);
303 if (out_ctxt == NULL) {
304 ALOGW("%s output not started", __func__);
305 ret = -ENOSYS;
306 goto exit;
307 }
308
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800309 list_for_each(fx_node, &out_ctxt->effects_list) {
310 effect_context_t *fx_ctxt = node_to_item(fx_node,
311 effect_context_t,
312 output_node);
313 if (fx_ctxt->ops.stop)
314 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
315 }
316
Dhananjay Kumar30410f62015-06-29 01:05:12 +0530317 if (out_ctxt->mixer)
318 mixer_close(out_ctxt->mixer);
319
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800320 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
454exit:
455 pthread_mutex_unlock(&lock);
456 return ret;
457}
458
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800459/*
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530460 * Effect Bundle Set and get param operations.
461 * currently only handles audio sphere scenario,
462 * but the interface itself can be utilized for any effect.
463 */
464__attribute__ ((visibility ("default")))
465void offload_effects_bundle_get_parameters(struct str_parms *query,
466 struct str_parms *reply)
467{
468 asphere_get_parameters(query, reply);
469}
470
471__attribute__ ((visibility ("default")))
472void offload_effects_bundle_set_parameters(struct str_parms *parms)
473{
474 asphere_set_parameters(parms);
475}
476
477/*
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800478 * Effect operations
479 */
480int set_config(effect_context_t *context, effect_config_t *config)
481{
482 context->config = *config;
483
484 if (context->ops.reset)
485 context->ops.reset(context);
486
487 return 0;
488}
489
490void get_config(effect_context_t *context, effect_config_t *config)
491{
492 *config = context->config;
493}
494
495
496/*
497 * Effect Library Interface Implementation
498 */
499int effect_lib_create(const effect_uuid_t *uuid,
500 int32_t sessionId,
501 int32_t ioId,
502 effect_handle_t *pHandle) {
503 int ret;
504 int i;
505
506 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
507 if (lib_init() != 0)
508 return init_status;
509
510 if (pHandle == NULL || uuid == NULL)
511 return -EINVAL;
512
513 for (i = 0; descriptors[i] != NULL; i++) {
514 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
515 break;
516 }
517
518 if (descriptors[i] == NULL)
519 return -EINVAL;
520
521 effect_context_t *context;
522 if (memcmp(uuid, &equalizer_descriptor.uuid,
523 sizeof(effect_uuid_t)) == 0) {
524 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
525 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800526 if (eq_ctxt == NULL) {
527 return -ENOMEM;
528 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800529 context = (effect_context_t *)eq_ctxt;
530 context->ops.init = equalizer_init;
531 context->ops.reset = equalizer_reset;
532 context->ops.set_parameter = equalizer_set_parameter;
533 context->ops.get_parameter = equalizer_get_parameter;
534 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700535 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800536 context->ops.enable = equalizer_enable;
537 context->ops.disable = equalizer_disable;
538 context->ops.start = equalizer_start;
539 context->ops.stop = equalizer_stop;
540
541 context->desc = &equalizer_descriptor;
542 eq_ctxt->ctl = NULL;
543 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
544 sizeof(effect_uuid_t)) == 0) {
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800545 bass_context_t *bass_ctxt = (bass_context_t *)
546 calloc(1, sizeof(bass_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800547 if (bass_ctxt == NULL) {
548 return -ENOMEM;
549 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800550 context = (effect_context_t *)bass_ctxt;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800551 context->ops.init = bass_init;
552 context->ops.reset = bass_reset;
553 context->ops.set_parameter = bass_set_parameter;
554 context->ops.get_parameter = bass_get_parameter;
555 context->ops.set_device = bass_set_device;
556 context->ops.set_hw_acc_mode = bass_set_mode;
557 context->ops.enable = bass_enable;
558 context->ops.disable = bass_disable;
559 context->ops.start = bass_start;
560 context->ops.stop = bass_stop;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800561
562 context->desc = &bassboost_descriptor;
Dhananjay Kumar5f15ff92014-05-19 16:45:08 +0800563 bass_ctxt->bassboost_ctxt.ctl = NULL;
564 bass_ctxt->pbe_ctxt.ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800565 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
566 sizeof(effect_uuid_t)) == 0) {
567 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
568 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800569 if (virt_ctxt == NULL) {
570 return -ENOMEM;
571 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800572 context = (effect_context_t *)virt_ctxt;
573 context->ops.init = virtualizer_init;
574 context->ops.reset = virtualizer_reset;
575 context->ops.set_parameter = virtualizer_set_parameter;
576 context->ops.get_parameter = virtualizer_get_parameter;
577 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700578 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800579 context->ops.enable = virtualizer_enable;
580 context->ops.disable = virtualizer_disable;
581 context->ops.start = virtualizer_start;
582 context->ops.stop = virtualizer_stop;
583
584 context->desc = &virtualizer_descriptor;
585 virt_ctxt->ctl = NULL;
586 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
587 sizeof(effect_uuid_t)) == 0) ||
588 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
589 sizeof(effect_uuid_t)) == 0) ||
590 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
591 sizeof(effect_uuid_t)) == 0) ||
592 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
593 sizeof(effect_uuid_t)) == 0)) {
594 reverb_context_t *reverb_ctxt = (reverb_context_t *)
595 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800596 if (reverb_ctxt == NULL) {
597 return -ENOMEM;
598 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800599 context = (effect_context_t *)reverb_ctxt;
600 context->ops.init = reverb_init;
601 context->ops.reset = reverb_reset;
602 context->ops.set_parameter = reverb_set_parameter;
603 context->ops.get_parameter = reverb_get_parameter;
604 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700605 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800606 context->ops.enable = reverb_enable;
607 context->ops.disable = reverb_disable;
608 context->ops.start = reverb_start;
609 context->ops.stop = reverb_stop;
610
611 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
612 sizeof(effect_uuid_t)) == 0) {
613 context->desc = &aux_env_reverb_descriptor;
614 reverb_auxiliary_init(reverb_ctxt);
615 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
616 sizeof(effect_uuid_t)) == 0) {
617 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700618 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800619 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
620 sizeof(effect_uuid_t)) == 0) {
621 context->desc = &aux_preset_reverb_descriptor;
622 reverb_auxiliary_init(reverb_ctxt);
623 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
624 sizeof(effect_uuid_t)) == 0) {
625 context->desc = &ins_preset_reverb_descriptor;
626 reverb_preset_init(reverb_ctxt);
627 }
628 reverb_ctxt->ctl = NULL;
Mingming Yin497419f2015-07-01 16:57:32 -0700629#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700630 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
631 sizeof(effect_uuid_t)) == 0) {
632 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
633 calloc(1, sizeof(hw_accelerator_context_t));
634 if (hw_acc_ctxt == NULL) {
635 ALOGE("h/w acc context allocation failed");
636 return -ENOMEM;
637 }
638 context = (effect_context_t *)hw_acc_ctxt;
639 context->ops.init = hw_accelerator_init;
640 context->ops.reset = hw_accelerator_reset;
641 context->ops.set_parameter = hw_accelerator_set_parameter;
642 context->ops.get_parameter = hw_accelerator_get_parameter;
643 context->ops.set_device = hw_accelerator_set_device;
644 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
645 context->ops.enable = hw_accelerator_enable;
646 context->ops.disable = hw_accelerator_disable;
647 context->ops.release = hw_accelerator_release;
648 context->ops.process = hw_accelerator_process;
649
650 context->desc = &hw_accelerator_descriptor;
Mingming Yin497419f2015-07-01 16:57:32 -0700651#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800652 } else {
653 return -EINVAL;
654 }
655
656 context->itfe = &effect_interface;
657 context->state = EFFECT_STATE_UNINITIALIZED;
658 context->out_handle = (audio_io_handle_t)ioId;
659
660 ret = context->ops.init(context);
661 if (ret < 0) {
662 ALOGW("%s init failed", __func__);
663 free(context);
664 return ret;
665 }
666
667 context->state = EFFECT_STATE_INITIALIZED;
668
669 pthread_mutex_lock(&lock);
670 list_add_tail(&created_effects_list, &context->effects_list_node);
671 output_context_t *out_ctxt = get_output(ioId);
672 if (out_ctxt != NULL)
673 add_effect_to_output(out_ctxt, context);
674 pthread_mutex_unlock(&lock);
675
676 *pHandle = (effect_handle_t)context;
677
678 ALOGV("%s created context %p", __func__, context);
679
680 return 0;
681
682}
683
684int effect_lib_release(effect_handle_t handle)
685{
686 effect_context_t *context = (effect_context_t *)handle;
687 int status;
688
689 if (lib_init() != 0)
690 return init_status;
691
692 ALOGV("%s context %p", __func__, handle);
693 pthread_mutex_lock(&lock);
694 status = -EINVAL;
695 if (effect_exists(context)) {
696 output_context_t *out_ctxt = get_output(context->out_handle);
697 if (out_ctxt != NULL)
698 remove_effect_from_output(out_ctxt, context);
699 list_remove(&context->effects_list_node);
700 if (context->ops.release)
701 context->ops.release(context);
702 free(context);
703 status = 0;
704 }
705 pthread_mutex_unlock(&lock);
706
707 return status;
708}
709
710int effect_lib_get_descriptor(const effect_uuid_t *uuid,
711 effect_descriptor_t *descriptor)
712{
713 int i;
714
715 if (lib_init() != 0)
716 return init_status;
717
718 if (descriptor == NULL || uuid == NULL) {
719 ALOGV("%s called with NULL pointer", __func__);
720 return -EINVAL;
721 }
722
723 for (i = 0; descriptors[i] != NULL; i++) {
724 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
725 *descriptor = *descriptors[i];
726 return 0;
727 }
728 }
729
730 return -EINVAL;
731}
732
733
734/*
735 * Effect Control Interface Implementation
736 */
737
738/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700739/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800740int effect_process(effect_handle_t self,
Weiyin Jiangb64b7dd2015-03-23 00:54:14 +0800741 audio_buffer_t *inBuffer __unused,
742 audio_buffer_t *outBuffer __unused)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800743{
744 effect_context_t * context = (effect_context_t *)self;
745 int status = 0;
746
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700747 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800748
749 pthread_mutex_lock(&lock);
750 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800751 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800752 goto exit;
753 }
754
755 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800756 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800757 goto exit;
758 }
759
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700760 if (context->ops.process)
761 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800762exit:
763 pthread_mutex_unlock(&lock);
764 return status;
765}
766
767int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
768 void *pCmdData, uint32_t *replySize, void *pReplyData)
769{
770
771 effect_context_t * context = (effect_context_t *)self;
772 int retsize;
773 int status = 0;
774
775 pthread_mutex_lock(&lock);
776
777 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800778 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800779 goto exit;
780 }
781
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530782 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800783 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800784 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800785 goto exit;
786 }
787
788 switch (cmdCode) {
789 case EFFECT_CMD_INIT:
790 if (pReplyData == NULL || *replySize != sizeof(int)) {
791 status = -EINVAL;
792 goto exit;
793 }
794 if (context->ops.init)
795 *(int *) pReplyData = context->ops.init(context);
796 else
797 *(int *) pReplyData = 0;
798 break;
799 case EFFECT_CMD_SET_CONFIG:
800 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
801 || pReplyData == NULL || *replySize != sizeof(int)) {
802 status = -EINVAL;
803 goto exit;
804 }
805 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
806 break;
807 case EFFECT_CMD_GET_CONFIG:
808 if (pReplyData == NULL ||
809 *replySize != sizeof(effect_config_t)) {
810 status = -EINVAL;
811 goto exit;
812 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700813 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800814 status = -EINVAL;
815 goto exit;
816 }
817
818 get_config(context, (effect_config_t *)pReplyData);
819 break;
820 case EFFECT_CMD_RESET:
821 if (context->ops.reset)
822 context->ops.reset(context);
823 break;
824 case EFFECT_CMD_ENABLE:
825 if (pReplyData == NULL || *replySize != sizeof(int)) {
826 status = -EINVAL;
827 goto exit;
828 }
829 if (context->state != EFFECT_STATE_INITIALIZED) {
830 status = -ENOSYS;
831 goto exit;
832 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530833 handle_asphere_on_effect_enabled(true, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800834 context->state = EFFECT_STATE_ACTIVE;
835 if (context->ops.enable)
836 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800837 *(int *)pReplyData = 0;
838 break;
839 case EFFECT_CMD_DISABLE:
840 if (pReplyData == NULL || *replySize != sizeof(int)) {
841 status = -EINVAL;
842 goto exit;
843 }
844 if (context->state != EFFECT_STATE_ACTIVE) {
845 status = -ENOSYS;
846 goto exit;
847 }
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530848 handle_asphere_on_effect_enabled(false, context, &created_effects_list);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800849 context->state = EFFECT_STATE_INITIALIZED;
850 if (context->ops.disable)
851 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800852 *(int *)pReplyData = 0;
853 break;
854 case EFFECT_CMD_GET_PARAM: {
855 if (pCmdData == NULL ||
856 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
857 pReplyData == NULL ||
858 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
859 sizeof(uint16_t))) {
860 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;
904 case EFFECT_CMD_SET_VOLUME:
905 case EFFECT_CMD_SET_AUDIO_MODE:
906 break;
907
908 case EFFECT_CMD_OFFLOAD: {
909 output_context_t *out_ctxt;
910
911 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
912 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530913 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800914 status = -EINVAL;
915 break;
916 }
917
918 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
919
920 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
921 offload_param->isOffload, offload_param->ioHandle);
922
923 *(int *)pReplyData = 0;
924
925 context->offload_enabled = offload_param->isOffload;
926 if (context->out_handle == offload_param->ioHandle)
927 break;
928
929 out_ctxt = get_output(context->out_handle);
930 if (out_ctxt != NULL)
931 remove_effect_from_output(out_ctxt, context);
932
933 context->out_handle = offload_param->ioHandle;
934 out_ctxt = get_output(context->out_handle);
935 if (out_ctxt != NULL)
936 add_effect_to_output(out_ctxt, context);
937
938 } break;
Mingming Yin497419f2015-07-01 16:57:32 -0700939#ifdef HW_ACCELERATED_EFFECTS
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700940 case EFFECT_CMD_HW_ACC: {
941 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
942 cmdSize, pCmdData, *replySize, pReplyData);
943 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
944 || pReplyData == NULL || *replySize != sizeof(int)) {
945 return -EINVAL;
946 }
947 uint32_t value = *(uint32_t *)pCmdData;
948 if (context->ops.set_hw_acc_mode)
949 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800950
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700951 context->hw_acc_enabled = (value > 0) ? true : false;
952 break;
953 }
Mingming Yin497419f2015-07-01 16:57:32 -0700954#endif
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800955 default:
956 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
957 status = context->ops.command(context, cmdCode, cmdSize,
958 pCmdData, replySize, pReplyData);
959 else {
960 ALOGW("%s invalid command %d", __func__, cmdCode);
961 status = -EINVAL;
962 }
963 break;
964 }
965
966exit:
967 pthread_mutex_unlock(&lock);
968
969 return status;
970}
971
972/* Effect Control Interface Implementation: get_descriptor */
973int effect_get_descriptor(effect_handle_t self,
974 effect_descriptor_t *descriptor)
975{
976 effect_context_t *context = (effect_context_t *)self;
977
978 if (!effect_exists(context) || (descriptor == NULL))
979 return -EINVAL;
980
981 *descriptor = *context->desc;
982
983 return 0;
984}
985
wjiang50b81f42014-08-06 08:03:14 +0800986bool effect_is_active(effect_context_t * ctxt) {
987 return ctxt->state == EFFECT_STATE_ACTIVE;
988}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800989
990/* effect_handle_t interface implementation for offload effects */
991const struct effect_interface_s effect_interface = {
992 effect_process,
993 effect_command,
994 effect_get_descriptor,
995 NULL,
996};
997
998__attribute__ ((visibility ("default")))
999audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1000 tag : AUDIO_EFFECT_LIBRARY_TAG,
1001 version : EFFECT_LIBRARY_API_VERSION,
1002 name : "Offload Effects Bundle Library",
1003 implementor : "The Linux Foundation",
1004 create_effect : effect_lib_create,
1005 release_effect : effect_lib_release,
1006 get_descriptor : effect_lib_get_descriptor,
1007};