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