hal: Add dynamic enablement of AEC/NS for VoIP

Add capability to dynamically enable or disable AEC/NS audio effects
on DSP for a VoIP call.

Bug: 70805651
Test: manual
Change-Id: I16f1f6664b39afaedfca92afbc87002685f6e369
diff --git a/hal/Android.mk b/hal/Android.mk
index 236ed11..7f93710 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -197,7 +197,6 @@
     LOCAL_SRC_FILES += audio_extn/sndmonitor.c
 endif
 
-
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_USB_SERVICE_INTERVAL)), true)
     LOCAL_CFLAGS += -DUSB_SERVICE_INTERVAL_ENABLED
 endif
@@ -215,6 +214,10 @@
     LOCAL_CFLAGS += -DBG_CODEC_CAL
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DYNAMIC_ECNS)),true)
+    LOCAL_CFLAGS += -DDYNAMIC_ECNS_ENABLED
+endif
+
 LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhwbinder libutils android.hardware.power@1.2 liblog
 
 LOCAL_SRC_FILES += audio_perf.cpp
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5af3897..e1d5309 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -807,6 +807,147 @@
     return 0;
 }
 
+#ifdef DYNAMIC_ECNS_ENABLED
+static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
+                          struct stream_in *in,
+                          struct audio_effect_config effect_config,
+                          unsigned int param_value)
+{
+    char mixer_ctl_name[] = "Audio Effect";
+    long set_values[6];
+
+    struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get mixer ctl - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    set_values[0] = 1; //0:Rx 1:Tx
+    set_values[1] = in->app_type_cfg.app_type;
+    set_values[2] = (long)effect_config.module_id;
+    set_values[3] = (long)effect_config.instance_id;
+    set_values[4] = (long)effect_config.param_id;
+    set_values[5] = param_value;
+
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    return 0;
+
+}
+
+static int update_effect_param_ecns(struct audio_usecase *usecase,
+                               unsigned int module_id, int effect_type,
+                               unsigned int *param_value)
+{
+    int ret = 0;
+    struct audio_effect_config other_effect_config;
+    struct stream_in *in = NULL;
+
+    if (!usecase)
+        return -EINVAL;
+
+    in = usecase->stream.in;
+
+    /* Get the effect config data of the other effect */
+    ret = platform_get_effect_config_data(usecase->in_snd_device,
+                                          &other_effect_config,
+                                          effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
+    if (ret < 0) {
+        ALOGE("%s Failed to get effect params %d", __func__, ret);
+        return ret;
+    }
+
+    if (module_id == other_effect_config.module_id) {
+            //Same module id for AEC/NS. Values need to be combined
+            if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
+                ((effect_type == EFFECT_NS) && (in->enable_aec)))
+                *param_value |= other_effect_config.param_value;
+    }
+
+    return ret;
+}
+
+static int enable_disable_effect(struct audio_device *adev, struct stream_in *in,
+                                   int effect_type, bool enable)
+{
+    struct audio_effect_config effect_config;
+    struct audio_usecase *usecase = NULL;
+    int ret = 0;
+    unsigned int param_value = 0;
+
+    if (!in) {
+        ALOGE("%s: Invalid input stream", __func__);
+        return -EINVAL;
+    }
+
+    ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
+
+    usecase = get_usecase_from_list(adev, in->usecase);
+
+    ret = platform_get_effect_config_data(usecase->in_snd_device,
+                                           &effect_config, effect_type);
+    if (ret < 0) {
+        ALOGE("%s Failed to get module id %d", __func__, ret);
+        return ret;
+    }
+    ALOGV("%s: module %d app_type %d usecase->id:%d usecase->in_snd_device:%d",
+           __func__, effect_config.module_id, in->app_type_cfg.app_type,
+          usecase->id, usecase->in_snd_device);
+
+    if (enable)
+        param_value = effect_config.param_value;
+
+    /*Special handling for AEC & NS effects Param values need to be
+      updated if module ids are same*/
+
+    if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
+        ret = update_effect_param_ecns(usecase, effect_config.module_id,
+                                       effect_type, &param_value);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = send_effect_enable_disable_mixer_ctl(adev, in,
+                                               effect_config, param_value);
+
+    return ret;
+}
+
+static int check_and_enable_effect(struct audio_device *adev)
+{
+    int ret = 0;
+
+    struct listnode *node;
+    struct stream_in *in = NULL;
+
+    list_for_each(node, &adev->usecase_list)
+    {
+        struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL) {
+            in = usecase->stream.in;
+
+            if (in->standby)
+                continue;
+
+            if (in->enable_aec) {
+                ret = enable_disable_effect(adev, in, EFFECT_AEC, true);
+            }
+
+            if (in->enable_ns &&
+                in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+                ret = enable_disable_effect(adev, in, EFFECT_NS, true);
+            }
+        }
+    }
+
+    return ret;
+}
+#else
+#define enable_disable_effect(w, x, y, z) -ENOSYS
+#define check_and_enable_effect(x) -ENOSYS
+#endif
+
 /*
   legend:
   uc - existing usecase
@@ -1543,6 +1684,11 @@
 
     audio_extn_ma_set_device(usecase);
 
+    /* If input stream is already running the effect needs to be
+       applied on the new input device that's being enabled here.  */
+    if (in_snd_device != SND_DEVICE_NONE)
+        check_and_enable_effect(adev);
+
     /* Applicable only on the targets that has external modem.
      * Enable device command should be sent to modem only after
      * enabling voice call mixer controls
@@ -1708,6 +1854,7 @@
         }
     }
     register_in_stream(in);
+    check_and_enable_effect(adev);
     audio_streaming_hint_end();
     audio_extn_perf_lock_release();
     ALOGV("%s: exit", __func__);
@@ -3954,6 +4101,8 @@
     effect_descriptor_t desc;
 
     status = (*effect)->get_descriptor(effect, &desc);
+    ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
+
     if (status != 0)
         return status;
 
@@ -3978,14 +4127,18 @@
                     select_devices(adev, usecase->id);
             }
         }
-        if (!in->standby)
+        if (!in->standby
+            && enable_disable_effect(in->dev, in, EFFECT_AEC, enable) == -ENOSYS)
             select_devices(in->dev, in->usecase);
     }
     if (in->enable_ns != enable &&
             (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
         in->enable_ns = enable;
-        if (!in->standby)
-            select_devices(in->dev, in->usecase);
+        if (!in->standby) {
+            if (in->source != AUDIO_SOURCE_VOICE_COMMUNICATION
+                || enable_disable_effect(in->dev, in, EFFECT_NS, enable) == -ENOSYS)
+                select_devices(in->dev, in->usecase);
+        }
     }
     pthread_mutex_unlock(&in->dev->lock);
     pthread_mutex_unlock(&in->lock);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 56220e1..7d35ff5 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -81,6 +81,8 @@
 #define TOSTRING_(x) #x
 #define TOSTRING(x) TOSTRING_(x)
 
+#define GET_IN_DEVICE_INDEX(SND_DEVICE) ((SND_DEVICE) - (SND_DEVICE_IN_BEGIN))
+
 char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
         [WCD9XXX_MBHC_CAL] = "mbhc_cal",
 };
@@ -301,6 +303,34 @@
     [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
 };
 
+static struct audio_effect_config \
+               effect_config_table[GET_IN_DEVICE_INDEX(SND_DEVICE_MAX)][EFFECT_COUNT] = {
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FLUENCE_PROV2, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FLUENCE_PROV2,  0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)][EFFECT_AEC] = \
+                                      {TX_VOICE_DM_FV5_BROADSIDE, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)][EFFECT_NS] = \
+                                      {TX_VOICE_DM_FV5_BROADSIDE, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x02},
+};
+
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
 static int acdb_device_table[SND_DEVICE_MAX] = {
     [SND_DEVICE_NONE] = -1,
@@ -1416,6 +1446,35 @@
     return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
 }
 
+int platform_get_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config *effect_config,
+                                      effect_type_t effect_type)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_IN_BEGIN) || (snd_device >= SND_DEVICE_MAX) ||
+        (effect_type <= EFFECT_NONE) || (effect_type >= EFFECT_COUNT)) {
+        ALOGE("%s: Invalid snd_device = %d or effect_type = %d",
+            __func__, snd_device, effect_type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (effect_config == NULL) {
+        ALOGE("%s: Invalid effect_config", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGV("%s: snd_device = %d module_id = %d",
+          __func__, snd_device,
+          effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type].module_id);
+    *effect_config = effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type];
+
+done:
+    return ret;
+}
+
 void platform_add_operator_specific_device(snd_device_t snd_device,
                                            const char *operator,
                                            const char *mixer_path,
@@ -1499,6 +1558,27 @@
         }
     }
     return key;
+
+int platform_set_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config effect_config,
+                                      effect_type_t effect_type)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_IN_BEGIN) || (snd_device >= SND_DEVICE_MAX) ||
+        (effect_type <= EFFECT_NONE) || (effect_type >= EFFECT_COUNT)) {
+        ALOGE("%s: Invalid snd_device = %d or effect_type = %d",
+            __func__, snd_device, effect_type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGV("%s 0x%x 0x%x 0x%x 0x%x", __func__, effect_config.module_id,
+           effect_config.instance_id, effect_config.param_id,
+           effect_config.param_value);
+    effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type] = effect_config;
+done:
+    return ret;
 }
 
 int platform_get_default_app_type_v2(void *platform, usecase_type_t type, int *app_type)
@@ -1930,6 +2010,139 @@
     return snd_device;
 }
 
+#ifdef DYNAMIC_ECNS_ENABLED
+static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data,
+                                                  struct stream_in *in __unused,
+                                                  audio_devices_t out_device,
+                                                  audio_devices_t in_device)
+{
+    struct audio_device *adev = my_data->adev;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    if (my_data->fluence_type != FLUENCE_NONE) {
+        switch(AUDIO_DEVICE_BIT_IN | in_device) {
+            case AUDIO_DEVICE_IN_BACK_MIC:
+                if (my_data->fluence_in_spkr_mode) {
+                    if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                        snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                    } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                    }
+                    adev->acdb_settings |= DMIC_FLAG;
+                } else
+                    snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+                break;
+            case AUDIO_DEVICE_IN_BUILTIN_MIC:
+                if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+                    adev->acdb_settings |= DMIC_FLAG;
+                } else
+                    snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+                break;
+            default:
+                ALOGE("%s: Unsupported in_device %#x", __func__, in_device);
+                break;
+        }
+        platform_set_echo_reference(adev, true, out_device);
+    }
+
+    return snd_device;
+}
+#else
+static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data,
+                                                  struct stream_in *in,
+                                                  audio_devices_t out_device,
+                                                  audio_devices_t in_device)
+{
+    struct audio_device *adev = my_data->adev;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    if (my_data->fluence_type != FLUENCE_NONE &&
+        in->enable_aec &&
+        in->enable_ns) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode) {
+                if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                    else
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                }
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+        }
+        platform_set_echo_reference(adev, true, out_device);
+    } else if (my_data->fluence_type != FLUENCE_NONE &&
+               in->enable_aec) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode) {
+                if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                    else
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                }
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+        }
+        platform_set_echo_reference(adev, true, out_device);
+    } else if (my_data->fluence_type != FLUENCE_NONE &&
+               in->enable_ns) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode) {
+                if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                    else
+                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                }
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+                adev->acdb_settings |= DMIC_FLAG;
+            } else
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+        }
+        platform_set_echo_reference(adev, false, out_device);
+    } else
+        platform_set_echo_reference(adev, false, out_device);
+
+    return snd_device;
+}
+#endif //DYNAMIC_ECNS_ENABLED
+
 snd_device_t platform_get_input_snd_device(void *platform,
                                            struct stream_in *in,
                                            audio_devices_t out_device)
@@ -2056,85 +2269,10 @@
               (mode == AUDIO_MODE_IN_COMMUNICATION)) {
         if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
             in_device = AUDIO_DEVICE_IN_BACK_MIC;
+
         if (in) {
-            if (my_data->fluence_type != FLUENCE_NONE &&
-                in->enable_aec &&
-                in->enable_ns) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
-                            else
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
-                        }
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
-                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
-                }
-                platform_set_echo_reference(adev, true, out_device);
-            } else if (my_data->fluence_type != FLUENCE_NONE &&
-                       in->enable_aec) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
-                            else
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
-                        }
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
-                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
-                }
-                platform_set_echo_reference(adev, true, out_device);
-            } else if (my_data->fluence_type != FLUENCE_NONE &&
-                       in->enable_ns) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
-                            else
-                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
-                        }
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
-                        adev->acdb_settings |= DMIC_FLAG;
-                    } else
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
-                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                    snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
-                }
-                platform_set_echo_reference(adev, false, out_device);
-            } else
-                platform_set_echo_reference(adev, false, out_device);
+            snd_device = get_snd_device_for_voice_comm(my_data, in, 
+                                                       out_device, in_device);
         }
     } else if (source == AUDIO_SOURCE_FM_TUNER) {
         snd_device = SND_DEVICE_IN_CAPTURE_FM;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 9913322..f3dbc3d 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -250,6 +250,11 @@
 
 #define AUDIO_MAKE_STRING_FROM_ENUM(X)   { #X, X }
 
+#define TX_VOICE_FLUENCE_PROV2 0x10F17
+#define TX_VOICE_DM_FV5_BROADSIDE 0x10F18
+#define TX_VOICE_FV5ECNS_SM 0x10F09
+#define TX_VOICE_FV5ECNS_DM 0x10F0A
+
 #define LIB_CSD_CLIENT "libcsd-client.so"
 /* CSD-CLIENT related functions */
 typedef int (*init_t)();
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 481b57d..f03356b 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -72,6 +72,8 @@
 #define TOSTRING_(x) #x
 #define TOSTRING(x) TOSTRING_(x)
 
+#define GET_IN_DEVICE_INDEX(SND_DEVICE) ((SND_DEVICE) - (SND_DEVICE_IN_BEGIN))
+
 struct audio_block_header
 {
     int reserved;
@@ -368,6 +370,32 @@
     [SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = "camcorder-mic",
     [SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = "camcorder-mic",
     [SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = "camcorder-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
+};
+
+static struct audio_effect_config \
+                  effect_config_table[GET_IN_DEVICE_INDEX(SND_DEVICE_MAX)][EFFECT_COUNT] = {
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FLUENCE_PROV2, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FLUENCE_PROV2,  0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_DM, 0x0, 0x10EAF, 0x02},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)][EFFECT_AEC] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x01},
+    [GET_IN_DEVICE_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)][EFFECT_NS] = \
+                                      {TX_VOICE_FV5ECNS_SM, 0x0, 0x10EAF, 0x02},
 };
 
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -491,6 +519,8 @@
     [SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = 61,
     [SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = 61,
     [SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = 61,
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = 129,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
 };
 
 // Platform specific backend bit width table
@@ -627,6 +657,8 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT)},
     /* For legacy xml file parsing */
     {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
 };
 
 static char * backend_tag_table[SND_DEVICE_MAX] = {0};
@@ -1342,6 +1374,8 @@
     hw_interface_table[SND_DEVICE_IN_SPEAKER_DMIC_STEREO] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_DMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_DMIC_TMUS] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_SPEAKER_QMIC_NS] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_MIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = strdup("SLIMBUS_0_TX");
@@ -2067,6 +2101,57 @@
     return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
 }
 
+int platform_get_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config *effect_config,
+                                      effect_type_t effect_type)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_IN_BEGIN) || (snd_device >= SND_DEVICE_MAX) ||
+        (effect_type <= EFFECT_NONE) || (effect_type >= EFFECT_COUNT)) {
+        ALOGE("%s: Invalid snd_device = %d or effect_type = %d",
+            __func__, snd_device, effect_type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (effect_config == NULL) {
+        ALOGE("%s: Invalid effect_config", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGV("%s: snd_device = %d module_id = %d",
+            __func__, snd_device, effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type].module_id);
+    *effect_config = effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type];
+
+done:
+    return ret;
+}
+
+int platform_set_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config effect_config,
+                                      effect_type_t effect_type)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_IN_BEGIN) || (snd_device >= SND_DEVICE_MAX) ||
+        (effect_type <= EFFECT_NONE) || (effect_type >= EFFECT_COUNT)) {
+        ALOGE("%s: Invalid snd_device = %d or effect_type = %d",
+            __func__, snd_device, effect_type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGV("%s 0x%x 0x%x 0x%x 0x%x", __func__, effect_config.module_id,
+           effect_config.instance_id, effect_config.param_id,
+           effect_config.param_value);
+    effect_config_table[GET_IN_DEVICE_INDEX(snd_device)][effect_type] = effect_config;
+
+done:
+    return ret;
+}
+
 void platform_add_operator_specific_device(snd_device_t snd_device,
                                            const char *operator,
                                            const char *mixer_path,
@@ -2865,6 +2950,126 @@
     return snd_device;
 }
 
+#ifdef DYNAMIC_ECNS_ENABLED
+static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data,
+                                                  struct stream_in *in __unused,
+                                                  audio_devices_t out_device,
+                                                  audio_devices_t in_device)
+{
+    struct audio_device *adev = my_data->adev;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    if (my_data->fluence_type != FLUENCE_DISABLE) {
+        switch(AUDIO_DEVICE_BIT_IN | in_device) {
+            case AUDIO_DEVICE_IN_BACK_MIC:
+                if (my_data->fluence_in_spkr_mode) {
+                    if ((my_data->fluence_type & FLUENCE_PRO_ENABLE) &&
+                        (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
+                        snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                    } else if (((my_data->fluence_type & FLUENCE_PRO_ENABLE) ||
+                               (my_data->fluence_type & FLUENCE_ENABLE)) &&
+                               (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                    }
+                    adev->acdb_settings |= DMIC_FLAG;
+                } else
+                    snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+                break;
+            case AUDIO_DEVICE_IN_BUILTIN_MIC:
+                if (((my_data->fluence_type & FLUENCE_PRO_ENABLE) ||
+                    (my_data->fluence_type & FLUENCE_ENABLE)) &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                    snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+                    adev->acdb_settings |= DMIC_FLAG;
+                } else
+                    snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+                break;
+            default:
+                ALOGE("%s: Unsupported in_device %#x", __func__, in_device);
+                break;
+        }
+        platform_set_echo_reference(adev, true, out_device);
+    }
+
+    return snd_device;
+}
+#else
+static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data,
+                                                  struct stream_in *in,
+                                                  audio_devices_t out_device,
+                                                  audio_devices_t in_device)
+{
+    struct audio_device *adev = my_data->adev;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+
+    if (in->enable_aec &&
+            in->enable_ns) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode &&
+                    my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+            } else {
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+            } else {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+        } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
+        }
+        platform_set_echo_reference(adev, true, out_device);
+    } else if (in->enable_aec) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode &&
+                    my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+            } else {
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+            } else {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+            }
+       } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+           snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+       } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+           snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
+       }
+       platform_set_echo_reference(adev, true, out_device);
+    } else if (in->enable_ns) {
+        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            if (my_data->fluence_in_spkr_mode &&
+                    my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+            } else {
+                snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+            }
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            if (my_data->fluence_in_voice_comm &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+            } else {
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+            }
+        }
+    }
+
+    return snd_device;
+}
+#endif //DYNAMIC_ECNS_ENABLED
+
 snd_device_t platform_get_input_snd_device(void *platform,
                                            struct stream_in *in,
                                            audio_devices_t out_device)
@@ -3091,70 +3296,9 @@
                 !audio_extn_usb_is_capture_supported())) {
             in_device = AUDIO_DEVICE_IN_BACK_MIC;
         }
+
         if (in) {
-            if (in->enable_aec &&
-                    in->enable_ns) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode &&
-                            my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
-                    } else {
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
-                    }
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
-                    } else {
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
-                    }
-                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                    snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
-                } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
-                    snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
-                }
-                platform_set_echo_reference(adev, true, out_device);
-            } else if (in->enable_aec) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode &&
-                            my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
-                    } else {
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
-                    }
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
-                    } else {
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
-                    }
-               } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                   snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
-               } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
-                   snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
-               }
-               platform_set_echo_reference(adev, true, out_device);
-            } else if (in->enable_ns) {
-                if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_in_spkr_mode &&
-                            my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
-                    } else {
-                        snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
-                    }
-                } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_in_voice_comm &&
-                            (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
-                        snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
-                    } else {
-                        snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
-                    }
-                }
-            }
+            snd_device = get_snd_device_for_voice_comm(my_data, in, out_device, in_device);
         }
     } else if (source == AUDIO_SOURCE_DEFAULT) {
         goto exit;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index f6c5a58..a885f27 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -190,6 +190,8 @@
     SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE,
     SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE,
     SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT,
+    SND_DEVICE_IN_SPEAKER_QMIC_NS,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -343,6 +345,11 @@
 #define HFP_ASM_RX_TX 24
 #endif
 
+#define TX_VOICE_FLUENCE_PROV2 0x10F17
+#define TX_VOICE_DM_FV5_BROADSIDE 0x10F18
+#define TX_VOICE_FV5ECNS_SM 0x10F09
+#define TX_VOICE_FV5ECNS_DM 0x10F0A
+
 #define LIB_CSD_CLIENT "libcsd-client.so"
 #define LIB_MDM_DETECT "libmdmdetect.so"
 
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 3cd2b8d..5e5b662 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -27,6 +27,20 @@
 #define SAMPLE_RATE_11025 11025
 #define sample_rate_multiple(sr, base) ((sr % base)== 0?true:false)
 
+typedef enum {
+    EFFECT_NONE = 0,
+    EFFECT_AEC,
+    EFFECT_NS,
+    EFFECT_COUNT
+} effect_type_t;
+
+struct audio_effect_config {
+    uint32_t module_id;
+    uint32_t instance_id;
+    uint32_t param_id;
+    uint32_t param_value;
+};
+
 struct amp_db_and_gain_table {
     float amp;
     float db;
@@ -56,6 +70,12 @@
 int platform_get_snd_device_index(char *snd_device_index_name);
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
 int platform_get_snd_device_acdb_id(snd_device_t snd_device);
+int platform_set_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config effect_config,
+                                      effect_type_t effect_type);
+int platform_get_effect_config_data(snd_device_t snd_device,
+                                      struct audio_effect_config *effect_config,
+                                      effect_type_t effect_type);
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
 int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
                                        int app_type, int sample_rate);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 0695592..233e120 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -38,6 +38,9 @@
 typedef enum {
     ROOT,
     ACDB,
+    MODULE,
+    AEC,
+    NS,
     PCM_ID,
     BACKEND_NAME,
     CONFIG_PARAMS,
@@ -56,6 +59,9 @@
 typedef void (* section_process_fn)(const XML_Char **attr);
 
 static void process_acdb_id(const XML_Char **attr);
+static void process_audio_effect(const XML_Char **attr, effect_type_t effect_type);
+static void process_effect_aec(const XML_Char **attr);
+static void process_effect_ns(const XML_Char **attr);
 static void process_pcm_id(const XML_Char **attr);
 static void process_backend_name(const XML_Char **attr);
 static void process_config_params(const XML_Char **attr);
@@ -71,6 +77,8 @@
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
     [ACDB] = process_acdb_id,
+    [AEC] = process_effect_aec,
+    [NS] = process_effect_ns,
     [PCM_ID] = process_pcm_id,
     [BACKEND_NAME] = process_backend_name,
     [CONFIG_PARAMS] = process_config_params,
@@ -185,6 +193,11 @@
  * ...
  * ...
  * </acdb_ids>
+ * <module_ids>
+ * <device name="???" module_id="???"/>
+ * ...
+ * ...
+ * </module_ids>
  * <backend_names>
  * <device name="???" backend="???"/>
  * ...
@@ -216,6 +229,77 @@
 {
 }
 
+static void process_audio_effect(const XML_Char **attr, effect_type_t effect_type)
+{
+    int index;
+    struct audio_effect_config effect_config;
+
+    if (strncmp(attr[0], "name", strlen("name")) != 0) {
+        ALOGE("%s: 'name' not found, no MODULE ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s in platform info xml not found, no MODULE ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strncmp(attr[2], "module_id", strlen("module_id")) != 0) {
+        ALOGE("%s: Device %s in platform info xml has no module_id, no MODULE ID set!",
+              __func__, attr[2]);
+        goto done;
+    }
+
+    if (strncmp(attr[4], "instance_id", strlen("instance_id")) != 0) {
+        ALOGE("%s: Device %s in platform info xml has no instance_id, no INSTANCE ID set!",
+              __func__, attr[4]);
+        goto done;
+    }
+
+    if (strncmp(attr[6], "param_id", strlen("param_id")) != 0) {
+        ALOGE("%s: Device %s in platform info xml has no param_id, no PARAM ID set!",
+              __func__, attr[6]);
+        goto done;
+    }
+
+    if (strncmp(attr[8], "param_value", strlen("param_value")) != 0) {
+        ALOGE("%s: Device %s in platform info xml has no param_value, no PARAM VALUE set!",
+              __func__, attr[8]);
+        goto done;
+    }
+
+    effect_config = (struct audio_effect_config){strtol((char *)attr[3], NULL, 0),
+                                                 strtol((char *)attr[5], NULL, 0),
+                                                 strtol((char *)attr[7], NULL, 0),
+                                                 strtol((char *)attr[9], NULL, 0)};
+
+
+    if (platform_set_effect_config_data(index, effect_config, effect_type) < 0) {
+        ALOGE("%s: Effect = %d Device %s, MODULE/INSTANCE/PARAM ID %u %u %u %u was not set!",
+              __func__, effect_type, attr[1], effect_config.module_id,
+              effect_config.instance_id, effect_config.param_id,
+              effect_config.param_value);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void process_effect_aec(const XML_Char **attr)
+{
+    process_audio_effect(attr, EFFECT_AEC);
+    return;
+}
+
+static void process_effect_ns(const XML_Char **attr)
+{
+    process_audio_effect(attr, EFFECT_NS);
+    return;
+}
+
 /* mapping from usecase to pcm dev id */
 static void process_pcm_id(const XML_Char **attr)
 {
@@ -717,6 +801,8 @@
     if (my_data.do_full_parse) {
         if (strcmp(tag_name, "acdb_ids") == 0) {
             section = ACDB;
+        } else if (strncmp(tag_name, "module_ids", strlen("module_ids")) == 0) {
+            section = MODULE;
         } else if (strcmp(tag_name, "pcm_ids") == 0) {
             section = PCM_ID;
         } else if (strcmp(tag_name, "backend_names") == 0) {
@@ -736,8 +822,9 @@
         } else if(strcmp(tag_name, "acdb_metainfo_key") == 0) {
             section = ACDB_METAINFO_KEY;
         } 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");
+            if ((section != ACDB) && (section != AEC) && (section != NS) &&
+                (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
+                ALOGE("device tag only supported for acdb/backend/aec/ns/operator_specific names");
                 return;
             }
 
@@ -814,6 +901,20 @@
             section_process_fn fn = section_table[MIC_INFO];
             fn(attr);
         }
+        else if (strncmp(tag_name, "aec", strlen("aec")) == 0) {
+            if (section != MODULE) {
+                ALOGE("aec tag only supported with MODULE section");
+                return;
+            }
+            section = AEC;
+        }
+        else if (strncmp(tag_name, "ns", strlen("ns")) == 0) {
+            if (section != MODULE) {
+                ALOGE("ns tag only supported with MODULE section");
+                return;
+            }
+            section = NS;
+        }
     } else {
         if(strcmp(tag_name, "config_params") == 0) {
             section = CONFIG_PARAMS;
@@ -835,6 +936,12 @@
 {
     if (strcmp(tag_name, "acdb_ids") == 0) {
         section = ROOT;
+    } else if (strncmp(tag_name, "module_ids", strlen("module_ids")) == 0) {
+        section = ROOT;
+    } else if (strncmp(tag_name, "aec", strlen("aec")) == 0) {
+        section = MODULE;
+    } else if (strncmp(tag_name, "ns", strlen("ns")) == 0) {
+        section = MODULE;
     } else if (strcmp(tag_name, "pcm_ids") == 0) {
         section = ROOT;
     } else if (strcmp(tag_name, "backend_names") == 0) {