audio: support custom acdb for external device

add the specific external device setting in audio_platform_info.xml

For example:
<external_specific_dev>
    <ext_device name="SND_DEVICE_OUT_USB_HEADSET" usbid="18d1:5034" acdb_id="10" />
</external_specific_dev>

Bug: 117336751
Test: manual test ok
Change-Id: Ie9abcadd9bcd6d06c5d8f0a9807c3935ee4a1d35
Signed-off-by: Carter Hsu <carterhsu@google.com>
Signed-off-by: Robert Lee <lerobert@google.com>
(cherry picked from commit 017c63ae09841070e587d0f9f5c396efcb07e46d)
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index efbd0ae..fceded3 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -235,6 +235,12 @@
     int acdb_id;
 };
 
+struct external_specific_device {
+    struct listnode list;
+    char *usbid;
+    int acdb_id;
+};
+
 static struct listnode operator_info_list;
 static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
 
@@ -261,6 +267,8 @@
     size_t mic_count;
 };
 
+static struct listnode *external_specific_device_table[SND_DEVICE_MAX];
+
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -1401,6 +1409,27 @@
 static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
 static bool is_tmus = false;
 
+static bool is_usb_snd_dev(snd_device_t snd_device)
+{
+    if (snd_device < SND_DEVICE_IN_BEGIN) {
+        if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||\
+            snd_device == SND_DEVICE_OUT_USB_HEADPHONES ||\
+            snd_device == SND_DEVICE_OUT_VOICE_USB_HEADPHONES ||\
+            snd_device == SND_DEVICE_OUT_VOICE_USB_HEADSET ||\
+            snd_device == SND_DEVICE_OUT_VOICE_TTY_FULL_USB ||\
+            snd_device == SND_DEVICE_OUT_VOICE_TTY_VCO_USB)
+            return true;
+    } else {
+        if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC ||\
+            snd_device == SND_DEVICE_IN_USB_HEADSET_MIC_AEC ||\
+            snd_device == SND_DEVICE_IN_VOICE_USB_HEADSET_MIC ||\
+            snd_device == SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC ||\
+            snd_device == SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC)
+            return true;
+    }
+    return false;
+}
+
 static void check_operator()
 {
     char value[PROPERTY_VALUE_MAX];
@@ -1489,6 +1518,30 @@
     return ret;
 }
 
+static int get_external_specific_device_acdb_id(snd_device_t snd_device)
+{
+    struct external_specific_device *ext_dev;
+    int ret = acdb_device_table[snd_device];
+    char *usbid = NULL;
+    struct listnode *node;
+
+    if (is_usb_snd_dev(snd_device))
+        usbid = audio_extn_usb_usbid();
+
+    if (usbid) {
+        list_for_each(node, external_specific_device_table[snd_device]) {
+            ext_dev = node_to_item(node, struct external_specific_device, list);
+            if (ext_dev->usbid && !strcmp(usbid, ext_dev->usbid)) {
+                ret = ext_dev->acdb_id;
+                break;
+            }
+        }
+
+        free(usbid);
+    }
+    return ret;
+}
+
 static const char *get_operator_specific_device_mixer_path(snd_device_t snd_device)
 {
     struct operator_specific_device *device;
@@ -1906,6 +1959,7 @@
         backend_tag_table[dev] = NULL;
         hw_interface_table[dev] = NULL;
         operator_specific_device_table[dev] = NULL;
+        external_specific_device_table[dev] = NULL;
     }
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
         backend_bit_width_table[dev] = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
@@ -3594,6 +3648,7 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     struct operator_info *info_item;
     struct operator_specific_device *device_item;
+    struct external_specific_device *ext_dev;
     struct app_type_entry *ap;
     struct listnode *node;
 
@@ -3647,6 +3702,17 @@
             free(operator_specific_device_table[dev]);
             operator_specific_device_table[dev] = NULL;
         }
+
+        if (external_specific_device_table[dev]) {
+            while (!list_empty(external_specific_device_table[dev])) {
+                node = list_head(external_specific_device_table[dev]);
+                list_remove(node);
+                ext_dev = node_to_item(node, struct external_specific_device, list);
+                free(ext_dev->usbid);
+                free(ext_dev);
+            }
+            free(external_specific_device_table[dev]);
+        }
     }
 
     while (!list_empty(&operator_info_list)) {
@@ -4029,6 +4095,29 @@
     return ret;
 }
 
+void platform_add_external_specific_device(snd_device_t snd_device,
+                                           const char *usbid,
+                                           unsigned int acdb_id)
+{
+    struct external_specific_device *device;
+
+    if (external_specific_device_table[snd_device] == NULL) {
+        external_specific_device_table[snd_device] =
+            (struct listnode *)calloc(1, sizeof(struct listnode));
+        list_init(external_specific_device_table[snd_device]);
+    }
+
+    device = (struct external_specific_device *)calloc(1, sizeof(struct external_specific_device));
+
+    device->usbid = strdup(usbid);
+    device->acdb_id = acdb_id;
+
+    list_add_tail(external_specific_device_table[snd_device], &device->list);
+
+    ALOGD("%s: device[%s] usbid[%s] -> acdb_id[%d]", __func__,
+            platform_get_snd_device_name(snd_device), usbid, acdb_id);
+}
+
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
 {
     int ret = 0;
@@ -4144,6 +4233,8 @@
 
     if (operator_specific_device_table[snd_device] != NULL)
         return get_operator_specific_device_acdb_id(snd_device);
+    else if (external_specific_device_table[snd_device] != NULL)
+        return get_external_specific_device_acdb_id(snd_device);
     else
         return acdb_device_table[snd_device];
 }