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
59 struct 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
70 int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
71
is_valid_call_state(int call_state)72 static 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
is_valid_vsid(uint32_t vsid)80 static 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
voice_extn_get_usecase_for_session_idx(const int index)92 static 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
get_session_id_with_state(struct audio_device * adev,int call_state)124 static 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
update_calls(struct audio_device * adev)142 static 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
update_call_states(struct audio_device * adev,const uint32_t vsid,const int call_state)275 static 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
voice_extn_get_active_session_id(struct audio_device * adev,uint32_t * session_id)314 int 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
voice_extn_is_call_state_active(struct audio_device * adev,bool * is_call_active)321 int 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
voice_extn_is_in_call_rec_stream(struct stream_in * in,bool * in_call_rec)338 int 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
voice_extn_init(struct audio_device * adev)351 void 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
voice_extn_get_session_from_use_case(struct audio_device * adev,const audio_usecase_t usecase_id,struct voice_session ** session)360 int 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
voice_extn_start_call(struct audio_device * adev)396 int 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
voice_extn_stop_call(struct audio_device * adev)405 int 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
voice_extn_set_parameters(struct audio_device * adev,struct str_parms * parms)429 int 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
493 done:
494 ALOGV("%s: exit with code(%d)", __func__, ret);
495 free(kv_pairs);
496 return ret;
497 }
498
get_all_call_states_str(const struct audio_device * adev,char * value)499 static 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
voice_extn_get_parameters(const struct audio_device * adev,struct str_parms * query,struct str_parms * reply)517 void 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
voice_extn_check_and_set_incall_music_usecase(struct audio_device * adev,struct stream_out * out)551 int 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