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 "compress_voip"
21/*#define LOG_NDEBUG 0*/
22#define LOG_NDDEBUG 0
23
24#include <errno.h>
25#include <pthread.h>
26#include <stdint.h>
27#include <sys/time.h>
28#include <stdlib.h>
29#include <math.h>
30#include <cutils/log.h>
31#include <cutils/str_parms.h>
32#include <cutils/properties.h>
33
34#include "audio_hw.h"
35#include "platform_api.h"
36#include "platform.h"
37#include "voice_extn.h"
38
39#define COMPRESS_VOIP_IO_BUF_SIZE_NB 320
40#define COMPRESS_VOIP_IO_BUF_SIZE_WB 640
41
42struct pcm_config pcm_config_voip_nb = {
43    .channels = 1,
44    .rate = 8000, /* changed when the stream is opened */
45    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_NB/2,
46    .period_count = 10,
47    .format = PCM_FORMAT_S16_LE,
48};
49
50struct pcm_config pcm_config_voip_wb = {
51    .channels = 1,
52    .rate = 16000, /* changed when the stream is opened */
53    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_WB/2,
54    .period_count = 10,
55    .format = PCM_FORMAT_S16_LE,
56};
57
58struct voip_data {
59    struct pcm *pcm_rx;
60    struct pcm *pcm_tx;
61    struct stream_out *out_stream;
62    uint32_t out_stream_count;
63    uint32_t in_stream_count;
64    uint32_t sample_rate;
65};
66
67#define MODE_IS127              0x2
68#define MODE_4GV_NB             0x3
69#define MODE_4GV_WB             0x4
70#define MODE_AMR                0x5
71#define MODE_AMR_WB             0xD
72#define MODE_PCM                0xC
73#define MODE_4GV_NW             0xE
74
75#define AUDIO_PARAMETER_KEY_VOIP_RATE               "voip_rate"
76#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN      "evrc_rate_min"
77#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX      "evrc_rate_max"
78#define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE           "dtx_on"
79#define AUDIO_PARAMETER_VALUE_VOIP_TRUE             "true"
80#define AUDIO_PARAMETER_KEY_VOIP_CHECK              "voip_flag"
81#define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT   "voip_out_stream_count"
82#define AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE        "voip_sample_rate"
83
84static struct voip_data voip_data = {
85  .pcm_rx = NULL,
86  .pcm_tx = NULL,
87  .out_stream = NULL,
88  .out_stream_count = 0,
89  .in_stream_count = 0,
90  .sample_rate = 0
91};
92
93static int voip_set_volume(struct audio_device *adev, int volume);
94static int voip_set_mic_mute(struct audio_device *adev, bool state);
95static int voip_set_mode(struct audio_device *adev, int format);
96static int voip_set_rate(struct audio_device *adev, int rate);
97static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
98                               int max_rate);
99static int voip_set_dtx(struct audio_device *adev, bool enable);
100static int voip_stop_call(struct audio_device *adev);
101static int voip_start_call(struct audio_device *adev,
102                           struct pcm_config *voip_config);
103
104static int audio_format_to_voip_mode(int format)
105{
106    int mode;
107
108    switch(format) {
109        case AUDIO_FORMAT_PCM_16_BIT:
110            mode = MODE_PCM;
111            break;
112        case AUDIO_FORMAT_AMR_NB:
113            mode = MODE_AMR;
114            break;
115        case AUDIO_FORMAT_AMR_WB:
116            mode = MODE_AMR_WB;
117            break;
118        case AUDIO_FORMAT_EVRC:
119            mode = MODE_IS127;
120            break;
121        case AUDIO_FORMAT_EVRCB:
122            mode = MODE_4GV_NB;
123            break;
124        case AUDIO_FORMAT_EVRCWB:
125            mode = MODE_4GV_WB;
126            break;
127        case AUDIO_FORMAT_EVRCNW:
128            mode = MODE_4GV_NW;
129            break;
130        default:
131            mode = MODE_PCM;
132    }
133    return mode;
134}
135
136static int voip_set_volume(struct audio_device *adev, int volume)
137{
138    struct mixer_ctl *ctl;
139    const char *mixer_ctl_name = "Voip Rx Gain";
140    int vol_index = 0;
141    uint32_t set_values[ ] = {0,
142                              DEFAULT_VOLUME_RAMP_DURATION_MS};
143
144    ALOGV("%s: enter", __func__);
145
146    /* Voice volume levels are mapped to adsp volume levels as follows.
147     * 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
148     * But this values don't changed in kernel. So, below change is need.
149     */
150    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
151    set_values[0] = vol_index;
152
153    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
154    if (!ctl) {
155        ALOGE("%s: Could not get ctl for mixer cmd - %s",
156              __func__, mixer_ctl_name);
157        return -EINVAL;
158    }
159    ALOGV("%s: Setting voip volume index: %d", __func__, set_values[0]);
160    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
161
162    ALOGV("%s: exit", __func__);
163    return 0;
164}
165
166static int voip_set_mic_mute(struct audio_device *adev, bool state)
167{
168    struct mixer_ctl *ctl;
169    const char *mixer_ctl_name = "Voip Tx Mute";
170    uint32_t set_values[ ] = {0,
171                              DEFAULT_VOLUME_RAMP_DURATION_MS};
172
173    ALOGV("%s: enter, state=%d", __func__, state);
174
175    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
176        set_values[0] = state;
177        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
178        if (!ctl) {
179            ALOGE("%s: Could not get ctl for mixer cmd - %s",
180                  __func__, mixer_ctl_name);
181            return -EINVAL;
182        }
183        mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
184    }
185
186    ALOGV("%s: exit", __func__);
187    return 0;
188}
189
190static int voip_set_mode(struct audio_device *adev, int format)
191{
192    struct mixer_ctl *ctl;
193    const char *mixer_ctl_name = "Voip Mode Config";
194    uint32_t set_values[ ] = {0};
195    int mode;
196
197    ALOGD("%s: enter, format=%d", __func__, format);
198
199    mode = audio_format_to_voip_mode(format);
200    ALOGD("%s: Derived mode = %d", __func__, mode);
201
202    set_values[0] = mode;
203    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
204    if (!ctl) {
205        ALOGE("%s: Could not get ctl for mixer cmd - %s",
206               __func__, mixer_ctl_name);
207        return -EINVAL;
208    }
209    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
210
211    ALOGV("%s: exit", __func__);
212    return 0;
213}
214
215static int voip_set_rate(struct audio_device *adev, int rate)
216{
217    struct mixer_ctl *ctl;
218    const char *mixer_ctl_name = "Voip Rate Config";
219    uint32_t set_values[ ] = {0};
220
221    ALOGD("%s: enter, rate=%d", __func__, rate);
222
223    set_values[0] = rate;
224    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
225    if (!ctl) {
226        ALOGE("%s: Could not get ctl for mixer cmd - %s",
227               __func__, mixer_ctl_name);
228        return -EINVAL;
229    }
230    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
231
232    ALOGV("%s: exit", __func__);
233    return 0;
234}
235
236static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
237                               int max_rate)
238{
239    struct mixer_ctl *ctl;
240    const char *mixer_ctl_name = "Voip Evrc Min Max Rate Config";
241    uint32_t set_values[ ] = {0, 0};
242
243    ALOGD("%s: enter, min_rate=%d, max_rate=%d",
244          __func__, min_rate, max_rate);
245
246    set_values[0] = min_rate;
247    set_values[1] = max_rate;
248    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
249    if (!ctl) {
250        ALOGE("%s: Could not get ctl for mixer cmd - %s",
251               __func__, mixer_ctl_name);
252        return -EINVAL;
253    }
254    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
255
256    ALOGV("%s: exit", __func__);
257    return 0;
258}
259
260static int voip_set_dtx(struct audio_device *adev, bool enable)
261{
262    struct mixer_ctl *ctl;
263    const char *mixer_ctl_name = "Voip Dtx Mode";
264    uint32_t set_values[ ] = {0};
265
266    ALOGD("%s: enter, enable=%d", __func__, enable);
267
268    set_values[0] = enable;
269    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
270    if (!ctl) {
271        ALOGE("%s: Could not get ctl for mixer cmd - %s",
272               __func__, mixer_ctl_name);
273        return -EINVAL;
274    }
275    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
276
277    ALOGV("%s: exit", __func__);
278    return 0;
279}
280
281static int voip_stop_call(struct audio_device *adev)
282{
283    int i, ret = 0;
284    struct audio_usecase *uc_info;
285
286    ALOGD("%s: enter, out_stream_count=%d, in_stream_count=%d",
287           __func__, voip_data.out_stream_count, voip_data.in_stream_count);
288
289    if (!voip_data.out_stream_count && !voip_data.in_stream_count) {
290        voip_data.sample_rate = 0;
291        uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
292        if (uc_info == NULL) {
293            ALOGE("%s: Could not find the usecase (%d) in the list",
294                  __func__, USECASE_COMPRESS_VOIP_CALL);
295            return -EINVAL;
296        }
297
298        /* 1. Close the PCM devices */
299        if (voip_data.pcm_rx) {
300            pcm_close(voip_data.pcm_rx);
301            voip_data.pcm_rx = NULL;
302        }
303        if (voip_data.pcm_tx) {
304            pcm_close(voip_data.pcm_tx);
305            voip_data.pcm_tx = NULL;
306        }
307
308        /* 2. Get and set stream specific mixer controls */
309        disable_audio_route(adev, uc_info);
310
311        /* 3. Disable the rx and tx devices */
312        disable_snd_device(adev, uc_info->out_snd_device);
313        disable_snd_device(adev, uc_info->in_snd_device);
314
315        list_remove(&uc_info->list);
316        free(uc_info);
317    } else
318        ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d",
319               __func__, voip_data.out_stream_count, voip_data.in_stream_count);
320
321    ALOGV("%s: exit: status(%d)", __func__, ret);
322    return ret;
323}
324
325static int voip_start_call(struct audio_device *adev,
326                           struct pcm_config *voip_config)
327{
328    int i, ret = 0;
329    struct audio_usecase *uc_info;
330    int pcm_dev_rx_id, pcm_dev_tx_id;
331
332    ALOGD("%s: enter", __func__);
333
334    uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
335    if (uc_info == NULL) {
336        ALOGV("%s: voip usecase is added to the list", __func__);
337        uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
338
339        if (!uc_info) {
340            ALOGE("failed to allocate voip usecase mem");
341            return -ENOMEM;
342        }
343
344        uc_info->id = USECASE_COMPRESS_VOIP_CALL;
345        uc_info->type = VOIP_CALL;
346        if (voip_data.out_stream)
347            uc_info->stream.out = voip_data.out_stream;
348        else
349            uc_info->stream.out = adev->primary_output;
350        uc_info->in_snd_device = SND_DEVICE_NONE;
351        uc_info->out_snd_device = SND_DEVICE_NONE;
352
353        list_add_tail(&adev->usecase_list, &uc_info->list);
354
355        select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
356
357        pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
358        pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
359
360        if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
361            ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
362                  __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
363            ret = -EIO;
364            goto error_start_voip;
365        }
366
367        ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)",
368              __func__, adev->snd_card, pcm_dev_rx_id);
369        voip_data.pcm_rx = pcm_open(adev->snd_card,
370                                    pcm_dev_rx_id,
371                                    PCM_OUT, voip_config);
372        if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) {
373            ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx));
374            pcm_close(voip_data.pcm_rx);
375            voip_data.pcm_rx = NULL;
376            ret = -EIO;
377            goto error_start_voip;
378        }
379
380        ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
381              __func__, adev->snd_card, pcm_dev_tx_id);
382        voip_data.pcm_tx = pcm_open(adev->snd_card,
383                                    pcm_dev_tx_id,
384                                    PCM_IN, voip_config);
385        if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) {
386            ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx));
387            pcm_close(voip_data.pcm_rx);
388            voip_data.pcm_tx = NULL;
389            if (voip_data.pcm_rx) {
390                pcm_close(voip_data.pcm_rx);
391                voip_data.pcm_rx = NULL;
392            }
393            ret = -EIO;
394            goto error_start_voip;
395        }
396        pcm_start(voip_data.pcm_rx);
397        pcm_start(voip_data.pcm_tx);
398
399        voice_extn_compress_voip_set_volume(adev, adev->voice.volume);
400
401        if (ret < 0) {
402            ALOGE("%s: error %d\n", __func__, ret);
403            goto error_start_voip;
404        }
405    } else {
406        ALOGV("%s: voip usecase is already enabled", __func__);
407        if (voip_data.out_stream)
408            uc_info->stream.out = voip_data.out_stream;
409        else
410            uc_info->stream.out = adev->primary_output;
411        select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
412    }
413
414    return 0;
415
416error_start_voip:
417    voip_stop_call(adev);
418
419    ALOGV("%s: exit: status(%d)", __func__, ret);
420    return ret;
421}
422
423int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
424                                             struct str_parms *parms)
425{
426    char *str;
427    char value[32]={0};
428    int ret = 0, err, rate;
429    int min_rate, max_rate;
430    bool flag;
431    char *kv_pairs = str_parms_to_str(parms);
432
433    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
434
435    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE,
436                            value, sizeof(value));
437    if (err >= 0) {
438        rate = atoi(value);
439        voip_set_rate(adev, rate);
440        voip_set_evrc_min_max_rate(adev, rate, rate);
441    }
442
443    memset(value, 0, sizeof(value));
444    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN,
445                            value, sizeof(value));
446    if (err >= 0) {
447        min_rate = atoi(value);
448        str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN);
449        memset(value, 0, sizeof(value));
450        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX,
451                                value, sizeof(value));
452        if (err >= 0) {
453            max_rate = atoi(value);
454            voip_set_evrc_min_max_rate(adev, min_rate, max_rate);
455        } else {
456            ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__);
457            ret = -EINVAL;
458            goto done;
459        }
460    }
461
462    memset(value, 0, sizeof(value));
463    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE,
464                            value, sizeof(value));
465    if (err >= 0) {
466        flag = false;
467        if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0)
468            flag = true;
469        voip_set_dtx(adev, flag);
470    }
471
472done:
473    ALOGV("%s: exit", __func__);
474    free(kv_pairs);
475    return ret;
476}
477
478void voice_extn_compress_voip_get_parameters(struct str_parms *query,
479                                             struct str_parms *reply)
480{
481    int ret;
482    char value[32]={0};
483    char *str = NULL;
484
485    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
486                            value, sizeof(value));
487    if (ret >= 0) {
488        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
489                          voip_data.out_stream_count);
490    }
491
492    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
493                            value, sizeof(value));
494    if (ret >= 0) {
495        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
496                          voip_data.sample_rate);
497    }
498}
499
500void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
501                                                 struct str_parms *query,
502                                                 struct str_parms *reply)
503{
504    int ret, val;
505    char value[32]={0};
506
507    ALOGD("%s: enter", __func__);
508
509    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
510
511    if (ret >= 0) {
512        if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
513            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
514        else
515            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
516    }
517
518    ALOGV("%s: exit", __func__);
519}
520
521void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
522                                                struct str_parms *query,
523                                                struct str_parms *reply)
524{
525    int ret, val;
526    char value[32]={0};
527    char *kv_pairs = NULL;
528
529    ALOGV("%s: enter", __func__);
530
531    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
532
533    if (ret >= 0) {
534        if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
535            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
536        else
537            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
538    }
539
540    kv_pairs = str_parms_to_str(reply);
541    ALOGD_IF(kv_pairs != NULL, "%s: exit: return - %s", __func__, kv_pairs);
542    free(kv_pairs);
543}
544
545int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out)
546{
547    if (out->config.rate == 16000)
548        return COMPRESS_VOIP_IO_BUF_SIZE_WB;
549    else
550        return COMPRESS_VOIP_IO_BUF_SIZE_NB;
551}
552
553int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in)
554{
555    if (in->config.rate == 16000)
556        return COMPRESS_VOIP_IO_BUF_SIZE_WB;
557    else
558        return COMPRESS_VOIP_IO_BUF_SIZE_NB;
559}
560
561int voice_extn_compress_voip_start_output_stream(struct stream_out *out)
562{
563    int ret = 0;
564    struct audio_device *adev = out->dev;
565    struct audio_usecase *uc_info;
566    int snd_card_status = get_snd_card_state(adev);
567
568    ALOGD("%s: enter", __func__);
569
570    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
571        ret = -ENETRESET;
572        ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
573        goto error;
574    }
575
576    if (!voip_data.out_stream_count)
577        ret = voice_extn_compress_voip_open_output_stream(out);
578
579    ret = voip_start_call(adev, &out->config);
580    out->pcm = voip_data.pcm_rx;
581    uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
582    if (uc_info) {
583        uc_info->stream.out = out;
584        uc_info->devices = out->devices;
585    } else {
586        ret = -EINVAL;
587        ALOGE("%s: exit(%d): failed to get use case info", __func__, ret);
588        goto error;
589    }
590
591error:
592    ALOGV("%s: exit: status(%d)", __func__, ret);
593    return ret;
594}
595
596int voice_extn_compress_voip_start_input_stream(struct stream_in *in)
597{
598    int ret = 0;
599    struct audio_usecase *uc_info;
600    struct audio_device *adev = in->dev;
601    int snd_card_status = get_snd_card_state(adev);
602
603    ALOGD("%s: enter", __func__);
604
605    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
606        ret = -ENETRESET;
607        ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
608        goto error;
609    }
610
611    if (!voip_data.in_stream_count)
612        ret = voice_extn_compress_voip_open_input_stream(in);
613
614    adev->active_input = in;
615    ret = voip_start_call(adev, &in->config);
616    in->pcm = voip_data.pcm_tx;
617
618error:
619    ALOGV("%s: exit: status(%d)", __func__, ret);
620    return ret;
621}
622
623int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream)
624{
625    struct stream_out *out = (struct stream_out *)stream;
626    struct audio_device *adev = out->dev;
627    int ret = 0;
628
629    ALOGD("%s: enter", __func__);
630    if (voip_data.out_stream_count > 0) {
631        voip_data.out_stream_count--;
632        ret = voip_stop_call(adev);
633        voip_data.out_stream = NULL;
634        out->pcm = NULL;
635    }
636
637    ALOGV("%s: exit: status(%d)", __func__, ret);
638    return ret;
639}
640
641int voice_extn_compress_voip_open_output_stream(struct stream_out *out)
642{
643    int mode, ret;
644
645    ALOGD("%s: enter", __func__);
646
647    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
648    out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
649    out->usecase = USECASE_COMPRESS_VOIP_CALL;
650    if (out->sample_rate == 16000)
651        out->config = pcm_config_voip_wb;
652    else
653        out->config = pcm_config_voip_nb;
654
655    voip_data.out_stream = out;
656    voip_data.out_stream_count++;
657    voip_data.sample_rate = out->sample_rate;
658    ret = voip_set_mode(out->dev, out->format);
659
660    ALOGV("%s: exit", __func__);
661    return ret;
662}
663
664int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream)
665{
666    struct stream_in *in = (struct stream_in *)stream;
667    struct audio_device *adev = in->dev;
668    int status = 0;
669
670    ALOGD("%s: enter", __func__);
671
672    if(voip_data.in_stream_count > 0) {
673       adev->active_input = NULL;
674       voip_data.in_stream_count--;
675       status = voip_stop_call(adev);
676       in->pcm = NULL;
677    }
678
679    ALOGV("%s: exit: status(%d)", __func__, status);
680    return status;
681}
682
683int voice_extn_compress_voip_open_input_stream(struct stream_in *in)
684{
685    int sample_rate;
686    int buffer_size,frame_size;
687    int mode, ret;
688
689    ALOGD("%s: enter", __func__);
690
691    if ((voip_data.sample_rate != 0) &&
692        (voip_data.sample_rate != in->config.rate)) {
693        ret = -ENOTSUP;
694        goto done;
695    } else {
696        voip_data.sample_rate = in->config.rate;
697    }
698
699    in->usecase = USECASE_COMPRESS_VOIP_CALL;
700    if (in->config.rate == 16000)
701        in->config = pcm_config_voip_wb;
702    else
703        in->config = pcm_config_voip_nb;
704
705    voip_data.in_stream_count++;
706    ret = voip_set_mode(in->dev, in->format);
707
708done:
709    ALOGV("%s: exit, ret=%d", __func__, ret);
710    return ret;
711}
712
713int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume)
714{
715    int vol, err = 0;
716
717    ALOGV("%s: enter", __func__);
718
719    if (volume < 0.0) {
720        volume = 0.0;
721    } else if (volume > 1.0) {
722        volume = 1.0;
723    }
724
725    vol = lrint(volume * 100.0);
726
727    /* Voice volume levels from android are mapped to driver volume levels as follows.
728     * 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
729     * So adjust the volume to get the correct volume index in driver
730     */
731    vol = 100 - vol;
732
733    err = voip_set_volume(adev, vol);
734
735    ALOGV("%s: exit: status(%d)", __func__, err);
736
737    return err;
738}
739
740int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state)
741{
742    int err = 0;
743
744    ALOGV("%s: enter", __func__);
745
746    err = voip_set_mic_mute(adev, state);
747
748    ALOGV("%s: exit: status(%d)", __func__, err);
749    return err;
750}
751
752bool voice_extn_compress_voip_pcm_prop_check()
753{
754    char prop_value[PROPERTY_VALUE_MAX] = {0};
755
756    property_get("use.voice.path.for.pcm.voip", prop_value, "0");
757    if (!strncmp("true", prop_value, sizeof("true")))
758    {
759        ALOGD("%s: VoIP PCM property is enabled", __func__);
760        return true;
761    }
762    else
763        return false;
764}
765
766bool voice_extn_compress_voip_is_active(struct audio_device *adev)
767{
768    struct audio_usecase *voip_usecase = NULL;
769    voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
770
771    if (voip_usecase != NULL)
772        return true;
773    else
774        return false;
775}
776
777bool voice_extn_compress_voip_is_format_supported(audio_format_t format)
778{
779    switch (format) {
780    case AUDIO_FORMAT_PCM_16_BIT:
781        if (voice_extn_compress_voip_pcm_prop_check())
782            return true;
783        else
784            return false;
785    case AUDIO_FORMAT_AMR_NB:
786    case AUDIO_FORMAT_AMR_WB:
787    case AUDIO_FORMAT_EVRC:
788    case AUDIO_FORMAT_EVRCB:
789    case AUDIO_FORMAT_EVRCWB:
790    case AUDIO_FORMAT_EVRCNW:
791        return true;
792    default:
793        return false;
794    }
795}
796
797bool voice_extn_compress_voip_is_config_supported(struct audio_config *config)
798{
799    bool ret = false;
800
801    ret = voice_extn_compress_voip_is_format_supported(config->format);
802    if (ret) {
803        if ((popcount(config->channel_mask) == 1) &&
804            (config->sample_rate == 8000 || config->sample_rate == 16000))
805            ret = ((voip_data.sample_rate == 0) ? true:
806                    (voip_data.sample_rate == config->sample_rate));
807        else
808            ret = false;
809    }
810    return ret;
811}
812