blob: 9271dc7f6d942059b71df2763223755b996a6ebf [file] [log] [blame]
jasmine cha75fa6f02018-03-30 15:41:33 +08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "ma_listener"
18/*#define LOG_NDEBUG 0*/
19
20#include <stdlib.h>
21#include <dlfcn.h>
22#include <math.h>
23#include <pthread.h>
24#include <unistd.h>
25#include <cutils/list.h>
Weiyin Jiang2995f662019-04-17 14:25:12 +080026#include <log/log.h>
jasmine cha75fa6f02018-03-30 15:41:33 +080027#include <hardware/audio_effect.h>
28#include <audio-base.h>
29
30#define MA_FLAG ( EFFECT_FLAG_TYPE_INSERT | \
31 EFFECT_FLAG_VOLUME_IND | \
32 EFFECT_FLAG_DEVICE_IND | \
33 EFFECT_FLAG_OFFLOAD_SUPPORTED | \
34 EFFECT_FLAG_NO_PROCESS)
35
36#define PRINT_STREAM_TYPE(i) ALOGV("descriptor found and is of stream type %s ",\
37 i == AUDIO_STREAM_MUSIC ? "MUSIC": \
38 i == AUDIO_STREAM_RING ? "RING": \
39 i == AUDIO_STREAM_ALARM ? "ALARM": \
40 i == AUDIO_STREAM_VOICE_CALL ? "Voice_call": \
41 i == AUDIO_STREAM_SYSTEM ? "SYSTEM": \
42 i == AUDIO_STREAM_NOTIFICATION ? "Notification":\
43 "--INVALID--"); \
44
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080045
46#define MA_SET_STATE "audio_hw_send_qdsp_parameter"
jasmine cha75fa6f02018-03-30 15:41:33 +080047#define HAL_VENDOR_PATH "/vendor/lib/hw"
48
49enum {
50 MA_LISTENER_STATE_UNINITIALIZED,
51 MA_LISTENER_STATE_INITIALIZED,
52 MA_LISTENER_STATE_ACTIVE,
53};
54
55typedef struct ma_listener_context_s ma_listener_context_t;
56static const struct effect_interface_s effect_interface;
57
58struct ma_state {
59 float vol;
60 bool active;
61};
62
63static const audio_stream_type_t MIN_STREAM_TYPES = AUDIO_STREAM_VOICE_CALL;
64static const audio_stream_type_t MAX_STREAM_TYPES = AUDIO_STREAM_NOTIFICATION;
Aalique Grahame5ce7fbe2019-01-28 12:08:13 -080065static struct ma_state g_cur_state[MAX_STREAM_TYPES + 1];
jasmine cha75fa6f02018-03-30 15:41:33 +080066
67struct ma_listener_context_s {
68 const struct effect_interface_s *itfe;
69 struct listnode effect_list_node;
70 effect_config_t config;
71 const effect_descriptor_t *desc;
72 uint32_t stream_type;
73 uint32_t session_id;
74 uint32_t state;
75 uint32_t dev_id;
76 float left_vol;
77 float right_vol;
78};
79
80/* voice UUID: 4ece09c2-3728-11e8-a9f9-fc4dd4486b6d */
81const effect_descriptor_t ma_listener_voice_descriptor = {
82 { 0x46f924ed, 0x25c3, 0x4272, 0x85b1, { 0x41, 0x78, 0x3f, 0x0d, 0xc6, 0x38 } }, // type
83 { 0x4ece09c2, 0x3728, 0x11e8, 0xa9f9, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
84 EFFECT_CONTROL_API_VERSION,
85 MA_FLAG,
86 0, /* TODO */
87 1,
88 "MAXXAUDIO listener for Voice",
89 "The Android Open Source Project",
90};
91
92/* system UUID: 4f705ff6-3728-11e8-a0c6-fc4dd4486b6d */
93const effect_descriptor_t ma_listener_system_descriptor = {
94 { 0x8bd0f979, 0x5266, 0x4791, 0x9213, { 0x11, 0x3a, 0xbc, 0xf7, 0xd3, 0xdc } }, // type
95 { 0x4f705ff6, 0x3728, 0x11e8, 0xa0c6, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
96 EFFECT_CONTROL_API_VERSION,
97 MA_FLAG,
98 0, /* TODO */
99 1,
100 "MAXXAUDIO listener for System",
101 "The Android Open Source Project",
102};
103
104/* ring UUID: 4fd6e5c8-3728-11e8-8303-fc4dd4486b6d */
105const effect_descriptor_t ma_listener_ring_descriptor = {
106 { 0x5380692a, 0x872e, 0x4697, 0x8e38, { 0xcd, 0xd1, 0x09, 0xf6, 0xcb, 0x87 } }, // type
107 { 0x4fd6e5c8, 0x3728, 0x11e8, 0x8303, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
108 EFFECT_CONTROL_API_VERSION,
109 MA_FLAG,
110 0, /* TODO */
111 1,
112 "MAXXAUDIO listener for Ring",
113 "The Android Open Source Project",
114};
115/* music UUID: 5036194e-3728-11e8-8db9-fc4dd4486b6d */
116const effect_descriptor_t ma_listener_music_descriptor = {
117 { 0x3a3a19b2, 0x62b1, 0x4785, 0xb55e, { 0xb2, 0x8f, 0xd4, 0x1b, 0x83, 0x58 } }, // type
118 { 0x5036194e, 0x3728, 0x11e8, 0x8db9, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
119 EFFECT_CONTROL_API_VERSION,
120 MA_FLAG,
121 0, /* TODO */
122 1,
123 "MAXXAUDIO listener for Music",
124 "The Android Open Source Project",
125};
126/* alarm UUID: 50b9f084-3728-11e8-9225-fc4dd4486b6d */
127const effect_descriptor_t ma_listener_alarm_descriptor = {
128 { 0x8d08d30f, 0xb4c3, 0x4600, 0x8f99, { 0xfc, 0xbb, 0x5d, 0x05, 0x8b, 0x60 } }, // type
129 { 0x50b9f084, 0x3728, 0x11e8, 0x9225, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
130 EFFECT_CONTROL_API_VERSION,
131 MA_FLAG,
132 0, /* TODO */
133 1,
134 "MAXXAUDIO listener for Alarm",
135 "The Android Open Source Project",
136};
137/* notification UUID: 50fe4d56-3728-11e8-ac73-fc4dd4486b6d */
138const effect_descriptor_t ma_listener_notification_descriptor = {
139 { 0x513d09f5, 0xae7f, 0x483d, 0x922a, { 0x5c, 0x72, 0xc5, 0xe5, 0x68, 0x4c } }, // type
140 { 0x50fe4d56, 0x3728, 0x11e8, 0xac73, { 0xfc, 0x4d, 0xd4, 0x48, 0x6b, 0x6d } }, // uuid
141 EFFECT_CONTROL_API_VERSION,
142 MA_FLAG,
143 0, /* TODO */
144 1,
145 "MAXXAUDIO listener for Notification",
146 "The Android Open Source Project",
147};
148
149static const effect_descriptor_t *descriptors[] = {
150 &ma_listener_voice_descriptor,
151 &ma_listener_system_descriptor,
152 &ma_listener_ring_descriptor,
153 &ma_listener_music_descriptor,
154 &ma_listener_alarm_descriptor,
155 &ma_listener_notification_descriptor,
156 NULL,
157};
158
159/* function of sending state to HAL */
160static bool (*send_ma_parameter)(int, float, bool);
161
162static int init_state = -1;
163pthread_once_t once = PTHREAD_ONCE_INIT;
164
165struct listnode ma_effect_list;
166pthread_mutex_t ma_listner_init_lock;
167
168/*
169 * Local functions
170 */
171static inline bool valid_dev_in_context(struct ma_listener_context_s *context)
172{
173 /* check device */
174 if ((context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) ||
175 (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
176 /* TODO: it should be dynamic if hybird split A2SP is implemented. */
177 (context->dev_id & AUDIO_DEVICE_OUT_ALL_A2DP) ||
178 (context->dev_id & AUDIO_DEVICE_OUT_ALL_USB)) {
179 return true;
180 }
181
182 return false;
183}
184
185static void check_and_set_ma_parameter(uint32_t stream_type)
186{
187 bool active = false;
188 float temp_vol = 0.0;
189 float max_vol = 0.0;
190 struct listnode *node = NULL;
191 ma_listener_context_t *context = NULL;
192
193 ALOGV("%s .. called ..", __func__);
194 // get maximum volume for the active session with same strem type
195 list_for_each(node, &ma_effect_list) {
196 context = node_to_item(node, struct ma_listener_context_s, effect_list_node);
197 if (context->stream_type == stream_type &&
198 valid_dev_in_context(context)) {
199 if (context->state == MA_LISTENER_STATE_ACTIVE) {
200 active = true;
201 temp_vol = fmax(context->left_vol, context->right_vol);
202 if (max_vol < temp_vol)
203 max_vol = temp_vol;
204 ALOGV("%s: check session(%d) volume(%f) for stream(%d)",
205 __func__, context->session_id, temp_vol, stream_type);
206 }
207 }
208 }
209
210 // check volume
211 if (max_vol < 0.0) max_vol = 0;
212 else if (max_vol > 1.0) max_vol = 1.0;
213
214 if (send_ma_parameter != NULL &&
Aalique Grahame5ce7fbe2019-01-28 12:08:13 -0800215 stream_type >= MIN_STREAM_TYPES &&
216 stream_type <= MAX_STREAM_TYPES &&
jasmine cha75fa6f02018-03-30 15:41:33 +0800217 (g_cur_state[stream_type].vol != max_vol ||
218 g_cur_state[stream_type].active != active)) {
219
220 ALOGV("%s: set stream(%d) active(%s->%s) volume(%f->%f)",
221 __func__, stream_type,
222 g_cur_state[stream_type].active ? "T" : "F", active ? "T" : "F",
223 g_cur_state[stream_type].vol, max_vol);
224
225 // update changes to hal
226 send_ma_parameter(stream_type, max_vol, active);
227 g_cur_state[stream_type].vol = max_vol;
228 g_cur_state[stream_type].active = active;
229 }
230
231 return;
232}
233
234/*
235 * Effect Control Interface Implementation
236 */
237static int ma_effect_command(effect_handle_t self,
238 uint32_t cmd_code, uint32_t cmd_size,
239 void *p_cmd_data, uint32_t *reply_size,
240 void *p_reply_data)
241{
242 ma_listener_context_t *context = (ma_listener_context_t *)self;
243 int status = 0;
244
245 ALOGV("%s .. called ..", __func__);
246 pthread_mutex_lock(&ma_listner_init_lock);
247
248 if (context == NULL || context->state == MA_LISTENER_STATE_UNINITIALIZED) {
249 ALOGE("%s: %s is NULL", __func__, (context == NULL) ?
250 "context" : "context->state");
251 status = -EINVAL;
252 goto exit;
253 }
254
255 switch (cmd_code) {
256 case EFFECT_CMD_INIT:
257 ALOGV("%s :: cmd called EFFECT_CMD_INIT", __func__);
258 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
259 ALOGE("%s: EFFECT_CMD_INIT: %s, sending -EINVAL", __func__,
260 (p_reply_data == NULL) ? "p_reply_data is NULL" :
261 "*reply_size != sizeof(int)");
262 status = -EINVAL;
263 goto exit;
264 }
265 *(int *)p_reply_data = 0;
266 break;
267
268 case EFFECT_CMD_SET_CONFIG:
269 ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
270 if (p_cmd_data == NULL || cmd_size != sizeof(effect_config_t)
271 || p_reply_data == NULL || reply_size == NULL || *reply_size != sizeof(int)) {
272 status = -EINVAL;
273 goto exit;
274 }
275 context->config = *(effect_config_t *)p_cmd_data;
276 *(int *)p_reply_data = 0;
277 break;
278
279 case EFFECT_CMD_GET_CONFIG:
280 ALOGV("%s :: cmd called EFFECT_CMD_GET_CONFIG", __func__);
281 break;
282
283 case EFFECT_CMD_RESET:
284 ALOGV("%s :: cmd called EFFECT_CMD_RESET", __func__);
285 break;
286
287 case EFFECT_CMD_SET_AUDIO_MODE:
288 ALOGV("%s :: cmd called EFFECT_CMD_SET_AUDIO_MODE", __func__);
289 break;
290
291 case EFFECT_CMD_OFFLOAD:
292 ALOGV("%s :: cmd called EFFECT_CMD_OFFLOAD", __func__);
293 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
294 ALOGE("%s: EFFECT_CMD_OFFLOAD: %s, sending -EINVAL", __func__,
295 (p_reply_data == NULL) ? "p_reply_data is NULL" :
296 "*reply_size != sizeof(int)");
297 status = -EINVAL;
298 goto exit;
299 }
300 *(int *)p_reply_data = 0;
301 break;
302
303 case EFFECT_CMD_ENABLE:
304 ALOGV("%s :: cmd called EFFECT_CMD_ENABLE", __func__);
305 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
306 ALOGE("%s: EFFECT_CMD_ENABLE: %s, sending -EINVAL", __func__,
307 (p_reply_data == NULL) ? "p_reply_data is NULL" :
308 "*reply_size != sizeof(int)");
309 status = -EINVAL;
310 goto exit;
311 }
312
313 if (context->state != MA_LISTENER_STATE_INITIALIZED) {
314 ALOGE("%s: EFFECT_CMD_ENABLE : state not INITIALIZED", __func__);
315 status = -ENOSYS;
316 goto exit;
317 }
318
319 context->state = MA_LISTENER_STATE_ACTIVE;
320 *(int *)p_reply_data = 0;
321
322 // After changing the state and if device is valid
323 // check and send state
324 if (valid_dev_in_context(context)) {
325 check_and_set_ma_parameter(context->stream_type);
326 }
327
328 break;
329
330 case EFFECT_CMD_DISABLE:
331 ALOGV("%s :: cmd called EFFECT_CMD_DISABLE", __func__);
332 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
333 ALOGE("%s: EFFECT_CMD_DISABLE: %s, sending -EINVAL", __func__,
334 (p_reply_data == NULL) ? "p_reply_data is NULL" :
335 "*reply_size != sizeof(int)");
336 status = -EINVAL;
337 goto exit;
338 }
339
340 if (context->state != MA_LISTENER_STATE_ACTIVE) {
341 ALOGE("%s: EFFECT_CMD_ENABLE : state not ACTIVE", __func__);
342 status = -ENOSYS;
343 goto exit;
344 }
345
346 context->state = MA_LISTENER_STATE_INITIALIZED;
347 *(int *)p_reply_data = 0;
348
349 // After changing the state and if device is valid
350 // check and send state
351 if (valid_dev_in_context(context)) {
352 check_and_set_ma_parameter(context->stream_type);
353 }
354
355 break;
356
357 case EFFECT_CMD_GET_PARAM:
358 ALOGV("%s :: cmd called EFFECT_CMD_GET_PARAM", __func__);
359 break;
360
361 case EFFECT_CMD_SET_PARAM:
362 ALOGV("%s :: cmd called EFFECT_CMD_SET_PARAM", __func__);
363 break;
364
365 case EFFECT_CMD_SET_DEVICE:
366 {
367 uint32_t new_device;
368
369 if (p_cmd_data == NULL) {
370 ALOGE("%s: EFFECT_CMD_SET_DEVICE: cmd data NULL", __func__);
371 status = -EINVAL;
372 goto exit;
373 }
374
375 new_device = *(uint32_t *)p_cmd_data;
376 ALOGV("%s :: EFFECT_CMD_SET_DEVICE: (current/new) device (0x%x / 0x%x)",
377 __func__, context->dev_id, new_device);
378
379 context->dev_id = new_device;
380 // After changing the state and if device is valid
381 // check and send parameter
382 if (valid_dev_in_context(context)) {
383 check_and_set_ma_parameter(context->stream_type);
384 }
385 }
386 break;
387
388 case EFFECT_CMD_SET_VOLUME:
389 {
390 float left_vol = 0, right_vol = 0;
391
392 ALOGV("cmd called EFFECT_CMD_SET_VOLUME");
393 if (p_cmd_data == NULL || cmd_size != 2 * sizeof(uint32_t)) {
394 ALOGE("%s: EFFECT_CMD_SET_VOLUME: %s", __func__, (p_cmd_data == NULL) ?
395 "p_cmd_data is NULL" : "cmd_size issue");
396 status = -EINVAL;
397 goto exit;
398 }
399
400 left_vol = (float)(*(uint32_t *)p_cmd_data) / (1 << 24);
401 right_vol = (float)(*((uint32_t *)p_cmd_data + 1)) / (1 << 24);
402 ALOGV("Current Volume (%f / %f ) new Volume (%f / %f)", context->left_vol,
403 context->right_vol, left_vol, right_vol);
404
405 context->left_vol = left_vol;
406 context->right_vol = right_vol;
407
408 // After changing the state and if device is valid
409 // check and send volume
410 if (valid_dev_in_context(context)) {
411 check_and_set_ma_parameter(context->stream_type);
412 }
413 }
414 break;
415
416 default:
417 ALOGW("%s: unknow command %d", __func__, cmd_code);
418 status = -ENOSYS;
419 break;
420 }
421
422exit:
423 pthread_mutex_unlock(&ma_listner_init_lock);
424 return status;
425}
426
427/* Effect Control Interface Implementation: get_descriptor */
428static int ma_effect_get_descriptor(effect_handle_t self,
429 effect_descriptor_t *descriptor)
430{
431 ma_listener_context_t *context = (ma_listener_context_t *)self;
432 ALOGV("%s .. called ..", __func__);
433
434 if (descriptor == NULL) {
435 ALOGE("%s: descriptor is NULL", __func__);
436 return -EINVAL;
437 }
438
439 *descriptor = *context->desc;
440 return 0;
441}
442
443static void init_once()
444{
445 int ret = 0;
446 void *handle = NULL;
447 char lib_path[PATH_MAX] = {0};
448
449 if (init_state == 0) {
450 ALOGD("%s : already init ... do nothing", __func__);
451 return;
452 }
453
454 ALOGV("%s .. called ..", __func__);
455
456 send_ma_parameter = NULL;
457
458 ret = snprintf(lib_path, PATH_MAX, "%s/%s", HAL_VENDOR_PATH, HAL_LIB_NAME);
459 if (ret < 0) {
460 ALOGE("%s: snprintf failed for lib %s ret %d", __func__, HAL_LIB_NAME, ret);
461 return;
462 }
463
464 handle = dlopen(lib_path, RTLD_NOW);
465 if (handle == NULL) {
466 ALOGE("%s: DLOPEN failed for %s", __func__, HAL_LIB_NAME);
467 return;
468 } else {
469 ALOGV("%s: DLOPEN successful for %s", __func__, HAL_LIB_NAME);
470 send_ma_parameter = (bool (*)(int, float, bool))dlsym(handle, MA_SET_STATE);
471
472 if (!send_ma_parameter) {
473 ALOGE("%s: dlsym error %s for send_ma_parameter", __func__, dlerror());
474 return;
475 }
476 }
477
478 pthread_mutex_init(&ma_listner_init_lock, NULL);
479 list_init(&ma_effect_list);
480 init_state = 0;
481
482 ALOGD("%s: exit ret %d", __func__, init_state);
483}
484
485static bool lib_init()
486{
487 pthread_once(&once, init_once);
488 return init_state;
489}
490
491static int ma_prc_lib_create(const effect_uuid_t *uuid,
492 int32_t session_id,
493 int32_t io_id __unused,
494 effect_handle_t *p_handle)
495{
496 int itt = 0;
497 ma_listener_context_t *context = NULL;
498
499 ALOGV("%s .. called ..", __func__);
500
501 if (lib_init() != 0) {
502 return init_state;
503 }
504
505 if (p_handle == NULL || uuid == NULL) {
506 ALOGE("%s: %s is NULL", __func__, (p_handle == NULL) ? "p_handle" : "uuid");
507 return -EINVAL;
508 }
509
510 context = (ma_listener_context_t *)calloc(1, sizeof(ma_listener_context_t));
511
512 if (context == NULL) {
513 ALOGE("%s: failed to allocate for context .. oops !!", __func__);
514 return -EINVAL;
515 }
516
517 // check if UUID is supported
518 for (itt = 0; descriptors[itt] != NULL; itt++) {
519 if (memcmp(uuid, &descriptors[itt]->uuid, sizeof(effect_uuid_t)) == 0) {
520 context->desc = descriptors[itt];
521 context->stream_type = itt;
522 PRINT_STREAM_TYPE(itt)
523 break;
524 }
525 }
526
527 if (descriptors[itt] == NULL) {
528 ALOGE("%s .. couldnt find passed uuid, something wrong", __func__);
529 free(context);
530 return -EINVAL;
531 }
532
533 ALOGV("%s CREATED_CONTEXT %p", __func__, context);
534
535 context->itfe = &effect_interface;
536 context->state = MA_LISTENER_STATE_INITIALIZED;
537 context->dev_id = AUDIO_DEVICE_NONE;
538 context->session_id = session_id;
539
540 // Add this to master list
541 pthread_mutex_lock(&ma_listner_init_lock);
542 list_add_tail(&ma_effect_list, &context->effect_list_node);
543
544 pthread_mutex_unlock(&ma_listner_init_lock);
545
546 *p_handle = (effect_handle_t)context;
547 return 0;
548}
549
550static int ma_prc_lib_release(effect_handle_t handle)
551{
552 struct listnode *node, *temp_node_next;
553 ma_listener_context_t *context = NULL;
554 ma_listener_context_t *recv_contex = (ma_listener_context_t *)handle;
555 int status = -EINVAL;
556
557 ALOGV("%s: context %p", __func__, handle);
558
559 if (recv_contex == NULL) {
560 return status;
561 }
562
563 pthread_mutex_lock(&ma_listner_init_lock);
564 // check if the handle/context provided is valid
565 list_for_each_safe(node, temp_node_next, &ma_effect_list) {
566 context = node_to_item(node, struct ma_listener_context_s, effect_list_node);
567 if (context == recv_contex) {
568 ALOGV("--- Found something to remove ---");
569 list_remove(node);
570 PRINT_STREAM_TYPE(context->stream_type);
571 free(context);
572 status = 0;
573 }
574 }
575
576 if (status != 0) {
577 ALOGE("%s: nothing to remove, ret %d", __func__, status);
578 pthread_mutex_unlock(&ma_listner_init_lock);
579 return status;
580 }
581
582 pthread_mutex_unlock(&ma_listner_init_lock);
583 return status;
584}
585
586static int ma_prc_lib_get_descriptor(const effect_uuid_t *uuid,
587 effect_descriptor_t *descriptor)
588{
589 int i = 0;
590
591 ALOGV("%s .. called ..", __func__);
592 if (lib_init() != 0) {
593 return init_state;
594 }
595
596 if (descriptor == NULL || uuid == NULL) {
597 ALOGE("%s: %s is NULL", __func__, (descriptor == NULL) ? "descriptor" : "uuid");
598 return -EINVAL;
599 }
600
601 for (i = 0; descriptors[i] != NULL; i++) {
602 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
603 *descriptor = *descriptors[i];
604 return 0;
605 }
606 }
607
608 ALOGE("%s: couldnt found uuid passed, oops", __func__);
609 return -EINVAL;
610}
611
612
613/* effect_handle_t interface implementation for volume listener effect */
614static const struct effect_interface_s effect_interface = {
615 NULL,
616 ma_effect_command,
617 ma_effect_get_descriptor,
618 NULL,
619};
620
621__attribute__((visibility("default")))
622audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
623 .tag = AUDIO_EFFECT_LIBRARY_TAG,
624 .version = EFFECT_LIBRARY_API_VERSION,
625 .name = "MAXXAUDIO Listener Effect Library",
626 .implementor = "The Android Open Source Project",
627 .create_effect = ma_prc_lib_create,
628 .release_effect = ma_prc_lib_release,
629 .get_descriptor = ma_prc_lib_get_descriptor,
630};