voice.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" 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 26#include "audio_hw.h" 27#include "voice.h" 28#include "voice_extn/voice_extn.h" 29#include "platform.h" 30#include "platform_api.h" 31 32struct pcm_config pcm_config_voice_call = { 33 .channels = 1, 34 .rate = 8000, 35 .period_size = 160, 36 .period_count = 2, 37 .format = PCM_FORMAT_S16_LE, 38}; 39 40extern const char * const use_case_table[AUDIO_USECASE_MAX]; 41 42static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev, 43 audio_usecase_t usecase_id) 44{ 45 struct voice_session *session = NULL; 46 int ret = 0; 47 48 ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session); 49 if (ret == -ENOSYS) { 50 session = &adev->voice.session[VOICE_SESS_IDX]; 51 } 52 53 return session; 54} 55 56int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) 57{ 58 int i, ret = 0; 59 struct audio_usecase *uc_info; 60 struct voice_session *session = NULL; 61 62 ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]); 63 64 session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); 65 session->state.current = CALL_INACTIVE; 66 67 ret = platform_stop_voice_call(adev->platform, session->vsid); 68 69 /* 1. Close the PCM devices */ 70 if (session->pcm_rx) { 71 pcm_close(session->pcm_rx); 72 session->pcm_rx = NULL; 73 } 74 if (session->pcm_tx) { 75 pcm_close(session->pcm_tx); 76 session->pcm_tx = NULL; 77 } 78 79 uc_info = get_usecase_from_list(adev, usecase_id); 80 if (uc_info == NULL) { 81 ALOGE("%s: Could not find the usecase (%d) in the list", 82 __func__, usecase_id); 83 return -EINVAL; 84 } 85 86 /* 2. Get and set stream specific mixer controls */ 87 disable_audio_route(adev, uc_info); 88 89 /* 3. Disable the rx and tx devices */ 90 disable_snd_device(adev, uc_info->out_snd_device); 91 disable_snd_device(adev, uc_info->in_snd_device); 92 93 list_remove(&uc_info->list); 94 free(uc_info); 95 96 ALOGD("%s: exit: status(%d)", __func__, ret); 97 return ret; 98} 99 100int start_call(struct audio_device *adev, audio_usecase_t usecase_id) 101{ 102 int i, ret = 0; 103 struct audio_usecase *uc_info; 104 int pcm_dev_rx_id, pcm_dev_tx_id; 105 struct voice_session *session = NULL; 106 struct pcm_config voice_config = pcm_config_voice_call; 107 108 ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]); 109 110 session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); 111 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); 112 uc_info->id = usecase_id; 113 uc_info->type = VOICE_CALL; 114 uc_info->stream.out = adev->primary_output; 115 uc_info->devices = adev->primary_output->devices; 116 uc_info->in_snd_device = SND_DEVICE_NONE; 117 uc_info->out_snd_device = SND_DEVICE_NONE; 118 119 list_add_tail(&adev->usecase_list, &uc_info->list); 120 121 select_devices(adev, usecase_id); 122 123 pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); 124 pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); 125 126 if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { 127 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", 128 __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); 129 ret = -EIO; 130 goto error_start_voice; 131 } 132 133 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", 134 __func__, adev->snd_card, pcm_dev_rx_id); 135 session->pcm_rx = pcm_open(adev->snd_card, 136 pcm_dev_rx_id, 137 PCM_OUT, &voice_config); 138 if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) { 139 ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx)); 140 ret = -EIO; 141 goto error_start_voice; 142 } 143 144 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", 145 __func__, adev->snd_card, pcm_dev_tx_id); 146 session->pcm_tx = pcm_open(adev->snd_card, 147 pcm_dev_tx_id, 148 PCM_IN, &voice_config); 149 if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) { 150 ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx)); 151 ret = -EIO; 152 goto error_start_voice; 153 } 154 pcm_start(session->pcm_rx); 155 pcm_start(session->pcm_tx); 156 157 voice_set_volume(adev, adev->voice.volume); 158 159 ret = platform_start_voice_call(adev->platform, session->vsid); 160 if (ret < 0) { 161 ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); 162 goto error_start_voice; 163 } 164 165 session->state.current = CALL_ACTIVE; 166 goto done; 167 168error_start_voice: 169 stop_call(adev, usecase_id); 170 171done: 172 ALOGD("%s: exit: status(%d)", __func__, ret); 173 return ret; 174} 175 176bool voice_is_call_state_active(struct audio_device *adev) 177{ 178 bool call_state = false; 179 int ret = 0; 180 181 ret = voice_extn_is_call_state_active(adev, &call_state); 182 if (ret == -ENOSYS) { 183 call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false; 184 } 185 186 return call_state; 187} 188 189bool voice_is_in_call(struct audio_device *adev) 190{ 191 return adev->voice.in_call; 192} 193 194bool voice_is_in_call_rec_stream(struct stream_in *in) 195{ 196 bool in_call_rec = false; 197 int ret = 0; 198 199 ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec); 200 if (ret == -ENOSYS) { 201 in_call_rec = false; 202 } 203 204 return in_call_rec; 205} 206 207uint32_t voice_get_active_session_id(struct audio_device *adev) 208{ 209 int ret = 0; 210 uint32_t session_id; 211 212 ret = voice_extn_get_active_session_id(adev, &session_id); 213 if (ret == -ENOSYS) { 214 session_id = VOICE_VSID; 215 } 216 return session_id; 217} 218 219int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, 220 struct stream_in *in) 221{ 222 int ret = 0; 223 uint32_t session_id; 224 int usecase_id; 225 int rec_mode = INCALL_REC_NONE; 226 227 if (voice_is_call_state_active(adev)) { 228 switch (in->source) { 229 case AUDIO_SOURCE_VOICE_UPLINK: 230 in->usecase = USECASE_INCALL_REC_UPLINK; 231 rec_mode = INCALL_REC_UPLINK; 232 break; 233 case AUDIO_SOURCE_VOICE_DOWNLINK: 234 in->usecase = USECASE_INCALL_REC_DOWNLINK; 235 rec_mode = INCALL_REC_DOWNLINK; 236 break; 237 case AUDIO_SOURCE_VOICE_CALL: 238 in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK; 239 rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK; 240 break; 241 default: 242 ALOGV("%s: Source type %d doesnt match incall recording criteria", 243 __func__, in->source); 244 return ret; 245 } 246 247 session_id = voice_get_active_session_id(adev); 248 ret = platform_set_incall_recording_session_id(adev->platform, 249 session_id, rec_mode); 250 ALOGV("%s: Update usecase to %d",__func__, in->usecase); 251 } else { 252 ALOGV("%s: voice call not active", __func__); 253 } 254 255 return ret; 256} 257 258int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev, 259 struct stream_in *in) 260{ 261 int ret = 0; 262 263 if (in->source == AUDIO_SOURCE_VOICE_UPLINK || 264 in->source == AUDIO_SOURCE_VOICE_DOWNLINK || 265 in->source == AUDIO_SOURCE_VOICE_CALL) { 266 ret = platform_stop_incall_recording_usecase(adev->platform); 267 ALOGV("%s: Stop In-call recording", __func__); 268 } 269 270 return ret; 271} 272 273int voice_check_and_set_incall_music_usecase(struct audio_device *adev, 274 struct stream_out *out) 275{ 276 int ret = 0; 277 278 ret = voice_extn_check_and_set_incall_music_usecase(adev, out); 279 if (ret == -ENOSYS) { 280 /* Incall music delivery is used only for LCH call state */ 281 ret = -EINVAL; 282 } 283 284 return ret; 285} 286 287int voice_set_mic_mute(struct audio_device *adev, bool state) 288{ 289 int err = 0; 290 291 adev->voice.mic_mute = state; 292 if (adev->mode == AUDIO_MODE_IN_CALL) 293 err = platform_set_mic_mute(adev->platform, state); 294 295 return err; 296} 297 298bool voice_get_mic_mute(struct audio_device *adev) 299{ 300 return adev->voice.mic_mute; 301} 302 303int voice_set_volume(struct audio_device *adev, float volume) 304{ 305 int vol, err = 0; 306 307 adev->voice.volume = volume; 308 if (adev->mode == AUDIO_MODE_IN_CALL) { 309 if (volume < 0.0) { 310 volume = 0.0; 311 } else if (volume > 1.0) { 312 volume = 1.0; 313 } 314 315 vol = lrint(volume * 100.0); 316 317 // Voice volume levels from android are mapped to driver volume levels as follows. 318 // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 319 // So adjust the volume to get the correct volume index in driver 320 vol = 100 - vol; 321 322 err = platform_set_voice_volume(adev->platform, vol); 323 } 324 325 return err; 326} 327 328int voice_start_call(struct audio_device *adev) 329{ 330 int ret = 0; 331 332 ret = voice_extn_start_call(adev); 333 if (ret == -ENOSYS) { 334 ret = start_call(adev, USECASE_VOICE_CALL); 335 } 336 adev->voice.in_call = true; 337 338 return ret; 339} 340 341int voice_stop_call(struct audio_device *adev) 342{ 343 int ret = 0; 344 345 adev->voice.in_call = false; 346 ret = voice_extn_stop_call(adev); 347 if (ret == -ENOSYS) { 348 ret = stop_call(adev, USECASE_VOICE_CALL); 349 } 350 351 return ret; 352} 353 354void voice_get_parameters(struct audio_device *adev, 355 struct str_parms *query, 356 struct str_parms *reply) 357{ 358 voice_extn_get_parameters(adev, query, reply); 359} 360 361int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) 362{ 363 char *str; 364 char value[32]; 365 int val; 366 int ret = 0, err; 367 char *kv_pairs = str_parms_to_str(parms); 368 369 ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); 370 371 ret = voice_extn_set_parameters(adev, parms); 372 if (ret != 0) { 373 if (ret == -ENOSYS) { 374 ret = 0; /* ignore error */ 375 } else { 376 goto done; 377 } 378 } 379 380 err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); 381 if (err >= 0) { 382 int tty_mode; 383 str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE); 384 if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0) 385 tty_mode = TTY_MODE_OFF; 386 else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0) 387 tty_mode = TTY_MODE_VCO; 388 else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0) 389 tty_mode = TTY_MODE_HCO; 390 else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0) 391 tty_mode = TTY_MODE_FULL; 392 else { 393 ret = -EINVAL; 394 goto done; 395 } 396 397 if (tty_mode != adev->voice.tty_mode) { 398 adev->voice.tty_mode = tty_mode; 399 adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; 400 if (voice_is_call_state_active(adev)) 401 voice_update_devices_for_all_voice_usecases(adev); 402 } 403 } 404 405 err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HAC, 406 value, sizeof(value)); 407 if (err >= 0) { 408 bool hac = false; 409 str_parms_del(parms, AUDIO_PARAMETER_KEY_HAC); 410 if (strcmp(value, AUDIO_PARAMETER_VALUE_HAC_ON) == 0) 411 hac = true; 412 413 if (hac != adev->voice.hac) { 414 adev->voice.hac = hac; 415 if (voice_is_in_call(adev)) 416 voice_update_devices_for_all_voice_usecases(adev); 417 } 418 } 419 420 err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC, 421 value, sizeof(value)); 422 if (err >= 0) { 423 str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC); 424 if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0) 425 platform_start_incall_music_usecase(adev->platform); 426 else 427 platform_stop_incall_music_usecase(adev->platform); 428 } 429 430done: 431 ALOGV("%s: exit with code(%d)", __func__, ret); 432 free(kv_pairs); 433 return ret; 434} 435 436void voice_init(struct audio_device *adev) 437{ 438 int i = 0; 439 440 memset(&adev->voice, 0, sizeof(adev->voice)); 441 adev->voice.tty_mode = TTY_MODE_OFF; 442 adev->voice.hac = false; 443 adev->voice.volume = 1.0f; 444 adev->voice.mic_mute = false; 445 adev->voice.in_call = false; 446 for (i = 0; i < MAX_VOICE_SESSIONS; i++) { 447 adev->voice.session[i].pcm_rx = NULL; 448 adev->voice.session[i].pcm_tx = NULL; 449 adev->voice.session[i].state.current = CALL_INACTIVE; 450 adev->voice.session[i].state.new = CALL_INACTIVE; 451 adev->voice.session[i].vsid = VOICE_VSID; 452 } 453 454 voice_extn_init(adev); 455} 456 457void voice_update_devices_for_all_voice_usecases(struct audio_device *adev) 458{ 459 struct listnode *node; 460 struct audio_usecase *usecase; 461 462 list_for_each(node, &adev->usecase_list) { 463 usecase = node_to_item(node, struct audio_usecase, list); 464 if (usecase->type == VOICE_CALL) { 465 ALOGV("%s: updating device for usecase:%s", __func__, 466 use_case_table[usecase->id]); 467 select_devices(adev, usecase->id); 468 } 469 } 470} 471 472 473