hal: Support for anc/aanc/proxy audio features
Added support for anc/aanc/proxy audio features
Change-Id: Id6ebdb9094635563cfafce9dc1d3449efe25bda4
diff --git a/hal/Android.mk b/hal/Android.mk
index 71e6d5a..649f6fe 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -19,6 +19,16 @@
audio_hw.c \
$(AUDIO_PLATFORM)/platform.c
+LOCAL_SRC_FILES += audio_extn/audio_extn.c
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true)
+ LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true)
+ LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
+endif
+
LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
@@ -31,7 +41,8 @@
external/tinyalsa/include \
$(call include-path-for, audio-route) \
$(call include-path-for, audio-effects) \
- $(LOCAL_PATH)/$(AUDIO_PLATFORM)
+ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \
+ $(LOCAL_PATH)/audio_extn
LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
new file mode 100644
index 0000000..610e0d1
--- /dev/null
+++ b/hal/audio_extn/audio_extn.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013, 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 "audio_hw_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "audio_extn.h"
+
+struct audio_extn_module {
+ bool anc_enabled;
+ bool aanc_enabled;
+ uint32_t proxy_channel_num;
+};
+
+static struct audio_extn_module aextnmod = {
+ .anc_enabled = 0,
+ .aanc_enabled = 0,
+ .proxy_channel_num = 2,
+};
+
+#define AUDIO_PARAMETER_KEY_ANC "anc_enabled"
+#define AUDIO_PARAMETER_KEY_WFD "wfd_channel_cap"
+#define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy"
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_set_anc_parameters(parms) (0)
+#else
+bool audio_extn_get_anc_enabled(void)
+{
+ ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+ return (aextnmod.anc_enabled ? true: false);
+}
+
+bool audio_extn_should_use_handset_anc(int in_channels)
+{
+ char prop_aanc[128] = "false";
+
+ property_get("persist.aanc.enable", prop_aanc, "0");
+ if (!strncmp("true", prop_aanc, 4)) {
+ ALOGD("%s: AANC enabled in the property", __func__);
+ aextnmod.aanc_enabled = 1;
+ }
+
+ return (aextnmod.aanc_enabled && aextnmod.anc_enabled
+ && (in_channels == 1));
+}
+
+bool audio_extn_should_use_fb_anc(void)
+{
+ char prop_anc[128] = "feedforward";
+
+ property_get("persist.headset.anc.type", prop_anc, "0");
+ if (!strncmp("feedback", prop_anc, sizeof("feedback"))) {
+ ALOGD("%s: FB ANC headset type enabled\n", __func__);
+ return true;
+ }
+ return false;
+}
+
+void audio_extn_set_anc_parameters(struct str_parms *parms)
+{
+ int ret;
+ char value[32] ={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ANC, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (strcmp(value, "true") == 0)
+ aextnmod.anc_enabled = true;
+ else
+ aextnmod.anc_enabled = false;
+ }
+
+ ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+}
+#endif /* ANC_HEADSET_ENABLED */
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_parameters(parms) (0)
+#define audio_extn_get_afe_proxy_parameters(query, reply) (0)
+#else
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev)
+{
+ int32_t ret = 0;
+ const char *channel_cnt_str = NULL;
+ struct mixer_ctl *ctl = NULL;
+ const char *mixer_ctl_name = "PROXY_RX Channels";
+
+
+ ALOGD("%s: entry", __func__);
+ /* use the existing channel count set by hardware params to
+ configure the back end for stereo as usb/a2dp would be
+ stereo by default */
+ ALOGD("%s: channels = %d", __func__,
+ aextnmod.proxy_channel_num);
+ switch (aextnmod.proxy_channel_num) {
+ case 8: channel_cnt_str = "Eight"; break;
+ case 7: channel_cnt_str = "Seven"; break;
+ case 6: channel_cnt_str = "Six"; break;
+ case 5: channel_cnt_str = "Five"; break;
+ case 4: channel_cnt_str = "Four"; break;
+ case 3: channel_cnt_str = "Three"; break;
+ default: channel_cnt_str = "Two"; break;
+ }
+
+ if(aextnmod.proxy_channel_num >= 2 && aextnmod.proxy_channel_num < 8) {
+ 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_enum_by_string(ctl, channel_cnt_str);
+
+ ALOGD("%s: exit", __func__);
+ return ret;
+}
+
+void audio_extn_set_afe_proxy_parameters(struct str_parms *parms)
+{
+ int ret, val;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_WFD, value,
+ sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ aextnmod.proxy_channel_num = val;
+ ALOGD("%s: channel capability set to: %d", __func__,
+ aextnmod.proxy_channel_num);
+ }
+}
+
+char* audio_extn_get_afe_proxy_parameters(struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret, val;
+ char value[32]={0};
+ char *str = NULL;
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value,
+ sizeof(value));
+ if (ret >= 0) {
+ /* Todo: check if proxy is free by maintaining a state flag*/
+ val = 1;
+ str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val);
+ str = str_parms_to_str(reply);
+ }
+
+ return str;
+}
+#endif /* AFE_PROXY_ENABLED */
+
+void audio_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ audio_extn_set_anc_parameters(parms);
+ audio_extn_set_afe_proxy_parameters(parms);
+}
+
+char* audio_extn_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ struct str_parms *query = str_parms_create_str(keys);
+ struct str_parms *reply = str_parms_create();
+ char *str = NULL;
+
+ ALOGD("%s: enter: keys - %s", __func__, keys);
+
+ if (NULL != (str = audio_extn_get_afe_proxy_parameters(query, reply)))
+ {
+ ALOGD("%s: handled %s", __func__, str);
+ goto exit;
+ } else {
+ str = strdup(keys);
+ }
+
+exit:
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ ALOGD("%s: exit: returns %s", __func__, str);
+ return str;
+}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
new file mode 100644
index 0000000..c537b77
--- /dev/null
+++ b/hal/audio_extn/audio_extn.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+#ifndef AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#include <cutils/str_parms.h>
+
+void audio_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+
+char* audio_extn_get_parameters(const struct audio_hw_device *dev,
+ const char *keys);
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_get_anc_enabled() (0)
+#define audio_extn_should_use_fb_anc() (0)
+#define audio_extn_should_use_handset_anc(in_channels) (0)
+#else
+bool audio_extn_get_anc_enabled(void);
+bool audio_extn_should_use_fb_anc(void);
+bool audio_extn_should_use_handset_anc(int in_channels);
+#endif
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_channel_mixer(adev) (0)
+#else
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev);
+#endif
+
+#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5e966d9..1f2cdbb 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, 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");
@@ -35,6 +38,7 @@
#include "audio_hw.h"
#include "platform_api.h"
#include <platform.h>
+#include "audio_extn.h"
struct pcm_config pcm_config_deep_buffer = {
.channels = 2,
@@ -1508,6 +1512,7 @@
pthread_mutex_unlock(&adev->lock);
}
+ audio_extn_set_parameters(adev, parms);
str_parms_destroy(parms);
ALOGV("%s: exit with code(%d)", __func__, ret);
return ret;
@@ -1516,7 +1521,7 @@
static char* adev_get_parameters(const struct audio_hw_device *dev,
const char *keys)
{
- return strdup("");
+ return audio_extn_get_parameters(dev, keys);
}
static int adev_init_check(const struct audio_hw_device *dev)
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3d13c7d..85c57fc 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, 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");
@@ -25,6 +28,7 @@
#include <audio_hw.h>
#include <platform_api.h>
#include "platform.h"
+#include "audio_extn.h"
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
#define LIB_ACDB_LOADER "libacdbloader.so"
@@ -50,7 +54,7 @@
#define MAX_VOL_INDEX 5
#define MIN_VOL_INDEX 0
#define percent_to_index(val, min, max) \
- ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+ ((val) * ((max) - (min)) * 0.01 + (min) + .5)
struct audio_block_header
{
@@ -110,6 +114,12 @@
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+ [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones",
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+ [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -132,6 +142,7 @@
[SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
[SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef",
[SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
};
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -152,6 +163,12 @@
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+ [SND_DEVICE_OUT_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = 26,
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 26,
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_HANDSET] = 103,
[SND_DEVICE_IN_HANDSET_MIC] = 4,
[SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */
@@ -171,6 +188,7 @@
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_REC_MIC] = 62,
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
/* TODO: Update with proper acdb ids */
[SND_DEVICE_IN_VOICE_REC_DMIC] = 62,
[SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6,
@@ -490,6 +508,10 @@
audio_mode_t mode = adev->mode;
snd_device_t snd_device = SND_DEVICE_NONE;
+ audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+ AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+ int channel_count = popcount(channel_mask);
+
ALOGV("%s: enter: output devices(%#x)", __func__, devices);
if (devices == AUDIO_DEVICE_NONE ||
devices & AUDIO_DEVICE_BIT_IN) {
@@ -497,6 +519,11 @@
goto exit;
}
+ if(devices & AUDIO_DEVICE_OUT_PROXY) {
+ ALOGD("%s: setting sink capability for Proxy", __func__);
+ audio_extn_set_afe_proxy_channel_mixer(adev);
+ }
+
if (mode == AUDIO_MODE_IN_CALL) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -506,6 +533,12 @@
snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
else if (adev->tty_mode == TTY_MODE_HCO)
snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+ else if (audio_extn_get_anc_enabled()) {
+ if (audio_extn_should_use_fb_anc())
+ snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
+ }
else
snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
@@ -515,6 +548,8 @@
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
if (is_operator_tmus())
snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS;
+ else if (audio_extn_should_use_handset_anc(channel_count))
+ snd_device = SND_DEVICE_OUT_ANC_HANDSET;
else
snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
}
@@ -529,7 +564,10 @@
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ if (audio_extn_get_anc_enabled())
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
AUDIO_DEVICE_OUT_SPEAKER)) {
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
@@ -549,7 +587,15 @@
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- snd_device = SND_DEVICE_OUT_HEADPHONES;
+ if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
+ && audio_extn_get_anc_enabled()) {
+ if (audio_extn_should_use_fb_anc())
+ snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+ }
+ else
+ snd_device = SND_DEVICE_OUT_HEADPHONES;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
if (adev->speaker_lr_swap)
snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
@@ -583,6 +629,7 @@
audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
snd_device_t snd_device = SND_DEVICE_NONE;
+ int channel_count = popcount(channel_mask);
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
@@ -612,7 +659,10 @@
}
if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
- if (my_data->fluence_type == FLUENCE_NONE ||
+ if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+ audio_extn_should_use_handset_anc(channel_count)) {
+ snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+ } else if (my_data->fluence_type == FLUENCE_NONE ||
my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 26d4a9f..bbbb821 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, 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");
@@ -57,6 +60,12 @@
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+ SND_DEVICE_OUT_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_HANDSET,
SND_DEVICE_OUT_END,
/*
@@ -86,6 +95,7 @@
SND_DEVICE_IN_VOICE_REC_MIC,
SND_DEVICE_IN_VOICE_REC_DMIC,
SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_AANC_HANDSET_MIC,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,