hal: Added support for HFP
- Added setparameter to be set from hfp app to enable
and disable hfp session.
- Implemeted start and stop hfp session which takes
care of switching device and setting the session
Change-Id: Ie8697328ccbfee09d0d162f6fad01ddb552e4f83
diff --git a/hal/Android.mk b/hal/Android.mk
index 86f92d9..d8a4733 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -47,6 +47,10 @@
LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED
LOCAL_SRC_FILES += audio_extn/usb.c
endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_HFP)),true)
+ LOCAL_CFLAGS += -DHFP_ENABLED
+ LOCAL_SRC_FILES += audio_extn/hfp.c
+endif
ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true)
LOCAL_CFLAGS += -DSSR_ENABLED
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 2c7fbca..72e2f9c 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -55,7 +55,12 @@
void audio_extn_fm_set_parameters(struct audio_device *adev,
struct str_parms *parms);
#endif
-
+#ifndef HFP_ENABLED
+void audio_extn_hfp_set_parameters(adev, parms) (0)
+#else
+void audio_extn_hfp_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+#endif
#ifndef SSR_ENABLED
#define audio_extn_ssr_get_parameters(query, reply) (0)
#else
@@ -219,6 +224,7 @@
audio_extn_set_afe_proxy_parameters(parms);
audio_extn_fm_set_parameters(adev, parms);
audio_extn_listen_set_parameters(adev, parms);
+ audio_extn_hfp_set_parameters(adev, parms);
}
void audio_extn_get_parameters(const struct audio_device *adev,
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
new file mode 100644
index 0000000..73824bd
--- /dev/null
+++ b/hal/audio_extn/hfp.c
@@ -0,0 +1,231 @@
+/* hfp.c
+Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
+
+#define LOG_TAG "audio_hw_hfp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef HFP_ENABLED
+#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
+
+static int32_t audio_extn_start_hfp(struct audio_device *adev,
+ struct str_parms *parms);
+
+static int32_t audio_extn_stop_hfp(struct audio_device *adev);
+
+struct hfp_module {
+ struct pcm *hfp_sco_rx;
+ struct pcm *hfp_sco_tx;
+ struct pcm *hfp_pcm_rx;
+ struct pcm *hfp_pcm_tx;
+ bool is_hfp_running;
+ int hfp_volume;
+};
+
+static struct hfp_module hfpmod = {
+ .hfp_sco_rx = NULL,
+ .hfp_sco_tx = NULL,
+ .hfp_pcm_rx = NULL,
+ .hfp_pcm_tx = NULL,
+ .hfp_volume = 0,
+ .is_hfp_running = 0,
+};
+static struct pcm_config pcm_config_hfp = {
+ .channels = 1,
+ .rate = 8000,
+ .period_size = 240,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ int ret;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if(!strncmp(value,"true",sizeof(value)))
+ ret = audio_extn_start_hfp(adev,parms);
+ else
+ audio_extn_stop_hfp(adev);
+ }
+}
+
+static int32_t audio_extn_start_hfp(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+ int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = USECASE_AUDIO_HFP_SCO;
+ uc_info->type = PCM_HFP_CALL;
+ uc_info->stream.out = adev->primary_output;
+ uc_info->devices = adev->primary_output->devices;
+ 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_AUDIO_HFP_SCO);
+
+ 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);
+ pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
+ pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
+ pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+ ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_rx_id);
+ hfpmod.hfp_sco_rx = pcm_open(SOUND_CARD,
+ pcm_dev_asm_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_rx = pcm_open(SOUND_CARD,
+ pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ hfpmod.hfp_sco_tx = pcm_open(SOUND_CARD,
+ pcm_dev_asm_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_tx = pcm_open(SOUND_CARD,
+ pcm_dev_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ pcm_start(hfpmod.hfp_sco_rx);
+ pcm_start(hfpmod.hfp_sco_tx);
+ pcm_start(hfpmod.hfp_pcm_rx);
+ pcm_start(hfpmod.hfp_pcm_tx);
+
+
+ hfpmod.is_hfp_running = true;
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return 0;
+
+exit:
+ audio_extn_stop_hfp(adev);
+ ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t audio_extn_stop_hfp(struct audio_device *adev)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+ hfpmod.is_hfp_running = false;
+
+ /* 1. Close the PCM devices */
+ if (hfpmod.hfp_sco_rx) {
+ pcm_close(hfpmod.hfp_sco_rx);
+ hfpmod.hfp_sco_rx = NULL;
+ }
+ if (hfpmod.hfp_sco_tx) {
+ pcm_close(hfpmod.hfp_sco_tx);
+ hfpmod.hfp_sco_tx = NULL;
+ }
+ if (hfpmod.hfp_pcm_rx) {
+ pcm_close(hfpmod.hfp_pcm_rx);
+ hfpmod.hfp_pcm_rx = NULL;
+ }
+ if (hfpmod.hfp_pcm_tx) {
+ pcm_close(hfpmod.hfp_pcm_tx);
+ hfpmod.hfp_pcm_tx = NULL;
+ }
+
+ uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, USECASE_AUDIO_HFP_SCO);
+ return -EINVAL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device, false);
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+#endif /*HFP_ENABLED*/
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ee67703..920dbc2 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -109,6 +109,7 @@
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
[USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+ [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
[USECASE_VOICE_CALL] = "voice-call",
[USECASE_VOICE2_CALL] = "voice2-call",
@@ -593,7 +594,8 @@
}
if ((usecase->type == VOICE_CALL) ||
- (usecase->type == VOIP_CALL)) {
+ (usecase->type == VOIP_CALL) ||
+ (usecase->type == PCM_HFP_CALL)) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out->devices);
in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 6ff6f40..639032f 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -62,6 +62,9 @@
/* FM usecase */
USECASE_AUDIO_PLAYBACK_FM,
+ /* HFP Use case*/
+ USECASE_AUDIO_HFP_SCO,
+
/* Capture usecases */
USECASE_AUDIO_RECORD,
USECASE_AUDIO_RECORD_COMPRESS,
@@ -179,7 +182,8 @@
PCM_PLAYBACK,
PCM_CAPTURE,
VOICE_CALL,
- VOIP_CALL
+ VOIP_CALL,
+ PCM_HFP_CALL
} usecase_type_t;
union stream_ptr {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a207c2f..da67145 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -109,6 +109,7 @@
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+ [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
[USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
[USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
[USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
@@ -989,6 +990,7 @@
} else if (my_data->fluence_type == FLUENCE_NONE ||
my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ set_echo_reference(adev->mixer, "SLIM_RX");
} else {
snd_device = SND_DEVICE_IN_VOICE_DMIC;
adev->acdb_settings |= DMIC_FLAG;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 7d80906..e1ae77b 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -170,6 +170,10 @@
#define MULTIMEDIA2_PCM_DEVICE 1
#define FM_PLAYBACK_PCM_DEVICE 5
#define FM_CAPTURE_PCM_DEVICE 6
+#define HFP_PCM_RX 5
+#define HFP_SCO_RX 35
+#define HFP_ASM_RX_TX 36
+
#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5