hal: update combo device handling
If the wired headset/headphone/line devices are handled by
a different backend than speaker/earpiece devices, the combo
devices such as speaker+headphones can be split into individual
devices and enabled/disabled independently.
Bug: 21581860.
Change-Id: Icdd962a4dc1da536fe89c4de2202e7383275603d
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 6303217..4d8b233 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -758,7 +758,8 @@
property_get("ro.board.platform", platform, "");
if (!strncmp("apq8084", platform, sizeof("apq8084"))) {
platform_set_snd_device_backend(SND_DEVICE_OUT_VOICE_SPEAKER,
- "speaker-protected");
+ "speaker-protected",
+ "SLIMBUS_0_RX");
}
}
}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5c46c1e..e9baf5e 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -265,6 +265,9 @@
int enable_snd_device(struct audio_device *adev,
snd_device_t snd_device)
{
+ int i, num_devices = 0;
+ snd_device_t new_snd_devices[2];
+
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -306,6 +309,10 @@
ALOGE("%s: spkr_start_processing failed", __func__);
return -EINVAL;
}
+ } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
+ for (i = 0; i < num_devices; i++) {
+ enable_snd_device(adev, new_snd_devices[i]);
+ }
} else {
const char * dev_path = platform_get_snd_device_name(snd_device);
ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
@@ -318,6 +325,9 @@
int disable_snd_device(struct audio_device *adev,
snd_device_t snd_device)
{
+ int i, num_devices = 0;
+ snd_device_t new_snd_devices[2];
+
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -337,6 +347,10 @@
snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
audio_extn_spkr_prot_is_enabled()) {
audio_extn_spkr_prot_stop_processing(snd_device);
+ } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
+ for (i = 0; i < num_devices; i++) {
+ disable_snd_device(adev, new_snd_devices[i]);
+ }
} else {
audio_route_reset_and_update_path(adev->audio_route, dev_path);
}
@@ -346,9 +360,9 @@
return 0;
}
-static void check_usecases_codec_backend(struct audio_device *adev,
- struct audio_usecase *uc_info,
- snd_device_t snd_device)
+static void check_and_route_playback_usecases(struct audio_device *adev,
+ struct audio_usecase *uc_info,
+ snd_device_t snd_device)
{
struct listnode *node;
struct audio_usecase *usecase;
@@ -375,7 +389,8 @@
if (usecase->type != PCM_CAPTURE &&
usecase != uc_info &&
usecase->out_snd_device != snd_device &&
- usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
+ platform_check_backends_match(snd_device, usecase->out_snd_device)) {
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
platform_get_snd_device_name(usecase->out_snd_device));
@@ -565,7 +580,7 @@
* so that it would not result any device switch. All the usecases will
* be switched to new device when select_devices() is called for voice call
* usecase. This is to avoid switching devices for voice call when
- * check_usecases_codec_backend() is called below.
+ * check_and_route_playback_usecases() is called below.
*/
if (voice_is_in_call(adev)) {
vc_usecase = get_usecase_from_list(adev,
@@ -660,7 +675,7 @@
/* Enable new sound devices */
if (out_snd_device != SND_DEVICE_NONE) {
if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
- check_usecases_codec_backend(adev, usecase, out_snd_device);
+ check_and_route_playback_usecases(adev, usecase, out_snd_device);
enable_snd_device(adev, out_snd_device);
}
@@ -1349,7 +1364,7 @@
/*
* select_devices() call below switches all the usecases on the same
- * backend to the new device. Refer to check_usecases_codec_backend() in
+ * backend to the new device. Refer to check_and_route_playback_usecases() in
* the select_devices(). But how do we undo this?
*
* For example, music playback is active on headset (deep-buffer usecase)
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index e2333ca..4536a05 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1002,7 +1002,8 @@
}
int platform_set_snd_device_backend(snd_device_t device __unused,
- const char *backend __unused)
+ const char *backend __unused,
+ const char *hw_interface __unused)
{
return -ENOSYS;
}
@@ -1041,3 +1042,22 @@
}
return status;
}
+
+bool platform_send_gain_dep_cal(void *platform __unused,
+ int level __unused)
+{
+ return 0;
+}
+
+bool platform_can_split_snd_device(snd_device_t in_snd_device __unused,
+ int *num_devices __unused,
+ snd_device_t *out_snd_devices __unused)
+{
+ return false;
+}
+
+bool platform_check_backends_match(snd_device_t snd_device1 __unused,
+ snd_device_t snd_device2 __unused)
+{
+ return true;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 39d1aa5..854acea 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -343,6 +343,7 @@
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_STEREO)},
{TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC_AEC)},
{TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC)},
@@ -367,7 +368,8 @@
{TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
};
-static char * backend_table[SND_DEVICE_MAX] = {0};
+static char * backend_tag_table[SND_DEVICE_MAX] = {0};
+static char * hw_interface_table[SND_DEVICE_MAX] = {0};
static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
@@ -634,42 +636,67 @@
#endif
}
-static void set_platform_defaults(struct platform_data * my_data)
+static void set_platform_defaults(struct platform_data * my_data __unused)
{
int32_t dev;
for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
- backend_table[dev] = NULL;
+ backend_tag_table[dev] = NULL;
+ hw_interface_table[dev] = NULL;
}
- // TBD - do these go to the platform-info.xml file.
- // will help in avoiding strdups here
- backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
- backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
- backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
- backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
- backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
- backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
- backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
- backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+ // To overwrite these go to the audio_platform_info.xml file.
+ backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+ backend_tag_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+ backend_tag_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+ backend_tag_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+ backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+ backend_tag_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
if (my_data->ext_speaker) {
- backend_table[SND_DEVICE_OUT_SPEAKER] = strdup("speaker");
- backend_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("speaker");
- backend_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("speaker");
- backend_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("speaker");
- backend_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] =
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER] = strdup("speaker");
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("speaker");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("speaker");
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("speaker");
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] =
strdup("speaker-and-headphones");
- backend_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] =
+ backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] =
strdup("speaker-and-line");
}
if (my_data->ext_earpiece) {
- backend_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("handset");
- backend_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("handset");
- backend_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("handset");
- backend_table[SND_DEVICE_OUT_HANDSET] = strdup("handset");
- backend_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("handset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("handset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("handset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("handset");
+ backend_tag_table[SND_DEVICE_OUT_HANDSET] = strdup("handset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("handset");
}
+
+ hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_HEADPHONES] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_LINE] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_HEADPHONES] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_LINE] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_HDMI] = strdup("HDMI_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("SLIMBUS_0_RX-and-HDMI_RX");
+ hw_interface_table[SND_DEVICE_OUT_BT_SCO] = strdup("SEC_AUX_PCM_RX");
+ hw_interface_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("SEC_AUX_PCM_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
+ hw_interface_table[SND_DEVICE_OUT_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
}
void *platform_init(struct audio_device *adev)
@@ -852,7 +879,7 @@
return;
}
- const char * suffix = backend_table[snd_device];
+ const char * suffix = backend_tag_table[snd_device];
if (suffix != NULL) {
strcat(mixer_path, " ");
@@ -860,6 +887,36 @@
}
}
+bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_device2)
+{
+ bool result = true;
+
+ ALOGV("%s: snd_device1 = %s, snd_device2 = %s", __func__,
+ platform_get_snd_device_name(snd_device1),
+ platform_get_snd_device_name(snd_device2));
+
+ if ((snd_device1 < SND_DEVICE_MIN) || (snd_device1 >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %s", __func__,
+ platform_get_snd_device_name(snd_device1));
+ return false;
+ }
+ if ((snd_device2 < SND_DEVICE_MIN) || (snd_device2 >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %s", __func__,
+ platform_get_snd_device_name(snd_device2));
+ return false;
+ }
+ const char * be_itf1 = hw_interface_table[snd_device1];
+ const char * be_itf2 = hw_interface_table[snd_device2];
+
+ if (NULL != be_itf1 && NULL != be_itf2) {
+ if (0 != strcmp(be_itf1, be_itf2))
+ result = false;
+ }
+
+ ALOGV("%s: be_itf1 = %s, be_itf2 = %s, match %d", __func__, be_itf1, be_itf2, result);
+ return result;
+}
+
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
{
int device_id;
@@ -922,6 +979,8 @@
goto done;
}
+ ALOGV("%s: acdb_device_table[%s]: old = %d new = %d", __func__,
+ platform_get_snd_device_name(snd_device), acdb_device_table[snd_device], acdb_id);
acdb_device_table[snd_device] = acdb_id;
done:
return ret;
@@ -1220,6 +1279,37 @@
return ret;
}
+bool platform_can_split_snd_device(snd_device_t snd_device,
+ int *num_devices,
+ snd_device_t *new_snd_devices)
+{
+ bool status = false;
+
+ if (NULL == num_devices || NULL == new_snd_devices) {
+ ALOGE("%s: NULL pointer ..", __func__);
+ return false;
+ }
+
+ /*
+ * If wired headset/headphones/line devices share the same backend
+ * with speaker/earpiece this routine returns false.
+ */
+ if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES &&
+ !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_HEADPHONES)) {
+ *num_devices = 2;
+ new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
+ new_snd_devices[1] = SND_DEVICE_OUT_HEADPHONES;
+ status = true;
+ } else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_LINE &&
+ !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_LINE)) {
+ *num_devices = 2;
+ new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
+ new_snd_devices[1] = SND_DEVICE_OUT_LINE;
+ status = true;
+ }
+ return status;
+}
+
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -1744,7 +1834,8 @@
}
}
-int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
+ const char * hw_interface)
{
int ret = 0;
@@ -1755,10 +1846,20 @@
goto done;
}
- if (backend_table[device]) {
- free(backend_table[device]);
+ ALOGV("%s: backend_tag_table[%s]: old = %s new = %s", __func__,
+ platform_get_snd_device_name(device),
+ backend_tag_table[device] != NULL ? backend_tag_table[device]: "null", backend_tag);
+ if (backend_tag_table[device]) {
+ free(backend_tag_table[device]);
}
- backend_table[device] = strdup(backend);
+ backend_tag_table[device] = strdup(backend_tag);
+
+ if (hw_interface != NULL) {
+ if (hw_interface_table[device])
+ free(hw_interface_table[device]);
+ ALOGV("%s: hw_interface_table[%d] = %s", __func__, device, hw_interface);
+ hw_interface_table[device] = strdup(hw_interface);
+ }
done:
return ret;
}
@@ -1776,6 +1877,7 @@
ALOGE("%s: invalid usecase type", __func__);
ret = -EINVAL;
}
+ ALOGV("%s: pcm_device_table[%d][%d] = %d", __func__, usecase, type, pcm_id);
pcm_device_table[usecase][type] = pcm_id;
done:
return ret;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index c242b16..e96c098 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -195,12 +195,6 @@
#define VOLTE_CALL_PCM_DEVICE 21
#define QCHAT_CALL_PCM_DEVICE 33
#define VOWLAN_CALL_PCM_DEVICE -1
-#elif PLATFORM_MSM8994
-#define VOICE_CALL_PCM_DEVICE 2
-#define VOICE2_CALL_PCM_DEVICE 22
-#define VOLTE_CALL_PCM_DEVICE 14
-#define QCHAT_CALL_PCM_DEVICE 20
-#define VOWLAN_CALL_PCM_DEVICE 36
#else
#define VOICE_CALL_PCM_DEVICE 2
#define VOICE2_CALL_PCM_DEVICE 22
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 2ab4419..9f65a63 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -57,7 +57,8 @@
int platform_start_incall_music_usecase(void *platform);
int platform_stop_incall_music_usecase(void *platform);
-int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend);
+int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend,
+ const char * hw_interface);
/* From platform_info_parser.c */
int platform_info_init(void);
@@ -66,4 +67,11 @@
int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels);
+
+bool platform_can_split_snd_device(snd_device_t in_snd_device,
+ int *num_devices,
+ snd_device_t *out_snd_devices);
+
+bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_device2);
+
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 832c0f0..e1ff361 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -128,6 +128,7 @@
static void process_backend_name(const XML_Char **attr)
{
int index;
+ char *hw_interface = NULL;
if (strcmp(attr[0], "name") != 0) {
ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
@@ -147,7 +148,15 @@
goto done;
}
- if (platform_set_snd_device_backend(index, attr[3]) < 0) {
+ if (attr[4] != NULL) {
+ if (strcmp(attr[4], "interface") != 0) {
+ hw_interface = NULL;
+ } else {
+ hw_interface = (char *)attr[5];
+ }
+ }
+
+ if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
ALOGE("%s: Device %s in %s, backend %s was not set!",
__func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
goto done;