hal: add support to set custom channel configs

Add generic implementation to set custom channel configs
as per usecase config present in platform info xml.
Each usecase identified by usecase id, input channels,
output channels, snd_device and feature id can have
a separate channel config.

Change-Id: I957b5b06adbcd17f65ed49b839327bf8e9e8b318
diff --git a/hal/platform_info.c b/hal/platform_info.c
index f8a78d8..da0223e 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -70,6 +70,8 @@
     INPUT_SND_DEVICE_TO_MIC_MAPPING,
     SND_DEV,
     MIC_INFO,
+    CUSTOM_MTMX_PARAMS,
+    CUSTOM_MTMX_PARAM_COEFFS,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -91,6 +93,8 @@
 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 void process_custom_mtmx_params(const XML_Char **attr);
+static void process_custom_mtmx_param_coeffs(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
@@ -109,6 +113,8 @@
     [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic,
     [SND_DEV] = process_snd_dev,
     [MIC_INFO] = process_mic_info,
+    [CUSTOM_MTMX_PARAMS] = process_custom_mtmx_params,
+    [CUSTOM_MTMX_PARAM_COEFFS] = process_custom_mtmx_param_coeffs,
 };
 
 static section_t section;
@@ -213,6 +219,9 @@
     }
     return false;
 }
+
+static struct audio_custom_mtmx_params_info mtmx_params_info;
+
 /*
  * <audio_platform_info>
  * <acdb_ids>
@@ -959,6 +968,84 @@
     return;
 }
 
+static void process_custom_mtmx_param_coeffs(const XML_Char **attr)
+{
+    uint32_t attr_idx = 0, out_ch_idx = -1, ch_coeff_count = 0;
+    uint32_t ip_channels = 0, op_channels = 0;
+    char *context = NULL, *ch_coeff_value = NULL;
+    struct audio_custom_mtmx_params *mtmx_params = NULL;
+
+    if (strcmp(attr[attr_idx++], "out_channel_index") != 0) {
+        ALOGE("%s: 'out_channel_index' not found", __func__);
+        return;
+    }
+    out_ch_idx = atoi((char *)attr[attr_idx++]);
+
+    if (out_ch_idx < 0 || out_ch_idx >= mtmx_params_info.op_channels) {
+        ALOGE("%s: invalid out channel index(%d)", __func__, out_ch_idx);
+        return;
+    }
+
+    if (strcmp(attr[attr_idx++], "values") != 0) {
+        ALOGE("%s: 'values' not found", __func__);
+        return;
+    }
+    mtmx_params = platform_get_custom_mtmx_params((void *)my_data.platform,
+                                                  &mtmx_params_info);
+    if (mtmx_params == NULL) {
+        ALOGE("%s: mtmx params with given param info, not found", __func__);
+        return;
+    }
+    ch_coeff_value = strtok_r((char *)attr[attr_idx++], " ", &context);
+    ip_channels = mtmx_params->info.ip_channels;
+    op_channels = mtmx_params->info.op_channels;
+    while(ch_coeff_value && ch_coeff_count < op_channels) {
+        mtmx_params->coeffs[ip_channels * out_ch_idx + ch_coeff_count++]
+                           = atoi(ch_coeff_value);
+        ch_coeff_value = strtok_r(NULL, " ", &context);
+    }
+    if (ch_coeff_count != mtmx_params->info.ip_channels ||
+        ch_coeff_value != NULL)
+        ALOGE("%s: invalid/malformed coefficient values", __func__);
+}
+
+static void process_custom_mtmx_params(const XML_Char **attr)
+{
+    int attr_idx = 0;
+
+    if (strcmp(attr[attr_idx++], "param_id") != 0) {
+        ALOGE("%s: 'param_id' not found", __func__);
+        return;
+    }
+    mtmx_params_info.id = atoi((char *)attr[attr_idx++]);
+
+    if (strcmp(attr[attr_idx++], "in_channel_count") != 0) {
+        ALOGE("%s: 'in_channel_count' not found", __func__);
+        return;
+    }
+    mtmx_params_info.ip_channels = atoi((char *)attr[attr_idx++]);
+
+    if (strcmp(attr[attr_idx++], "out_channel_count") != 0) {
+        ALOGE("%s: 'out_channel_count' not found", __func__);
+        return;
+    }
+    mtmx_params_info.op_channels = atoi((char *)attr[attr_idx++]);
+
+    if (strcmp(attr[attr_idx++], "usecase") != 0) {
+        ALOGE("%s: 'usecase' not found", __func__);
+        return;
+    }
+    mtmx_params_info.usecase_id = platform_get_usecase_index((char *)attr[attr_idx++]);
+
+    if (strcmp(attr[attr_idx++], "snd_device") != 0) {
+        ALOGE("%s: 'snd_device' not found", __func__);
+        return;
+    }
+    mtmx_params_info.snd_device = platform_get_snd_device_index((char *)attr[attr_idx++]);
+    platform_add_custom_mtmx_params((void *)my_data.platform, &mtmx_params_info);
+
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -1101,7 +1188,23 @@
             }
             section_process_fn fn = section_table[MIC_INFO];
             fn(attr);
-      }
+        } else if (strcmp(tag_name, "custom_mtmx_params") == 0) {
+            if (section != ROOT) {
+                ALOGE("custom_mtmx_params tag supported only in ROOT section");
+                return;
+            }
+            section = CUSTOM_MTMX_PARAMS;
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        } else if (strcmp(tag_name, "custom_mtmx_param_coeffs") == 0) {
+            if (section != CUSTOM_MTMX_PARAMS) {
+                ALOGE("custom_mtmx_param_coeffs tag supported only with CUSTOM_MTMX_PARAMS section");
+                return;
+            }
+            section = CUSTOM_MTMX_PARAM_COEFFS;
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        }
     } else {
         if(strcmp(tag_name, "config_params") == 0) {
             section = CONFIG_PARAMS;
@@ -1157,6 +1260,10 @@
         section = SND_DEVICES;
     } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
         section = INPUT_SND_DEVICE;
+    } else if (strcmp(tag_name, "custom_mtmx_params") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "custom_mtmx_param_coeffs") == 0) {
+        section = CUSTOM_MTMX_PARAMS;
     }
 }