Merge "hal: sndmonitor: Add support for trinket sound card in sndmonitor"
diff --git a/configs/kona/sound_trigger_platform_info.xml b/configs/kona/sound_trigger_platform_info.xml
index ad3e712..18f15ff 100644
--- a/configs/kona/sound_trigger_platform_info.xml
+++ b/configs/kona/sound_trigger_platform_info.xml
@@ -60,6 +60,7 @@
         <param DEVICE_HANDSET_TMIC_LPI_APE="157" />
         <param DEVICE_HANDSET_QMIC_APE="137" />
         <param DEVICE_HANDSET_QMIC_LPI_APE="137" />
+        <param DEVICE_HEADSET_MIC_APE="141" />
     </acdb_ids>
 
     <!-- Multiple sound_model_config tags can be listed, each with unique   -->
diff --git a/configs/msm8909/audio_policy_configuration.xml b/configs/msm8909/audio_policy_configuration.xml
index 8abf817..4555ec5 100644
--- a/configs/msm8909/audio_policy_configuration.xml
+++ b/configs/msm8909/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2017, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -100,7 +100,7 @@
                     <profile name="" format="AUDIO_FORMAT_EVRCNW"
                              samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msm8937/audio_policy_configuration.xml b/configs/msm8937/audio_policy_configuration.xml
index b4b0358..1deb121 100644
--- a/configs/msm8937/audio_policy_configuration.xml
+++ b/configs/msm8937/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2017, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -137,7 +137,7 @@
                              samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msm8953/audio_policy_configuration.xml b/configs/msm8953/audio_policy_configuration.xml
index f54d6b4..fd298ff 100644
--- a/configs/msm8953/audio_policy_configuration.xml
+++ b/configs/msm8953/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2017, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -137,7 +137,7 @@
                              samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msm8996/audio_policy_configuration.xml b/configs/msm8996/audio_policy_configuration.xml
index 9b0234b..8572a8a 100644
--- a/configs/msm8996/audio_policy_configuration.xml
+++ b/configs/msm8996/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2017, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -137,7 +137,7 @@
                              samplingRates="8000,16000,32000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msm8998/audio_policy_configuration.xml b/configs/msm8998/audio_policy_configuration.xml
index 6c14ce4..df3a6d2 100644
--- a/configs/msm8998/audio_policy_configuration.xml
+++ b/configs/msm8998/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -171,7 +171,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msmnile/audio_policy_configuration.xml b/configs/msmnile/audio_policy_configuration.xml
index 3f1622e..8d8b5af 100644
--- a/configs/msmnile/audio_policy_configuration.xml
+++ b/configs/msmnile/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -177,7 +177,7 @@
                              channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msmnile_au/audio_policy_configuration.xml b/configs/msmnile_au/audio_policy_configuration.xml
index 1daf1dd..d1df042 100644
--- a/configs/msmnile_au/audio_policy_configuration.xml
+++ b/configs/msmnile_au/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -171,7 +171,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/msmsteppe/audio_policy_configuration.xml b/configs/msmsteppe/audio_policy_configuration.xml
index 31c7881..ee52d7f 100644
--- a/configs/msmsteppe/audio_policy_configuration.xml
+++ b/configs/msmsteppe/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -171,7 +171,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/sdm660/audio_policy_configuration.xml b/configs/sdm660/audio_policy_configuration.xml
index d7a338b..fb33910 100644
--- a/configs/sdm660/audio_policy_configuration.xml
+++ b/configs/sdm660/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -167,7 +167,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/sdm710/audio_policy_configuration.xml b/configs/sdm710/audio_policy_configuration.xml
index 0eafd18..f32f916 100644
--- a/configs/sdm710/audio_policy_configuration.xml
+++ b/configs/sdm710/audio_policy_configuration.xml
@@ -171,7 +171,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/configs/sdm845/audio_policy_configuration.xml b/configs/sdm845/audio_policy_configuration.xml
index c034774..e773ba1 100644
--- a/configs/sdm845/audio_policy_configuration.xml
+++ b/configs/sdm845/audio_policy_configuration.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- Copyright (c) 2016-2018, The Linux Foundation. All rights reserved
+<!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved
      Not a Contribution.
 -->
 <!-- Copyright (C) 2015 The Android Open Source Project
@@ -171,7 +171,7 @@
                              samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </mixPort>
 
-                <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2">
+                <mixPort name="primary input" role="sink">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index e03230a..20d760c 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -373,6 +373,157 @@
 }
 #endif /* CUSTOM_STEREO_ENABLED */
 
+static int update_custom_mtmx_coefficients(struct audio_device *adev,
+                                           struct audio_custom_mtmx_params *params,
+                                           int pcm_device_id)
+{
+    struct mixer_ctl *ctl = NULL;
+    char *mixer_name_prefix = "AudStr";
+    char *mixer_name_suffix = "ChMixer Weight Ch";
+    char mixer_ctl_name[128] = {0};
+    struct audio_custom_mtmx_params_info *pinfo = &params->info;
+    int i = 0, err = 0;
+
+    ALOGI("%s: ip_channels %d, op_channels %d, pcm_device_id %d",
+          __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id);
+
+    for (i = 0; i < (int)pinfo->op_channels; i++) {
+         snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %d %s %d",
+                  mixer_name_prefix, pcm_device_id, mixer_name_suffix, i+1);
+         ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+         if (!ctl) {
+             ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
+                   __func__, mixer_ctl_name);
+             return -EINVAL;
+         }
+
+         err = mixer_ctl_set_array(ctl,
+                                   &params->coeffs[pinfo->ip_channels * i],
+                                   pinfo->ip_channels);
+         if (err) {
+             ALOGE("%s: ERROR. Mixer ctl set failed", __func__);
+             return -EINVAL;
+         }
+    }
+    return 0;
+}
+
+static void set_custom_mtmx_params(struct audio_device *adev,
+                                   struct audio_custom_mtmx_params_info *pinfo,
+                                   int pcm_device_id, bool enable)
+{
+    struct mixer_ctl *ctl = NULL;
+    char *mixer_name_prefix = "AudStr";
+    char *mixer_name_suffix = "ChMixer Cfg";
+    char mixer_ctl_name[128] = {0};
+    int chmixer_cfg[5] = {0}, len = 0;
+    int be_id = -1, err = 0;
+
+    be_id = platform_get_snd_device_backend_index(pinfo->snd_device);
+
+    ALOGI("%s: ip_channels %d,op_channels %d,pcm_device_id %d,be_id %d",
+          __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id, be_id);
+
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+             "%s %d %s", mixer_name_prefix, pcm_device_id, mixer_name_suffix);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return;
+    }
+    chmixer_cfg[len++] = enable ? 1 : 0;
+    chmixer_cfg[len++] = 0; /* rule index */
+    chmixer_cfg[len++] = pinfo->ip_channels;
+    chmixer_cfg[len++] = pinfo->op_channels;
+    chmixer_cfg[len++] = be_id + 1;
+
+    err = mixer_ctl_set_array(ctl, chmixer_cfg, len);
+    if (err)
+        ALOGE("%s: ERROR. Mixer ctl set failed", __func__);
+}
+
+void audio_extn_set_custom_mtmx_params(struct audio_device *adev,
+                                        struct audio_usecase *usecase,
+                                        bool enable)
+{
+    struct audio_custom_mtmx_params_info info = {0};
+    struct audio_custom_mtmx_params *params = NULL;
+    int num_devices = 0, pcm_device_id = -1, i = 0, ret = 0;
+    snd_device_t new_snd_devices[SND_DEVICE_OUT_END] = {0};
+    struct audio_backend_cfg backend_cfg = {0};
+    uint32_t feature_id = 0;
+
+    switch(usecase->type) {
+    case PCM_PLAYBACK:
+        if (usecase->stream.out) {
+            pcm_device_id =
+                platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+            if (platform_split_snd_device(adev->platform,
+                                          usecase->out_snd_device,
+                                          &num_devices, new_snd_devices)) {
+                new_snd_devices[0] = usecase->out_snd_device;
+                num_devices = 1;
+            }
+        } else {
+            ALOGE("%s: invalid output stream for playback usecase id:%d",
+                  __func__, usecase->id);
+            return;
+        }
+        break;
+    case PCM_CAPTURE:
+        if (usecase->stream.in) {
+            pcm_device_id =
+                platform_get_pcm_device_id(usecase->id, PCM_CAPTURE);
+            if (platform_split_snd_device(adev->platform,
+                                          usecase->in_snd_device,
+                                          &num_devices, new_snd_devices)) {
+                new_snd_devices[0] = usecase->in_snd_device;
+                num_devices = 1;
+            }
+        } else {
+            ALOGE("%s: invalid input stream for capture usecase id:%d",
+                  __func__, usecase->id);
+            return;
+        }
+        break;
+    default:
+        ALOGV("%s: unsupported usecase id:%d", __func__, usecase->id);
+        return;
+    }
+
+    /*
+     * check and update feature_id before this assignment,
+     * if features like dual_mono is enabled and overrides the default(i.e. 0).
+     */
+    info.id = feature_id;
+    info.usecase_id = usecase->id;
+    for (i = 0, ret = 0; i < num_devices; i++) {
+         info.snd_device = new_snd_devices[i];
+         platform_get_codec_backend_cfg(adev, info.snd_device, &backend_cfg);
+         if (usecase->type == PCM_PLAYBACK) {
+             info.ip_channels = audio_channel_count_from_out_mask(
+                                    usecase->stream.out->channel_mask);
+             info.op_channels = backend_cfg.channels;
+         } else {
+             info.ip_channels = backend_cfg.channels;
+             info.op_channels = audio_channel_count_from_in_mask(
+                                    usecase->stream.in->channel_mask);
+         }
+
+         params = platform_get_custom_mtmx_params(adev->platform, &info);
+         if (params) {
+             if (enable)
+                 ret = update_custom_mtmx_coefficients(adev, params,
+                                                       pcm_device_id);
+             if (ret < 0)
+                 ALOGE("%s: error updating mtmx coeffs err:%d", __func__, ret);
+             else
+                 set_custom_mtmx_params(adev, &info, pcm_device_id, enable);
+         }
+    }
+}
+
 #ifndef DTS_EAGLE
 #define audio_extn_hpx_set_parameters(adev, parms)         (0)
 #define audio_extn_hpx_get_parameters(query, reply)  (0)
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 6fa6b78..6b08671 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1141,4 +1141,7 @@
 #else
 void audio_extn_send_dual_mono_mixing_coefficients(struct stream_out *out);
 #endif
+void audio_extn_set_custom_mtmx_params(struct audio_device *adev,
+                                        struct audio_usecase *usecase,
+                                        bool enable);
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 91f2a74..13dd4a0 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -992,6 +992,7 @@
         if (out && out->compr)
             audio_extn_utils_compress_set_clk_rec_mode(usecase);
     }
+    audio_extn_set_custom_mtmx_params(adev, usecase, true);
 
     strlcpy(mixer_path, use_case_table[usecase->id], MIXER_PATH_MAX_LENGTH);
     platform_add_backend_name(mixer_path, snd_device, usecase);
@@ -1028,6 +1029,7 @@
     audio_route_reset_and_update_path(adev->audio_route, mixer_path);
     audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
     audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
+    audio_extn_set_custom_mtmx_params(adev, usecase, false);
     ALOGV("%s: exit", __func__);
     return 0;
 }
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index a900ecd..263fe9f 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -306,6 +306,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];
+    struct listnode custom_mtmx_params_list;
 };
 
 static bool is_external_codec = false;
@@ -2413,6 +2414,7 @@
         my_data->hifi_audio = true;
 
     list_init(&my_data->acdb_meta_key_list);
+    list_init(&my_data->custom_mtmx_params_list);
 
     set_platform_defaults(my_data);
 
@@ -2783,6 +2785,86 @@
     return my_data;
 }
 
+struct audio_custom_mtmx_params *
+    platform_get_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node = NULL;
+    struct audio_custom_mtmx_params *params = NULL;
+
+    list_for_each(node, &my_data->custom_mtmx_params_list) {
+        params = node_to_item(node, struct audio_custom_mtmx_params, list);
+        if (params &&
+            params->info.id == info->id &&
+            params->info.ip_channels == info->ip_channels &&
+            params->info.op_channels == info->op_channels &&
+            params->info.usecase_id == info->usecase_id &&
+            params->info.snd_device == info->snd_device) {
+            ALOGV("%s: found params with ip_ch %d op_ch %d uc_id %d snd_dev %d",
+                  __func__, info->ip_channels, info->op_channels,
+                  info->usecase_id, info->snd_device);
+            return params;
+        }
+    }
+    ALOGI("%s: no matching param with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d",
+          __func__, info->id, info->ip_channels, info->op_channels,
+          info->usecase_id, info->snd_device);
+    return NULL;
+}
+
+int platform_add_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_custom_mtmx_params *params = NULL;
+    uint32_t size = sizeof(*params);
+
+    if (info->ip_channels > AUDIO_CHANNEL_COUNT_MAX ||
+        info->op_channels > AUDIO_CHANNEL_COUNT_MAX) {
+        ALOGE("%s: unusupported channels in %d, out %d",
+              __func__, info->ip_channels, info->op_channels);
+        return -EINVAL;
+    }
+
+    size += sizeof(params->coeffs[0]) * info->ip_channels * info->op_channels;
+    params = (struct audio_custom_mtmx_params *) calloc(1, size);
+    if (!params) {
+        ALOGE("%s: failed to add custom mtmx params", __func__);
+        return -ENOMEM;
+    }
+
+    ALOGI("%s: adding mtmx params with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d",
+          __func__, info->id, info->ip_channels, info->op_channels,
+          info->usecase_id, info->snd_device);
+
+    params->info = *info;
+    list_add_tail(&my_data->custom_mtmx_params_list, &params->list);
+    return 0;
+}
+
+static void platform_release_custom_mtmx_params(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node = NULL, *tempnode = NULL;
+
+    list_for_each_safe(node, tempnode, &my_data->custom_mtmx_params_list) {
+        list_remove(node);
+        free(node_to_item(node, struct audio_custom_mtmx_params, list));
+    }
+}
+
+void platform_release_acdb_metainfo_key(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node, *tempnode;
+
+    list_for_each_safe(node, tempnode, &my_data->acdb_meta_key_list) {
+        list_remove(node);
+        free(node_to_item(node, struct meta_key_list, list));
+    }
+}
+
 void platform_deinit(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2831,6 +2913,27 @@
         my_data->adev->mixer = NULL;
     }
 
+    int32_t idx;
+
+    for (idx = 0; idx < MAX_CODEC_BACKENDS; idx++) {
+         if (my_data->current_backend_cfg[idx].bitwidth_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].bitwidth_mixer_ctl);
+             my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
+         }
+
+         if (my_data->current_backend_cfg[idx].samplerate_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].samplerate_mixer_ctl);
+             my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
+         }
+
+         if (my_data->current_backend_cfg[idx].channels_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].channels_mixer_ctl);
+             my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
+         }
+    }
+
+    platform_release_custom_mtmx_params(platform);
+
     if (my_data->acdb_deallocate)
         my_data->acdb_deallocate();
 
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 480ef13..f7a7ebf 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -353,6 +353,27 @@
     return my_data;
 }
 
+struct audio_custom_mtmx_params *
+    platform_get_custom_mtmx_params
+    (
+        void *platform __unused,
+        struct audio_custom_mtmx_params_info *info __unused
+    )
+{
+    ALOGW("%s: not implemented!", __func__);
+    return NULL;
+}
+
+int platform_add_custom_mtmx_params
+    (
+        void *platform __unused,
+        struct audio_custom_mtmx_params_info *info __unused
+    )
+{
+    ALOGW("%s: not implemented!", __func__);
+    return -ENOSYS;
+}
+
 void platform_deinit(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index c019d0e..03dd0c7 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -289,6 +289,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];
+    struct listnode custom_mtmx_params_list;
 
 };
 
@@ -2277,6 +2278,7 @@
         my_data->is_bcl_speaker = true;
 
     list_init(&my_data->acdb_meta_key_list);
+    list_init(&my_data->custom_mtmx_params_list);
 
     set_platform_defaults(my_data);
 
@@ -2691,6 +2693,86 @@
     return my_data;
 }
 
+struct audio_custom_mtmx_params *
+    platform_get_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node = NULL;
+    struct audio_custom_mtmx_params *params = NULL;
+
+    list_for_each(node, &my_data->custom_mtmx_params_list) {
+        params = node_to_item(node, struct audio_custom_mtmx_params, list);
+        if (params &&
+            params->info.id == info->id &&
+            params->info.ip_channels == info->ip_channels &&
+            params->info.op_channels == info->op_channels &&
+            params->info.usecase_id == info->usecase_id &&
+            params->info.snd_device == info->snd_device) {
+            ALOGV("%s: found params with ip_ch %d op_ch %d uc_id %d snd_dev %d",
+                  __func__, info->ip_channels, info->op_channels,
+                  info->usecase_id, info->snd_device);
+            return params;
+        }
+    }
+    ALOGI("%s: no matching param with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d",
+          __func__, info->id, info->ip_channels, info->op_channels,
+          info->usecase_id, info->snd_device);
+    return NULL;
+}
+
+int platform_add_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_custom_mtmx_params *params = NULL;
+    uint32_t size = sizeof(*params);
+
+    if (info->ip_channels > AUDIO_CHANNEL_COUNT_MAX ||
+        info->op_channels > AUDIO_CHANNEL_COUNT_MAX) {
+        ALOGE("%s: unusupported channels in %d, out %d",
+              __func__, info->ip_channels, info->op_channels);
+        return -EINVAL;
+    }
+
+    size += sizeof(params->coeffs[0]) * info->ip_channels * info->op_channels;
+    params = (struct audio_custom_mtmx_params *) calloc(1, size);
+    if (!params) {
+        ALOGE("%s: failed to add custom mtmx params", __func__);
+        return -ENOMEM;
+    }
+
+    ALOGI("%s: adding mtmx params with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d",
+          __func__, info->id, info->ip_channels, info->op_channels,
+          info->usecase_id, info->snd_device);
+
+    params->info = *info;
+    list_add_tail(&my_data->custom_mtmx_params_list, &params->list);
+    return 0;
+}
+
+static void platform_release_custom_mtmx_params(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node = NULL, *tempnode = NULL;
+
+    list_for_each_safe(node, tempnode, &my_data->custom_mtmx_params_list) {
+        list_remove(node);
+        free(node_to_item(node, struct audio_custom_mtmx_params, list));
+    }
+}
+
+void platform_release_acdb_metainfo_key(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct listnode *node, *tempnode;
+
+    list_for_each_safe(node, tempnode, &my_data->acdb_meta_key_list) {
+        list_remove(node);
+        free(node_to_item(node, struct meta_key_list, list));
+    }
+}
+
 void platform_deinit(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2738,6 +2820,27 @@
         my_data->adev->mixer = NULL;
     }
 
+    int32_t idx;
+
+    for (idx = 0; idx < MAX_CODEC_BACKENDS; idx++) {
+         if (my_data->current_backend_cfg[idx].bitwidth_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].bitwidth_mixer_ctl);
+             my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
+         }
+
+         if (my_data->current_backend_cfg[idx].samplerate_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].samplerate_mixer_ctl);
+             my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
+         }
+
+         if (my_data->current_backend_cfg[idx].channels_mixer_ctl) {
+             free(my_data->current_backend_cfg[idx].channels_mixer_ctl);
+             my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
+         }
+    }
+
+    platform_release_custom_mtmx_params(platform);
+
     if (my_data->acdb_deallocate)
         my_data->acdb_deallocate();
 
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 6ba962d..80138c8 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -93,6 +93,21 @@
     uint32_t             param_id;
 } acdb_audio_cal_cfg_t;
 
+
+struct audio_custom_mtmx_params_info {
+    uint32_t id;
+    uint32_t ip_channels;
+    uint32_t op_channels;
+    uint32_t usecase_id;
+    uint32_t snd_device;
+};
+
+struct audio_custom_mtmx_params {
+    struct listnode list;
+    struct audio_custom_mtmx_params_info info;
+    uint32_t coeffs[0];
+};
+
 enum card_status_t;
 
 void *platform_init(struct audio_device *adev);
@@ -304,4 +319,9 @@
                                     audio_usecase_t usecase,
                                     struct audio_microphone_characteristic_t *mic_array,
                                     size_t *mic_count);
+struct audio_custom_mtmx_params *
+    platform_get_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info);
+int platform_add_custom_mtmx_params(void *platform,
+                                    struct audio_custom_mtmx_params_info *info);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 3341f20..70c2b70 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -68,6 +68,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);
@@ -87,6 +89,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,
@@ -103,6 +107,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;
@@ -207,6 +213,9 @@
     }
     return false;
 }
+
+static struct audio_custom_mtmx_params_info mtmx_params_info;
+
 /*
  * <audio_platform_info>
  * <acdb_ids>
@@ -871,6 +880,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)
 {
@@ -993,7 +1080,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 {
             ALOGE("%s: unknown caller!", __func__);
     }
@@ -1035,6 +1138,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;
     }
 }