summaryrefslogtreecommitdiffstats
path: root/audio/voice.c
diff options
context:
space:
mode:
authorChristopher N. Hesse <raymanfx@gmail.com>2017-02-02 20:49:55 +0100
committerChristopher N. Hesse <raymanfx@gmail.com>2017-02-10 21:41:49 +0100
commit696959dda1cd4437dd672a61d7a3266169ad3019 (patch)
treecd9520cfd640c79efa5dfc90d58d85b9bbdc78ea /audio/voice.c
parent5a2f10031a49f65b98ae0f495197689ee5c01cf8 (diff)
downloadhardware_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.c270
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;
}