• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
3  * Not a contribution.
4  *
5  * Copyright (C) 2013 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #define LOG_TAG "voice_extn"
21 /*#define LOG_NDEBUG 0*/
22 #define LOG_NDDEBUG 0
23 
24 #include <errno.h>
25 #include <math.h>
26 #include <cutils/log.h>
27 #include <cutils/str_parms.h>
28 #include <sys/ioctl.h>
29 #include <sound/voice_params.h>
30 #include <stdlib.h>
31 
32 #include "audio_hw.h"
33 #include "voice.h"
34 #include "platform.h"
35 #include "platform_api.h"
36 #include "voice_extn.h"
37 
38 #define AUDIO_PARAMETER_KEY_VSID                "vsid"
39 #define AUDIO_PARAMETER_KEY_CALL_STATE          "call_state"
40 #define AUDIO_PARAMETER_KEY_AUDIO_MODE          "audio_mode"
41 #define AUDIO_PARAMETER_KEY_ALL_CALL_STATES     "all_call_states"
42 #define AUDIO_PARAMETER_KEY_DEVICE_MUTE         "device_mute"
43 #define AUDIO_PARAMETER_KEY_DIRECTION           "direction"
44 #define AUDIO_PARAMETER_KEY_IN_CALL             "in_call"
45 
46 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
47 
48 #define VOICE2_VSID 0x10DC1000
49 #define VOLTE_VSID  0x10C02000
50 #define QCHAT_VSID  0x10803000
51 #define VOWLAN_VSID 0x10002000
52 #define ALL_VSID    0xFFFFFFFF
53 
54 /* Voice Session Indices */
55 #define VOICE2_SESS_IDX    (VOICE_SESS_IDX + 1)
56 #define VOLTE_SESS_IDX     (VOICE_SESS_IDX + 2)
57 #define QCHAT_SESS_IDX     (VOICE_SESS_IDX + 3)
58 #define VOWLAN_SESS_IDX    (VOICE_SESS_IDX + 4)
59 
60 /* Call States */
61 #define CALL_HOLD           (BASE_CALL_STATE + 2)
62 #define CALL_LOCAL_HOLD     (BASE_CALL_STATE + 3)
63 
64 struct pcm_config pcm_config_incall_music = {
65     .channels = 1,
66     .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
67     .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
68     .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
69     .format = PCM_FORMAT_S16_LE,
70     .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
71     .stop_threshold = INT_MAX,
72     .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
73 };
74 
75 int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
76 
is_valid_call_state(int call_state)77 static bool is_valid_call_state(int call_state)
78 {
79     if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
80         return false;
81     else
82         return true;
83 }
84 
is_valid_vsid(uint32_t vsid)85 static bool is_valid_vsid(uint32_t vsid)
86 {
87     if (vsid == VOICE_VSID ||
88         vsid == VOICE2_VSID ||
89         vsid == VOLTE_VSID ||
90         vsid == QCHAT_VSID ||
91         vsid == VOWLAN_VSID)
92         return true;
93     else
94         return false;
95 }
96 
voice_extn_get_usecase_for_session_idx(const int index)97 static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
98 {
99     audio_usecase_t usecase_id = -1;
100 
101     switch(index) {
102     case VOICE_SESS_IDX:
103         usecase_id = USECASE_VOICE_CALL;
104         break;
105 
106     case VOICE2_SESS_IDX:
107         usecase_id = USECASE_VOICE2_CALL;
108         break;
109 
110     case VOLTE_SESS_IDX:
111         usecase_id = USECASE_VOLTE_CALL;
112         break;
113 
114     case QCHAT_SESS_IDX:
115         usecase_id = USECASE_QCHAT_CALL;
116         break;
117 
118     case VOWLAN_SESS_IDX:
119         usecase_id = USECASE_VOWLAN_CALL;
120         break;
121 
122     default:
123         ALOGE("%s: Invalid voice session index\n", __func__);
124     }
125 
126     return usecase_id;
127 }
128 
get_session_id_with_state(struct audio_device * adev,int call_state)129 static uint32_t get_session_id_with_state(struct audio_device *adev,
130                                           int call_state)
131 {
132     struct voice_session *session = NULL;
133     int i = 0;
134     uint32_t session_id = 0;
135 
136     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
137         session = &adev->voice.session[i];
138         if(session->state.current == call_state){
139             session_id = session->vsid;
140             break;
141         }
142     }
143 
144     return session_id;
145 }
146 
update_calls(struct audio_device * adev)147 static int update_calls(struct audio_device *adev)
148 {
149     int i = 0;
150     audio_usecase_t usecase_id = 0;
151     enum voice_lch_mode lch_mode;
152     struct voice_session *session = NULL;
153     int fd = 0;
154     int ret = 0;
155 
156     ALOGD("%s: enter:", __func__);
157 
158     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
159         usecase_id = voice_extn_get_usecase_for_session_idx(i);
160         session = &adev->voice.session[i];
161         ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
162               __func__, session->state.current, session->state.new, session->vsid);
163 
164         switch(session->state.new)
165         {
166         case CALL_ACTIVE:
167             switch(session->state.current)
168             {
169             case CALL_INACTIVE:
170                 ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
171                 ret = voice_start_usecase(adev, usecase_id);
172                 if(ret < 0) {
173                     ALOGE("%s: voice_start_usecase() failed for usecase: %d\n",
174                           __func__, usecase_id);
175                 } else {
176                     session->state.current = session->state.new;
177                 }
178                 break;
179 
180             case CALL_HOLD:
181                 ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
182                 session->state.current = session->state.new;
183                 break;
184 
185             case CALL_LOCAL_HOLD:
186                 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
187                 lch_mode = VOICE_LCH_STOP;
188                 ret = platform_update_lch(adev->platform, session, lch_mode);
189                 if (ret < 0)
190                     ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
191                 else
192                     session->state.current = session->state.new;
193                 break;
194 
195             default:
196                 ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
197                       __func__, session->state.current, session->vsid);
198                 break;
199             }
200             break;
201 
202         case CALL_INACTIVE:
203             switch(session->state.current)
204             {
205             case CALL_ACTIVE:
206             case CALL_HOLD:
207             case CALL_LOCAL_HOLD:
208                 ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
209                 ret = voice_stop_usecase(adev, usecase_id);
210                 if(ret < 0) {
211                     ALOGE("%s: voice_stop_usecase() failed for usecase: %d\n",
212                           __func__, usecase_id);
213                 } else {
214                     session->state.current = session->state.new;
215                 }
216                 break;
217 
218             default:
219                 ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
220                       __func__, session->state.current, session->vsid);
221                 break;
222             }
223             break;
224 
225         case CALL_HOLD:
226             switch(session->state.current)
227             {
228             case CALL_ACTIVE:
229                 ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
230                 session->state.current = session->state.new;
231                 break;
232 
233             case CALL_LOCAL_HOLD:
234                 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
235                 lch_mode = VOICE_LCH_STOP;
236                 ret = platform_update_lch(adev->platform, session, lch_mode);
237                 if (ret < 0)
238                     ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
239                 else
240                     session->state.current = session->state.new;
241                 break;
242 
243             default:
244                 ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
245                       __func__, session->state.current, session->vsid);
246                 break;
247             }
248             break;
249 
250         case CALL_LOCAL_HOLD:
251             switch(session->state.current)
252             {
253             case CALL_ACTIVE:
254             case CALL_HOLD:
255                 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
256                       session->vsid);
257                 lch_mode = VOICE_LCH_START;
258                 ret = platform_update_lch(adev->platform, session, lch_mode);
259                 if (ret < 0)
260                     ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
261                 else
262                     session->state.current = session->state.new;
263                 break;
264 
265             default:
266                 ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
267                       __func__, session->state.current, session->vsid);
268                 break;
269             }
270             break;
271 
272         default:
273             break;
274         } //end out switch loop
275     } //end for loop
276 
277     return ret;
278 }
279 
update_call_states(struct audio_device * adev,const uint32_t vsid,const int call_state)280 static int update_call_states(struct audio_device *adev,
281                                     const uint32_t vsid, const int call_state)
282 {
283     struct voice_session *session = NULL;
284     int i = 0;
285     bool is_call_active;
286 
287     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
288         if (vsid == adev->voice.session[i].vsid) {
289             session = &adev->voice.session[i];
290             break;
291         }
292     }
293 
294     if (session) {
295         session->state.new = call_state;
296         voice_extn_is_call_state_active(adev, &is_call_active);
297         ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
298               __func__, is_call_active, adev->voice.in_call, adev->mode);
299         /* Dont start voice call before device routing for voice usescases has
300          * occured, otherwise voice calls will be started unintendedly on
301          * speaker.
302          */
303         if (is_call_active ||
304                 (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL)) {
305             /* Device routing is not triggered for voice calls on the subsequent
306              * subs, Hence update the call states if voice call is already
307              * active on other sub.
308              */
309             update_calls(adev);
310         }
311     } else {
312         return -EINVAL;
313     }
314 
315     return 0;
316 
317 }
318 
voice_extn_get_active_session_id(struct audio_device * adev,uint32_t * session_id)319 int voice_extn_get_active_session_id(struct audio_device *adev,
320                                      uint32_t *session_id)
321 {
322     *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
323     return 0;
324 }
325 
voice_extn_is_call_state_active(struct audio_device * adev,bool * is_call_active)326 int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active)
327 {
328     struct voice_session *session = NULL;
329     int i = 0;
330     *is_call_active = false;
331 
332     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
333         session = &adev->voice.session[i];
334         if(session->state.current != CALL_INACTIVE){
335             *is_call_active = true;
336             break;
337         }
338     }
339 
340     return 0;
341 }
342 
voice_extn_is_in_call_rec_stream(struct stream_in * in,bool * in_call_rec)343 int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec)
344 {
345     *in_call_rec = false;
346 
347     if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
348        in->source == AUDIO_SOURCE_VOICE_UPLINK ||
349        in->source == AUDIO_SOURCE_VOICE_CALL) {
350        *in_call_rec = true;
351     }
352 
353     return 0;
354 }
355 
voice_extn_init(struct audio_device * adev)356 void voice_extn_init(struct audio_device *adev)
357 {
358     adev->voice.session[VOICE_SESS_IDX].vsid =  VOICE_VSID;
359     adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
360     adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
361     adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
362     adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID;
363 }
364 
voice_extn_get_session_from_use_case(struct audio_device * adev,const audio_usecase_t usecase_id,struct voice_session ** session)365 int voice_extn_get_session_from_use_case(struct audio_device *adev,
366                                          const audio_usecase_t usecase_id,
367                                          struct voice_session **session)
368 {
369 
370     switch(usecase_id)
371     {
372     case USECASE_VOICE_CALL:
373         *session = &adev->voice.session[VOICE_SESS_IDX];
374         break;
375 
376     case USECASE_VOICE2_CALL:
377         *session = &adev->voice.session[VOICE2_SESS_IDX];
378         break;
379 
380     case USECASE_VOLTE_CALL:
381         *session = &adev->voice.session[VOLTE_SESS_IDX];
382         break;
383 
384     case USECASE_QCHAT_CALL:
385         *session = &adev->voice.session[QCHAT_SESS_IDX];
386         break;
387 
388     case USECASE_VOWLAN_CALL:
389         *session = &adev->voice.session[VOWLAN_SESS_IDX];
390         break;
391 
392     default:
393         ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
394         *session = NULL;
395         return -EINVAL;
396     }
397 
398     return 0;
399 }
400 
voice_extn_start_call(struct audio_device * adev)401 int voice_extn_start_call(struct audio_device *adev)
402 {
403     /* Start voice calls on sessions whose call state has been
404      * udpated.
405      */
406     ALOGV("%s: enter:", __func__);
407     return update_calls(adev);
408 }
409 
voice_extn_stop_call(struct audio_device * adev)410 int voice_extn_stop_call(struct audio_device *adev)
411 {
412     int i;
413     int ret = 0;
414 
415     ALOGV("%s: enter:", __func__);
416 
417     /* If BT device is enabled and voice calls are ended, telephony will call
418      * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
419      * set routing with device BT A2DP profile. Hence end all voice calls when
420      * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
421      */
422     if (adev->mode == AUDIO_MODE_NORMAL) {
423         ALOGD("%s: end all calls", __func__);
424         for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
425             adev->voice.session[i].state.new = CALL_INACTIVE;
426         }
427 
428         ret = update_calls(adev);
429     }
430 
431     return ret;
432 }
433 
voice_extn_set_parameters(struct audio_device * adev,struct str_parms * parms)434 int voice_extn_set_parameters(struct audio_device *adev,
435                               struct str_parms *parms)
436 {
437     char *str;
438     int value;
439     int ret = 0, err;
440     char *kv_pairs = str_parms_to_str(parms);
441     char str_value[256] = {0};
442 
443     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
444 
445     err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
446     if (err >= 0) {
447         str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
448         uint32_t vsid = value;
449         int call_state = -1;
450         err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
451         if (err >= 0) {
452             call_state = value;
453             str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE);
454         } else {
455             ALOGE("%s: call_state key not found", __func__);
456             ret = -EINVAL;
457             goto done;
458         }
459 
460         if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
461             ret = update_call_states(adev, vsid, call_state);
462         } else {
463             ALOGE("%s: invalid vsid:%x or call_state:%d",
464                   __func__, vsid, call_state);
465             ret = -EINVAL;
466             goto done;
467         }
468     }
469 
470     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value,
471                             sizeof(str_value));
472     if (err >= 0) {
473         str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE);
474         bool mute = false;
475 
476         if (!strncmp("true", str_value, sizeof("true"))) {
477             mute = true;
478         }
479 
480         err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value,
481                                 sizeof(str_value));
482         if (err >= 0) {
483             str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION);
484         } else {
485             ALOGE("%s: direction key not found", __func__);
486             ret = -EINVAL;
487             goto done;
488         }
489 
490         ret = platform_set_device_mute(adev->platform, mute, str_value);
491         if (ret != 0) {
492             ALOGE("%s: Failed to set mute err:%d", __func__, ret);
493             ret = -EINVAL;
494             goto done;
495         }
496     }
497 
498     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_IN_CALL, str_value,
499                             sizeof(str_value));
500     if (err >= 0) {
501           str_parms_del(parms, AUDIO_PARAMETER_KEY_IN_CALL);
502            if (!strncmp("true", str_value, sizeof("true"))) {
503            adev->voice.is_in_call = true;
504         }
505     }
506 
507 done:
508     ALOGV("%s: exit with code(%d)", __func__, ret);
509     free(kv_pairs);
510     return ret;
511 }
512 
get_all_call_states_str(const struct audio_device * adev,char * value)513 static int get_all_call_states_str(const struct audio_device *adev,
514                             char *value)
515 {
516     int ret = 0;
517     char *cur_ptr = value;
518     int i, len=0;
519 
520     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
521         snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len,
522                  "%d:%d,",adev->voice.session[i].vsid,
523                  adev->voice.session[i].state.current);
524         len = strlen(cur_ptr);
525         cur_ptr = cur_ptr + len;
526     }
527     ALOGV("%s:value=%s", __func__, value);
528     return ret;
529 }
530 
voice_extn_get_parameters(const struct audio_device * adev,struct str_parms * query,struct str_parms * reply)531 void voice_extn_get_parameters(const struct audio_device *adev,
532                                struct str_parms *query,
533                                struct str_parms *reply)
534 {
535     int ret;
536     char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0};
537     char *str = str_parms_to_str(query);
538     int val = 0;
539 
540     ALOGV_IF(str != NULL, "%s: enter %s", __func__, str);
541     free(str);
542 
543     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_IN_CALL, value,
544                             sizeof(value));
545     if (ret >=0) {
546         if (adev->voice.is_in_call)
547             val = 1;
548         str_parms_add_int(reply, AUDIO_PARAMETER_KEY_IN_CALL, val);
549     }
550 
551     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value,
552                             sizeof(value));
553     if (ret >= 0) {
554         str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode);
555     }
556 
557     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES,
558                             value, sizeof(value));
559     if (ret >= 0) {
560         ret = get_all_call_states_str(adev, value);
561         if (ret) {
562             ALOGE("%s: Error fetching call states, err:%d", __func__, ret);
563             return;
564         }
565         str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value);
566     }
567     voice_extn_compress_voip_get_parameters(query, reply);
568 
569     str = str_parms_to_str(reply);
570     ALOGV_IF(str != NULL, "%s: exit: returns \"%s\"", __func__, str);
571     free(str);
572 }
573 
voice_extn_out_get_parameters(struct stream_out * out,struct str_parms * query,struct str_parms * reply)574 void voice_extn_out_get_parameters(struct stream_out *out,
575                                    struct str_parms *query,
576                                    struct str_parms *reply)
577 {
578     voice_extn_compress_voip_out_get_parameters(out, query, reply);
579 }
580 
voice_extn_in_get_parameters(struct stream_in * in,struct str_parms * query,struct str_parms * reply)581 void voice_extn_in_get_parameters(struct stream_in *in,
582                                   struct str_parms *query,
583                                   struct str_parms *reply)
584 {
585     voice_extn_compress_voip_in_get_parameters(in, query, reply);
586 }
587 
588 #ifdef INCALL_MUSIC_ENABLED
voice_extn_check_and_set_incall_music_usecase(struct audio_device * adev,struct stream_out * out)589 int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
590                                                   struct stream_out *out)
591 {
592     uint32_t session_id = 0;
593 
594     session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
595     if (session_id == VOICE_VSID) {
596         out->usecase = USECASE_INCALL_MUSIC_UPLINK;
597     } else if (session_id == VOICE2_VSID) {
598         out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
599     } else {
600         ALOGE("%s: Invalid session id %x", __func__, session_id);
601         return -EINVAL;
602     }
603 
604     out->config = pcm_config_incall_music;
605     out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
606     out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
607 
608     return 0;
609 }
610 #endif
611 
612