• 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 <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