blob: 871b0874aace9b8cb489fe9fa02232d44c72c1f8 [file] [log] [blame]
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -08001/*
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -07002 * Copyright (c) 2013-2014, 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
41#include <cutils/list.h>
42#include <cutils/log.h>
43#include <system/thread_defs.h>
44#include <tinyalsa/asoundlib.h>
45#include <hardware/audio_effect.h>
46
47#include "bundle.h"
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070048#include "hw_accelerator.h"
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080049#include "equalizer.h"
50#include "bass_boost.h"
51#include "virtualizer.h"
52#include "reverb.h"
53
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080054#ifdef DTS_EAGLE
55#include "effect_util.h"
56#endif
57
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080058enum {
59 EFFECT_STATE_UNINITIALIZED,
60 EFFECT_STATE_INITIALIZED,
61 EFFECT_STATE_ACTIVE,
62};
63
64const effect_descriptor_t *descriptors[] = {
65 &equalizer_descriptor,
66 &bassboost_descriptor,
67 &virtualizer_descriptor,
68 &aux_env_reverb_descriptor,
69 &ins_env_reverb_descriptor,
70 &aux_preset_reverb_descriptor,
71 &ins_preset_reverb_descriptor,
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070072 &hw_accelerator_descriptor,
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -080073 NULL,
74};
75
76pthread_once_t once = PTHREAD_ONCE_INIT;
77int init_status;
78/*
79 * list of created effects.
80 * Updated by offload_effects_bundle_hal_start_output()
81 * and offload_effects_bundle_hal_stop_output()
82 */
83struct listnode created_effects_list;
84/*
85 * list of active output streams.
86 * Updated by offload_effects_bundle_hal_start_output()
87 * and offload_effects_bundle_hal_stop_output()
88 */
89struct listnode active_outputs_list;
90/*
91 * lock must be held when modifying or accessing
92 * created_effects_list or active_outputs_list
93 */
94pthread_mutex_t lock;
95
96
97/*
98 * Local functions
99 */
100static void init_once() {
101 list_init(&created_effects_list);
102 list_init(&active_outputs_list);
103
104 pthread_mutex_init(&lock, NULL);
105
106 init_status = 0;
107}
108
109int lib_init()
110{
111 pthread_once(&once, init_once);
112 return init_status;
113}
114
115bool effect_exists(effect_context_t *context)
116{
117 struct listnode *node;
118
119 list_for_each(node, &created_effects_list) {
120 effect_context_t *fx_ctxt = node_to_item(node,
121 effect_context_t,
122 effects_list_node);
123 if (fx_ctxt == context) {
124 return true;
125 }
126 }
127 return false;
128}
129
130output_context_t *get_output(audio_io_handle_t output)
131{
132 struct listnode *node;
133
134 list_for_each(node, &active_outputs_list) {
135 output_context_t *out_ctxt = node_to_item(node,
136 output_context_t,
137 outputs_list_node);
138 if (out_ctxt->handle == output)
139 return out_ctxt;
140 }
141 return NULL;
142}
143
144void add_effect_to_output(output_context_t * output, effect_context_t *context)
145{
146 struct listnode *fx_node;
147
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530148 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800149 list_for_each(fx_node, &output->effects_list) {
150 effect_context_t *fx_ctxt = node_to_item(fx_node,
151 effect_context_t,
152 output_node);
153 if (fx_ctxt == context)
154 return;
155 }
156 list_add_tail(&output->effects_list, &context->output_node);
157 if (context->ops.start)
158 context->ops.start(context, output);
159
160}
161
162void remove_effect_from_output(output_context_t * output,
163 effect_context_t *context)
164{
165 struct listnode *fx_node;
166
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530167 ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800168 list_for_each(fx_node, &output->effects_list) {
169 effect_context_t *fx_ctxt = node_to_item(fx_node,
170 effect_context_t,
171 output_node);
172 if (fx_ctxt == context) {
173 if (context->ops.stop)
174 context->ops.stop(context, output);
175 list_remove(&context->output_node);
176 return;
177 }
178 }
179}
180
181bool effects_enabled()
182{
183 struct listnode *out_node;
184
185 list_for_each(out_node, &active_outputs_list) {
186 struct listnode *fx_node;
187 output_context_t *out_ctxt = node_to_item(out_node,
188 output_context_t,
189 outputs_list_node);
190
191 list_for_each(fx_node, &out_ctxt->effects_list) {
192 effect_context_t *fx_ctxt = node_to_item(fx_node,
193 effect_context_t,
194 output_node);
195 if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
196 (fx_ctxt->ops.process != NULL))
197 return true;
198 }
199 }
200 return false;
201}
202
203
204/*
205 * Interface from audio HAL
206 */
207__attribute__ ((visibility ("default")))
208int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
209{
210 int ret = 0;
211 struct listnode *node;
212 char mixer_string[128];
wjiang50b81f42014-08-06 08:03:14 +0800213 output_context_t * out_ctxt = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800214
215 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
216
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800217#ifdef DTS_EAGLE
218 create_effect_state_node(pcm_id);
219#endif
220
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800221 if (lib_init() != 0)
222 return init_status;
223
224 pthread_mutex_lock(&lock);
225 if (get_output(output) != NULL) {
226 ALOGW("%s output already started", __func__);
227 ret = -ENOSYS;
228 goto exit;
229 }
230
wjiang50b81f42014-08-06 08:03:14 +0800231 out_ctxt = (output_context_t *)
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800232 malloc(sizeof(output_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800233 if (!out_ctxt) {
234 ALOGE("%s fail to allocate for output context", __func__);
235 ret = -ENOMEM;
236 goto exit;
237 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800238 out_ctxt->handle = output;
239 out_ctxt->pcm_device_id = pcm_id;
240
241 /* populate the mixer control to send offload parameters */
242 snprintf(mixer_string, sizeof(mixer_string),
243 "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
244 out_ctxt->mixer = mixer_open(MIXER_CARD);
245 if (!out_ctxt->mixer) {
246 ALOGE("Failed to open mixer");
247 out_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700248 out_ctxt->ref_ctl = NULL;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800249 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800250 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800251 goto exit;
252 } else {
253 out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
254 if (!out_ctxt->ctl) {
255 ALOGE("mixer_get_ctl_by_name failed");
256 mixer_close(out_ctxt->mixer);
257 out_ctxt->mixer = NULL;
258 ret = -EINVAL;
wjiang50b81f42014-08-06 08:03:14 +0800259 free(out_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800260 goto exit;
261 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700262 out_ctxt->ref_ctl = out_ctxt->ctl;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800263 }
264
265 list_init(&out_ctxt->effects_list);
266
267 list_for_each(node, &created_effects_list) {
268 effect_context_t *fx_ctxt = node_to_item(node,
269 effect_context_t,
270 effects_list_node);
271 if (fx_ctxt->out_handle == output) {
272 if (fx_ctxt->ops.start)
273 fx_ctxt->ops.start(fx_ctxt, out_ctxt);
274 list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
275 }
276 }
277 list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
278exit:
279 pthread_mutex_unlock(&lock);
280 return ret;
281}
282
283__attribute__ ((visibility ("default")))
284int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
285{
286 int ret;
287 struct listnode *node;
288 struct listnode *fx_node;
289 output_context_t *out_ctxt;
290
291 ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
292
293 if (lib_init() != 0)
294 return init_status;
295
296 pthread_mutex_lock(&lock);
297
298 out_ctxt = get_output(output);
299 if (out_ctxt == NULL) {
300 ALOGW("%s output not started", __func__);
301 ret = -ENOSYS;
302 goto exit;
303 }
304
305 if (out_ctxt->mixer)
306 mixer_close(out_ctxt->mixer);
307
308 list_for_each(fx_node, &out_ctxt->effects_list) {
309 effect_context_t *fx_ctxt = node_to_item(fx_node,
310 effect_context_t,
311 output_node);
312 if (fx_ctxt->ops.stop)
313 fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
314 }
315
316 list_remove(&out_ctxt->outputs_list_node);
317
Jitendra Naruka1b6513f2014-11-22 19:34:13 -0800318#ifdef DTS_EAGLE
319 remove_effect_state_node(pcm_id);
320#endif
321
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800322 free(out_ctxt);
323
324exit:
325 pthread_mutex_unlock(&lock);
326 return ret;
327}
328
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800329/*
330 * Effect operations
331 */
332int set_config(effect_context_t *context, effect_config_t *config)
333{
334 context->config = *config;
335
336 if (context->ops.reset)
337 context->ops.reset(context);
338
339 return 0;
340}
341
342void get_config(effect_context_t *context, effect_config_t *config)
343{
344 *config = context->config;
345}
346
347
348/*
349 * Effect Library Interface Implementation
350 */
351int effect_lib_create(const effect_uuid_t *uuid,
352 int32_t sessionId,
353 int32_t ioId,
354 effect_handle_t *pHandle) {
355 int ret;
356 int i;
357
358 ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
359 if (lib_init() != 0)
360 return init_status;
361
362 if (pHandle == NULL || uuid == NULL)
363 return -EINVAL;
364
365 for (i = 0; descriptors[i] != NULL; i++) {
366 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
367 break;
368 }
369
370 if (descriptors[i] == NULL)
371 return -EINVAL;
372
373 effect_context_t *context;
374 if (memcmp(uuid, &equalizer_descriptor.uuid,
375 sizeof(effect_uuid_t)) == 0) {
376 equalizer_context_t *eq_ctxt = (equalizer_context_t *)
377 calloc(1, sizeof(equalizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800378 if (eq_ctxt == NULL) {
379 return -ENOMEM;
380 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800381 context = (effect_context_t *)eq_ctxt;
382 context->ops.init = equalizer_init;
383 context->ops.reset = equalizer_reset;
384 context->ops.set_parameter = equalizer_set_parameter;
385 context->ops.get_parameter = equalizer_get_parameter;
386 context->ops.set_device = equalizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700387 context->ops.set_hw_acc_mode = equalizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800388 context->ops.enable = equalizer_enable;
389 context->ops.disable = equalizer_disable;
390 context->ops.start = equalizer_start;
391 context->ops.stop = equalizer_stop;
392
393 context->desc = &equalizer_descriptor;
394 eq_ctxt->ctl = NULL;
395 } else if (memcmp(uuid, &bassboost_descriptor.uuid,
396 sizeof(effect_uuid_t)) == 0) {
397 bassboost_context_t *bass_ctxt = (bassboost_context_t *)
398 calloc(1, sizeof(bassboost_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800399 if (bass_ctxt == NULL) {
400 return -ENOMEM;
401 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800402 context = (effect_context_t *)bass_ctxt;
403 context->ops.init = bassboost_init;
404 context->ops.reset = bassboost_reset;
405 context->ops.set_parameter = bassboost_set_parameter;
406 context->ops.get_parameter = bassboost_get_parameter;
407 context->ops.set_device = bassboost_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700408 context->ops.set_hw_acc_mode = bassboost_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800409 context->ops.enable = bassboost_enable;
410 context->ops.disable = bassboost_disable;
411 context->ops.start = bassboost_start;
412 context->ops.stop = bassboost_stop;
413
414 context->desc = &bassboost_descriptor;
415 bass_ctxt->ctl = NULL;
416 } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
417 sizeof(effect_uuid_t)) == 0) {
418 virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
419 calloc(1, sizeof(virtualizer_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800420 if (virt_ctxt == NULL) {
421 return -ENOMEM;
422 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800423 context = (effect_context_t *)virt_ctxt;
424 context->ops.init = virtualizer_init;
425 context->ops.reset = virtualizer_reset;
426 context->ops.set_parameter = virtualizer_set_parameter;
427 context->ops.get_parameter = virtualizer_get_parameter;
428 context->ops.set_device = virtualizer_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700429 context->ops.set_hw_acc_mode = virtualizer_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800430 context->ops.enable = virtualizer_enable;
431 context->ops.disable = virtualizer_disable;
432 context->ops.start = virtualizer_start;
433 context->ops.stop = virtualizer_stop;
434
435 context->desc = &virtualizer_descriptor;
436 virt_ctxt->ctl = NULL;
437 } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
438 sizeof(effect_uuid_t)) == 0) ||
439 (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
440 sizeof(effect_uuid_t)) == 0) ||
441 (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
442 sizeof(effect_uuid_t)) == 0) ||
443 (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
444 sizeof(effect_uuid_t)) == 0)) {
445 reverb_context_t *reverb_ctxt = (reverb_context_t *)
446 calloc(1, sizeof(reverb_context_t));
wjiangebb69fa2014-05-15 19:38:26 +0800447 if (reverb_ctxt == NULL) {
448 return -ENOMEM;
449 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800450 context = (effect_context_t *)reverb_ctxt;
451 context->ops.init = reverb_init;
452 context->ops.reset = reverb_reset;
453 context->ops.set_parameter = reverb_set_parameter;
454 context->ops.get_parameter = reverb_get_parameter;
455 context->ops.set_device = reverb_set_device;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700456 context->ops.set_hw_acc_mode = reverb_set_mode;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800457 context->ops.enable = reverb_enable;
458 context->ops.disable = reverb_disable;
459 context->ops.start = reverb_start;
460 context->ops.stop = reverb_stop;
461
462 if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
463 sizeof(effect_uuid_t)) == 0) {
464 context->desc = &aux_env_reverb_descriptor;
465 reverb_auxiliary_init(reverb_ctxt);
466 } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
467 sizeof(effect_uuid_t)) == 0) {
468 context->desc = &ins_env_reverb_descriptor;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700469 reverb_insert_init(reverb_ctxt);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800470 } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
471 sizeof(effect_uuid_t)) == 0) {
472 context->desc = &aux_preset_reverb_descriptor;
473 reverb_auxiliary_init(reverb_ctxt);
474 } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
475 sizeof(effect_uuid_t)) == 0) {
476 context->desc = &ins_preset_reverb_descriptor;
477 reverb_preset_init(reverb_ctxt);
478 }
479 reverb_ctxt->ctl = NULL;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700480 } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
481 sizeof(effect_uuid_t)) == 0) {
482 hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
483 calloc(1, sizeof(hw_accelerator_context_t));
484 if (hw_acc_ctxt == NULL) {
485 ALOGE("h/w acc context allocation failed");
486 return -ENOMEM;
487 }
488 context = (effect_context_t *)hw_acc_ctxt;
489 context->ops.init = hw_accelerator_init;
490 context->ops.reset = hw_accelerator_reset;
491 context->ops.set_parameter = hw_accelerator_set_parameter;
492 context->ops.get_parameter = hw_accelerator_get_parameter;
493 context->ops.set_device = hw_accelerator_set_device;
494 context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
495 context->ops.enable = hw_accelerator_enable;
496 context->ops.disable = hw_accelerator_disable;
497 context->ops.release = hw_accelerator_release;
498 context->ops.process = hw_accelerator_process;
499
500 context->desc = &hw_accelerator_descriptor;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800501 } else {
502 return -EINVAL;
503 }
504
505 context->itfe = &effect_interface;
506 context->state = EFFECT_STATE_UNINITIALIZED;
507 context->out_handle = (audio_io_handle_t)ioId;
508
509 ret = context->ops.init(context);
510 if (ret < 0) {
511 ALOGW("%s init failed", __func__);
512 free(context);
513 return ret;
514 }
515
516 context->state = EFFECT_STATE_INITIALIZED;
517
518 pthread_mutex_lock(&lock);
519 list_add_tail(&created_effects_list, &context->effects_list_node);
520 output_context_t *out_ctxt = get_output(ioId);
521 if (out_ctxt != NULL)
522 add_effect_to_output(out_ctxt, context);
523 pthread_mutex_unlock(&lock);
524
525 *pHandle = (effect_handle_t)context;
526
527 ALOGV("%s created context %p", __func__, context);
528
529 return 0;
530
531}
532
533int effect_lib_release(effect_handle_t handle)
534{
535 effect_context_t *context = (effect_context_t *)handle;
536 int status;
537
538 if (lib_init() != 0)
539 return init_status;
540
541 ALOGV("%s context %p", __func__, handle);
542 pthread_mutex_lock(&lock);
543 status = -EINVAL;
544 if (effect_exists(context)) {
545 output_context_t *out_ctxt = get_output(context->out_handle);
546 if (out_ctxt != NULL)
547 remove_effect_from_output(out_ctxt, context);
548 list_remove(&context->effects_list_node);
549 if (context->ops.release)
550 context->ops.release(context);
551 free(context);
552 status = 0;
553 }
554 pthread_mutex_unlock(&lock);
555
556 return status;
557}
558
559int effect_lib_get_descriptor(const effect_uuid_t *uuid,
560 effect_descriptor_t *descriptor)
561{
562 int i;
563
564 if (lib_init() != 0)
565 return init_status;
566
567 if (descriptor == NULL || uuid == NULL) {
568 ALOGV("%s called with NULL pointer", __func__);
569 return -EINVAL;
570 }
571
572 for (i = 0; descriptors[i] != NULL; i++) {
573 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
574 *descriptor = *descriptors[i];
575 return 0;
576 }
577 }
578
579 return -EINVAL;
580}
581
582
583/*
584 * Effect Control Interface Implementation
585 */
586
587/* Stub function for effect interface: never called for offloaded effects */
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700588/* called for hw accelerated effects */
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800589int effect_process(effect_handle_t self,
590 audio_buffer_t *inBuffer,
591 audio_buffer_t *outBuffer)
592{
593 effect_context_t * context = (effect_context_t *)self;
594 int status = 0;
595
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700596 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800597
598 pthread_mutex_lock(&lock);
599 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800600 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800601 goto exit;
602 }
603
604 if (context->state != EFFECT_STATE_ACTIVE) {
wjiang50b81f42014-08-06 08:03:14 +0800605 status = -ENODATA;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800606 goto exit;
607 }
608
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700609 if (context->ops.process)
610 status = context->ops.process(context, inBuffer, outBuffer);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800611exit:
612 pthread_mutex_unlock(&lock);
613 return status;
614}
615
616int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
617 void *pCmdData, uint32_t *replySize, void *pReplyData)
618{
619
620 effect_context_t * context = (effect_context_t *)self;
621 int retsize;
622 int status = 0;
623
624 pthread_mutex_lock(&lock);
625
626 if (!effect_exists(context)) {
wjiang50b81f42014-08-06 08:03:14 +0800627 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800628 goto exit;
629 }
630
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530631 ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800632 if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
wjiang50b81f42014-08-06 08:03:14 +0800633 status = -ENOSYS;
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800634 goto exit;
635 }
636
637 switch (cmdCode) {
638 case EFFECT_CMD_INIT:
639 if (pReplyData == NULL || *replySize != sizeof(int)) {
640 status = -EINVAL;
641 goto exit;
642 }
643 if (context->ops.init)
644 *(int *) pReplyData = context->ops.init(context);
645 else
646 *(int *) pReplyData = 0;
647 break;
648 case EFFECT_CMD_SET_CONFIG:
649 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
650 || pReplyData == NULL || *replySize != sizeof(int)) {
651 status = -EINVAL;
652 goto exit;
653 }
654 *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
655 break;
656 case EFFECT_CMD_GET_CONFIG:
657 if (pReplyData == NULL ||
658 *replySize != sizeof(effect_config_t)) {
659 status = -EINVAL;
660 goto exit;
661 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700662 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800663 status = -EINVAL;
664 goto exit;
665 }
666
667 get_config(context, (effect_config_t *)pReplyData);
668 break;
669 case EFFECT_CMD_RESET:
670 if (context->ops.reset)
671 context->ops.reset(context);
672 break;
673 case EFFECT_CMD_ENABLE:
674 if (pReplyData == NULL || *replySize != sizeof(int)) {
675 status = -EINVAL;
676 goto exit;
677 }
678 if (context->state != EFFECT_STATE_INITIALIZED) {
679 status = -ENOSYS;
680 goto exit;
681 }
682 context->state = EFFECT_STATE_ACTIVE;
683 if (context->ops.enable)
684 context->ops.enable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800685 *(int *)pReplyData = 0;
686 break;
687 case EFFECT_CMD_DISABLE:
688 if (pReplyData == NULL || *replySize != sizeof(int)) {
689 status = -EINVAL;
690 goto exit;
691 }
692 if (context->state != EFFECT_STATE_ACTIVE) {
693 status = -ENOSYS;
694 goto exit;
695 }
696 context->state = EFFECT_STATE_INITIALIZED;
697 if (context->ops.disable)
698 context->ops.disable(context);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800699 *(int *)pReplyData = 0;
700 break;
701 case EFFECT_CMD_GET_PARAM: {
702 if (pCmdData == NULL ||
703 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
704 pReplyData == NULL ||
705 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
706 sizeof(uint16_t))) {
707 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530708 ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800709 cmdSize, *replySize);
710 goto exit;
711 }
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700712 if (!context->offload_enabled && !context->hw_acc_enabled) {
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800713 status = -EINVAL;
714 goto exit;
715 }
716 effect_param_t *q = (effect_param_t *)pCmdData;
717 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
718 effect_param_t *p = (effect_param_t *)pReplyData;
719 if (context->ops.get_parameter)
720 context->ops.get_parameter(context, p, replySize);
721 } break;
722 case EFFECT_CMD_SET_PARAM: {
723 if (pCmdData == NULL ||
724 cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
725 sizeof(uint16_t)) ||
726 pReplyData == NULL || *replySize != sizeof(int32_t)) {
727 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530728 ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800729 cmdSize, *replySize);
730 goto exit;
731 }
732 *(int32_t *)pReplyData = 0;
733 effect_param_t *p = (effect_param_t *)pCmdData;
734 if (context->ops.set_parameter)
735 *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
736 *replySize);
737
738 } break;
739 case EFFECT_CMD_SET_DEVICE: {
740 uint32_t device;
741 ALOGV("\t EFFECT_CMD_SET_DEVICE start");
742 if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
743 status = -EINVAL;
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530744 ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800745 goto exit;
746 }
747 device = *(uint32_t *)pCmdData;
748 if (context->ops.set_device)
749 context->ops.set_device(context, device);
750 } break;
751 case EFFECT_CMD_SET_VOLUME:
752 case EFFECT_CMD_SET_AUDIO_MODE:
753 break;
754
755 case EFFECT_CMD_OFFLOAD: {
756 output_context_t *out_ctxt;
757
758 if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
759 || pReplyData == NULL || *replySize != sizeof(int)) {
Dhananjay Kumar574f3922014-03-25 17:41:44 +0530760 ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800761 status = -EINVAL;
762 break;
763 }
764
765 effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
766
767 ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
768 offload_param->isOffload, offload_param->ioHandle);
769
770 *(int *)pReplyData = 0;
771
772 context->offload_enabled = offload_param->isOffload;
773 if (context->out_handle == offload_param->ioHandle)
774 break;
775
776 out_ctxt = get_output(context->out_handle);
777 if (out_ctxt != NULL)
778 remove_effect_from_output(out_ctxt, context);
779
780 context->out_handle = offload_param->ioHandle;
781 out_ctxt = get_output(context->out_handle);
782 if (out_ctxt != NULL)
783 add_effect_to_output(out_ctxt, context);
784
785 } break;
786
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700787 case EFFECT_CMD_HW_ACC: {
788 ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
789 cmdSize, pCmdData, *replySize, pReplyData);
790 if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
791 || pReplyData == NULL || *replySize != sizeof(int)) {
792 return -EINVAL;
793 }
794 uint32_t value = *(uint32_t *)pCmdData;
795 if (context->ops.set_hw_acc_mode)
796 context->ops.set_hw_acc_mode(context, value);
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800797
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700798 context->hw_acc_enabled = (value > 0) ? true : false;
799 break;
800 }
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800801 default:
802 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
803 status = context->ops.command(context, cmdCode, cmdSize,
804 pCmdData, replySize, pReplyData);
805 else {
806 ALOGW("%s invalid command %d", __func__, cmdCode);
807 status = -EINVAL;
808 }
809 break;
810 }
811
812exit:
813 pthread_mutex_unlock(&lock);
814
815 return status;
816}
817
818/* Effect Control Interface Implementation: get_descriptor */
819int effect_get_descriptor(effect_handle_t self,
820 effect_descriptor_t *descriptor)
821{
822 effect_context_t *context = (effect_context_t *)self;
823
824 if (!effect_exists(context) || (descriptor == NULL))
825 return -EINVAL;
826
827 *descriptor = *context->desc;
828
829 return 0;
830}
831
wjiang50b81f42014-08-06 08:03:14 +0800832bool effect_is_active(effect_context_t * ctxt) {
833 return ctxt->state == EFFECT_STATE_ACTIVE;
834}
Subhash Chandra Bose Naripeddy3eedc002013-11-12 20:45:15 -0800835
836/* effect_handle_t interface implementation for offload effects */
837const struct effect_interface_s effect_interface = {
838 effect_process,
839 effect_command,
840 effect_get_descriptor,
841 NULL,
842};
843
844__attribute__ ((visibility ("default")))
845audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
846 tag : AUDIO_EFFECT_LIBRARY_TAG,
847 version : EFFECT_LIBRARY_API_VERSION,
848 name : "Offload Effects Bundle Library",
849 implementor : "The Linux Foundation",
850 create_effect : effect_lib_create,
851 release_effect : effect_lib_release,
852 get_descriptor : effect_lib_get_descriptor,
853};