voice_extn.c revision f1819247a21f755757a28ea313678faff73ef349
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
59struct 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
70extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
71extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
72int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
73
74static bool is_valid_call_state(int call_state)
75{
76    if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
77        return false;
78    else
79        return true;
80}
81
82static bool is_valid_vsid(uint32_t vsid)
83{
84    if (vsid == VOICE_VSID ||
85        vsid == VOICE2_VSID ||
86        vsid == VOLTE_VSID ||
87        vsid == QCHAT_VSID ||
88        vsid == VOWLAN_VSID)
89        return true;
90    else
91        return false;
92}
93
94static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
95{
96    audio_usecase_t usecase_id = -1;
97
98    switch(index) {
99    case VOICE_SESS_IDX:
100        usecase_id = USECASE_VOICE_CALL;
101        break;
102
103    case VOICE2_SESS_IDX:
104        usecase_id = USECASE_VOICE2_CALL;
105        break;
106
107    case VOLTE_SESS_IDX:
108        usecase_id = USECASE_VOLTE_CALL;
109        break;
110
111    case QCHAT_SESS_IDX:
112        usecase_id = USECASE_QCHAT_CALL;
113        break;
114
115    case VOWLAN_SESS_IDX:
116        usecase_id = USECASE_VOWLAN_CALL;
117        break;
118
119    default:
120        ALOGE("%s: Invalid voice session index\n", __func__);
121    }
122
123    return usecase_id;
124}
125
126static uint32_t get_session_id_with_state(struct audio_device *adev,
127                                          int call_state)
128{
129    struct voice_session *session = NULL;
130    int i = 0;
131    uint32_t session_id = 0;
132
133    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
134        session = &adev->voice.session[i];
135        if(session->state.current == call_state){
136            session_id = session->vsid;
137            break;
138        }
139    }
140
141    return session_id;
142}
143
144static int update_calls(struct audio_device *adev)
145{
146    int i = 0;
147    audio_usecase_t usecase_id = 0;
148    enum voice_lch_mode lch_mode;
149    struct voice_session *session = NULL;
150    int fd = 0;
151    int ret = 0;
152
153    ALOGD("%s: enter:", __func__);
154
155    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
156        usecase_id = voice_extn_get_usecase_for_session_idx(i);
157        session = &adev->voice.session[i];
158        ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
159              __func__, session->state.current, session->state.new, session->vsid);
160
161        switch(session->state.new)
162        {
163        case CALL_ACTIVE:
164            switch(session->state.current)
165            {
166            case CALL_INACTIVE:
167                ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
168                ret = start_call(adev, usecase_id);
169                if(ret < 0) {
170                    ALOGE("%s: voice_start_call() failed for usecase: %d\n",
171                          __func__, usecase_id);
172                } else {
173                    session->state.current = session->state.new;
174                }
175                break;
176
177            case CALL_HOLD:
178                ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
179                session->state.current = session->state.new;
180                break;
181
182            case CALL_LOCAL_HOLD:
183                ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
184                lch_mode = VOICE_LCH_STOP;
185                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
186                    ALOGE("LOCAL_HOLD -> ACTIVE failed");
187                } else {
188                    session->state.current = session->state.new;
189                }
190                break;
191
192            default:
193                ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
194                      __func__, session->state.current, session->vsid);
195                break;
196            }
197            break;
198
199        case CALL_INACTIVE:
200            switch(session->state.current)
201            {
202            case CALL_ACTIVE:
203            case CALL_HOLD:
204            case CALL_LOCAL_HOLD:
205                ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
206                ret = stop_call(adev, usecase_id);
207                if(ret < 0) {
208                    ALOGE("%s: voice_end_call() failed for usecase: %d\n",
209                          __func__, usecase_id);
210                } else {
211                    session->state.current = session->state.new;
212                }
213                break;
214
215            default:
216                ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
217                      __func__, session->state.current, session->vsid);
218                break;
219            }
220            break;
221
222        case CALL_HOLD:
223            switch(session->state.current)
224            {
225            case CALL_ACTIVE:
226                ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
227                session->state.current = session->state.new;
228                break;
229
230            case CALL_LOCAL_HOLD:
231                ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
232                lch_mode = VOICE_LCH_STOP;
233                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
234                    ALOGE("LOCAL_HOLD -> HOLD failed");
235                } else {
236                    session->state.current = session->state.new;
237                }
238                break;
239
240            default:
241                ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
242                      __func__, session->state.current, session->vsid);
243                break;
244            }
245            break;
246
247        case CALL_LOCAL_HOLD:
248            switch(session->state.current)
249            {
250            case CALL_ACTIVE:
251            case CALL_HOLD:
252                ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
253                      session->vsid);
254                lch_mode = VOICE_LCH_START;
255                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
256                    ALOGE("LOCAL_HOLD -> HOLD failed");
257                } else {
258                    session->state.current = session->state.new;
259                }
260                break;
261
262            default:
263                ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
264                      __func__, session->state.current, session->vsid);
265                break;
266            }
267            break;
268
269        default:
270            break;
271        } //end out switch loop
272    } //end for loop
273
274    return ret;
275}
276
277static int update_call_states(struct audio_device *adev,
278                                    const uint32_t vsid, const int call_state)
279{
280    struct voice_session *session = NULL;
281    int i = 0;
282    bool is_call_active;
283
284    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
285        if (vsid == adev->voice.session[i].vsid) {
286            session = &adev->voice.session[i];
287            break;
288        }
289    }
290
291    if (session) {
292        session->state.new = call_state;
293        voice_extn_is_call_state_active(adev, &is_call_active);
294        ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
295              __func__, is_call_active, adev->voice.in_call, adev->mode);
296        /* Dont start voice call before device routing for voice usescases has
297         * occured, otherwise voice calls will be started unintendedly on
298         * speaker.
299         */
300        if (is_call_active || adev->voice.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
315int 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
322int 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
339int 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
352void 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
361int 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
397int 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
406int 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
430int 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
494done:
495    ALOGV("%s: exit with code(%d)", __func__, ret);
496    free(kv_pairs);
497    return ret;
498}
499
500static 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
518void 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
552int 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