voice_extn.c revision f1819247a21f755757a28ea313678faff73ef349
1/* 2 * Copyright (C) 2014 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 "voice_extn" 18/*#define LOG_NDEBUG 0*/ 19#define LOG_NDDEBUG 0 20 21#include <errno.h> 22#include <math.h> 23#include <cutils/log.h> 24#include <cutils/str_parms.h> 25#include <sys/ioctl.h> 26#include <sound/voice_params.h> 27 28#include "audio_hw.h" 29#include "voice.h" 30#include "platform.h" 31#include "platform_api.h" 32#include "voice_extn.h" 33 34#define AUDIO_PARAMETER_KEY_VSID "vsid" 35#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" 36#define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode" 37#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states" 38#define AUDIO_PARAMETER_KEY_DEVICE_MUTE "device_mute" 39#define AUDIO_PARAMETER_KEY_DIRECTION "direction" 40 41#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256 42 43#define VOICE2_VSID 0x10DC1000 44#define VOLTE_VSID 0x10C02000 45#define QCHAT_VSID 0x10803000 46#define VOWLAN_VSID 0x10002000 47#define ALL_VSID 0xFFFFFFFF 48 49/* Voice Session Indices */ 50#define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1) 51#define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2) 52#define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3) 53#define VOWLAN_SESS_IDX (VOICE_SESS_IDX + 4) 54 55/* Call States */ 56#define CALL_HOLD (BASE_CALL_STATE + 2) 57#define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3) 58 59struct pcm_config pcm_config_incall_music = { 60 .channels = 1, 61 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, 62 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, 63 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, 64 .format = PCM_FORMAT_S16_LE, 65 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, 66 .stop_threshold = INT_MAX, 67 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, 68}; 69 70extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id); 71extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id); 72int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active); 73 74static bool is_valid_call_state(int call_state) 75{ 76 if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD) 77 return false; 78 else 79 return true; 80} 81 82static bool is_valid_vsid(uint32_t vsid) 83{ 84 if (vsid == VOICE_VSID || 85 vsid == VOICE2_VSID || 86 vsid == VOLTE_VSID || 87 vsid == QCHAT_VSID || 88 vsid == VOWLAN_VSID) 89 return true; 90 else 91 return false; 92} 93 94static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index) 95{ 96 audio_usecase_t usecase_id = -1; 97 98 switch(index) { 99 case VOICE_SESS_IDX: 100 usecase_id = USECASE_VOICE_CALL; 101 break; 102 103 case VOICE2_SESS_IDX: 104 usecase_id = USECASE_VOICE2_CALL; 105 break; 106 107 case VOLTE_SESS_IDX: 108 usecase_id = USECASE_VOLTE_CALL; 109 break; 110 111 case QCHAT_SESS_IDX: 112 usecase_id = USECASE_QCHAT_CALL; 113 break; 114 115 case VOWLAN_SESS_IDX: 116 usecase_id = USECASE_VOWLAN_CALL; 117 break; 118 119 default: 120 ALOGE("%s: Invalid voice session index\n", __func__); 121 } 122 123 return usecase_id; 124} 125 126static uint32_t get_session_id_with_state(struct audio_device *adev, 127 int call_state) 128{ 129 struct voice_session *session = NULL; 130 int i = 0; 131 uint32_t session_id = 0; 132 133 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 134 session = &adev->voice.session[i]; 135 if(session->state.current == call_state){ 136 session_id = session->vsid; 137 break; 138 } 139 } 140 141 return session_id; 142} 143 144static int update_calls(struct audio_device *adev) 145{ 146 int i = 0; 147 audio_usecase_t usecase_id = 0; 148 enum voice_lch_mode lch_mode; 149 struct voice_session *session = NULL; 150 int fd = 0; 151 int ret = 0; 152 153 ALOGD("%s: enter:", __func__); 154 155 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 156 usecase_id = voice_extn_get_usecase_for_session_idx(i); 157 session = &adev->voice.session[i]; 158 ALOGD("%s: cur_state=%d new_state=%d vsid=%x", 159 __func__, session->state.current, session->state.new, session->vsid); 160 161 switch(session->state.new) 162 { 163 case CALL_ACTIVE: 164 switch(session->state.current) 165 { 166 case CALL_INACTIVE: 167 ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid); 168 ret = start_call(adev, usecase_id); 169 if(ret < 0) { 170 ALOGE("%s: voice_start_call() failed for usecase: %d\n", 171 __func__, usecase_id); 172 } else { 173 session->state.current = session->state.new; 174 } 175 break; 176 177 case CALL_HOLD: 178 ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid); 179 session->state.current = session->state.new; 180 break; 181 182 case CALL_LOCAL_HOLD: 183 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid); 184 lch_mode = VOICE_LCH_STOP; 185 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { 186 ALOGE("LOCAL_HOLD -> ACTIVE failed"); 187 } else { 188 session->state.current = session->state.new; 189 } 190 break; 191 192 default: 193 ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x", 194 __func__, session->state.current, session->vsid); 195 break; 196 } 197 break; 198 199 case CALL_INACTIVE: 200 switch(session->state.current) 201 { 202 case CALL_ACTIVE: 203 case CALL_HOLD: 204 case CALL_LOCAL_HOLD: 205 ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid); 206 ret = stop_call(adev, usecase_id); 207 if(ret < 0) { 208 ALOGE("%s: voice_end_call() failed for usecase: %d\n", 209 __func__, usecase_id); 210 } else { 211 session->state.current = session->state.new; 212 } 213 break; 214 215 default: 216 ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x", 217 __func__, session->state.current, session->vsid); 218 break; 219 } 220 break; 221 222 case CALL_HOLD: 223 switch(session->state.current) 224 { 225 case CALL_ACTIVE: 226 ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid); 227 session->state.current = session->state.new; 228 break; 229 230 case CALL_LOCAL_HOLD: 231 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid); 232 lch_mode = VOICE_LCH_STOP; 233 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { 234 ALOGE("LOCAL_HOLD -> HOLD failed"); 235 } else { 236 session->state.current = session->state.new; 237 } 238 break; 239 240 default: 241 ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x", 242 __func__, session->state.current, session->vsid); 243 break; 244 } 245 break; 246 247 case CALL_LOCAL_HOLD: 248 switch(session->state.current) 249 { 250 case CALL_ACTIVE: 251 case CALL_HOLD: 252 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__, 253 session->vsid); 254 lch_mode = VOICE_LCH_START; 255 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { 256 ALOGE("LOCAL_HOLD -> HOLD failed"); 257 } else { 258 session->state.current = session->state.new; 259 } 260 break; 261 262 default: 263 ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x", 264 __func__, session->state.current, session->vsid); 265 break; 266 } 267 break; 268 269 default: 270 break; 271 } //end out switch loop 272 } //end for loop 273 274 return ret; 275} 276 277static int update_call_states(struct audio_device *adev, 278 const uint32_t vsid, const int call_state) 279{ 280 struct voice_session *session = NULL; 281 int i = 0; 282 bool is_call_active; 283 284 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 285 if (vsid == adev->voice.session[i].vsid) { 286 session = &adev->voice.session[i]; 287 break; 288 } 289 } 290 291 if (session) { 292 session->state.new = call_state; 293 voice_extn_is_call_state_active(adev, &is_call_active); 294 ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n", 295 __func__, is_call_active, adev->voice.in_call, adev->mode); 296 /* Dont start voice call before device routing for voice usescases has 297 * occured, otherwise voice calls will be started unintendedly on 298 * speaker. 299 */ 300 if (is_call_active || adev->voice.in_call) { 301 /* Device routing is not triggered for voice calls on the subsequent 302 * subs, Hence update the call states if voice call is already 303 * active on other sub. 304 */ 305 update_calls(adev); 306 } 307 } else { 308 return -EINVAL; 309 } 310 311 return 0; 312 313} 314 315int voice_extn_get_active_session_id(struct audio_device *adev, 316 uint32_t *session_id) 317{ 318 *session_id = get_session_id_with_state(adev, CALL_ACTIVE); 319 return 0; 320} 321 322int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active) 323{ 324 struct voice_session *session = NULL; 325 int i = 0; 326 *is_call_active = false; 327 328 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 329 session = &adev->voice.session[i]; 330 if(session->state.current != CALL_INACTIVE){ 331 *is_call_active = true; 332 break; 333 } 334 } 335 336 return 0; 337} 338 339int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec) 340{ 341 *in_call_rec = false; 342 343 if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK || 344 in->source == AUDIO_SOURCE_VOICE_UPLINK || 345 in->source == AUDIO_SOURCE_VOICE_CALL) { 346 *in_call_rec = true; 347 } 348 349 return 0; 350} 351 352void voice_extn_init(struct audio_device *adev) 353{ 354 adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID; 355 adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID; 356 adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID; 357 adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID; 358 adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID; 359} 360 361int voice_extn_get_session_from_use_case(struct audio_device *adev, 362 const audio_usecase_t usecase_id, 363 struct voice_session **session) 364{ 365 366 switch(usecase_id) 367 { 368 case USECASE_VOICE_CALL: 369 *session = &adev->voice.session[VOICE_SESS_IDX]; 370 break; 371 372 case USECASE_VOICE2_CALL: 373 *session = &adev->voice.session[VOICE2_SESS_IDX]; 374 break; 375 376 case USECASE_VOLTE_CALL: 377 *session = &adev->voice.session[VOLTE_SESS_IDX]; 378 break; 379 380 case USECASE_QCHAT_CALL: 381 *session = &adev->voice.session[QCHAT_SESS_IDX]; 382 break; 383 384 case USECASE_VOWLAN_CALL: 385 *session = &adev->voice.session[VOWLAN_SESS_IDX]; 386 break; 387 388 default: 389 ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id); 390 *session = NULL; 391 return -EINVAL; 392 } 393 394 return 0; 395} 396 397int voice_extn_start_call(struct audio_device *adev) 398{ 399 /* Start voice calls on sessions whose call state has been 400 * udpated. 401 */ 402 ALOGV("%s: enter:", __func__); 403 return update_calls(adev); 404} 405 406int voice_extn_stop_call(struct audio_device *adev) 407{ 408 int i; 409 int ret = 0; 410 411 ALOGV("%s: enter:", __func__); 412 413 /* If BT device is enabled and voice calls are ended, telephony will call 414 * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to 415 * set routing with device BT A2DP profile. Hence end all voice calls when 416 * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected. 417 */ 418 if (adev->mode == AUDIO_MODE_NORMAL) { 419 ALOGD("%s: end all calls", __func__); 420 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 421 adev->voice.session[i].state.new = CALL_INACTIVE; 422 } 423 424 ret = update_calls(adev); 425 } 426 427 return ret; 428} 429 430int voice_extn_set_parameters(struct audio_device *adev, 431 struct str_parms *parms) 432{ 433 char *str; 434 int value; 435 int ret = 0, err; 436 char *kv_pairs = str_parms_to_str(parms); 437 char str_value[256] = {0}; 438 439 ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); 440 441 err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value); 442 if (err >= 0) { 443 str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID); 444 uint32_t vsid = value; 445 int call_state = -1; 446 err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); 447 if (err >= 0) { 448 call_state = value; 449 str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE); 450 } else { 451 ALOGE("%s: call_state key not found", __func__); 452 ret = -EINVAL; 453 goto done; 454 } 455 456 if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) { 457 ret = update_call_states(adev, vsid, call_state); 458 } else { 459 ALOGE("%s: invalid vsid:%x or call_state:%d", 460 __func__, vsid, call_state); 461 ret = -EINVAL; 462 goto done; 463 } 464 } 465 466 err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value, 467 sizeof(str_value)); 468 if (err >= 0) { 469 str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE); 470 bool mute = false; 471 472 if (!strncmp("true", str_value, sizeof("true"))) { 473 mute = true; 474 } 475 476 err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value, 477 sizeof(str_value)); 478 if (err >= 0) { 479 str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION); 480 } else { 481 ALOGE("%s: direction key not found", __func__); 482 ret = -EINVAL; 483 goto done; 484 } 485 486 ret = platform_set_device_mute(adev->platform, mute, str_value); 487 if (ret != 0) { 488 ALOGE("%s: Failed to set mute err:%d", __func__, ret); 489 ret = -EINVAL; 490 goto done; 491 } 492 } 493 494done: 495 ALOGV("%s: exit with code(%d)", __func__, ret); 496 free(kv_pairs); 497 return ret; 498} 499 500static int get_all_call_states_str(const struct audio_device *adev, 501 char *value) 502{ 503 int ret = 0; 504 char *cur_ptr = value; 505 int i, len=0; 506 507 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 508 snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len, 509 "%d:%d,",adev->voice.session[i].vsid, 510 adev->voice.session[i].state.current); 511 len = strlen(cur_ptr); 512 cur_ptr = cur_ptr + len; 513 } 514 ALOGV("%s:value=%s", __func__, value); 515 return ret; 516} 517 518void voice_extn_get_parameters(const struct audio_device *adev, 519 struct str_parms *query, 520 struct str_parms *reply) 521{ 522 int ret; 523 char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0}; 524 char *str = str_parms_to_str(query); 525 526 ALOGV_IF(str != NULL, "%s: enter %s", __func__, str); 527 free(str); 528 529 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value, 530 sizeof(value)); 531 if (ret >= 0) { 532 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode); 533 } 534 535 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, 536 value, sizeof(value)); 537 if (ret >= 0) { 538 ret = get_all_call_states_str(adev, value); 539 if (ret) { 540 ALOGE("%s: Error fetching call states, err:%d", __func__, ret); 541 return; 542 } 543 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value); 544 } 545 546 str = str_parms_to_str(reply); 547 ALOGV_IF(str != NULL, "%s: exit: returns \"%s\"", __func__, str); 548 free(str); 549} 550 551#ifdef INCALL_MUSIC_ENABLED 552int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, 553 struct stream_out *out) 554{ 555 uint32_t session_id = 0; 556 557 session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD); 558 if (session_id == VOICE_VSID) { 559 out->usecase = USECASE_INCALL_MUSIC_UPLINK; 560 } else if (session_id == VOICE2_VSID) { 561 out->usecase = USECASE_INCALL_MUSIC_UPLINK2; 562 } else { 563 ALOGE("%s: Invalid session id %x", __func__, session_id); 564 return -EINVAL; 565 } 566 567 out->config = pcm_config_incall_music; 568 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO; 569 out->channel_mask = AUDIO_CHANNEL_OUT_MONO; 570 571 return 0; 572} 573#endif 574 575