hal: Add support for In-Car Communication usecase
* Add ICC library functionality in icc.c
* Add support in audio_extn to open and initialize icc library
* Add platform changes for device selection in ICC usecase
* Add support for sending ICC audio calibration/app type cfg
Suggested-by: Tahir Dawson <dawson@qti.qualcomm.com>
Change-Id: I26937da282fcdd31d59a54b180dca5d7740fbfb0
diff --git a/hal/audio_extn/Android.mk b/hal/audio_extn/Android.mk
index c32d1d4..eaf8926 100644
--- a/hal/audio_extn/Android.mk
+++ b/hal/audio_extn/Android.mk
@@ -605,6 +605,74 @@
include $(BUILD_SHARED_LIBRARY)
#-------------------------------------------
+# Build ICC LIB
+#-------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libicc
+LOCAL_VENDOR_MODULE := true
+
+PRIMARY_HAL_PATH := vendor/qcom/opensource/audio-hal/primary-hal/hal
+AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
+
+ifneq ($(filter sdm845 sdm710 sdmshrike msmnile kona lito bengal atoll sdm660 msm8937 msm8998 $(MSMSTEPPE) $(TRINKET),$(TARGET_BOARD_PLATFORM)),)
+ # B-family platform uses msm8974 code base
+ AUDIO_PLATFORM := msm8974
+ MULTIPLE_HW_VARIANTS_ENABLED := true
+endif
+
+ifeq ($(TARGET_BOARD_AUTO),true)
+ LOCAL_CFLAGS += -DPLATFORM_AUTO
+endif
+
+LOCAL_SRC_FILES:= \
+ icc.c \
+ device_utils.c
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Werror \
+ -Wno-unused-function \
+ -Wno-unused-variable
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioroute \
+ libaudioutils \
+ libcutils \
+ libdl \
+ libexpat \
+ liblog \
+ libtinyalsa \
+ libtinycompress
+
+LOCAL_C_INCLUDES := \
+ $(PRIMARY_HAL_PATH) \
+ $(PRIMARY_HAL_PATH)/$(AUDIO_PLATFORM) \
+ external/tinyalsa/include \
+ external/tinycompress/include \
+ external/expat/lib \
+ system/media/audio_utils/include \
+ $(call include-path-for, audio-route) \
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/audio
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DLKM)),true)
+ LOCAL_HEADER_LIBRARIES += audio_kernel_headers
+ LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+ LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
+
+LOCAL_HEADER_LIBRARIES += libhardware_headers
+LOCAL_HEADER_LIBRARIES += libsystem_headers
+ifneq ($(filter kona,$(TARGET_BOARD_PLATFORM)),)
+LOCAL_SANITIZE := integer_overflow
+endif
+include $(BUILD_SHARED_LIBRARY)
+
+#-------------------------------------------
# Build HDMI PASSTHROUGH
#-------------------------------------------
include $(CLEAR_VARS)
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 39d491d..c3c80a0 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -4989,6 +4989,107 @@
}
// END: HFP ========================================================================
+// START: ICC ======================================================================
+#ifdef __LP64__
+#define ICC_LIB_PATH "/vendor/lib64/libicc.so"
+#else
+#define ICC_LIB_PATH "/vendor/lib/libicc.so"
+#endif
+
+static void *icc_lib_handle = NULL;
+
+typedef void (*icc_init_t)(icc_init_config_t);
+static icc_init_t icc_init;
+
+typedef bool (*icc_is_active_t)(struct audio_device *adev);
+static icc_is_active_t icc_is_active;
+
+typedef audio_usecase_t (*icc_get_usecase_t)();
+static icc_get_usecase_t icc_get_usecase;
+
+typedef void (*icc_set_parameters_t)(struct audio_device *adev,
+ struct str_parms *parms);
+static icc_set_parameters_t icc_set_parameters;
+
+int icc_feature_init(bool is_feature_enabled)
+{
+ ALOGD("%s: Called with feature %s", __func__,
+ is_feature_enabled ? "Enabled" : "NOT Enabled");
+ if (is_feature_enabled) {
+ // dlopen lib
+ icc_lib_handle = dlopen(ICC_LIB_PATH, RTLD_NOW);
+
+ if (!icc_lib_handle) {
+ ALOGE("%s: dlopen failed", __func__);
+ goto feature_disabled;
+ }
+ if (!(icc_init = (icc_init_t)dlsym(
+ icc_lib_handle, "icc_init")) ||
+ !(icc_is_active =
+ (icc_is_active_t)dlsym(
+ icc_lib_handle, "icc_is_active")) ||
+ !(icc_get_usecase =
+ (icc_get_usecase_t)dlsym(
+ icc_lib_handle, "icc_get_usecase")) ||
+ !(icc_set_parameters =
+ (icc_set_parameters_t)dlsym(
+ icc_lib_handle, "icc_set_parameters"))) {
+ ALOGE("%s: dlsym failed", __func__);
+ goto feature_disabled;
+ }
+ icc_init_config_t init_config;
+ init_config.fp_platform_get_pcm_device_id = platform_get_pcm_device_id;
+ init_config.fp_platform_set_echo_reference = platform_set_echo_reference;
+ init_config.fp_select_devices = select_devices;
+ init_config.fp_audio_extn_ext_hw_plugin_usecase_start =
+ audio_extn_ext_hw_plugin_usecase_start;
+ init_config.fp_audio_extn_ext_hw_plugin_usecase_stop =
+ audio_extn_ext_hw_plugin_usecase_stop;
+ init_config.fp_get_usecase_from_list = get_usecase_from_list;
+ init_config.fp_disable_audio_route = disable_audio_route;
+ init_config.fp_disable_snd_device = disable_snd_device;
+
+ icc_init(init_config);
+ ALOGD("%s:: ---- Feature ICC is Enabled ----", __func__);
+ return 0;
+ }
+
+feature_disabled:
+ if (icc_lib_handle) {
+ dlclose(icc_lib_handle);
+ icc_lib_handle = NULL;
+ }
+
+ icc_init = NULL;
+ icc_is_active = NULL;
+ icc_get_usecase = NULL;
+ icc_set_parameters = NULL;
+
+ ALOGW(":: %s: ---- Feature ICC is disabled ----", __func__);
+ return -ENOSYS;
+}
+
+bool audio_extn_icc_is_active(struct audio_device *adev)
+{
+ return ((icc_is_active) ?
+ icc_is_active(adev): false);
+}
+
+audio_usecase_t audio_extn_icc_get_usecase()
+{
+ return ((icc_get_usecase) ?
+ icc_get_usecase(): -1);
+}
+
+void audio_extn_icc_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ ((icc_set_parameters) ?
+ icc_set_parameters(adev, parms): NULL);
+}
+
+// END: ICC ========================================================================
+
// START: EXT_HW_PLUGIN ===================================================================
#ifdef __LP64__
#define EXT_HW_PLUGIN_LIB_PATH "/vendor/lib64/libexthwplugin.so"
@@ -6313,6 +6414,9 @@
hfp_feature_init(
property_get_bool("vendor.audio.feature.hfp.enable",
false));
+ icc_feature_init(
+ property_get_bool("vendor.audio.feature.icc.enable",
+ false));
ext_hw_plugin_feature_init(
property_get_bool("vendor.audio.feature.ext_hw_plugin.enable",
false));
@@ -6372,6 +6476,7 @@
audio_extn_set_aptx_dec_bt_addr(adev, parms);
audio_extn_ffv_set_parameters(adev, parms);
audio_extn_ext_hw_plugin_set_parameters(adev->ext_hw_plugin, parms);
+ audio_extn_icc_set_parameters(adev, parms);
}
void audio_extn_get_parameters(const struct audio_device *adev,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index f5bc244..8820d01 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -722,6 +722,25 @@
// END: HFP FEATURE ==================================================
+// START: ICC FEATURE ====================================================
+bool audio_extn_icc_is_active(struct audio_device *adev);
+audio_usecase_t audio_extn_icc_get_usecase();
+void audio_extn_icc_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+
+typedef struct icc_init_config {
+ fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
+ fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
+ fp_select_devices_t fp_select_devices;
+ fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
+ fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
+ fp_get_usecase_from_list_t fp_get_usecase_from_list;
+ fp_disable_audio_route_t fp_disable_audio_route;
+ fp_disable_snd_device_t fp_disable_snd_device;
+} icc_init_config_t;
+
+//END: ICC FEAUTRE =======================================================
+
// START: EXT_HW_PLUGIN FEATURE ==================================================
void* audio_extn_ext_hw_plugin_init(struct audio_device *adev);
int audio_extn_ext_hw_plugin_deinit(void *plugin);
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index b0f7c0c..abddeb0 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -734,6 +734,9 @@
case USECASE_VOICE_CALL:
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
break;
+ case USECASE_ICC_CALL:
+ snd_device = SND_DEVICE_IN_ICC;
+ break;
default:
ALOGE("%s: Usecase (%d) not supported", __func__, uc_id);
return -EINVAL;
@@ -826,6 +829,9 @@
case USECASE_AUDIO_PLAYBACK_REAR_SEAT:
snd_device = SND_DEVICE_OUT_BUS_RSE;
break;
+ case USECASE_ICC_CALL:
+ snd_device = SND_DEVICE_OUT_ICC;
+ break;
default:
ALOGE("%s: Usecase (%d) not supported", __func__, uc_id);
return -EINVAL;
diff --git a/hal/audio_extn/ext_hw_plugin.c b/hal/audio_extn/ext_hw_plugin.c
index 92f3f30..5c78caa 100644
--- a/hal/audio_extn/ext_hw_plugin.c
+++ b/hal/audio_extn/ext_hw_plugin.c
@@ -199,6 +199,8 @@
case USECASE_AUDIO_FM_TUNER_EXT:
*plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_FM_TUNER;
break;
+ case USECASE_ICC_CALL:
+ *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_ICC;
default:
ret = -EINVAL;
}
@@ -242,7 +244,7 @@
if (((usecase->type == PCM_CAPTURE) || (usecase->type == VOICE_CALL) ||
(usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL) ||
- (usecase->type == PCM_PASSTHROUGH)) &&
+ (usecase->type == ICC_CALL) || (usecase->type == PCM_PASSTHROUGH)) &&
(usecase->in_snd_device != SND_DEVICE_NONE)) {
codec_enable.snd_dev = usecase->in_snd_device;
/* TODO - below should be related with in_snd_dev */
@@ -316,8 +318,8 @@
}
if (((usecase->type == PCM_PLAYBACK) || (usecase->type == VOICE_CALL) ||
- (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) &&
- (usecase->out_snd_device != SND_DEVICE_NONE)) {
+ (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL) ||
+ (usecase->type == ICC_CALL)) && (usecase->out_snd_device != SND_DEVICE_NONE)) {
codec_enable.snd_dev = usecase->out_snd_device;
/* TODO - below should be related with out_snd_dev */
codec_enable.sample_rate = 48000;
@@ -384,8 +386,8 @@
}
if (((usecase->type == PCM_PLAYBACK) || (usecase->type == VOICE_CALL) ||
- (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL)) &&
- (usecase->out_snd_device != SND_DEVICE_NONE)) {
+ (usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL) ||
+ (usecase->type == ICC_CALL)) && (usecase->out_snd_device != SND_DEVICE_NONE)) {
codec_disable.snd_dev = usecase->out_snd_device;
ALOGD("%s: disable audio hal plugin output, %d, %d",
@@ -401,7 +403,7 @@
}
if (((usecase->type == PCM_CAPTURE) || (usecase->type == VOICE_CALL) ||
(usecase->type == VOIP_CALL) || (usecase->type == PCM_HFP_CALL) ||
- (usecase->type == PCM_PASSTHROUGH)) &&
+ (usecase->type == PCM_PASSTHROUGH) || (usecase->type == ICC_CALL)) &&
(usecase->in_snd_device != SND_DEVICE_NONE)) {
codec_disable.snd_dev = usecase->in_snd_device;
diff --git a/hal/audio_extn/icc.c b/hal/audio_extn/icc.c
new file mode 100644
index 0000000..a38080f
--- /dev/null
+++ b/hal/audio_extn/icc.c
@@ -0,0 +1,353 @@
+/* icc.c
+Copyright (c) 2012-2015, 2016, 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_icc"
+/*#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>
+#include "audio_extn.h"
+
+#define AUDIO_PARAMETER_ICC_ENABLE "conversation_mode_state"
+#define AUDIO_PARAMETER_ICC_SET_SAMPLING_RATE "icc_set_sampling_rate"
+#define AUDIO_PARAMETER_KEY_ICC_VOLUME "icc_volume"
+
+#ifdef PLATFORM_AUTO
+#define ICC_RX_VOLUME "Playback 33 Volume"
+#else
+#define ICC_RX_VOLUME "NULL"
+#endif
+
+static int32_t start_icc(struct audio_device *adev,
+ struct str_parms *parms);
+
+static int32_t stop_icc(struct audio_device *adev);
+
+struct icc_module {
+ struct pcm *icc_pcm_rx;
+ struct pcm *icc_pcm_tx;
+ bool is_icc_running;
+ float icc_volume;
+ audio_usecase_t ucid;
+};
+
+static struct icc_module iccmod = {
+ .icc_pcm_rx = NULL,
+ .icc_pcm_tx = NULL,
+ .icc_volume = 0,
+ .is_icc_running = 0,
+ .ucid = USECASE_ICC_CALL,
+};
+static struct pcm_config pcm_config_icc = {
+ .channels = 4,
+ .rate = 16000,
+ .period_size = 240,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+static fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
+static fp_platform_set_echo_reference_t fp_platform_set_echo_reference;
+static fp_select_devices_t fp_select_devices;
+static fp_audio_extn_ext_hw_plugin_usecase_start_t fp_audio_extn_ext_hw_plugin_usecase_start;
+static fp_audio_extn_ext_hw_plugin_usecase_stop_t fp_audio_extn_ext_hw_plugin_usecase_stop;
+static fp_get_usecase_from_list_t fp_get_usecase_from_list;
+static fp_disable_audio_route_t fp_disable_audio_route;
+static fp_disable_snd_device_t fp_disable_snd_device;
+
+static int32_t icc_set_volume(struct audio_device *adev, float value)
+{
+ int32_t ret = 0, vol = 0;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = ICC_RX_VOLUME;
+
+ ALOGD("%s: enter", __func__);
+ ALOGD("%s: (%f)", __func__, value);
+
+ iccmod.icc_volume = value;
+ if (value < 0.0) {
+ ALOGW("%s: (%f) Under 0.0, assuming 0.0", __func__, value);
+ value = 0.0;
+ } else {
+ value = ((value > 15.000000) ? 1.0 : (value / 15));
+ ALOGW("%s: Volume brought with in range (%f)", __func__, value);
+ }
+ vol = lrint((value * 0x2000) + 0.5);
+
+ if(!iccmod.is_icc_running) {
+ ALOGV("%s: ICC not active, ignoring icc_set_volume call", __func__);
+ return -EIO;
+ }
+
+ ALOGD("%s: Setting ICC Volume to %d", __func__, vol);
+ 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;
+ }
+ if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
+ ALOGE("%s: Couldn't set ICC Volume [%d]", __func__, vol);
+ return -EINVAL;
+ }
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t start_icc(struct audio_device *adev,
+ struct str_parms *parms __unused)
+{
+ int32_t ret = 0;
+ struct audio_usecase *uc_info;
+ int32_t pcm_dev_rx_id, pcm_dev_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+ if (!uc_info)
+ return -ENOMEM;
+
+ uc_info->id = iccmod.ucid;
+ uc_info->type = ICC_CALL;
+ uc_info->stream.out = adev->primary_output;
+ list_init(&uc_info->device_list);
+ assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
+ 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);
+
+ fp_select_devices(adev, iccmod.ucid);
+
+ if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
+ (uc_info->in_snd_device != SND_DEVICE_NONE)) {
+ if (fp_audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
+ ALOGE("%s: failed to start ext hw plugin", __func__);
+ }
+
+ pcm_dev_rx_id = fp_platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = fp_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 exit;
+ }
+
+ ALOGV("%s: ICC PCM devices (ICC pcm rx: %d pcm tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+ iccmod.icc_pcm_rx = pcm_open(adev->snd_card,
+ pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_icc);
+ if (iccmod.icc_pcm_rx && !pcm_is_ready(iccmod.icc_pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(iccmod.icc_pcm_rx));
+ ret = -EIO;
+ goto exit;
+ }
+
+ iccmod.icc_pcm_tx = pcm_open(adev->snd_card,
+ pcm_dev_tx_id,
+ PCM_IN, &pcm_config_icc);
+ if (iccmod.icc_pcm_tx && !pcm_is_ready(iccmod.icc_pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(iccmod.icc_pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+
+ if (pcm_start(iccmod.icc_pcm_rx) < 0) {
+ ALOGE("%s: pcm start for icc pcm rx failed", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (pcm_start(iccmod.icc_pcm_tx) < 0) {
+ ALOGE("%s: pcm start for icc pcm tx failed", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ iccmod.is_icc_running = true;
+ icc_set_volume(adev, iccmod.icc_volume);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return 0;
+
+exit:
+ stop_icc(adev);
+ ALOGE("%s: Problem in ICC start: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t stop_icc(struct audio_device *adev)
+{
+ int32_t ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+ iccmod.is_icc_running = false;
+
+ /* 1. Close the PCM devices */
+
+ if (iccmod.icc_pcm_rx) {
+ pcm_close(iccmod.icc_pcm_rx);
+ iccmod.icc_pcm_rx = NULL;
+ }
+ if (iccmod.icc_pcm_tx) {
+ pcm_close(iccmod.icc_pcm_tx);
+ iccmod.icc_pcm_tx = NULL;
+ }
+
+ uc_info = fp_get_usecase_from_list(adev, iccmod.ucid);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, iccmod.ucid);
+ return -EINVAL;
+ }
+
+ if ((uc_info->out_snd_device != SND_DEVICE_NONE) ||
+ (uc_info->in_snd_device != SND_DEVICE_NONE)) {
+ if (fp_audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
+ ALOGE("%s: failed to stop ext hw plugin", __func__);
+ }
+
+ /* 2. Disable echo reference while stopping icc */
+ fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
+
+ /* 3. Get and set stream specific mixer controls */
+ fp_disable_audio_route(adev, uc_info);
+
+ /* 4. Disable the rx and tx devices */
+ fp_disable_snd_device(adev, uc_info->out_snd_device);
+ fp_disable_snd_device(adev, uc_info->in_snd_device);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+void icc_init(icc_init_config_t init_config)
+{
+ fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
+ fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
+ fp_select_devices = init_config.fp_select_devices;
+ fp_audio_extn_ext_hw_plugin_usecase_start =
+ init_config.fp_audio_extn_ext_hw_plugin_usecase_start;
+ fp_audio_extn_ext_hw_plugin_usecase_stop =
+ init_config.fp_audio_extn_ext_hw_plugin_usecase_stop;
+ fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
+ fp_disable_audio_route = init_config.fp_disable_audio_route;
+ fp_disable_snd_device = init_config.fp_disable_snd_device;
+}
+
+bool icc_is_active(struct audio_device *adev)
+{
+ struct audio_usecase *icc_usecase = NULL;
+ icc_usecase = fp_get_usecase_from_list(adev, iccmod.ucid);
+
+ if (icc_usecase != NULL)
+ return true;
+ else
+ return false;
+}
+
+audio_usecase_t icc_get_usecase()
+{
+ return iccmod.ucid;
+}
+
+void icc_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ int ret;
+ int rate;
+ int val;
+ float vol;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_ICC_ENABLE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (!strncmp(value,"true",sizeof(value)) && !iccmod.is_icc_running)
+ ret = start_icc(adev,parms);
+ else if (!strncmp(value, "false", sizeof(value)) && iccmod.is_icc_running)
+ stop_icc(adev);
+ else
+ ALOGE("%s=%s is unsupported", AUDIO_PARAMETER_ICC_ENABLE, value);
+ }
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms,AUDIO_PARAMETER_ICC_SET_SAMPLING_RATE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ rate = atoi(value);
+ if (rate == 16000){
+ iccmod.ucid = USECASE_ICC_CALL;
+ pcm_config_icc.rate = rate;
+ } else
+ ALOGE("Unsupported rate..");
+ }
+
+ if (iccmod.is_icc_running) {
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+ value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if (val > 0)
+ fp_select_devices(adev, iccmod.ucid);
+ }
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ICC_VOLUME,
+ value, sizeof(value));
+ if (ret >= 0) {
+ if (sscanf(value, "%f", &vol) != 1){
+ ALOGE("%s: error in retrieving icc volume", __func__);
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: icc_set_volume usecase, Vol: [%f]", __func__, vol);
+ icc_set_volume(adev, vol);
+ }
+exit:
+ ALOGV("%s Exit",__func__);
+}
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 66d7441..366fc85 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -981,6 +981,20 @@
ALOGV("%s Selected apptype: playback %d capture %d",
__func__, usecase->out_app_type_cfg.app_type, usecase->in_app_type_cfg.app_type);
break;
+ case ICC_CALL:
+ /* ICC usecase: Loopback from TERT_TDM_TX to TERT_TDM_RX */
+ /* update out_app_type_cfg */
+ usecase->out_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ usecase->out_app_type_cfg.bit_width = platform_get_snd_device_bit_width(usecase->out_snd_device);
+ usecase->out_app_type_cfg.app_type = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK);
+ /* update in_app_type_cfg */
+ usecase->in_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ usecase->in_app_type_cfg.bit_width = platform_get_snd_device_bit_width(usecase->in_snd_device);
+ usecase->in_app_type_cfg.app_type = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE);
+
+ ALOGV("%s Selected apptype: playback %d capture %d",
+ __func__, usecase->out_app_type_cfg.app_type, usecase->in_app_type_cfg.app_type);
+ break;
default:
ALOGE("%s: app type cfg not supported for usecase type (%d)",
__func__, usecase->type);
@@ -1142,6 +1156,64 @@
return rc;
}
+int audio_extn_utils_send_app_type_cfg_icc(struct audio_device *adev,
+ struct audio_usecase *usecase)
+{
+ int pcm_device_id, acdb_dev_id = 0, snd_device = usecase->out_snd_device;
+ int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ int app_type = 0, rc = 0;
+
+ ALOGV("%s", __func__);
+
+ if (usecase->type != ICC_CALL) {
+ ALOGV("%s: not an ICC path, no need to cfg app type", __func__);
+ rc = 0;
+ goto exit_send_app_type_cfg;
+ }
+ if (usecase->id != USECASE_ICC_CALL) {
+ ALOGV("%s: a usecase where app type cfg is not required", __func__);
+ rc = 0;
+ goto exit_send_app_type_cfg;
+ }
+
+ snd_device = usecase->out_snd_device;
+ pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+ acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+ if (acdb_dev_id < 0) {
+ ALOGE("%s: Couldn't get the acdb dev id", __func__);
+ rc = -EINVAL;
+ goto exit_send_app_type_cfg;
+ }
+ /* config ICC session: playback path */
+ app_type = usecase->out_app_type_cfg.app_type;
+ sample_rate= usecase->out_app_type_cfg.sample_rate;
+
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate,
+ PCM_PLAYBACK,
+ snd_device);
+ if (rc < 0)
+ goto exit_send_app_type_cfg;
+
+ /* config ICC session: capture path */
+ snd_device = usecase->in_snd_device;
+ pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE);
+ acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+ if (acdb_dev_id < 0) {
+ ALOGE("%s: Couldn't get the acdb dev id", __func__);
+ rc = -EINVAL;
+ goto exit_send_app_type_cfg;
+ }
+ app_type = usecase->in_app_type_cfg.app_type;
+ sample_rate= usecase->in_app_type_cfg.sample_rate;
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate,
+ PCM_CAPTURE,
+ snd_device);
+exit_send_app_type_cfg:
+ return rc;
+}
+
int audio_extn_utils_get_app_sample_rate_for_device(
struct audio_device *adev,
struct audio_usecase *usecase, int snd_device)
@@ -1487,6 +1559,8 @@
if (usecase->type == PCM_HFP_CALL) {
return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
+ } else if (usecase->type == ICC_CALL) {
+ return audio_extn_utils_send_app_type_cfg_icc(adev, usecase);
}
switch (usecase->type) {
@@ -1888,7 +1962,8 @@
platform_send_audio_calibration(adev->platform, usecase,
usecase->stream.in->app_type_cfg.app_type);
} else if ((type == PCM_HFP_CALL) || (type == PCM_CAPTURE) ||
- (type == TRANSCODE_LOOPBACK_RX && usecase->stream.inout != NULL)) {
+ (type == TRANSCODE_LOOPBACK_RX && usecase->stream.inout != NULL) ||
+ (type == ICC_CALL)) {
platform_send_audio_calibration(adev->platform, usecase,
platform_get_default_app_type_v2(adev->platform, usecase->type));
} else {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 7ccef0a..3ad03f4 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -421,6 +421,7 @@
[USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
[USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
[USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
+ [USECASE_ICC_CALL] = "icc-call",
};
static const audio_usecase_t offload_usecases[] = {
@@ -2687,7 +2688,8 @@
if ((usecase->type == VOICE_CALL) ||
(usecase->type == VOIP_CALL) ||
- (usecase->type == PCM_HFP_CALL)) {
+ (usecase->type == PCM_HFP_CALL)||
+ (usecase->type == ICC_CALL)) {
if(usecase->stream.out == NULL) {
ALOGE("%s: stream.out is NULL", __func__);
return -EINVAL;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 3adba6e..da68656 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -249,6 +249,9 @@
USECASE_AUDIO_FM_TUNER_EXT,
/*voip usecase with low latency path*/
USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY,
+
+ /*In Car Communication Usecase*/
+ USECASE_ICC_CALL,
AUDIO_USECASE_MAX
};
@@ -546,6 +549,7 @@
TRANSCODE_LOOPBACK_RX,
TRANSCODE_LOOPBACK_TX,
PCM_PASSTHROUGH,
+ ICC_CALL,
USECASE_TYPE_MAX
} usecase_type_t;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 9550f5a..4335991 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -522,6 +522,7 @@
[USECASE_AUDIO_PLAYBACK_REAR_SEAT] = {REAR_SEAT_PCM_DEVICE,
REAR_SEAT_PCM_DEVICE},
[USECASE_AUDIO_FM_TUNER_EXT] = {-1, -1},
+ [USECASE_ICC_CALL] = {ICC_PCM_DEVICE, ICC_PCM_DEVICE},
};
/* Array to store sound devices */
@@ -631,6 +632,7 @@
[SND_DEVICE_OUT_BUS_RSE] = "bus-speaker",
[SND_DEVICE_OUT_CALL_PROXY] = "call-proxy",
[SND_DEVICE_OUT_HAPTICS] = "haptics",
+ [SND_DEVICE_OUT_ICC] = "bus-speaker",
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -780,6 +782,7 @@
[SND_DEVICE_IN_HANDSET_6MIC_AND_EC_REF_LOOPBACK] = "handset-6mic-and-ec-ref-loopback",
[SND_DEVICE_IN_HANDSET_8MIC_AND_EC_REF_LOOPBACK] = "handset-8mic-and-ec-ref-loopback",
[SND_DEVICE_IN_CALL_PROXY] = "call-proxy-in",
+ [SND_DEVICE_IN_ICC] = "speaker-mic",
};
// Platform specific backend bit width table
@@ -923,6 +926,7 @@
[SND_DEVICE_OUT_BUS_RSE] = 60,
[SND_DEVICE_OUT_CALL_PROXY] = 32,
[SND_DEVICE_OUT_HAPTICS] = 200,
+ [SND_DEVICE_OUT_ICC] = 16,
[SND_DEVICE_IN_HANDSET_MIC] = 4,
[SND_DEVICE_IN_HANDSET_MIC_SB] = 163,
[SND_DEVICE_IN_HANDSET_MIC_NN] = 183,
@@ -1062,6 +1066,7 @@
[SND_DEVICE_IN_VOICE_HEARING_AID] = 44,
[SND_DEVICE_IN_BUS] = 11,
[SND_DEVICE_IN_CALL_PROXY] = 33,
+ [SND_DEVICE_IN_ICC] = 46,
};
struct name_to_index {
@@ -1317,6 +1322,9 @@
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_6MIC_AND_EC_REF_LOOPBACK)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_8MIC_AND_EC_REF_LOOPBACK)},
{TO_NAME_INDEX(SND_DEVICE_IN_CALL_PROXY)},
+ /* ICC */
+ {TO_NAME_INDEX(SND_DEVICE_IN_ICC)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_ICC)},
};
static char * backend_tag_table[SND_DEVICE_MAX] = {0};
@@ -2601,6 +2609,8 @@
hw_interface_table[SND_DEVICE_IN_VOICE_HEARING_AID] = strdup("SLIMBUS_0_TX");
hw_interface_table[SND_DEVICE_IN_BUS] = strdup("TERT_TDM_TX_0");
hw_interface_table[SND_DEVICE_IN_CALL_PROXY] = strdup("CALL_PROXY_TX");
+ hw_interface_table[SND_DEVICE_IN_ICC] = strdup("TERT_TDM_TX_0");
+ hw_interface_table[SND_DEVICE_OUT_ICC] = strdup("TERT_TDM_RX_0");
my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
/*remove ALAC & APE from DSP decoder list based on software decoder availability*/
@@ -5365,7 +5375,8 @@
snd_device = usecase->out_snd_device;
else if ((usecase->type == PCM_CAPTURE) && is_incall_rec_usecase)
snd_device = voice_get_incall_rec_snd_device(usecase->in_snd_device);
- else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
+ else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE)||
+ (usecase->type == ICC_CALL))
snd_device = usecase->in_snd_device;
else if (usecase->type == TRANSCODE_LOOPBACK_RX)
snd_device = usecase->out_snd_device;
@@ -5389,7 +5400,8 @@
new_snd_device[0] = snd_device;
}
}
- if ((usecase->type == PCM_HFP_CALL) && is_bus_dev_usecase) {
+ if (((usecase->type == PCM_HFP_CALL) || (usecase->type == ICC_CALL)) &&
+ is_bus_dev_usecase) {
num_devices = 2;
new_snd_device[0] = usecase->in_snd_device;
new_snd_device[1] = usecase->out_snd_device;
@@ -5413,7 +5425,8 @@
if ((usecase->type == PCM_CAPTURE) && (app_type == DEFAULT_APP_TYPE_RX_PATH)) {
ALOGD("Resetting app type for Tx path to default");
app_type = DEFAULT_APP_TYPE_TX_PATH;
- } else if ((usecase->type == PCM_HFP_CALL) && is_bus_dev_usecase) {
+ } else if (((usecase->type == PCM_HFP_CALL) || (usecase->type == ICC_CALL)) &&
+ is_bus_dev_usecase) {
if (new_snd_device[i] >= SND_DEVICE_OUT_BEGIN &&
new_snd_device[i] < SND_DEVICE_OUT_END) {
app_type = usecase->out_app_type_cfg.app_type;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 8fa4591..ca091ff 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -167,6 +167,7 @@
SND_DEVICE_OUT_BUS_RSE,
SND_DEVICE_OUT_CALL_PROXY,
SND_DEVICE_OUT_HAPTICS,
+ SND_DEVICE_OUT_ICC,
SND_DEVICE_OUT_END,
/*
@@ -320,6 +321,7 @@
SND_DEVICE_IN_HANDSET_6MIC_AND_EC_REF_LOOPBACK,
SND_DEVICE_IN_HANDSET_8MIC_AND_EC_REF_LOOPBACK,
SND_DEVICE_IN_CALL_PROXY,
+ SND_DEVICE_IN_ICC,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,