diff options
author | Christopher N. Hesse <raymanfx@gmail.com> | 2017-02-02 20:49:55 +0100 |
---|---|---|
committer | Christopher N. Hesse <raymanfx@gmail.com> | 2017-02-10 21:41:49 +0100 |
commit | 696959dda1cd4437dd672a61d7a3266169ad3019 (patch) | |
tree | cd9520cfd640c79efa5dfc90d58d85b9bbdc78ea /audio/voice.c | |
parent | 5a2f10031a49f65b98ae0f495197689ee5c01cf8 (diff) | |
download | hardware_samsung-696959dda1cd4437dd672a61d7a3266169ad3019.tar.gz hardware_samsung-696959dda1cd4437dd672a61d7a3266169ad3019.tar.bz2 hardware_samsung-696959dda1cd4437dd672a61d7a3266169ad3019.zip |
audio: Enable voice call support
Pair-Programmed-With: Andreas Schneider <asn@cryptomilk.org>
Change-Id: I284f21240e56dda93cb8a2ab98b903ff712504a6
Diffstat (limited to 'audio/voice.c')
-rw-r--r-- | audio/voice.c | 270 |
1 files changed, 269 insertions, 1 deletions
diff --git a/audio/voice.c b/audio/voice.c index 57fcc60..f10d8ed 100644 --- a/audio/voice.c +++ b/audio/voice.c @@ -26,11 +26,252 @@ #include <stdlib.h> #include <pthread.h> +#include <cutils/log.h> +#include <cutils/properties.h> + +#include <samsung_audio.h> + #include "audio_hw.h" #include "voice.h" -struct voice_session *voice_session_init(void) +static struct pcm_config pcm_config_voicecall = { + .channels = 2, + .rate = 8000, + .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY, + .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY, + .format = PCM_FORMAT_S16_LE, +}; + +static struct pcm_config pcm_config_voicecall_wideband = { + .channels = 2, + .rate = 16000, + .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY, + .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY, + .format = PCM_FORMAT_S16_LE, +}; + +/* Prototypes */ +int start_voice_call(struct audio_device *adev); +int stop_voice_call(struct audio_device *adev); + +void set_voice_session_audio_path(struct voice_session *session) +{ + enum _AudioPath device_type; + + switch(session->out_device) { + case AUDIO_DEVICE_OUT_SPEAKER: + device_type = SOUND_AUDIO_PATH_SPEAKER; + break; + case AUDIO_DEVICE_OUT_EARPIECE: + device_type = SOUND_AUDIO_PATH_HANDSET; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + device_type = SOUND_AUDIO_PATH_HEADSET; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + device_type = SOUND_AUDIO_PATH_HEADPHONE; + break; + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + device_type = SOUND_AUDIO_PATH_BLUETOOTH; + break; + default: + /* if output device isn't supported, use handset by default */ + device_type = SOUND_AUDIO_PATH_HANDSET; + break; + } + + ALOGV("%s: ril_set_call_audio_path(%d)", __func__, device_type); + + ril_set_call_audio_path(&session->ril, device_type); +} + +/* + * This decides based on the output device, if we enable + * two mic control + */ +void prepare_voice_session(struct voice_session *session, + audio_devices_t active_out_devices) +{ + ALOGV("%s: active_out_devices: 0x%x", __func__, active_out_devices); + + session->out_device = active_out_devices; + + switch (session->out_device) { + case AUDIO_DEVICE_OUT_EARPIECE: + case AUDIO_DEVICE_OUT_SPEAKER: + session->two_mic_control = true; + break; + default: + session->two_mic_control = false; + break; + } + + if (session->two_mic_disabled) { + session->two_mic_control = false; + } +} + +/* + * This function must be called with hw device mutex locked, OK to hold other + * mutexes + */ +int start_voice_session(struct voice_session *session) { + struct pcm_config *voice_config; + + if (session->pcm_voice_rx != NULL || session->pcm_voice_tx != NULL) { + ALOGW("%s: Voice PCMs already open!\n", __func__); + return 0; + } + + ALOGV("%s: Opening voice PCMs", __func__); + + if (session->wb_amr) { + ALOGV("%s: pcm_config wideband", __func__); + voice_config = &pcm_config_voicecall_wideband; + } else { + ALOGV("%s: pcm_config narrowband", __func__); + voice_config = &pcm_config_voicecall; + } + + /* Open modem PCM channels */ + session->pcm_voice_rx = pcm_open(SOUND_CARD, + SOUND_PLAYBACK_VOICE_DEVICE, + PCM_OUT|PCM_MONOTONIC, + voice_config); + if (session->pcm_voice_rx != NULL && !pcm_is_ready(session->pcm_voice_rx)) { + ALOGE("%s: cannot open PCM voice RX stream: %s", + __func__, + pcm_get_error(session->pcm_voice_rx)); + + pcm_close(session->pcm_voice_tx); + session->pcm_voice_tx = NULL; + + return -ENOMEM; + } + + session->pcm_voice_tx = pcm_open(SOUND_CARD, + SOUND_CAPTURE_VOICE_DEVICE, + PCM_IN|PCM_MONOTONIC, + voice_config); + if (session->pcm_voice_tx != NULL && !pcm_is_ready(session->pcm_voice_tx)) { + ALOGE("%s: cannot open PCM voice TX stream: %s", + __func__, + pcm_get_error(session->pcm_voice_tx)); + + pcm_close(session->pcm_voice_rx); + session->pcm_voice_rx = NULL; + + return -ENOMEM; + } + + pcm_start(session->pcm_voice_rx); + pcm_start(session->pcm_voice_tx); + + /* TODO: handle SCO */ + + if (session->two_mic_control) { + ALOGV("%s: enabling two mic control", __func__); + ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_ON); + } else { + ALOGV("%s: disabling two mic control", __func__); + ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_OFF); + } + + ril_set_call_clock_sync(&session->ril, SOUND_CLOCK_START); + + return 0; +} + +/* + * This function must be called with hw device mutex locked, OK to hold other + * mutexes + */ +void stop_voice_session(struct voice_session *session) +{ + int status = 0; + + ALOGV("%s: Closing active PCMs", __func__); + + if (session->pcm_voice_rx != NULL) { + pcm_stop(session->pcm_voice_rx); + pcm_close(session->pcm_voice_rx); + session->pcm_voice_rx = NULL; + status++; + } + + if (session->pcm_voice_tx != NULL) { + pcm_stop(session->pcm_voice_tx); + pcm_close(session->pcm_voice_tx); + session->pcm_voice_tx = NULL; + status++; + } + + /* TODO: handle SCO */ + + session->out_device = AUDIO_DEVICE_NONE; + + ALOGV("%s: Successfully closed %d active PCMs", __func__, status); +} + +void set_voice_session_volume(struct voice_session *session, float volume) +{ + enum _SoundType sound_type; + + switch (session->out_device) { + case AUDIO_DEVICE_OUT_EARPIECE: + sound_type = SOUND_TYPE_VOICE; + break; + case AUDIO_DEVICE_OUT_SPEAKER: + sound_type = SOUND_TYPE_SPEAKER; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + sound_type = SOUND_TYPE_HEADSET; + break; + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + case AUDIO_DEVICE_OUT_ALL_SCO: + sound_type = SOUND_TYPE_BTVOICE; + break; + default: + sound_type = SOUND_TYPE_VOICE; + } + + ril_set_call_volume(&session->ril, sound_type, volume); +} + +static void voice_session_wb_amr_callback(void *data, int enable) +{ + struct audio_device *adev = (struct audio_device *)data; + struct voice_session *session = + (struct voice_session *)adev->voice.session; + + pthread_mutex_lock(&adev->lock); + + if (session->wb_amr != enable) { + session->wb_amr = enable; + + /* reopen the modem PCMs at the new rate */ + if (adev->voice.in_call) { + ALOGV("%s: %s wide band voice call", + __func__, + enable ? "Enable" : "Disable"); + + stop_voice_call(adev); + start_voice_call(adev); + } + } + + pthread_mutex_unlock(&adev->lock); +} + +struct voice_session *voice_session_init(struct audio_device *adev) +{ + char voice_config[PROPERTY_VALUE_MAX]; struct voice_session *session; int ret; @@ -39,6 +280,12 @@ struct voice_session *voice_session_init(void) return NULL; } + /* Two mic control */ + ret = property_get_bool("audio_hal.disable_two_mic", false); + if (ret > 0) { + session->two_mic_disabled = true; + } + /* Do this as the last step so we do not have to close it on error */ ret = ril_open(&session->ril); if (ret != 0) { @@ -46,6 +293,27 @@ struct voice_session *voice_session_init(void) return NULL; } + ret = property_get("audio_hal.force_voice_config", voice_config, ""); + if (ret > 0) { + if ((strncmp(voice_config, "narrow", 6)) == 0) + session->wb_amr = false; + else if ((strncmp(voice_config, "wide", 4)) == 0) + session->wb_amr = true; + ALOGV("%s: Forcing voice config: %s", __func__, voice_config); + } else { + /* register callback for wideband AMR setting */ + ret = ril_set_wb_amr_callback(&session->ril, + voice_session_wb_amr_callback, + (void *)adev); + if (ret != 0) { + ALOGE("%s: Failed to register WB_AMR callback", __func__); + free(session); + return NULL; + } + + ALOGV("%s: Registered WB_AMR callback", __func__); + } + return session; } |