1 /*
2 * Copyright (C) 2015 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 "volume_listener"
18 //#define LOG_NDEBUG 0
19 #include <stdlib.h>
20 #include <dlfcn.h>
21
22 #include <cutils/list.h>
23 #include <cutils/log.h>
24 #include <hardware/audio_effect.h>
25 #include <cutils/properties.h>
26 #include <platform_api.h>
27
28 #define PRIMARY_HAL_PATH XSTR(LIB_AUDIO_HAL)
29 #define XSTR(x) STR(x)
30 #define STR(x) #x
31
32 #define VOL_FLAG ( EFFECT_FLAG_TYPE_INSERT | \
33 EFFECT_FLAG_VOLUME_IND | \
34 EFFECT_FLAG_DEVICE_IND | \
35 EFFECT_FLAG_OFFLOAD_SUPPORTED)
36
37 #define PRINT_STREAM_TYPE(i) ALOGV("descriptor found and is of stream type %s ",\
38 i == MUSIC?"MUSIC": \
39 i == RING?"RING": \
40 i == ALARM?"ALARM": \
41 i == VOICE_CALL?"Voice_call": \
42 i == NOTIFICATION?"Notification":\
43 "--INVALID--"); \
44
45 #define MAX_GAIN_LEVELS 5
46
47 #define AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION "audio_hw_send_gain_dep_calibration"
48 #define AHAL_GAIN_GET_MAPPING_TABLE "audio_hw_get_gain_level_mapping"
49 #define DEFAULT_CAL_STEP 0
50
51 enum {
52 VOL_LISTENER_STATE_UNINITIALIZED,
53 VOL_LISTENER_STATE_INITIALIZED,
54 VOL_LISTENER_STATE_ACTIVE,
55 };
56
57 typedef struct vol_listener_context_s vol_listener_context_t;
58 static const struct effect_interface_s effect_interface;
59
60 /* flag to avoid multiple initialization */
61 static bool initialized = false;
62
63 /* current gain dep cal level that was pushed succesfully */
64 static int current_gain_dep_cal_level = -1;
65
66 enum STREAM_TYPE {
67 MUSIC,
68 RING,
69 ALARM,
70 VOICE_CALL,
71 NOTIFICATION,
72 MAX_STREAM_TYPES,
73 };
74
75 struct vol_listener_context_s {
76 const struct effect_interface_s *itfe;
77 struct listnode effect_list_node;
78 effect_config_t config;
79 const effect_descriptor_t *desc;
80 uint32_t stream_type;
81 uint32_t session_id;
82 uint32_t state;
83 uint32_t dev_id;
84 float left_vol;
85 float right_vol;
86 };
87
88 /* volume listener, music UUID: 08b8b058-0590-11e5-ac71-0025b32654a0 */
89 const effect_descriptor_t vol_listener_music_descriptor = {
90 { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
91 { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
92 EFFECT_CONTROL_API_VERSION,
93 VOL_FLAG,
94 0, /* TODO */
95 1,
96 "Volume listener for Music",
97 "Qualcomm Technologies Inc.",
98 };
99
100 /* volume listener, ring UUID: 0956df94-0590-11e5-bdbe-0025b32654a0 */
101 const effect_descriptor_t vol_listener_ring_descriptor = {
102 { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
103 { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
104 EFFECT_CONTROL_API_VERSION,
105 VOL_FLAG,
106 0, /* TODO */
107 1,
108 "Volume listener for ring",
109 "Qualcomm Technologies Inc",
110 };
111
112 /* volume listener, alarm UUID: 09f303e2-0590-11e5-8fdb-0025b32654a0 */
113 const effect_descriptor_t vol_listener_alarm_descriptor = {
114 { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
115 { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
116 EFFECT_CONTROL_API_VERSION,
117 VOL_FLAG,
118 0, /* TODO */
119 1,
120 "Volume listener for alarm",
121 "Qualcomm Technologies Inc",
122 };
123
124 /* volume listener, voice call UUID: 0ace5c08-0590-11e5-ae9e-0025b32654a0 */
125 const effect_descriptor_t vol_listener_voice_call_descriptor = {
126 { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
127 { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
128 EFFECT_CONTROL_API_VERSION,
129 VOL_FLAG,
130 0, /* TODO */
131 1,
132 "Volume listener for voice call",
133 "Qualcomm Technologies Inc",
134 };
135
136 /* volume listener, notification UUID: 0b776dde-0590-11e5-81ba-0025b32654a0 */
137 const effect_descriptor_t vol_listener_notification_descriptor = {
138 { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
139 { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
140 EFFECT_CONTROL_API_VERSION,
141 VOL_FLAG,
142 0, /* TODO */
143 1,
144 "Volume listener for notification",
145 "Qualcomm Technologies Inc",
146 };
147
148 static int total_volume_cal_step = MAX_GAIN_LEVELS;
149
150 // using gain level for non-drc volume curve
151 struct amp_db_and_gain_table volume_curve_gain_mapping_table[MAX_VOLUME_CAL_STEPS] =
152 {
153 /* Level 0 in the calibration database contains default calibration */
154 { 0.001774, -55, 5 },
155 { 0.501187, -6, 4 },
156 { 0.630957, -4, 3 },
157 { 0.794328, -2, 2 },
158 { 1.0, 0, 1 },
159 { 0, 0, -1 },
160 { 0, 0, -1 },
161 { 0, 0, -1 },
162 { 0, 0, -1 },
163 { 0, 0, -1 },
164 { 0, 0, -1 },
165 { 0, 0, -1 },
166 { 0, 0, -1 },
167 { 0, 0, -1 },
168 { 0, 0, -1 }
169 };
170
171 static const effect_descriptor_t *descriptors[] = {
172 &vol_listener_music_descriptor,
173 &vol_listener_ring_descriptor,
174 &vol_listener_alarm_descriptor,
175 &vol_listener_voice_call_descriptor,
176 &vol_listener_notification_descriptor,
177 NULL,
178 };
179
180 pthread_once_t once = PTHREAD_ONCE_INIT;
181 /* flag to indicate if init was success */
182 static int init_status;
183
184 /* current volume level for which gain dep cal level was selected */
185 static float current_vol = 0.0;
186
187 /* HAL interface to send calibration */
188 static bool (*send_gain_dep_cal)(int);
189
190 static int (*get_custom_gain_table)(struct amp_db_and_gain_table *, int);
191
192 /* if dumping allowed */
193 static bool dumping_enabled = false;
194
195 /* list of created effects. */
196 struct listnode vol_effect_list;
197
198 /* lock must be held when modifying or accessing created_effects_list */
199 pthread_mutex_t vol_listner_init_lock;
200
201 /*
202 * Local functions
203 */
dump_list_l()204 static void dump_list_l()
205 {
206 struct listnode *node;
207 vol_listener_context_t *context;
208
209 ALOGW("DUMP_START :: ===========");
210
211 list_for_each(node, &vol_effect_list) {
212 context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
213 // dump stream_type / Device / session_id / left / righ volume
214 ALOGW("%s: streamType [%s] Device [%d] state [%d] sessionID [%d] volume (L/R) [%f / %f] ",
215 __func__,
216 context->stream_type == MUSIC ? "MUSIC" :
217 context->stream_type == RING ? "RING" :
218 context->stream_type == ALARM ? "ALARM" :
219 context->stream_type == VOICE_CALL ? "VOICE_CALL" :
220 context->stream_type == NOTIFICATION ? "NOTIFICATION" : "--INVALID--",
221 context->dev_id, context->state, context->session_id, context->left_vol,context->right_vol);
222 }
223
224 ALOGW("DUMP_END :: ===========");
225 }
226
check_and_set_gain_dep_cal()227 static void check_and_set_gain_dep_cal()
228 {
229 // iterate through list and make decision to set new gain dep cal level for speaker device
230 // 1. find all usecase active on speaker
231 // 2. find average of left and right for each usecase
232 // 3. find the highest of all the active usecase
233 // 4. if new value is different than the current value then load new calibration
234
235 struct listnode *node = NULL;
236 float new_vol = -1.0;
237 int max_level = 0;
238 vol_listener_context_t *context = NULL;
239 if (dumping_enabled) {
240 dump_list_l();
241 }
242
243 ALOGV("%s ==> Start ...", __func__);
244
245 // select the highest volume on speaker device
246 list_for_each(node, &vol_effect_list) {
247 context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
248 if ((context->state == VOL_LISTENER_STATE_ACTIVE) &&
249 (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) &&
250 (new_vol < (context->left_vol + context->right_vol) / 2)) {
251 new_vol = (context->left_vol + context->right_vol) / 2;
252 }
253 }
254
255 if (new_vol != current_vol) {
256 ALOGV("%s:: Change in decision :: current volume is %f new volume is %f",
257 __func__, current_vol, new_vol);
258
259 if (send_gain_dep_cal != NULL) {
260 // send Gain dep cal level
261 int gain_dep_cal_level = -1;
262
263 if (new_vol >= 1 && total_volume_cal_step > 0) { // max amplitude, use highest DRC level
264 gain_dep_cal_level = volume_curve_gain_mapping_table[total_volume_cal_step - 1].level;
265 } else if (new_vol == -1) {
266 gain_dep_cal_level = DEFAULT_CAL_STEP;
267 } else if (new_vol == 0) {
268 gain_dep_cal_level = volume_curve_gain_mapping_table[0].level;
269 } else {
270 for (max_level = 0; max_level + 1 < total_volume_cal_step; max_level++) {
271 if (new_vol < volume_curve_gain_mapping_table[max_level + 1].amp &&
272 new_vol >= volume_curve_gain_mapping_table[max_level].amp) {
273 gain_dep_cal_level = volume_curve_gain_mapping_table[max_level].level;
274 ALOGV("%s: volume(%f), gain dep cal selcetd %d ",
275 __func__, current_vol, gain_dep_cal_level);
276 break;
277 }
278 }
279 }
280
281 // check here if previous gain dep cal level was not same
282 if (gain_dep_cal_level != -1) {
283 if (gain_dep_cal_level != current_gain_dep_cal_level) {
284 // decision made .. send new level now
285 if (!send_gain_dep_cal(gain_dep_cal_level)) {
286 ALOGE("%s: Failed to set gain dep cal level", __func__);
287 } else {
288 // Success in setting the gain dep cal level, store new level and Volume
289 if (dumping_enabled) {
290 ALOGW("%s: (old/new) Volume (%f/%f) (old/new) level (%d/%d)",
291 __func__, current_vol, new_vol, current_gain_dep_cal_level,
292 gain_dep_cal_level);
293 } else {
294 ALOGV("%s: Change in Cal::(old/new) Volume (%f/%f) (old/new) level (%d/%d)",
295 __func__, current_vol, new_vol, current_gain_dep_cal_level,
296 gain_dep_cal_level);
297 }
298 current_gain_dep_cal_level = gain_dep_cal_level;
299 current_vol = new_vol;
300 }
301 } else {
302 if (dumping_enabled) {
303 ALOGW("%s: volume changed but gain dep cal level is still the same",
304 __func__);
305 } else {
306 ALOGV("%s: volume changed but gain dep cal level is still the same",
307 __func__);
308 }
309 }
310 } else {
311 ALOGW("%s: Failed to find gain dep cal level for volume %f", __func__, new_vol);
312 }
313 } else {
314 ALOGE("%s: not able to send calibration, NULL function pointer",
315 __func__);
316 }
317 } else {
318 ALOGV("%s:: volume not changed, stick to same config ..... ", __func__);
319 }
320
321 ALOGV("check_and_set_gain_dep_cal ==> End ");
322 }
323
324 /*
325 * Effect Control Interface Implementation
326 */
327
clamp16(int32_t sample)328 static inline int16_t clamp16(int32_t sample)
329 {
330 if ((sample>>15) ^ (sample>>31))
331 sample = 0x7FFF ^ (sample>>31);
332 return sample;
333 }
334
vol_effect_process(effect_handle_t self,audio_buffer_t * in_buffer,audio_buffer_t * out_buffer)335 static int vol_effect_process(effect_handle_t self,
336 audio_buffer_t *in_buffer,
337 audio_buffer_t *out_buffer)
338 {
339 int status = 0;
340 ALOGV("%s Called ", __func__);
341
342 vol_listener_context_t *context = (vol_listener_context_t *)self;
343 pthread_mutex_lock(&vol_listner_init_lock);
344
345 if (context->state != VOL_LISTENER_STATE_ACTIVE) {
346 ALOGE("%s: state is not active .. return error", __func__);
347 status = -EINVAL;
348 goto exit;
349 }
350
351 // calculation based on channel count 2
352 if (in_buffer->raw != out_buffer->raw) {
353 if (context->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
354 size_t i;
355 for (i = 0; i < out_buffer->frameCount*2; i++) {
356 out_buffer->s16[i] = clamp16(out_buffer->s16[i] + in_buffer->s16[i]);
357 }
358 } else {
359 memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
360 }
361
362 }
363
364 exit:
365 pthread_mutex_unlock(&vol_listner_init_lock);
366 return status;
367 }
368
369
vol_effect_command(effect_handle_t self,uint32_t cmd_code,uint32_t cmd_size,void * p_cmd_data,uint32_t * reply_size,void * p_reply_data)370 static int vol_effect_command(effect_handle_t self,
371 uint32_t cmd_code, uint32_t cmd_size,
372 void *p_cmd_data, uint32_t *reply_size,
373 void *p_reply_data)
374 {
375 vol_listener_context_t *context = (vol_listener_context_t *)self;
376 int status = 0;
377
378 ALOGV("%s Called ", __func__);
379 pthread_mutex_lock(&vol_listner_init_lock);
380
381 if (context == NULL || context->state == VOL_LISTENER_STATE_UNINITIALIZED) {
382 ALOGE("%s: %s is NULL", __func__, (context == NULL) ?
383 "context" : "context->state");
384 status = -EINVAL;
385 goto exit;
386 }
387
388 switch (cmd_code) {
389 case EFFECT_CMD_INIT:
390 ALOGV("%s :: cmd called EFFECT_CMD_INIT", __func__);
391 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
392 ALOGE("%s: EFFECT_CMD_INIT: %s, sending -EINVAL", __func__,
393 (p_reply_data == NULL) ? "p_reply_data is NULL" :
394 "*reply_size != sizeof(int)");
395 return -EINVAL;
396 }
397 *(int *)p_reply_data = 0;
398 break;
399
400 case EFFECT_CMD_SET_CONFIG:
401 ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
402 if (p_cmd_data == NULL || cmd_size != sizeof(effect_config_t)
403 || p_reply_data == NULL || reply_size == NULL || *reply_size != sizeof(int)) {
404 return -EINVAL;
405 }
406 context->config = *(effect_config_t *)p_cmd_data;
407 *(int *)p_reply_data = 0;
408 break;
409
410 case EFFECT_CMD_GET_CONFIG:
411 ALOGV("%s :: cmd called EFFECT_CMD_GET_CONFIG", __func__);
412 break;
413
414 case EFFECT_CMD_RESET:
415 ALOGV("%s :: cmd called EFFECT_CMD_RESET", __func__);
416 break;
417
418 case EFFECT_CMD_SET_AUDIO_MODE:
419 ALOGV("%s :: cmd called EFFECT_CMD_SET_AUDIO_MODE", __func__);
420 break;
421
422 case EFFECT_CMD_OFFLOAD:
423 ALOGV("%s :: cmd called EFFECT_CMD_OFFLOAD", __func__);
424 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
425 ALOGE("%s: EFFECT_CMD_OFFLOAD: %s, sending -EINVAL", __func__,
426 (p_reply_data == NULL) ? "p_reply_data is NULL" :
427 "*reply_size != sizeof(int)");
428 return -EINVAL;
429 }
430 *(int *)p_reply_data = 0;
431 break;
432
433 case EFFECT_CMD_ENABLE:
434 ALOGV("%s :: cmd called EFFECT_CMD_ENABLE", __func__);
435 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
436 ALOGE("%s: EFFECT_CMD_ENABLE: %s, sending -EINVAL", __func__,
437 (p_reply_data == NULL) ? "p_reply_data is NULL" :
438 "*reply_size != sizeof(int)");
439 status = -EINVAL;
440 goto exit;
441 }
442
443 if (context->state != VOL_LISTENER_STATE_INITIALIZED) {
444 ALOGE("%s: EFFECT_CMD_ENABLE : state not INITIALIZED", __func__);
445 status = -ENOSYS;
446 goto exit;
447 }
448
449 context->state = VOL_LISTENER_STATE_ACTIVE;
450 *(int *)p_reply_data = 0;
451
452 // After changing the state and if device is speaker
453 // recalculate gain dep cal level
454 if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
455 check_and_set_gain_dep_cal();
456 }
457
458 break;
459
460 case EFFECT_CMD_DISABLE:
461 ALOGV("%s :: cmd called EFFECT_CMD_DISABLE", __func__);
462 if (p_reply_data == NULL || *reply_size != sizeof(int)) {
463 ALOGE("%s: EFFECT_CMD_DISABLE: %s, sending -EINVAL", __func__,
464 (p_reply_data == NULL) ? "p_reply_data is NULL" :
465 "*reply_size != sizeof(int)");
466 status = -EINVAL;
467 goto exit;
468 }
469
470 if (context->state != VOL_LISTENER_STATE_ACTIVE) {
471 ALOGE("%s: EFFECT_CMD_ENABLE : state not ACTIVE", __func__);
472 status = -ENOSYS;
473 goto exit;
474 }
475
476 context->state = VOL_LISTENER_STATE_INITIALIZED;
477 *(int *)p_reply_data = 0;
478
479 // After changing the state and if device is speaker
480 // recalculate gain dep cal level
481 if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
482 check_and_set_gain_dep_cal();
483 }
484
485 break;
486
487 case EFFECT_CMD_GET_PARAM:
488 ALOGV("%s :: cmd called EFFECT_CMD_GET_PARAM", __func__);
489 break;
490
491 case EFFECT_CMD_SET_PARAM:
492 ALOGV("%s :: cmd called EFFECT_CMD_SET_PARAM", __func__);
493 break;
494
495 case EFFECT_CMD_SET_DEVICE:
496 {
497 uint32_t new_device;
498 bool recompute_gain_dep_cal_Level = false;
499 ALOGV("cmd called EFFECT_CMD_SET_DEVICE ");
500
501 if (p_cmd_data == NULL) {
502 ALOGE("%s: EFFECT_CMD_SET_DEVICE: cmd data NULL", __func__);
503 status = -EINVAL;
504 goto exit;
505 }
506
507 new_device = *(uint32_t *)p_cmd_data;
508 ALOGV("%s :: EFFECT_CMD_SET_DEVICE: (current/new) device (0x%x / 0x%x)",
509 __func__, context->dev_id, new_device);
510
511 // check if old or new device is speaker
512 if ((context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) ||
513 (new_device == AUDIO_DEVICE_OUT_SPEAKER)) {
514 recompute_gain_dep_cal_Level = true;
515 }
516
517 context->dev_id = new_device;
518
519 if (recompute_gain_dep_cal_Level) {
520 check_and_set_gain_dep_cal();
521 }
522 }
523 break;
524
525 case EFFECT_CMD_SET_VOLUME:
526 {
527 float left_vol = 0, right_vol = 0;
528 bool recompute_gain_dep_cal_Level = false;
529
530 ALOGV("cmd called EFFECT_CMD_SET_VOLUME");
531 if (p_cmd_data == NULL || cmd_size != 2 * sizeof(uint32_t)) {
532 ALOGE("%s: EFFECT_CMD_SET_VOLUME: %s", __func__, (p_cmd_data == NULL) ?
533 "p_cmd_data is NULL" : "cmd_size issue");
534 status = -EINVAL;
535 goto exit;
536 }
537
538 if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
539 recompute_gain_dep_cal_Level = true;
540 }
541
542 left_vol = (float)(*(uint32_t *)p_cmd_data) / (1 << 24);
543 right_vol = (float)(*((uint32_t *)p_cmd_data + 1)) / (1 << 24);
544 ALOGV("Current Volume (%f / %f ) new Volume (%f / %f)", context->left_vol,
545 context->right_vol, left_vol, right_vol);
546
547 context->left_vol = left_vol;
548 context->right_vol = right_vol;
549
550 // recompute gan dep cal level only if volume changed on speaker device
551 if (recompute_gain_dep_cal_Level) {
552 check_and_set_gain_dep_cal();
553 }
554 }
555 break;
556
557 default:
558 ALOGW("volume_listener_command invalid command %d", cmd_code);
559 status = -ENOSYS;
560 break;
561 }
562
563 exit:
564 pthread_mutex_unlock(&vol_listner_init_lock);
565 return status;
566 }
567
568 /* Effect Control Interface Implementation: get_descriptor */
vol_effect_get_descriptor(effect_handle_t self,effect_descriptor_t * descriptor)569 static int vol_effect_get_descriptor(effect_handle_t self,
570 effect_descriptor_t *descriptor)
571 {
572 vol_listener_context_t *context = (vol_listener_context_t *)self;
573 ALOGV("%s Called ", __func__);
574
575 if (descriptor == NULL) {
576 ALOGE("%s: descriptor is NULL", __func__);
577 return -EINVAL;
578 }
579
580 *descriptor = *context->desc;
581 return 0;
582 }
583
init_once()584 static void init_once()
585 {
586 int max_table_ent = 0;
587 if (initialized) {
588 ALOGV("%s : already init .. do nothing", __func__);
589 return;
590 }
591
592 ALOGD("%s Called ", __func__);
593 send_gain_dep_cal = NULL;
594 get_custom_gain_table = NULL;
595
596 pthread_mutex_init(&vol_listner_init_lock, NULL);
597
598 // get hal function pointer
599 if (access(PRIMARY_HAL_PATH, R_OK) == 0) {
600 void *hal_lib_pointer = dlopen(PRIMARY_HAL_PATH, RTLD_NOW);
601 if (hal_lib_pointer == NULL) {
602 ALOGE("%s: DLOPEN failed for %s", __func__, PRIMARY_HAL_PATH);
603 } else {
604 ALOGV("%s: DLOPEN of %s Succes .. next get HAL entry function", __func__, PRIMARY_HAL_PATH);
605 send_gain_dep_cal = (bool (*)(int))dlsym(hal_lib_pointer, AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION);
606 if (send_gain_dep_cal == NULL) {
607 ALOGE("Couldnt able to get the function symbol");
608 }
609 get_custom_gain_table = (int (*) (struct amp_db_and_gain_table *, int))dlsym(hal_lib_pointer, AHAL_GAIN_GET_MAPPING_TABLE);
610 if (get_custom_gain_table == NULL) {
611 ALOGE("Couldnt able to get the function AHAL_GAIN_GET_MAPPING_TABLE symbol");
612 } else {
613 max_table_ent = get_custom_gain_table(volume_curve_gain_mapping_table, MAX_VOLUME_CAL_STEPS);
614 // if number of entries is 0 use default
615 // if number of entries > MAX_VOLUME_CAL_STEPS (this should never happen) then in this case
616 // use only default number of steps but this will result in unexpected behaviour
617
618 if (max_table_ent > 0 && max_table_ent <= MAX_VOLUME_CAL_STEPS) {
619 if (max_table_ent < total_volume_cal_step) {
620 for (int i = max_table_ent; i < total_volume_cal_step; i++ ) {
621 volume_curve_gain_mapping_table[i].amp = 0;
622 volume_curve_gain_mapping_table[i].db = 0;
623 volume_curve_gain_mapping_table[i].level = -1;
624 }
625 }
626 total_volume_cal_step = max_table_ent;
627 ALOGD("%s: using custome volume table", __func__);
628 } else {
629 ALOGD("%s: using default volume table", __func__);
630 }
631
632 if (dumping_enabled) {
633 ALOGD("%s: dumping table here .. size of table received %d",
634 __func__, max_table_ent);
635 for (int i = 0; i < MAX_VOLUME_CAL_STEPS ; i++)
636 ALOGD("[%d] %f %f %d", i, volume_curve_gain_mapping_table[i].amp,
637 volume_curve_gain_mapping_table[i].db,
638 volume_curve_gain_mapping_table[i].level);
639 }
640 }
641 }
642 } else {
643 ALOGE("%s: not able to acces lib %s ", __func__, PRIMARY_HAL_PATH);
644 }
645
646 // check system property to see if dumping is required
647 char check_dump_val[PROPERTY_VALUE_MAX];
648 property_get("audio.volume.listener.dump", check_dump_val, "0");
649 if (atoi(check_dump_val)) {
650 dumping_enabled = true;
651 }
652
653 init_status = 0;
654 list_init(&vol_effect_list);
655 initialized = true;
656 }
657
lib_init()658 static int lib_init()
659 {
660 pthread_once(&once, init_once);
661 ALOGV("%s Called ", __func__);
662 return init_status;
663 }
664
vol_prc_lib_create(const effect_uuid_t * uuid,int32_t session_id,int32_t io_id __unused,effect_handle_t * p_handle)665 static int vol_prc_lib_create(const effect_uuid_t *uuid,
666 int32_t session_id,
667 int32_t io_id __unused,
668 effect_handle_t *p_handle)
669 {
670 int itt = 0;
671 vol_listener_context_t *context = NULL;
672
673 ALOGV("volume_prc_lib_create .. called ..");
674
675 if (lib_init() != 0) {
676 return init_status;
677 }
678
679 if (p_handle == NULL || uuid == NULL) {
680 ALOGE("%s: %s is NULL", __func__, (p_handle == NULL) ? "p_handle" : "uuid");
681 return -EINVAL;
682 }
683
684 context = (vol_listener_context_t *)calloc(1, sizeof(vol_listener_context_t));
685
686 if (context == NULL) {
687 ALOGE("%s: failed to allocate for context .. oops !!", __func__);
688 return -EINVAL;
689 }
690
691 // check if UUID is supported
692 for (itt = 0; descriptors[itt] != NULL; itt++) {
693 if (memcmp(uuid, &descriptors[itt]->uuid, sizeof(effect_uuid_t)) == 0) {
694 // check if this correct .. very imp
695 context->desc = descriptors[itt];
696 context->stream_type = itt;
697 PRINT_STREAM_TYPE(itt)
698 break;
699 }
700 }
701
702 if (descriptors[itt] == NULL) {
703 ALOGE("%s .. couldnt find passed uuid, something wrong", __func__);
704 free(context);
705 return -EINVAL;
706 }
707
708 ALOGV("%s CREATED_CONTEXT %p", __func__, context);
709
710 context->itfe = &effect_interface;
711 context->state = VOL_LISTENER_STATE_INITIALIZED;
712 context->dev_id = AUDIO_DEVICE_NONE;
713 context->session_id = session_id;
714
715 // Add this to master list
716 pthread_mutex_lock(&vol_listner_init_lock);
717 list_add_tail(&vol_effect_list, &context->effect_list_node);
718
719 if (dumping_enabled) {
720 dump_list_l();
721 }
722
723 pthread_mutex_unlock(&vol_listner_init_lock);
724
725 *p_handle = (effect_handle_t)context;
726 return 0;
727 }
728
vol_prc_lib_release(effect_handle_t handle)729 static int vol_prc_lib_release(effect_handle_t handle)
730 {
731 struct listnode *node, *temp_node_next;
732 vol_listener_context_t *context = NULL;
733 vol_listener_context_t *recv_contex = (vol_listener_context_t *)handle;
734 int status = -EINVAL;
735 bool recompute_flag = false;
736 int active_stream_count = 0;
737 uint32_t session_id;
738 uint32_t stream_type;
739 effect_uuid_t uuid;
740
741 ALOGV("%s context %p", __func__, handle);
742
743 if (recv_contex == NULL) {
744 return status;
745 }
746 pthread_mutex_lock(&vol_listner_init_lock);
747 session_id = recv_contex->session_id;
748 stream_type = recv_contex->stream_type;
749 uuid = recv_contex->desc->uuid;
750
751 // check if the handle/context provided is valid
752 list_for_each_safe(node, temp_node_next, &vol_effect_list) {
753 context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
754 if ((memcmp(&(context->desc->uuid), &uuid, sizeof(effect_uuid_t)) == 0)
755 && (context->session_id == session_id)
756 && (context->stream_type == stream_type)) {
757 ALOGV("--- Found something to remove ---");
758 list_remove(node);
759 PRINT_STREAM_TYPE(context->stream_type);
760 if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
761 recompute_flag = true;
762 }
763 free(context);
764 status = 0;
765 } else {
766 ++active_stream_count;
767 }
768 }
769
770 if (status != 0) {
771 ALOGE("something wrong ... <<<--- Found NOTHING to remove ... ???? --->>>>>");
772 pthread_mutex_unlock(&vol_listner_init_lock);
773 return status;
774 }
775
776 // if there are no active streams, reset cal and volume level
777 if (active_stream_count == 0) {
778 current_gain_dep_cal_level = -1;
779 current_vol = 0.0;
780 }
781
782 if (recompute_flag) {
783 check_and_set_gain_dep_cal();
784 }
785
786 if (dumping_enabled) {
787 dump_list_l();
788 }
789 pthread_mutex_unlock(&vol_listner_init_lock);
790 return status;
791 }
792
vol_prc_lib_get_descriptor(const effect_uuid_t * uuid,effect_descriptor_t * descriptor)793 static int vol_prc_lib_get_descriptor(const effect_uuid_t *uuid,
794 effect_descriptor_t *descriptor)
795 {
796 int i = 0;
797 ALOGV("%s Called ", __func__);
798 if (lib_init() != 0) {
799 return init_status;
800 }
801
802 if (descriptor == NULL || uuid == NULL) {
803 ALOGE("%s: %s is NULL", __func__, (descriptor == NULL) ? "descriptor" : "uuid");
804 return -EINVAL;
805 }
806
807 for (i = 0; descriptors[i] != NULL; i++) {
808 if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
809 *descriptor = *descriptors[i];
810 return 0;
811 }
812 }
813
814 ALOGE("%s: couldnt found uuid passed, oops", __func__);
815 return -EINVAL;
816 }
817
818
819 /* effect_handle_t interface implementation for volume listener effect */
820 static const struct effect_interface_s effect_interface = {
821 vol_effect_process,
822 vol_effect_command,
823 vol_effect_get_descriptor,
824 NULL,
825 };
826
827 __attribute__((visibility("default")))
828 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
829 .tag = AUDIO_EFFECT_LIBRARY_TAG,
830 .version = EFFECT_LIBRARY_API_VERSION,
831 .name = "Volume Listener Effect Library",
832 .implementor = "Qualcomm Technologies Inc.",
833 .create_effect = vol_prc_lib_create,
834 .release_effect = vol_prc_lib_release,
835 .get_descriptor = vol_prc_lib_get_descriptor,
836 };
837