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