diff options
Diffstat (limited to 'audio/hal/voice_extn/compress_voip.c')
-rw-r--r-- | audio/hal/voice_extn/compress_voip.c | 811 |
1 files changed, 811 insertions, 0 deletions
diff --git a/audio/hal/voice_extn/compress_voip.c b/audio/hal/voice_extn/compress_voip.c new file mode 100644 index 0000000..26636db --- /dev/null +++ b/audio/hal/voice_extn/compress_voip.c @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "compress_voip" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <sys/time.h> +#include <stdlib.h> +#include <math.h> +#include <cutils/log.h> +#include <cutils/str_parms.h> +#include <cutils/properties.h> + +#include "audio_hw.h" +#include "platform_api.h" +#include "platform.h" +#include "voice_extn.h" + +#define COMPRESS_VOIP_IO_BUF_SIZE_NB 320 +#define COMPRESS_VOIP_IO_BUF_SIZE_WB 640 + +struct pcm_config pcm_config_voip_nb = { + .channels = 1, + .rate = 8000, /* changed when the stream is opened */ + .period_size = COMPRESS_VOIP_IO_BUF_SIZE_NB/2, + .period_count = 10, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_voip_wb = { + .channels = 1, + .rate = 16000, /* changed when the stream is opened */ + .period_size = COMPRESS_VOIP_IO_BUF_SIZE_WB/2, + .period_count = 10, + .format = PCM_FORMAT_S16_LE, +}; + +struct voip_data { + struct pcm *pcm_rx; + struct pcm *pcm_tx; + struct stream_out *out_stream; + uint32_t out_stream_count; + uint32_t in_stream_count; + uint32_t sample_rate; +}; + +#define MODE_IS127 0x2 +#define MODE_4GV_NB 0x3 +#define MODE_4GV_WB 0x4 +#define MODE_AMR 0x5 +#define MODE_AMR_WB 0xD +#define MODE_PCM 0xC +#define MODE_4GV_NW 0xE + +#define AUDIO_PARAMETER_KEY_VOIP_RATE "voip_rate" +#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN "evrc_rate_min" +#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX "evrc_rate_max" +#define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE "dtx_on" +#define AUDIO_PARAMETER_VALUE_VOIP_TRUE "true" +#define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag" +#define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT "voip_out_stream_count" +#define AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE "voip_sample_rate" + +static struct voip_data voip_data = { + .pcm_rx = NULL, + .pcm_tx = NULL, + .out_stream = NULL, + .out_stream_count = 0, + .in_stream_count = 0, + .sample_rate = 0 +}; + +static int voip_set_volume(struct audio_device *adev, int volume); +static int voip_set_mic_mute(struct audio_device *adev, bool state); +static int voip_set_mode(struct audio_device *adev, int format); +static int voip_set_rate(struct audio_device *adev, int rate); +static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate, + int max_rate); +static int voip_set_dtx(struct audio_device *adev, bool enable); +static int voip_stop_call(struct audio_device *adev); +static int voip_start_call(struct audio_device *adev, + struct pcm_config *voip_config); + +static int audio_format_to_voip_mode(int format) +{ + int mode; + + switch(format) { + case AUDIO_FORMAT_PCM_16_BIT: + mode = MODE_PCM; + break; + case AUDIO_FORMAT_AMR_NB: + mode = MODE_AMR; + break; + case AUDIO_FORMAT_AMR_WB: + mode = MODE_AMR_WB; + break; + case AUDIO_FORMAT_EVRC: + mode = MODE_IS127; + break; + case AUDIO_FORMAT_EVRCB: + mode = MODE_4GV_NB; + break; + case AUDIO_FORMAT_EVRCWB: + mode = MODE_4GV_WB; + break; + case AUDIO_FORMAT_EVRCNW: + mode = MODE_4GV_NW; + break; + default: + mode = MODE_PCM; + } + return mode; +} + +static int voip_set_volume(struct audio_device *adev, int volume) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Rx Gain"; + int vol_index = 0; + uint32_t set_values[ ] = {0, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + ALOGV("%s: enter", __func__); + + /* Voice volume levels are mapped to adsp volume levels as follows. + * 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 + * But this values don't changed in kernel. So, below change is need. + */ + vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); + set_values[0] = vol_index; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("%s: Setting voip volume index: %d", __func__, set_values[0]); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_mic_mute(struct audio_device *adev, bool state) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Tx Mute"; + uint32_t set_values[ ] = {0, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + ALOGV("%s: enter, state=%d", __func__, state); + + if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) { + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + } + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_mode(struct audio_device *adev, int format) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Mode Config"; + uint32_t set_values[ ] = {0}; + int mode; + + ALOGD("%s: enter, format=%d", __func__, format); + + mode = audio_format_to_voip_mode(format); + ALOGD("%s: Derived mode = %d", __func__, mode); + + set_values[0] = mode; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_rate(struct audio_device *adev, int rate) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Rate Config"; + uint32_t set_values[ ] = {0}; + + ALOGD("%s: enter, rate=%d", __func__, rate); + + set_values[0] = rate; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate, + int max_rate) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Evrc Min Max Rate Config"; + uint32_t set_values[ ] = {0, 0}; + + ALOGD("%s: enter, min_rate=%d, max_rate=%d", + __func__, min_rate, max_rate); + + set_values[0] = min_rate; + set_values[1] = max_rate; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_dtx(struct audio_device *adev, bool enable) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Dtx Mode"; + uint32_t set_values[ ] = {0}; + + ALOGD("%s: enter, enable=%d", __func__, enable); + + set_values[0] = enable; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_stop_call(struct audio_device *adev) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + + ALOGD("%s: enter, out_stream_count=%d, in_stream_count=%d", + __func__, voip_data.out_stream_count, voip_data.in_stream_count); + + if (!voip_data.out_stream_count && !voip_data.in_stream_count) { + voip_data.sample_rate = 0; + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, USECASE_COMPRESS_VOIP_CALL); + return -EINVAL; + } + + /* 1. Close the PCM devices */ + if (voip_data.pcm_rx) { + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + } + if (voip_data.pcm_tx) { + pcm_close(voip_data.pcm_tx); + voip_data.pcm_tx = NULL; + } + + /* 2. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info); + + /* 3. Disable the rx and tx devices */ + disable_snd_device(adev, uc_info->out_snd_device); + disable_snd_device(adev, uc_info->in_snd_device); + + list_remove(&uc_info->list); + free(uc_info); + } else + ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d", + __func__, voip_data.out_stream_count, voip_data.in_stream_count); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +static int voip_start_call(struct audio_device *adev, + struct pcm_config *voip_config) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + int pcm_dev_rx_id, pcm_dev_tx_id; + + ALOGD("%s: enter", __func__); + + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if (uc_info == NULL) { + ALOGV("%s: voip usecase is added to the list", __func__); + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + + if (!uc_info) { + ALOGE("failed to allocate voip usecase mem"); + return -ENOMEM; + } + + uc_info->id = USECASE_COMPRESS_VOIP_CALL; + uc_info->type = VOIP_CALL; + if (voip_data.out_stream) + uc_info->stream.out = voip_data.out_stream; + else + uc_info->stream.out = adev->primary_output; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, USECASE_COMPRESS_VOIP_CALL); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); + + if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + ret = -EIO; + goto error_start_voip; + } + + ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)", + __func__, adev->snd_card, pcm_dev_rx_id); + voip_data.pcm_rx = pcm_open(adev->snd_card, + pcm_dev_rx_id, + PCM_OUT, voip_config); + if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx)); + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + ret = -EIO; + goto error_start_voip; + } + + ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, adev->snd_card, pcm_dev_tx_id); + voip_data.pcm_tx = pcm_open(adev->snd_card, + pcm_dev_tx_id, + PCM_IN, voip_config); + if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx)); + pcm_close(voip_data.pcm_rx); + voip_data.pcm_tx = NULL; + if (voip_data.pcm_rx) { + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + } + ret = -EIO; + goto error_start_voip; + } + pcm_start(voip_data.pcm_rx); + pcm_start(voip_data.pcm_tx); + + voice_extn_compress_voip_set_volume(adev, adev->voice.volume); + + if (ret < 0) { + ALOGE("%s: error %d\n", __func__, ret); + goto error_start_voip; + } + } else { + ALOGV("%s: voip usecase is already enabled", __func__); + if (voip_data.out_stream) + uc_info->stream.out = voip_data.out_stream; + else + uc_info->stream.out = adev->primary_output; + select_devices(adev, USECASE_COMPRESS_VOIP_CALL); + } + + return 0; + +error_start_voip: + voip_stop_call(adev); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + char *str; + char value[32]={0}; + int ret = 0, err, rate; + int min_rate, max_rate; + bool flag; + char *kv_pairs = str_parms_to_str(parms); + + ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); + + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE, + value, sizeof(value)); + if (err >= 0) { + rate = atoi(value); + voip_set_rate(adev, rate); + voip_set_evrc_min_max_rate(adev, rate, rate); + } + + memset(value, 0, sizeof(value)); + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN, + value, sizeof(value)); + if (err >= 0) { + min_rate = atoi(value); + str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN); + memset(value, 0, sizeof(value)); + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX, + value, sizeof(value)); + if (err >= 0) { + max_rate = atoi(value); + voip_set_evrc_min_max_rate(adev, min_rate, max_rate); + } else { + ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__); + ret = -EINVAL; + goto done; + } + } + + memset(value, 0, sizeof(value)); + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE, + value, sizeof(value)); + if (err >= 0) { + flag = false; + if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0) + flag = true; + voip_set_dtx(adev, flag); + } + +done: + ALOGV("%s: exit", __func__); + free(kv_pairs); + return ret; +} + +void voice_extn_compress_voip_get_parameters(struct str_parms *query, + struct str_parms *reply) +{ + int ret; + char value[32]={0}; + char *str = NULL; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT, + voip_data.out_stream_count); + } + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE, + voip_data.sample_rate); + } +} + +void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + + ALOGD("%s: enter", __func__); + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value)); + + if (ret >= 0) { + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true); + else + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false); + } + + ALOGV("%s: exit", __func__); +} + +void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + char *kv_pairs = NULL; + + ALOGV("%s: enter", __func__); + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value)); + + if (ret >= 0) { + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true); + else + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false); + } + + kv_pairs = str_parms_to_str(reply); + ALOGD_IF(kv_pairs != NULL, "%s: exit: return - %s", __func__, kv_pairs); + free(kv_pairs); +} + +int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out) +{ + if (out->config.rate == 16000) + return COMPRESS_VOIP_IO_BUF_SIZE_WB; + else + return COMPRESS_VOIP_IO_BUF_SIZE_NB; +} + +int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in) +{ + if (in->config.rate == 16000) + return COMPRESS_VOIP_IO_BUF_SIZE_WB; + else + return COMPRESS_VOIP_IO_BUF_SIZE_NB; +} + +int voice_extn_compress_voip_start_output_stream(struct stream_out *out) +{ + int ret = 0; + struct audio_device *adev = out->dev; + struct audio_usecase *uc_info; + int snd_card_status = get_snd_card_state(adev); + + ALOGD("%s: enter", __func__); + + if (SND_CARD_STATE_OFFLINE == snd_card_status) { + ret = -ENETRESET; + ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret); + goto error; + } + + if (!voip_data.out_stream_count) + ret = voice_extn_compress_voip_open_output_stream(out); + + ret = voip_start_call(adev, &out->config); + out->pcm = voip_data.pcm_rx; + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if (uc_info) { + uc_info->stream.out = out; + uc_info->devices = out->devices; + } else { + ret = -EINVAL; + ALOGE("%s: exit(%d): failed to get use case info", __func__, ret); + goto error; + } + +error: + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_start_input_stream(struct stream_in *in) +{ + int ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = in->dev; + int snd_card_status = get_snd_card_state(adev); + + ALOGD("%s: enter", __func__); + + if (SND_CARD_STATE_OFFLINE == snd_card_status) { + ret = -ENETRESET; + ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret); + goto error; + } + + if (!voip_data.in_stream_count) + ret = voice_extn_compress_voip_open_input_stream(in); + + adev->active_input = in; + ret = voip_start_call(adev, &in->config); + in->pcm = voip_data.pcm_tx; + +error: + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + int ret = 0; + + ALOGD("%s: enter", __func__); + if (voip_data.out_stream_count > 0) { + voip_data.out_stream_count--; + ret = voip_stop_call(adev); + voip_data.out_stream = NULL; + out->pcm = NULL; + } + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_open_output_stream(struct stream_out *out) +{ + int mode, ret; + + ALOGD("%s: enter", __func__); + + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO; + out->channel_mask = AUDIO_CHANNEL_OUT_MONO; + out->usecase = USECASE_COMPRESS_VOIP_CALL; + if (out->sample_rate == 16000) + out->config = pcm_config_voip_wb; + else + out->config = pcm_config_voip_nb; + + voip_data.out_stream = out; + voip_data.out_stream_count++; + voip_data.sample_rate = out->sample_rate; + ret = voip_set_mode(out->dev, out->format); + + ALOGV("%s: exit", __func__); + return ret; +} + +int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + int status = 0; + + ALOGD("%s: enter", __func__); + + if(voip_data.in_stream_count > 0) { + adev->active_input = NULL; + voip_data.in_stream_count--; + status = voip_stop_call(adev); + in->pcm = NULL; + } + + ALOGV("%s: exit: status(%d)", __func__, status); + return status; +} + +int voice_extn_compress_voip_open_input_stream(struct stream_in *in) +{ + int sample_rate; + int buffer_size,frame_size; + int mode, ret; + + ALOGD("%s: enter", __func__); + + if ((voip_data.sample_rate != 0) && + (voip_data.sample_rate != in->config.rate)) { + ret = -ENOTSUP; + goto done; + } else { + voip_data.sample_rate = in->config.rate; + } + + in->usecase = USECASE_COMPRESS_VOIP_CALL; + if (in->config.rate == 16000) + in->config = pcm_config_voip_wb; + else + in->config = pcm_config_voip_nb; + + voip_data.in_stream_count++; + ret = voip_set_mode(in->dev, in->format); + +done: + ALOGV("%s: exit, ret=%d", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume) +{ + int vol, err = 0; + + ALOGV("%s: enter", __func__); + + if (volume < 0.0) { + volume = 0.0; + } else if (volume > 1.0) { + volume = 1.0; + } + + vol = lrint(volume * 100.0); + + /* Voice volume levels from android are mapped to driver volume levels as follows. + * 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 + * So adjust the volume to get the correct volume index in driver + */ + vol = 100 - vol; + + err = voip_set_volume(adev, vol); + + ALOGV("%s: exit: status(%d)", __func__, err); + + return err; +} + +int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state) +{ + int err = 0; + + ALOGV("%s: enter", __func__); + + err = voip_set_mic_mute(adev, state); + + ALOGV("%s: exit: status(%d)", __func__, err); + return err; +} + +bool voice_extn_compress_voip_pcm_prop_check() +{ + char prop_value[PROPERTY_VALUE_MAX] = {0}; + + property_get("use.voice.path.for.pcm.voip", prop_value, "0"); + if (!strncmp("true", prop_value, sizeof("true"))) + { + ALOGD("%s: VoIP PCM property is enabled", __func__); + return true; + } + else + return false; +} + +bool voice_extn_compress_voip_is_active(struct audio_device *adev) +{ + struct audio_usecase *voip_usecase = NULL; + voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + + if (voip_usecase != NULL) + return true; + else + return false; +} + +bool voice_extn_compress_voip_is_format_supported(audio_format_t format) +{ + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + if (voice_extn_compress_voip_pcm_prop_check()) + return true; + else + return false; + case AUDIO_FORMAT_AMR_NB: + case AUDIO_FORMAT_AMR_WB: + case AUDIO_FORMAT_EVRC: + case AUDIO_FORMAT_EVRCB: + case AUDIO_FORMAT_EVRCWB: + case AUDIO_FORMAT_EVRCNW: + return true; + default: + return false; + } +} + +bool voice_extn_compress_voip_is_config_supported(struct audio_config *config) +{ + bool ret = false; + + ret = voice_extn_compress_voip_is_format_supported(config->format); + if (ret) { + if ((popcount(config->channel_mask) == 1) && + (config->sample_rate == 8000 || config->sample_rate == 16000)) + ret = ((voip_data.sample_rate == 0) ? true: + (voip_data.sample_rate == config->sample_rate)); + else + ret = false; + } + return ret; +} |