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