Merge "agm: Add support for echo reference capture"
diff --git a/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp b/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp
index eececa5..feeb7fa 100644
--- a/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp
+++ b/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp
@@ -626,6 +626,20 @@
     return -EINVAL;
 }
 
+int agm_set_params_to_acdb_tunnel(void *payload, size_t size)
+{
+    if (!agm_server_died) {
+        android::sp<IAGM> agm_client = get_agm_server();
+
+        uint32_t size_hidl = (uint32_t) size;
+        hidl_vec<uint8_t> payload_hidl;
+        payload_hidl.resize(size_hidl);
+        memcpy(payload_hidl.data(), payload, size_hidl);
+        return agm_client->ipc_agm_set_params_to_acdb_tunnel(payload_hidl, size_hidl);
+    }
+    return -EINVAL;
+}
+
 int agm_session_register_for_events(uint32_t session_id,
                                           struct agm_event_reg_cfg *evt_reg_cfg)
 {
diff --git a/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h b/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h
index f1592ec..4c64508 100644
--- a/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h
+++ b/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h
@@ -178,6 +178,9 @@
                             uint32_t aif_id,
                             const hidl_vec<uint8_t>& payload,
                             uint32_t size) override;
+    Return<int32_t> ipc_agm_set_params_to_acdb_tunnel(
+                            const hidl_vec<uint8_t>& payload,
+                            uint32_t size) override;
     Return<int32_t> ipc_agm_session_register_for_events(uint32_t session_id,
                          const hidl_vec<AgmEventRegCfg>& evt_reg_cfg) override;
     Return<void> ipc_agm_session_open(uint32_t session_id,
diff --git a/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp b/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
index b281108..1cc0add 100644
--- a/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
+++ b/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
@@ -785,6 +785,26 @@
     return ret;
 }
 
+Return<int32_t> AGM::ipc_agm_set_params_to_acdb_tunnel(
+                                     const hidl_vec<uint8_t>& payload,
+                                     uint32_t size) {
+    size_t size_local = (size_t) size;
+    void * payload_local = NULL;
+    int32_t ret = 0;
+
+    payload_local = (void*) calloc(1, size);
+    if (payload_local == NULL) {
+        ALOGE("%s: Cannot allocate memory for payload_local\n", __func__);
+        return -ENOMEM;
+    }
+
+    memcpy(payload_local, payload.data(), size);
+    ret = agm_set_params_to_acdb_tunnel(payload_local, size_local);
+    free(payload_local);
+
+    return ret;
+}
+
 Return<int32_t> AGM::ipc_agm_session_register_for_events(uint32_t session_id,
                                   const hidl_vec<AgmEventRegCfg>& evt_reg_cfg) {
     ALOGV("%s : session_id = %d\n", __func__, session_id);
diff --git a/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal b/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
index 4389f90..c08f145 100644
--- a/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
+++ b/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
@@ -104,6 +104,9 @@
     ipc_agm_set_params_with_tag_to_acdb(uint32_t session_id, uint32_t aif_id,
                     vec<uint8_t> payload, uint32_t size)
                     generates (int32_t ret);
+    ipc_agm_set_params_to_acdb_tunnel(
+                    vec<uint8_t> payload, uint32_t size)
+                    generates (int32_t ret);
     ipc_agm_session_register_for_events(uint32_t session_id,
                     vec<AgmEventRegCfg> evt_reg_cfg) generates (int32_t ret);
     ipc_agm_session_open(uint32_t session_id, AgmSessionMode sess_mode)
diff --git a/ipc/HwBinders/interfaces/AGMIPC/current.txt b/ipc/HwBinders/interfaces/AGMIPC/current.txt
index 7b0e356..b588d4c 100644
--- a/ipc/HwBinders/interfaces/AGMIPC/current.txt
+++ b/ipc/HwBinders/interfaces/AGMIPC/current.txt
@@ -1,4 +1,4 @@
 # Hash for vendor.qti.hardware.AGMIPC@1.0 package
 1846dac975898187405fcd011ea43c98415334e187a74a2e4fcaea123e0064b7 vendor.qti.hardware.AGMIPC@1.0::types
-ebe001f8ed01031e9ff3899b00f7e527346e89b271070064e55c4b3e70492d90 vendor.qti.hardware.AGMIPC@1.0::IAGM
+830fff3e1bdf65d1ea4d12272031a5d4b74171a70d207fbe65166f53ec5c7fe8 vendor.qti.hardware.AGMIPC@1.0::IAGM
 e8d1ca223a57cfacc7373f6418555330bb545c43a1e9d2c3a1fdd984fcec4a14 vendor.qti.hardware.AGMIPC@1.0::IAGMCallback
diff --git a/plugins/tinyalsa/src/agm_mixer_plugin.c b/plugins/tinyalsa/src/agm_mixer_plugin.c
index 2c69c27..e946732 100644
--- a/plugins/tinyalsa/src/agm_mixer_plugin.c
+++ b/plugins/tinyalsa/src/agm_mixer_plugin.c
@@ -83,6 +83,14 @@
 };
 
 enum {
+    STATIC_CTL_SET_ACDB_TUNNEL = 0,
+};
+
+static char *static_acdb_ctl_name_extn[] = {
+    "setACDBTunnel",
+};
+
+enum {
     BE_GROUP_CTL_NAME_MEDIA_CONFIG = 0,
 };
 
@@ -192,6 +200,7 @@
     struct amp_dev_info tx_be_devs;
     struct amp_dev_info rx_pcm_devs;
     struct amp_dev_info tx_pcm_devs;
+    struct amp_dev_info acdb_tunnels;
 
     struct amp_be_group_info group_be_devs;
 
@@ -308,6 +317,11 @@
     }
 }
 
+static void amp_free_acdb_dev_info(struct amp_priv *amp_priv)
+{
+    amp_free_dev_info(&amp_priv->acdb_tunnels);
+}
+
 static void amp_free_pcm_dev_info(struct amp_priv *amp_priv)
 {
     amp_free_dev_info(&amp_priv->rx_pcm_devs);
@@ -695,7 +709,42 @@
     rx_adi->dev_enum.texts = rx_adi->names;
     tx_adi->dev_enum.items = tx_adi->count;
     tx_adi->dev_enum.texts = tx_adi->names;
+    goto done;
 
+err_alloc_rx_tx:
+    amp_free_pcm_dev_info(amp_priv);
+
+done:
+    if (pcm_node_list)
+        free(pcm_node_list);
+
+    return ret;
+}
+
+static int amp_get_acdb_info(struct amp_priv *amp_priv)
+{
+    struct amp_dev_info *acdb_adi = &amp_priv->acdb_tunnels;
+    void **pcm_node_list = NULL;
+    int total_pcms, ret = 0;
+
+    total_pcms = 1;
+    acdb_adi->count = 1;
+    pcm_node_list = calloc(total_pcms, sizeof(*pcm_node_list));
+    if (!pcm_node_list) {
+        AGM_LOGE("%s: alloc for pcm_node_list failed\n", __func__);
+        return -ENOMEM;
+    }
+
+    /* Allocate rx and tx structures */
+    acdb_adi->names = calloc(acdb_adi->count, sizeof(*acdb_adi->names));
+    acdb_adi->idx_arr = calloc(acdb_adi->count, sizeof(*acdb_adi->idx_arr));
+    if (!acdb_adi->names ||!acdb_adi->idx_arr) {
+        ret = -ENOMEM;
+        goto err_alloc_rx_tx;
+    }
+
+    acdb_adi->dev_enum.items = acdb_adi->count;
+    acdb_adi->dev_enum.texts = acdb_adi->names;
     goto done;
 
 err_alloc_rx_tx:
@@ -1228,6 +1277,27 @@
     return ret;
 }
 
+static int amp_pcm_set_acdb_tunnel_get(struct mixer_plugin *plugin __unused,
+                struct snd_control *ctl __unused, struct snd_ctl_tlv *ev __unused)
+{
+    /* get of set_param not implemented */
+    return 0;
+}
+
+static int amp_pcm_set_acdb_tunnel_put(struct mixer_plugin *plugin,
+                struct snd_control *ctl, struct snd_ctl_tlv *tlv)
+{
+    void *payload;
+    int ret = 0;
+    size_t tlv_size;
+
+    payload = &tlv->tlv[0];
+    tlv_size = tlv->length;
+    ret = agm_set_params_to_acdb_tunnel(payload, tlv_size);
+
+    return ret;
+}
+
 static int amp_pcm_set_param_get(struct mixer_plugin *plugin __unused,
                 struct snd_control *ctl __unused, struct snd_ctl_tlv *ev __unused)
 {
@@ -1384,12 +1454,12 @@
         be_idx = be_adi->idx_arr[pcm_control];
     }
 
-	get_size = tlv_size;
-	ret = agm_session_aif_get_tag_module_info(pcm_idx, be_idx,
-			payload, &get_size);
-	if (ret || get_size == 0 || tlv_size < get_size)
-		AGM_LOGE("%s: failed with err %d, tlv_size %zu, get_size %zu for %s\n",
-				__func__, ret, tlv_size, get_size, ctl->name);
+    get_size = tlv_size;
+    ret = agm_session_aif_get_tag_module_info(pcm_idx, be_idx,
+            payload, &get_size);
+    if (ret || get_size == 0 || tlv_size < get_size)
+        AGM_LOGE("%s: failed with err %d, tlv_size %zu, get_size %zu for %s\n",
+                __func__, ret, tlv_size, get_size, ctl->name);
 
     return ret;
 }
@@ -1539,6 +1609,8 @@
     SND_VALUE_TLV_BYTES(256 * 1024, amp_pcm_set_param_get, amp_pcm_set_param_put);
 static struct snd_value_tlv_bytes pcm_setparamtagacdb_bytes =
     SND_VALUE_TLV_BYTES(256 * 1024, amp_pcm_set_param_get, amp_pcm_set_param_put);
+static struct snd_value_tlv_bytes pcm_setacdbtunnel_bytes =
+    SND_VALUE_TLV_BYTES(256 * 1024, amp_pcm_set_acdb_tunnel_get, amp_pcm_set_acdb_tunnel_put);
 static struct snd_value_tlv_bytes pcm_setparam_bytes =
     SND_VALUE_TLV_BYTES(256 * 1024, amp_pcm_set_param_get, amp_pcm_set_param_put);
 static struct snd_value_tlv_bytes pcm_getparam_bytes =
@@ -1778,6 +1850,17 @@
             pval, pdata);
 }
 
+/* static mixer control for ACDB parameter set */
+static void amp_create_acdb_tunnel_set_ctl(struct amp_priv *amp_priv,
+                int ctl_idx, int pval, void *pdata)
+{
+    struct snd_control *ctl = AMP_PRIV_GET_CTL_PTR(amp_priv, ctl_idx);
+
+    INIT_SND_CONTROL_TLV_BYTES(ctl,
+            static_acdb_ctl_name_extn[STATIC_CTL_SET_ACDB_TUNNEL],
+            pcm_setacdbtunnel_bytes, pval, pdata);
+}
+
 /* BE related mixer control creations here */
 static void amp_create_metadata_ctl(struct amp_priv *amp_priv,
                 char *be_name, int ctl_idx, int pval, void *pdata)
@@ -1996,6 +2079,16 @@
     return 0;
 }
 
+static int amp_form_acdb_ctls(struct amp_priv *amp_priv, int ctl_idx)
+{
+    struct amp_dev_info *acdb_adi = &amp_priv->acdb_tunnels;
+
+    amp_create_acdb_tunnel_set_ctl(amp_priv, ctl_idx, acdb_adi->idx_arr[0],
+                                    acdb_adi);
+
+    return 0;
+}
+
 static ssize_t amp_read_event(struct mixer_plugin *plugin,
                               struct ctl_event *ev, size_t size)
 {
@@ -2127,6 +2220,10 @@
     if (ret)
         goto err_get_pcm_info;
 
+    ret = amp_get_acdb_info(amp_priv);
+    if (ret)
+        goto err_get_acdb_info;
+
     /* Get total count of controls to be registered */
     be_ctl_cnt = amp_get_be_ctl_count(amp_priv);
     total_ctl_cnt += be_ctl_cnt;
@@ -2134,7 +2231,8 @@
     total_ctl_cnt += be_grp_ctl_cnt;
     pcm_ctl_cnt = amp_get_pcm_ctl_count(amp_priv);
     total_ctl_cnt += pcm_ctl_cnt;
-
+    /* add one static mixer control for acdb param set */
+    total_ctl_cnt += 1;
     /*
      * Create the controls to be registered
      * When changing this code, be careful to make sure to create
@@ -2159,6 +2257,10 @@
     if (ret)
         goto err_ctls_alloc;
 
+    ret = amp_form_acdb_ctls(amp_priv, be_ctl_cnt + be_grp_ctl_cnt + pcm_ctl_cnt);
+    if (ret)
+        goto err_ctls_alloc;
+
     /* Register the controls */
     if (total_ctl_cnt > 0) {
         amp_priv->ctl_count = total_ctl_cnt;
@@ -2179,6 +2281,9 @@
 
 err_ctls_alloc:
     amp_free_ctls(amp_priv);
+    amp_free_acdb_dev_info(amp_priv);
+
+err_get_acdb_info:
     amp_free_pcm_dev_info(amp_priv);
 
 err_get_pcm_info:
diff --git a/service/inc/private/agm/graph.h b/service/inc/private/agm/graph.h
index 3564392..1ac2986 100644
--- a/service/inc/private/agm/graph.h
+++ b/service/inc/private/agm/graph.h
@@ -313,6 +313,8 @@
 int graph_set_cal(struct graph_obj *gph_obj,
                               struct agm_meta_data_gsl *meta_data);
 
+int graph_set_acdb_param(void *payload);
+
 /**
  *\brief Issue eos to the associated graph
  *\param [in] graph_obj: associated graph obj
diff --git a/service/inc/private/agm/session_obj.h b/service/inc/private/agm/session_obj.h
index 231cf5a..acd1f49 100644
--- a/service/inc/private/agm/session_obj.h
+++ b/service/inc/private/agm/session_obj.h
@@ -152,6 +152,11 @@
                              struct agm_cal_config *cal_config);
 int session_obj_get_tag_with_module_info(struct session_obj *sess_obj,
                              uint32_t audio_intf, void *payload, size_t *size);
+int session_dummy_get_tag_with_module_info(
+                             struct agm_key_vector_gsl *gkv,
+                             void *payload, size_t *size);
+int session_dummy_rw_acdb_tunnel(
+                             void *payload, bool is_param_set);
 size_t session_obj_hw_processed_buff_cnt(struct session_obj *sess_obj,
                              enum direction dir);
 int session_obj_set_loopback(struct session_obj *sess_obj,
diff --git a/service/inc/public/agm/agm_api.h b/service/inc/public/agm/agm_api.h
index 2906e8b..f366088 100644
--- a/service/inc/public/agm/agm_api.h
+++ b/service/inc/public/agm/agm_api.h
@@ -433,6 +433,15 @@
     uint8_t blob[];            /**< kv + payload */
 };
 
+struct agm_acdb_tunnel_param {
+    bool isTKV;
+    uint32_t tag;
+    uint32_t num_gkvs;         /**< number of gkv*/
+    uint32_t num_kvs;          /**< number of ckv or tkv*/
+    uint32_t blob_size;        /**< gkv size + t/ckv size + payload size*/
+    uint8_t blob[];            /**< gkv + t/ckv + payload */
+};
+
 /**
  * Event types
  */
@@ -757,6 +766,18 @@
                                 void *payload, size_t size);
 
 /**
+ * \brief Set parameters for modules at acd without session
+ *
+
+ * \param[in] payload - payload with tag and calibration date
+ * \param[in] size - size of payload
+ *
+ *  \return 0 on success, error code on failure.
+ */
+
+int agm_set_params_to_acdb_tunnel(void *payload, size_t size);
+
+/**
   * \brief Open the session with specified session id.
   *
   * \param[in] session_id - Valid audio session id
@@ -1063,7 +1084,7 @@
  * \brief Write data buffers with metadata to session
  *
  * \param[in] handle: session handle returned from
- *  	 agm_session_open
+ *       agm_session_open
  * \param[in] buff: agm_buffer where data will be copied from
  * \param[in] consumed size: Actual number of bytes that were consumed by AGM
  *
@@ -1076,7 +1097,7 @@
  * \brief Read data buffers with metadata to session
  *
  * \param[in] handle: session handle returned from
- *  	 agm_session_open
+ *       agm_session_open
  * \param[in] buff: agm_buffer where data will be copied to
  * \param[in] captured_size: Actual number of bytes that were captured
  *
@@ -1089,7 +1110,7 @@
  * \brief Helps set config for non tunnel mode (rx and tx path)
  *
  * \param[in] handle: session handle returned from
- *  	 agm_session_open
+ *       agm_session_open
  * \param[in] session_config - valid stream configuration of the
  *       sessions
  * \param[in] in_media_config - valid media configuration of the
diff --git a/service/src/agm.c b/service/src/agm.c
index ad2a773..777fbb1 100644
--- a/service/src/agm.c
+++ b/service/src/agm.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -492,6 +493,50 @@
     return ret;
 }
 
+int agm_set_params_to_acdb_tunnel(void *payload, size_t size)
+{
+    int ret = 0;
+    struct agm_acdb_tunnel_param *payloadACDBTunnelInfo = NULL;
+    uint32_t k = 0;
+    uint32_t *ptr = NULL;
+    uint32_t tag = 0;
+
+    AGM_LOGD("enter\n");
+
+    if (!payload) {
+        AGM_LOGE("payload is nullptr");
+        return -EINVAL;
+    }
+
+    payloadACDBTunnelInfo = (struct agm_acdb_tunnel_param *)payload;
+    AGM_LOGD("payload size is 0x%x", size);
+    AGM_LOGD("tag=%x istkv=%x num_gkvs=0x%x num_kvs=0x%x blob_size=0x%x",
+        payloadACDBTunnelInfo->tag,
+        payloadACDBTunnelInfo->isTKV,
+        payloadACDBTunnelInfo->num_gkvs,
+        payloadACDBTunnelInfo->num_kvs,
+        payloadACDBTunnelInfo->blob_size);
+
+    ptr = payloadACDBTunnelInfo->blob;
+    for (k = 0; k < payloadACDBTunnelInfo->blob_size / 4; k++) {
+        AGM_LOGV("%d data = 0x%x", k, *ptr++);
+    }
+
+    ptr = payloadACDBTunnelInfo->blob + sizeof(struct agm_key_value) *
+            (payloadACDBTunnelInfo->num_gkvs + payloadACDBTunnelInfo->num_kvs);
+    // tag is stored at miid. Convertion happens next.
+    AGM_LOGI("tag = 0x%x", *ptr);
+
+    ret = session_dummy_rw_acdb_tunnel(payload, TRUE);
+    if (ret) {
+         AGM_LOGE("Error get tag list");
+         goto error;
+    }
+
+error:
+    return ret;
+}
+
 int agm_session_register_cb(uint32_t session_id, agm_event_cb cb,
                             enum event_type evt_type, void *client_data)
 {
diff --git a/service/src/graph.c b/service/src/graph.c
index 5a59dbf..50f8d33 100644
--- a/service/src/graph.c
+++ b/service/src/graph.c
@@ -1119,6 +1119,143 @@
      return ret;
 }
 
+int graph_set_acdb_param(void *payload)
+{
+    int ret = 0;
+    struct agm_acdb_tunnel_param *payloadACDBTunnelInfo = NULL;
+    uint32_t i = 0;
+    uint32_t *ptr = NULL;
+    uint8_t *ptr_to_param = NULL;
+    size_t actual_size = 0;
+    uint32_t tag = 0;
+    uint32_t miid = 0;
+    struct agm_key_vector_gsl gkv = {0, NULL};
+    struct agm_key_vector_gsl kv = {0, NULL};
+    struct apm_module_param_data_t* header;
+    size_t size = 0;
+    struct gsl_tag_module_info *tag_info;
+    struct gsl_tag_module_info_entry *tag_entry;
+    uint32_t offset = 0;
+    uint32_t total_parsed_size = 0;
+    uint8_t tag_pool[TAGGED_MOD_SIZE_BYTES] = { 0 };
+
+    AGM_LOGD("enter");
+
+    if (!payload) {
+        AGM_LOGE("payload is nullptr");
+        return -EINVAL;
+    }
+
+    payloadACDBTunnelInfo = (struct agm_acdb_tunnel_param *)payload;
+    AGM_LOGD("istkv=%x num_gkvs=0x%x num_kvs=0x%x blob_size=0x%x",
+        payloadACDBTunnelInfo->isTKV,
+        payloadACDBTunnelInfo->num_gkvs,
+        payloadACDBTunnelInfo->num_kvs,
+        payloadACDBTunnelInfo->blob_size);
+
+    ptr = payloadACDBTunnelInfo->blob;
+    for (i = 0; i < payloadACDBTunnelInfo->blob_size / 4; i++) {
+        AGM_LOGV("%d data = 0x%x", i, *ptr++);
+    }
+
+    ptr = payloadACDBTunnelInfo->blob + sizeof(struct agm_key_value) *
+            (payloadACDBTunnelInfo->num_gkvs + payloadACDBTunnelInfo->num_kvs);
+    header = (struct apm_module_param_data_t *)ptr;
+    ptr_to_param = header;
+
+    // tag is stored at miid. Convertion happens next.
+    tag = *ptr;
+    AGM_LOGD("tag to be translated is 0x%x", tag);
+
+    gkv.num_kvs = payloadACDBTunnelInfo->num_gkvs;
+    gkv.kv = payloadACDBTunnelInfo->blob;
+
+    ret = gsl_get_tags_with_module_info(&gkv, NULL, &size);
+    if (ret) {
+        AGM_LOGE("failed to get tag info size = %d size=0x%x", ret, size);
+        return ret;
+    }
+
+    ret = gsl_get_tags_with_module_info(&gkv, tag_pool, &size);
+    if (ret) {
+        AGM_LOGE("failed to get tag pool ret = %d size=0x%x", ret, size);
+        return ret;
+    }
+
+    tag_info = (struct gsl_tag_module_info *)tag_pool;
+    AGM_LOGD("num of tags is %d\n", tag_info->num_tags);
+    ret = -1;
+    tag_entry = (struct gsl_tag_module_info_entry *)(&tag_info->tag_module_entry[0]);
+
+    offset = 0;
+    for (i = 0; i < tag_info->num_tags; i++) {
+        tag_entry += offset/sizeof(struct gsl_tag_module_info_entry);
+
+        AGM_LOGD("tag id[%d] = 0x%x, num_modules = 0x%x\n", i,
+                    tag_entry->tag_id, tag_entry->num_modules);
+        offset = sizeof(struct gsl_tag_module_info_entry) +
+                    (tag_entry->num_modules *
+                    sizeof(struct gsl_module_id_info_entry));
+        if (tag_entry->tag_id == tag) {
+            struct gsl_module_id_info_entry *mod_info_entry;
+
+            if (tag_entry->num_modules) {
+                 mod_info_entry = &tag_entry->module_entry[0];
+                 miid = mod_info_entry->module_iid;
+                 AGM_LOGI("MIID is 0x%x\n", miid);
+                 ret = 0;
+                 break;
+            }
+        }
+    }
+
+    AGM_LOGI("originally tag = 0x%x", header->module_instance_id);
+    header->module_instance_id = miid;
+    AGM_LOGI("translated miid is = 0x%x", header->module_instance_id);
+    kv.num_kvs = payloadACDBTunnelInfo->num_kvs;
+    kv.kv = payloadACDBTunnelInfo->blob +
+        payloadACDBTunnelInfo->num_gkvs * sizeof(struct agm_key_value);
+
+    AGM_LOGD("blob size = %d", payloadACDBTunnelInfo->blob_size);
+    actual_size = payloadACDBTunnelInfo->blob_size -
+        (payloadACDBTunnelInfo->num_gkvs + payloadACDBTunnelInfo->num_kvs) *
+                sizeof(struct agm_key_value);
+    AGM_LOGD("actual size = 0x%x", actual_size);
+    AGM_LOGI("num kvs = %d", kv.num_kvs);
+    ptr = kv.kv;
+    for (i = 0; i < kv.num_kvs; i++) {
+        AGM_LOGI("kv %d %x", i, *ptr++);
+        AGM_LOGI("kv %d %x", i, *ptr++);
+    }
+
+    // for multiple param, we have to fill the miid in each line item.
+    offset = sizeof(struct apm_module_param_data_t) + header->param_size;
+    ALIGN_PAYLOAD(offset, 8);
+    total_parsed_size = offset;
+    while (total_parsed_size < actual_size) {
+        AGM_LOGI("multiple param: offset=0x%x", offset);
+        header = (struct apm_module_param_data_t*)((uint8_t *)header + offset);
+        header->module_instance_id = miid;
+        offset = sizeof(struct apm_module_param_data_t) + header->param_size;
+        ALIGN_PAYLOAD(offset, 8);
+        total_parsed_size += offset;
+        AGM_LOGI("total parsed size=0x%x param_size=0x%x offset=0x%x",
+            total_parsed_size, header->param_size, offset);
+    }
+
+    ptr = ptr_to_param;
+    for (i = 0; i < actual_size / 4; i++) {
+        AGM_LOGV("%d data to acdb = 0x%x", i, *ptr++);
+    }
+
+    if (payloadACDBTunnelInfo->isTKV)
+        ret = gsl_set_tag_data_to_acdb(&gkv, tag, &kv, ptr_to_param, actual_size);
+    else
+        ret = gsl_set_cal_data_to_acdb(&gkv, &kv, ptr_to_param, actual_size);
+
+    return ar_err_get_lnx_err_code(ret);
+}
+
 int graph_write(struct graph_obj *graph_obj, struct agm_buff *buffer, size_t *size)
 {
     int ret = 0;
diff --git a/service/src/session_obj.c b/service/src/session_obj.c
index fb2fdca..fbacbd5 100644
--- a/service/src/session_obj.c
+++ b/service/src/session_obj.c
@@ -1592,15 +1592,19 @@
     memcpy((uint8_t *)tckv.kv, acdb_param->blob,
                 tckv.num_kvs*sizeof(struct agm_key_value));
     ptr = acdb_param->blob + tckv.num_kvs * sizeof(struct agm_key_value);
+    AGM_LOGV("blob_size = %d", acdb_param->blob_size);
     actual_size = acdb_param->blob_size -
                         acdb_param->num_kvs * sizeof(struct agm_key_value);
+    for (int f = 0; f < actual_size; f++) {
+        AGM_LOGV("%d blob data is 0x%x", f, ptr[f]);
+    }
     if (acdb_param->isTKV) {
-        AGM_LOGD("%s: TKV param to ACDB.\n", __func__);
+        AGM_LOGI("%s: TKV param to ACDB.\n", __func__);
         ret = graph_set_tag_data_to_acdb(&merged_metadata->gkv,
                                 acdb_param->tag, &tckv,
                                 ptr, actual_size);
     } else {
-        AGM_LOGD("%s: CKV param to ACDB.\n", __func__);
+        AGM_LOGI("%s: CKV param to ACDB.\n", __func__);
         ret = graph_set_cal_data_to_acdb(&merged_metadata->gkv,
                                     &tckv, ptr, actual_size);
     }
@@ -1617,6 +1621,27 @@
     return ret;
 }
 
+int session_dummy_rw_acdb_tunnel(
+                             void *payload, bool is_param_set)
+{
+    int ret = 0;
+    uint8_t enable_flag = 1;
+
+    AGM_LOGD("enter");
+    ret = graph_enable_acdb_persistence(enable_flag);
+    if (ret) {
+        AGM_LOGE("Error: graph_enable_acdb_persistence failed. ret = %d\n", ret);
+        return ret;
+    }
+
+    if (is_param_set)
+        ret = graph_set_acdb_param(payload);
+
+    AGM_LOGD("exit status=%d", ret);
+
+    return ret;
+}
+
 int session_obj_set_sess_aif_cal(struct session_obj *sess_obj,
     uint32_t aif_id,
     struct agm_cal_config *cal_config)
@@ -1802,6 +1827,19 @@
     return ret;
 }
 
+int session_dummy_get_tag_with_module_info(struct agm_key_vector_gsl *gkv,
+                                         void *payload, size_t *size)
+{
+    int ret = 0;
+
+    ret = graph_get_tags_with_module_info(gkv, payload, size);
+    if (ret) {
+        AGM_LOGE("Error getting tag with module info from graph");
+    }
+
+    return ret;
+}
+
 int session_obj_register_cb(struct session_obj *sess_obj, agm_event_cb cb,
                               enum event_type evt_type, void *client_data)
 {