Merge "agm: Add support for echo reference capture"
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 dfd3841..1cc0add 100644
--- a/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
+++ b/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
@@ -95,7 +95,7 @@
    pthread_mutex_t handle_lock;
    uint64_t handle;
    std::vector<std::pair<int, int>> shared_mem_fd_list;
-   std::vector<int> aif_id_list;
+   std::vector<uint32_t> aif_id_list;
 } agm_client_session_handle;
 
 typedef struct {
@@ -297,7 +297,7 @@
     }
 }
 
-static void add_session_aif_to_list_l(uint32_t session_id, uint64_t aif_id)
+static void add_session_aif_to_list_l(uint32_t session_id, uint32_t aif_id)
 {
     agm_client_session_handle *session_handle = NULL;
 
@@ -315,7 +315,7 @@
     session_handle->aif_id_list.push_back(aif_id);
 }
 
-static void remove_session_aif_from_list_l(uint32_t session_id, uint64_t aif_id)
+static void remove_session_aif_from_list_l(uint32_t session_id, uint32_t aif_id)
 {
     agm_client_session_handle *session_handle = NULL;
 
diff --git a/ipc/SwBinders/agm_server/src/ipc_proxy_server.cpp b/ipc/SwBinders/agm_server/src/ipc_proxy_server.cpp
index bedb56e..2840a1c 100644
--- a/ipc/SwBinders/agm_server/src/ipc_proxy_server.cpp
+++ b/ipc/SwBinders/agm_server/src/ipc_proxy_server.cpp
@@ -1162,6 +1162,7 @@
                                 blob.data(), blob_size);
          blob.release();
          rc = ipc_agm_session_register_for_events(session_id, evt_reg_cfg);
+         free(evt_reg_cfg);
          reply->writeInt32(rc);
          break; }
 
diff --git a/plugins/tinyalsa/src/agm_pcm_plugin.c b/plugins/tinyalsa/src/agm_pcm_plugin.c
index fd9fa02..53c86b3 100644
--- a/plugins/tinyalsa/src/agm_pcm_plugin.c
+++ b/plugins/tinyalsa/src/agm_pcm_plugin.c
@@ -96,6 +96,7 @@
     snd_pcm_uframes_t total_size_frames;
     /* idx: 0: out port, 1: in port */
     struct agm_mmap_buffer_port mmap_buffer_port[2];
+    bool mmap_status;
 };
 
 struct pcm_plugin_hw_constraints agm_pcm_constrs = {
@@ -648,6 +649,7 @@
 {
     struct agm_pcm_priv *priv = plugin->priv;
     uint64_t handle;
+    enum direction dir;
     int ret = 0;
 
     ret = agm_get_session_handle(priv, &handle);
@@ -661,6 +663,21 @@
     free(priv->buffer_config);
     free(priv->media_config);
     free(priv->session_config);
+    // unmap memory in case agm_pcm_munmap not called before close
+    if (priv->mmap_status) {
+        if (plugin->mode & PCM_NOIRQ) {
+            if (priv->pos_buf) {
+                munmap(priv->pos_buf->pos_buf_addr,
+                        priv->buf_info->pos_buf_size);
+                free(priv->pos_buf);
+                priv->pos_buf = NULL;
+            }
+        }
+        dir = (plugin->mode & PCM_IN) ? TX : RX;
+        munmap(priv->mmap_buffer_port[dir-1].mmap_buffer_addr,
+            priv->mmap_buffer_port[dir-1].mmap_buffer_length);
+        priv->mmap_status = false;
+    }
     if (priv->buf_info) {
         if (priv->buf_info->data_buf_fd != -1)
             close(priv->buf_info->data_buf_fd);
@@ -796,6 +813,7 @@
         priv->mmap_buffer_port[dir-1].mmap_buffer_addr = mmap_addr;
         priv->mmap_buffer_port[dir-1].mmap_buffer_length = length;
     }
+    priv->mmap_status = true;
     return mmap_addr;
 }
 
@@ -803,6 +821,7 @@
 {
     struct agm_pcm_priv *priv = plugin->priv;
 
+    priv->mmap_status = false;
     if (plugin->mode & PCM_NOIRQ) {
         if (priv->pos_buf) {
             munmap(priv->pos_buf->pos_buf_addr,
@@ -929,6 +948,7 @@
     priv->session_config = session_config;
     priv->card_node = card_node;
     priv->session_id = session_id;
+    priv->mmap_status = false;
     snd_card_def_get_int(pcm_node, "session_mode", &sess_mode);
 
     ret = agm_session_open(session_id, sess_mode, &handle);
diff --git a/service/inc/private/agm/device.h b/service/inc/private/agm/device.h
index 7dadaf8..5546720 100644
--- a/service/inc/private/agm/device.h
+++ b/service/inc/private/agm/device.h
@@ -25,6 +25,39 @@
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** Changes from Qualcomm Innovation Center are provided under the following license:
+** Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted (subject to the limitations in the
+** disclaimer below) provided that the following conditions are met:
+**
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**
+**   * Redistributions in binary form must reproduce the above
+**     copyright notice, this list of conditions and the following
+**     disclaimer in the documentation and/or other materials provided
+**     with the distribution.
+**
+**   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+**     contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+** NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+** GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+** HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+** IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/
 
 #ifndef __AGM_DEVICE_H__
@@ -55,6 +88,7 @@
 #define  USB_AUDIO                  0x6
 #define  PCM_RT_PROXY               0x7
 #define  AUDIOSS_DMA                0x8
+#define  PCM_DUMMY                  0x9
 
 #define  AUDIO_OUTPUT               0x1 /**< playback usecases*/
 #define  AUDIO_INPUT                0x2 /**< capture/voice activation usecases*/
@@ -102,11 +136,17 @@
     uint32_t dev_id;
 };
 
+struct hw_ep_pcm_dummy_config {
+    /* PCM dummy device id */
+    uint32_t dev_id;
+};
+
 union hw_ep_config {
     struct hw_ep_cdc_dma_i2s_tdm_config cdc_dma_i2s_tdm_config;
     struct hw_ep_slimbus_config slim_config;
     struct hw_ep_pcm_rt_proxy_config pcm_rt_proxy_config;
     struct hw_ep_audioss_dma_config audioss_dma_config;
+    struct hw_ep_pcm_dummy_config pcm_dummy_config;
 };
 
 typedef struct hw_ep_info
diff --git a/service/src/device_hw_ep.c b/service/src/device_hw_ep.c
index 4e001c0..155f0a0 100644
--- a/service/src/device_hw_ep.c
+++ b/service/src/device_hw_ep.c
@@ -25,6 +25,39 @@
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** Changes from Qualcomm Innovation Center are provided under the following license:
+** Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted (subject to the limitations in the
+** disclaimer below) provided that the following conditions are met:
+**
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**
+**   * Redistributions in binary form must reproduce the above
+**     copyright notice, this list of conditions and the following
+**     disclaimer in the documentation and/or other materials provided
+**     with the distribution.
+**
+**   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+**     contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+** NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+** GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+** HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+** IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/
 
 #define LOG_TAG "AGM: device"
@@ -143,6 +176,8 @@
         hw_ep_info->intf = PCM_RT_PROXY;
     else if (!strcmp(intf, "AUDIOSS_DMA"))
         hw_ep_info->intf = AUDIOSS_DMA;
+    else if (!strcmp(intf, "PCM_DUMMY"))
+        hw_ep_info->intf = PCM_DUMMY;
     else {
         AGM_LOGE("No matching intf found\n");
         return -EINVAL;
@@ -217,6 +252,26 @@
     return ret;
 }
 
+static int populate_pcm_dummy_ep_info(hw_ep_info_t *hw_ep_info, char *value)
+{
+    char arg[DEV_ARG_SIZE] = {0};
+    struct hw_ep_pcm_dummy_config *pcm_dummy_config;
+    int ret = 0;
+
+    sscanf(value, "%20[^-]-%60s", arg, value);
+    ret = populate_hw_ep_direction(hw_ep_info, arg);
+    if (ret) {
+        AGM_LOGE("failed to parse direction\n");
+        return ret;
+    }
+
+    pcm_dummy_config = &hw_ep_info->ep_config.pcm_dummy_config;
+    sscanf(value, "%20[^-]-%60s", arg, value);
+    pcm_dummy_config->dev_id = atoi(arg);
+
+    return ret;
+}
+
 static int populate_slim_dp_usb_ep_info(hw_ep_info_t *hw_ep_info, char *value)
 {
     char dir[DEV_ARG_SIZE], arg[DEV_ARG_SIZE] = {0};
@@ -358,6 +413,8 @@
         return populate_pcm_rt_proxy_ep_info(&dev_obj->hw_ep_info, value);
     case AUDIOSS_DMA:
         return populate_audioss_dma_ep_info(&dev_obj->hw_ep_info, value);
+    case PCM_DUMMY:
+        return populate_pcm_dummy_ep_info(&dev_obj->hw_ep_info, value);
     default:
         AGM_LOGE("Unsupported interface name %s\n", __func__, dev_obj->name);
         return -EINVAL;
diff --git a/service/src/graph.c b/service/src/graph.c
index 069bd82..50f8d33 100644
--- a/service/src/graph.c
+++ b/service/src/graph.c
@@ -570,8 +570,6 @@
                     mod->mid = gsl_tag_entry->module_entry[0].module_id;
                     AGM_LOGD("miid %x mid %x tag %x", mod->miid, mod->mid, mod->tag);
                     ADD_MODULE(*mod, NULL);
-                    /*Remove the module from the node_sess list*/
-                    list_remove(node_list);
                     goto tag_list;
                 }
             }
@@ -615,8 +613,6 @@
                     mod->gkv = gkv;
                     AGM_LOGD("miid %x mid %x tag %x", mod->miid, mod->mid, mod->tag);
                     ADD_MODULE(*mod, dev_obj);
-                    /*Remove the module from node_hw list*/
-                    list_remove(node_list);
                     goto tag_list;
                 }
             }
@@ -667,6 +663,21 @@
     pthread_mutex_destroy(&graph_obj->lock);
     free(graph_obj);
 done:
+    // free memory allocated in node sess/hw
+    list_for_each_safe(node, temp_node, &node_sess) {
+        list_remove(node);
+        mod_list = node_to_item(node, module_info_link_list_t, tagged_list);
+        if (mod_list)
+            free(mod_list);
+    }
+
+    list_for_each_safe(node, temp_node, &node_hw) {
+        list_remove(node);
+        mod_list = node_to_item(node, module_info_link_list_t, tagged_list);
+        if (mod_list)
+            free(mod_list);
+    }
+
     AGM_LOGD("exit, ret %d", ret);
     if (tag_module_info)
         free(tag_module_info);
@@ -1738,6 +1749,7 @@
        ret = ar_err_get_lnx_err_code(ret);
        AGM_LOGE("event registration failed with error %d\n", ret);
     }
+    free(reg_ev_payload);
     pthread_mutex_unlock(&gph_obj->lock);
 
     gph_obj->buf_info.timestamp = 0;
diff --git a/service/src/graph_module.c b/service/src/graph_module.c
index 4af4273..83e5c10 100644
--- a/service/src/graph_module.c
+++ b/service/src/graph_module.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
@@ -25,6 +26,39 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #define LOG_TAG "AGM: graph_module"
@@ -676,7 +710,7 @@
     int ret = 0;
     struct device_obj *dev_obj = mod->dev_obj;
 
-    if(dev_obj->hw_ep_info.intf == PCM_RT_PROXY) {
+    if(dev_obj->hw_ep_info.intf == PCM_RT_PROXY || dev_obj->hw_ep_info.intf == PCM_DUMMY) {
         AGM_LOGD("no ep media config for %d\n",  dev_obj->hw_ep_info.intf);
     }
     else {
@@ -712,6 +746,9 @@
     case AUDIOSS_DMA:
         AGM_LOGD("no ep configuration for %d\n",  dev_obj->hw_ep_info.intf);
         break;
+    case PCM_DUMMY:
+        AGM_LOGD("no ep configuration for %d\n",  dev_obj->hw_ep_info.intf);
+        break;
     default:
          AGM_LOGE("hw intf %d not enabled yet", dev_obj->hw_ep_info.intf);
          break;
@@ -1662,6 +1699,8 @@
         }
     }
 done:
+    if (payload)
+        free(payload);
     return ret;
 }
 
@@ -1707,6 +1746,8 @@
     }
 
 done:
+    if (reg_ev_payload)
+        free(reg_ev_payload);
     return ret;
 }
 
diff --git a/service/src/session_obj.c b/service/src/session_obj.c
index b88e1f6..fbacbd5 100644
--- a/service/src/session_obj.c
+++ b/service/src/session_obj.c
@@ -515,7 +515,7 @@
                       audio interface id:%d \n",
                        sess_obj->sess_id, aif_obj->aif_id);
         ret = -ENOMEM;
-        return ret;
+        goto done;
     }
 
     pthread_mutex_lock(&hwep_lock);
@@ -532,7 +532,7 @@
                           sess_obj->sess_id, aif_obj->aif_id);
             ret = -ENOMEM;
             pthread_mutex_unlock(&hwep_lock);
-            return ret;
+            goto done;
         }
 
         temp.gkv = merged_metadata->gkv;
@@ -562,10 +562,17 @@
             ret, aif_obj->aif_id);
     }
     pthread_mutex_unlock(&hwep_lock);
-    if (merged_meta_sess_aif)
-        metadata_free(merged_meta_sess_aif);
 
-    metadata_free(merged_metadata);
+done:
+    if (merged_meta_sess_aif) {
+        metadata_free(merged_meta_sess_aif);
+        free(merged_meta_sess_aif);
+    }
+
+    if (merged_metadata) {
+        metadata_free(merged_metadata);
+        free(merged_metadata);
+    }
     return ret;
 }