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