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/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;