hal: Add support to get active microphones on input stream

Add support to get active microphones on input stream.
Get microphone device id and channel map based on active
usecase and sound device. Active microphone characteristics
are retrieved from platform info using this device id.

Bug: 75041465
Test: try open mic and print log to check if the info is correct
Change-Id: Ied7d0ff9541420b57459893317537ac77b346643
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 34cb938..8a2562f 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -4086,9 +4086,9 @@
 
     lock_input_stream(in);
     pthread_mutex_lock(&adev->lock);
-    int ret = platform_get_active_microphones(adev->platform, in->device,
+    int ret = platform_get_active_microphones(adev->platform,
                                               audio_channel_count_from_in_mask(in->channel_mask),
-                                              in->source, in->usecase, mic_array, mic_count);
+                                              in->usecase, mic_array, mic_count);
     pthread_mutex_unlock(&adev->lock);
     pthread_mutex_unlock(&in->lock);
 
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 7f46b58..38c4f49 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2504,6 +2504,11 @@
     return -ENOSYS;
 }
 
+bool platform_set_microphone_map(void *platform __unused, snd_device_t in_snd_device __unused,
+                                 const struct mic_info *info __unused) {
+    return false;
+}
+
 int platform_get_active_microphones(void *platform __unused,
                                     audio_devices_t device __unused,
                                     unsigned int channels __unused,
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index fbb166d..450e31c 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -105,6 +105,11 @@
     char be_name[BE_DAI_NAME_MAX_LENGTH];
 };
 
+struct snd_device_to_mic_map {
+    struct mic_info microphones[AUDIO_MICROPHONE_MAX_COUNT];
+    size_t mic_count;
+};
+
 static struct listnode operator_info_list;
 static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
 
@@ -167,6 +172,7 @@
 
     uint32_t declared_mic_count;
     struct audio_microphone_characteristic_t microphones[AUDIO_MICROPHONE_MAX_COUNT];
+    struct snd_device_to_mic_map mic_map[SND_DEVICE_MAX];
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -4547,38 +4553,64 @@
     return 0;
 }
 
-int platform_get_active_microphones(void *platform, audio_devices_t device, unsigned int channels,
-                                    int source __unused, audio_usecase_t usecase __unused,
+bool platform_set_microphone_map(void *platform, snd_device_t in_snd_device,
+                                 const struct mic_info *info) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    if (in_snd_device < SND_DEVICE_IN_BEGIN || in_snd_device >= SND_DEVICE_IN_END) {
+        ALOGE("%s: Sound device not valid", __func__);
+        return false;
+    }
+    size_t m_count = my_data->mic_map[in_snd_device].mic_count++;
+    if (m_count >= AUDIO_MICROPHONE_MAX_COUNT) {
+        ALOGE("%s: Microphone count is greater than max allowed value", __func__);
+        my_data->mic_map[in_snd_device].mic_count--;
+        return false;
+    }
+    my_data->mic_map[in_snd_device].microphones[m_count] = *info;
+    return true;
+}
+
+int platform_get_active_microphones(void *platform, unsigned int channels,
+                                    audio_usecase_t uc_id,
                                     struct audio_microphone_characteristic_t *mic_array,
                                     size_t *mic_count) {
     struct platform_data *my_data = (struct platform_data *)platform;
-    if (mic_count == NULL) {
+    struct audio_usecase *usecase = get_usecase_from_list(my_data->adev, uc_id);
+    if (mic_count == NULL || mic_array == NULL || usecase == NULL) {
         return -EINVAL;
     }
-    if (mic_array == NULL) {
-        return -EINVAL;
-    }
-
-    if (*mic_count == 0) {
-        // TODO: return declared mic count as a preliminary implementation, the final
-        // implementation will derive mic count and channel mapping from use case, source and device
-        *mic_count = my_data->declared_mic_count;
-        return 0;
-    }
-
-    size_t max_mic_count = *mic_count;
+    size_t max_mic_count = my_data->declared_mic_count;
     size_t actual_mic_count = 0;
-    for (size_t i = 0; i < max_mic_count && i < my_data->declared_mic_count; i++) {
-        // TODO: get actual microphone and channel mapping type.
-        if ((my_data->microphones[i].device & device) == device) {
-            mic_array[actual_mic_count] = my_data->microphones[i];
-            for (size_t ch = 0; ch < channels; ch++) {
-                mic_array[actual_mic_count].channel_mapping[ch] =
-                        AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT;
+
+    snd_device_t active_input_snd_device =
+            platform_get_input_snd_device(platform, usecase->stream.in->device);
+    if (active_input_snd_device == SND_DEVICE_NONE) {
+        ALOGI("%s: No active microphones found", __func__);
+        goto end;
+    }
+
+    size_t  active_mic_count = my_data->mic_map[active_input_snd_device].mic_count;
+    struct mic_info *m_info = my_data->mic_map[active_input_snd_device].microphones;
+
+    for (size_t i = 0; i < active_mic_count; i++) {
+        unsigned int channels_for_active_mic = channels;
+        if (channels_for_active_mic > m_info[i].channel_count) {
+            channels_for_active_mic = m_info[i].channel_count;
+        }
+        for (size_t j = 0; j < max_mic_count; j++) {
+            if (strcmp(my_data->microphones[j].device_id,
+                       m_info[i].device_id) == 0) {
+                mic_array[actual_mic_count] = my_data->microphones[j];
+                for (size_t ch = 0; ch < channels_for_active_mic; ch++) {
+                     mic_array[actual_mic_count].channel_mapping[ch] =
+                             m_info[i].channel_mapping[ch];
+                }
+                actual_mic_count++;
+                break;
             }
-            actual_mic_count++;
         }
     }
+end:
     *mic_count = actual_mic_count;
     return 0;
 }
diff --git a/hal/platform_api.h b/hal/platform_api.h
index e3dc5d1..5c7d81f 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -33,6 +33,12 @@
     uint32_t level;
 };
 
+struct mic_info {
+    char device_id[AUDIO_MICROPHONE_ID_MAX_LEN];
+    size_t channel_count;
+    audio_microphone_channel_mapping_t channel_mapping[AUDIO_CHANNEL_COUNT_MAX];
+};
+
 enum card_status_t;
 struct audio_usecase;
 enum usecase_type_t;
@@ -156,11 +162,13 @@
 
 bool platform_set_microphone_characteristic(void *platform,
                                             struct audio_microphone_characteristic_t mic);
+bool platform_set_microphone_map(void *platform, snd_device_t in_snd_device,
+                                 const struct mic_info *info);
 int platform_get_microphones(void *platform,
                              struct audio_microphone_characteristic_t *mic_array,
                              size_t *mic_count);
-int platform_get_active_microphones(void *platform, audio_devices_t device,
-                                    unsigned int channels, int source, audio_usecase_t usecase,
+int platform_get_active_microphones(void *platform, unsigned int channels,
+                                    audio_usecase_t usecase,
                                     struct audio_microphone_characteristic_t *mic_array,
                                     size_t *mic_count);
 int platform_set_usb_service_interval(void *platform,
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 58631f2..181460e 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -36,6 +36,11 @@
     GAIN_LEVEL_MAPPING,
     APP_TYPE,
     MICROPHONE_CHARACTERISTIC,
+    SND_DEVICES,
+    INPUT_SND_DEVICE,
+    INPUT_SND_DEVICE_TO_MIC_MAPPING,
+    SND_DEV,
+    MIC_INFO,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -49,6 +54,8 @@
 static void process_gain_db_to_level_map(const XML_Char **attr);
 static void process_app_type(const XML_Char **attr);
 static void process_microphone_characteristic(const XML_Char **attr);
+static void process_snd_dev(const XML_Char **attr);
+static void process_mic_info(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
@@ -60,6 +67,8 @@
     [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
     [APP_TYPE] = process_app_type,
     [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic,
+    [SND_DEV] = process_snd_dev,
+    [MIC_INFO] = process_mic_info,
 };
 
 static set_parameters_fn set_parameters = &platform_set_parameters;
@@ -79,6 +88,8 @@
     unsigned int value;
 };
 
+static snd_device_t in_snd_device;
+
 static const struct audio_string_to_enum mic_locations[AUDIO_MICROPHONE_LOCATION_CNT] = {
     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_UNKNOWN),
     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY),
@@ -95,6 +106,12 @@
     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID),
 };
 
+static const struct audio_string_to_enum mic_channel_mapping[AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT] = {
+    AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED),
+    AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT),
+    AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED),
+};
+
 static const struct audio_string_to_enum device_in_types[] = {
     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_COMMUNICATION),
@@ -660,6 +677,66 @@
     return;
 }
 
+static void process_snd_dev(const XML_Char **attr)
+{
+    uint32_t curIdx = 0;
+    in_snd_device = SND_DEVICE_NONE;
+
+    if (strcmp(attr[curIdx++], "in_snd_device")) {
+        ALOGE("%s: snd_device not found", __func__);
+        return;
+    }
+    in_snd_device = platform_get_snd_device_index((char *)attr[curIdx++]);
+    if (in_snd_device < SND_DEVICE_IN_BEGIN ||
+            in_snd_device >= SND_DEVICE_IN_END) {
+        ALOGE("%s: Sound device not valid", __func__);
+        in_snd_device = SND_DEVICE_NONE;
+    }
+
+    return;
+}
+
+static void process_mic_info(const XML_Char **attr)
+{
+    uint32_t curIdx = 0;
+    struct mic_info microphone;
+
+    memset(&microphone.channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED,
+               sizeof(microphone.channel_mapping));
+
+    if (strcmp(attr[curIdx++], "mic_device_id")) {
+        ALOGE("%s: mic_device_id not found", __func__);
+        goto on_error;
+    }
+    strlcpy(microphone.device_id,
+                (char *)attr[curIdx++], AUDIO_MICROPHONE_ID_MAX_LEN);
+
+    if (strcmp(attr[curIdx++], "channel_mapping")) {
+        ALOGE("%s: channel_mapping not found", __func__);
+        goto on_error;
+    }
+    const char *token = strtok((char *)attr[curIdx++], " ");
+    uint32_t idx = 0;
+    while (token) {
+        if (!find_enum_by_string(mic_channel_mapping, token,
+                AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT,
+                &microphone.channel_mapping[idx++])) {
+            ALOGE("%s: channel_mapping %s in %s not found!",
+                      __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
+            goto on_error;
+        }
+        token = strtok(NULL, " ");
+    }
+    microphone.channel_count = idx;
+
+    platform_set_microphone_map(my_data.platform, in_snd_device,
+                                    &microphone);
+    return;
+on_error:
+    in_snd_device = SND_DEVICE_NONE;
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -685,6 +762,8 @@
             section = APP_TYPE;
         } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
             section = MICROPHONE_CHARACTERISTIC;
+        } else if (strcmp(tag_name, "snd_devices") == 0) {
+            section = SND_DEVICES;
         } else if (strcmp(tag_name, "device") == 0) {
             if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
                 ALOGE("device tag only supported for acdb/backend names");
@@ -733,6 +812,36 @@
             }
             section_process_fn fn = section_table[MICROPHONE_CHARACTERISTIC];
             fn(attr);
+        } else if (strcmp(tag_name, "input_snd_device") == 0) {
+            if (section != SND_DEVICES) {
+                ALOGE("input_snd_device tag only supported with SND_DEVICES section");
+                return;
+            }
+            section = INPUT_SND_DEVICE;
+        } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
+            if (section != INPUT_SND_DEVICE) {
+                ALOGE("input_snd_device_mic_mapping tag only supported with INPUT_SND_DEVICE section");
+                return;
+            }
+            section = INPUT_SND_DEVICE_TO_MIC_MAPPING;
+        } else if (strcmp(tag_name, "snd_dev") == 0) {
+            if (section != INPUT_SND_DEVICE_TO_MIC_MAPPING) {
+                ALOGE("snd_dev tag only supported with INPUT_SND_DEVICE_TO_MIC_MAPPING section");
+                return;
+            }
+            section_process_fn fn = section_table[SND_DEV];
+            fn(attr);
+        } else if (strcmp(tag_name, "mic_info") == 0) {
+            if (section != INPUT_SND_DEVICE_TO_MIC_MAPPING) {
+                ALOGE("mic_info tag only supported with INPUT_SND_DEVICE_TO_MIC_MAPPING section");
+                return;
+            }
+            if (in_snd_device == SND_DEVICE_NONE) {
+                ALOGE("%s: Error in previous tags, do not process mic info", __func__);
+                return;
+            }
+            section_process_fn fn = section_table[MIC_INFO];
+            fn(attr);
         }
     } else {
         if(strcmp(tag_name, "config_params") == 0) {
@@ -769,6 +878,12 @@
         section = ROOT;
     } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
         section = ROOT;
+    } else if (strcmp(tag_name, "snd_devices") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "input_snd_device") == 0) {
+        section = SND_DEVICES;
+    } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
+        section = INPUT_SND_DEVICE;
     }
 }