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 <stdlib.h>
24 #include <cutils/log.h>
25 #include <cutils/str_parms.h>
26 #include <sys/ioctl.h>
27 #include <sound/voice_params.h>
28
29 #include "audio_hw.h"
30 #include "voice.h"
31 #include "platform.h"
32 #include "platform_api.h"
33 #include "voice_extn.h"
34
35 #define AUDIO_PARAMETER_KEY_VSID "vsid"
36 #define AUDIO_PARAMETER_KEY_CALL_STATE "call_state"
37 #define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode"
38 #define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states"
39 #define AUDIO_PARAMETER_KEY_DEVICE_MUTE "device_mute"
40 #define AUDIO_PARAMETER_KEY_DIRECTION "direction"
41
42 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
43
44 #define VOICE2_VSID 0x10DC1000
45 #define VOLTE_VSID 0x10C02000
46 #define QCHAT_VSID 0x10803000
47 #define VOWLAN_VSID 0x10002000
48 #define ALL_VSID 0xFFFFFFFF
49
50 /* Voice Session Indices */
51 #define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1)
52 #define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2)
53 #define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3)
54 #define VOWLAN_SESS_IDX (VOICE_SESS_IDX + 4)
55
56 /* Call States */
57 #define CALL_HOLD (BASE_CALL_STATE + 2)
58 #define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3)
59
60 struct pcm_config pcm_config_incall_music = {
61 .channels = 1,
62 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
63 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
64 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
65 .format = PCM_FORMAT_S16_LE,
66 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
67 .stop_threshold = INT_MAX,
68 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
69 };
70
71 int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
72
is_valid_call_state(int call_state)73 static bool is_valid_call_state(int call_state)
74 {
75 if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
76 return false;
77 else
78 return true;
79 }
80
is_valid_vsid(uint32_t vsid)81 static bool is_valid_vsid(uint32_t vsid)
82 {
83 if (vsid == VOICE_VSID ||
84 vsid == VOICE2_VSID ||
85 vsid == VOLTE_VSID ||
86 vsid == QCHAT_VSID ||
87 vsid == VOWLAN_VSID)
88 return true;
89 else
90 return false;
91 }
92
voice_extn_get_usecase_for_session_idx(const int index)93 static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
94 {
95 audio_usecase_t usecase_id = -1;
96
97 switch(index) {
98 case VOICE_SESS_IDX:
99 usecase_id = USECASE_VOICE_CALL;
100 break;
101
102 case VOICE2_SESS_IDX:
103 usecase_id = USECASE_VOICE2_CALL;
104 break;
105
106 case VOLTE_SESS_IDX:
107 usecase_id = USECASE_VOLTE_CALL;
108 break;
109
110 case QCHAT_SESS_IDX:
111 usecase_id = USECASE_QCHAT_CALL;
112 break;
113
114 case VOWLAN_SESS_IDX:
115 usecase_id = USECASE_VOWLAN_CALL;
116 break;
117
118 default:
119 ALOGE("%s: Invalid voice session index\n", __func__);
120 }
121
122 return usecase_id;
123 }
124
get_session_id_with_state(struct audio_device * adev,int call_state)125 static uint32_t get_session_id_with_state(struct audio_device *adev,
126 int call_state)
127 {
128 struct voice_session *session = NULL;
129 int i = 0;
130 uint32_t session_id = 0;
131
132 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
133 session = &adev->voice.session[i];
134 if(session->state.current == call_state){
135 session_id = session->vsid;
136 break;
137 }
138 }
139
140 return session_id;
141 }
142
update_calls(struct audio_device * adev)143 static int update_calls(struct audio_device *adev)
144 {
145 int i = 0;
146 audio_usecase_t usecase_id = 0;
147 enum voice_lch_mode lch_mode;
148 struct voice_session *session = NULL;
149 int fd = 0;
150 int ret = 0;
151
152 ALOGD("%s: enter:", __func__);
153
154 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
155 usecase_id = voice_extn_get_usecase_for_session_idx(i);
156 session = &adev->voice.session[i];
157 ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
158 __func__, session->state.current, session->state.new, session->vsid);
159
160 switch(session->state.new)
161 {
162 case CALL_ACTIVE:
163 switch(session->state.current)
164 {
165 case CALL_INACTIVE:
166 ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
167 ret = voice_start_usecase(adev, usecase_id);
168 if(ret < 0) {
169 ALOGE("%s: voice_start_usecase() failed for usecase: %d\n",
170 __func__, usecase_id);
171 } else {
172 session->state.current = session->state.new;
173 }
174 break;
175
176 case CALL_HOLD:
177 ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
178 session->state.current = session->state.new;
179 break;
180
181 case CALL_LOCAL_HOLD:
182 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
183 lch_mode = VOICE_LCH_STOP;
184 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
185 ALOGE("LOCAL_HOLD -> ACTIVE failed");
186 } else {
187 session->state.current = session->state.new;
188 }
189 break;
190
191 default:
192 ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
193 __func__, session->state.current, session->vsid);
194 break;
195 }
196 break;
197
198 case CALL_INACTIVE:
199 switch(session->state.current)
200 {
201 case CALL_ACTIVE:
202 case CALL_HOLD:
203 case CALL_LOCAL_HOLD:
204 ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
205 ret = voice_stop_usecase(adev, usecase_id);
206 if(ret < 0) {
207 ALOGE("%s: voice_stop_usecase() failed for usecase: %d\n",
208 __func__, usecase_id);
209 } else {
210 session->state.current = session->state.new;
211 }
212 break;
213
214 default:
215 ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
216 __func__, session->state.current, session->vsid);
217 break;
218 }
219 break;
220
221 case CALL_HOLD:
222 switch(session->state.current)
223 {
224 case CALL_ACTIVE:
225 ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
226 session->state.current = session->state.new;
227 break;
228
229 case CALL_LOCAL_HOLD:
230 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
231 lch_mode = VOICE_LCH_STOP;
232 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
233 ALOGE("LOCAL_HOLD -> HOLD failed");
234 } else {
235 session->state.current = session->state.new;
236 }
237 break;
238
239 default:
240 ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
241 __func__, session->state.current, session->vsid);
242 break;
243 }
244 break;
245
246 case CALL_LOCAL_HOLD:
247 switch(session->state.current)
248 {
249 case CALL_ACTIVE:
250 case CALL_HOLD:
251 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
252 session->vsid);
253 lch_mode = VOICE_LCH_START;
254 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
255 ALOGE("LOCAL_HOLD -> HOLD failed");
256 } else {
257 session->state.current = session->state.new;
258 }
259 break;
260
261 default:
262 ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
263 __func__, session->state.current, session->vsid);
264 break;
265 }
266 break;
267
268 default:
269 break;
270 } //end out switch loop
271 } //end for loop
272
273 return ret;
274 }
275
update_call_states(struct audio_device * adev,const uint32_t vsid,const int call_state)276 static int update_call_states(struct audio_device *adev,
277 const uint32_t vsid, const int call_state)
278 {
279 struct voice_session *session = NULL;
280 int i = 0;
281 bool is_call_active;
282
283 for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
284 if (vsid == adev->voice.session[i].vsid) {
285 session = &adev->voice.session[i];
286 break;
287 }
288 }
289
290 if (session) {
291 session->state.new = call_state;
292 voice_extn_is_call_state_active(adev, &is_call_active);
293 ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
294 __func__, is_call_active, adev->voice.in_call, adev->mode);
295 /* Dont start voice call before device routing for voice usescases has
296 * occured, otherwise voice calls will be started unintendedly on
297 * speaker.
298 */
299 if (is_call_active ||
300 (adev->voice.in_call && adev->mode == AUDIO_MODE_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
voice_extn_get_active_session_id(struct audio_device * adev,uint32_t * session_id)315 int 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
voice_extn_is_call_state_active(struct audio_device * adev,bool * is_call_active)322 int 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
voice_extn_is_in_call_rec_stream(struct stream_in * in,bool * in_call_rec)339 int 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
voice_extn_init(struct audio_device * adev)352 void 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
voice_extn_get_session_from_use_case(struct audio_device * adev,const audio_usecase_t usecase_id,struct voice_session ** session)361 int 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
voice_extn_start_call(struct audio_device * adev)397 int 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
voice_extn_stop_call(struct audio_device * adev)406 int 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
voice_extn_set_parameters(struct audio_device * adev,struct str_parms * parms)430 int 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
494 done:
495 ALOGV("%s: exit with code(%d)", __func__, ret);
496 free(kv_pairs);
497 return ret;
498 }
499
get_all_call_states_str(const struct audio_device * adev,char * value)500 static 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
voice_extn_get_parameters(const struct audio_device * adev,struct str_parms * query,struct str_parms * reply)518 void 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
voice_extn_check_and_set_incall_music_usecase(struct audio_device * adev,struct stream_out * out)552 int 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