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