• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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