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