Merge "agm: add SYS_NICE capability to inherit RT priority"
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 200f44e..a728797 100644
--- a/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp
+++ b/ipc/HwBinders/agm_ipc_client/src/agm_client_wrapper.cpp
@@ -997,3 +997,29 @@
     }
     return -EINVAL;
 }
+
+int agm_session_write_datapath_params(uint32_t session_id, struct agm_buff *buf)
+{
+    ALOGV("%s called with session id = %d \n", __func__, session_id);
+
+    if (!agm_server_died) {
+        android::sp<IAGM> agm_client = get_agm_server();
+        hidl_vec<AgmBuff> buf_hidl;
+        buf_hidl.resize(sizeof(struct agm_buff));
+        AgmBuff *agmBuff = buf_hidl.data();
+        agmBuff->size = buf->size;
+        agmBuff->buffer.resize(buf->size);
+        agmBuff->flags = buf->flags;
+        agmBuff->timestamp = buf->timestamp;
+        if (buf->size && buf->addr)
+            memcpy(agmBuff->buffer.data(), buf->addr, buf->size);
+        else {
+            ALOGE("%s: buf size or addr is null", __func__);
+            return -EINVAL;
+        }
+
+        return agm_client->ipc_agm_session_write_datapath_params(
+                                            session_id, buf_hidl);
+    }
+    return -EINVAL;
+}
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 99c5c2d..e5e0b6d 100644
--- a/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h
+++ b/ipc/HwBinders/agm_ipc_service/inc/agm_server_wrapper.h
@@ -255,6 +255,8 @@
                         const hidl_vec<AgmGroupMediaConfig>& media_config) override;
     Return<void> ipc_agm_get_group_aif_info_list(uint32_t num_groups,
                                ipc_agm_get_aif_info_list_cb _hidl_cb) override;
+    Return<int32_t> ipc_agm_session_write_datapath_params(uint32_t session_id,
+                               const hidl_vec<AgmBuff>& buff) override;
 
     int is_agm_initialized() { return agm_initialized;}
 
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 a3c599a..f05167e 100644
--- a/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
+++ b/ipc/HwBinders/agm_ipc_service/src/agm_server_wrapper.cpp
@@ -1312,6 +1312,40 @@
     return Void();
 }
 
+Return<int32_t> AGM::ipc_agm_session_write_datapath_params(uint32_t session_id,
+                                                const hidl_vec<AgmBuff>& buff_hidl)
+{
+    int32_t ret = -EINVAL;
+    struct agm_buff buf;
+    uint32_t bufSize;
+    buf.addr = nullptr;
+    buf.metadata = nullptr;
+
+    bufSize = buff_hidl.data()->size;
+    buf.addr = (uint8_t *)calloc(1, bufSize);
+    if (!buf.addr) {
+        ALOGE("%s: failed to calloc", __func__);
+        goto exit;
+    }
+    buf.size = (size_t)bufSize;
+    buf.timestamp = buff_hidl.data()->timestamp;
+    buf.flags = buff_hidl.data()->flags;
+
+    if (bufSize)
+        memcpy(buf.addr, buff_hidl.data()->buffer.data(), bufSize);
+    else {
+        ALOGE("%s: buf size is null", __func__);
+        goto exit;
+    }
+    ALOGV("%s: sz %d", __func__, bufSize);
+    ret = agm_session_write_datapath_params(session_id, &buf);
+
+exit:
+    if (buf.addr != nullptr)
+        free(buf.addr);
+    return ret;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace AGMIPC
diff --git a/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal b/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
index 75cfea3..02b39a6 100644
--- a/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
+++ b/ipc/HwBinders/interfaces/AGMIPC/1.0/IAGM.hal
@@ -127,4 +127,7 @@
     ipc_agm_get_group_aif_info_list(uint32_t num_groups)
                     generates (int32_t ret, vec<AifInfo> aif_group_list_ret,
                                uint32_t num_groups_ret);
+    ipc_agm_session_write_datapath_params(uint32_t session_id, vec<AgmBuff> buff)
+                    generates (int32_t ret);
+
 };
diff --git a/ipc/HwBinders/interfaces/AGMIPC/current.txt b/ipc/HwBinders/interfaces/AGMIPC/current.txt
new file mode 100644
index 0000000..d178fa3
--- /dev/null
+++ b/ipc/HwBinders/interfaces/AGMIPC/current.txt
@@ -0,0 +1,4 @@
+# Hash for vendor.qti.hardware.AGMIPC@1.0 package
+14e9644e8ff286a5d00825c97d46056b12af94c103f81976a4c3b71fc681909d vendor.qti.hardware.AGMIPC@1.0::types
+7c4ef018df8bcf680fc3ba4c740b9d34873ca0495955e412a4312ea6f6715e76 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 a66ed88..22553d2 100644
--- a/plugins/tinyalsa/src/agm_mixer_plugin.c
+++ b/plugins/tinyalsa/src/agm_mixer_plugin.c
@@ -118,7 +118,7 @@
     "event",
     "setCalibration",
     "getParam",
-    "getBufInfo"
+    "getBufInfo",
     /* Add new ones below, be sure to update enum as well */
 };
 
@@ -138,10 +138,12 @@
 
 enum {
     PCM_RX_CTL_NAME_SIDETONE = 0,
+    PCM_RX_CTL_NAME_DATAPATH_PARAMS,
 };
 /* strings should be at the index as per the enum */
 static char *amp_pcm_rx_ctl_names[] = {
     "sidetone",
+    "datapathParams",
 };
 
 struct amp_dev_info {
@@ -1457,6 +1459,29 @@
     return 0;
 }
 
+static int amp_pcm_write_datapath_params_get(struct mixer_plugin *plugin __unused,
+                struct snd_control *ctl __unused, struct snd_ctl_elem_value *ev __unused)
+{
+    return 0;
+}
+
+static int amp_pcm_write_datapath_params_put(struct mixer_plugin *plugin,
+                struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+    struct agm_buff *buffer;
+    int pcm_idx = ctl->private_value;
+    int ret;
+
+    AGM_LOGV("%s: enter sesid:%d ev pointer %p\n", __func__, pcm_idx, ev->value.bytes.data);
+    buffer = (struct agm_buff *)ev->value.bytes.data;
+
+    ret = agm_session_write_datapath_params(pcm_idx, buffer);
+    if (ret)
+        AGM_LOGE("%s: write_with_metadata failed, err %d\n",
+               __func__, ret);
+    return ret;
+}
+
 /* 512 max bytes for non-tlv controls, reserving 16 for future use */
 static struct snd_value_bytes pcm_event_bytes =
     SND_VALUE_BYTES(512 - 16);
@@ -1480,6 +1505,8 @@
     SND_VALUE_TLV_BYTES(128 * 1024, amp_pcm_get_param_get, amp_pcm_get_param_put);
 static struct snd_value_bytes pcm_buf_info_bytes =
     SND_VALUE_BYTES(512 - 16);
+static struct snd_value_bytes pcm_write_datapath_params_bytes =
+    SND_VALUE_BYTES(512 - 16);
 
 static struct snd_value_int media_fmt_int =
     SND_VALUE_INTEGER(4, 0, 384000, 1);
@@ -1696,6 +1723,20 @@
             pval, pdata);
 }
 
+static void amp_create_pcm_write_with_metadata_ctl(struct amp_priv *amp_priv,
+    char *name, int ctl_idx, int pval, void *pdata)
+{
+    struct snd_control *ctl = AMP_PRIV_GET_CTL_PTR(amp_priv, ctl_idx);
+    char *ctl_name = AMP_PRIV_GET_CTL_NAME_PTR(amp_priv, ctl_idx);
+
+    snprintf(ctl_name, AIF_NAME_MAX_LEN + 16, "%s %s",
+            name, amp_pcm_rx_ctl_names[PCM_RX_CTL_NAME_DATAPATH_PARAMS]);
+
+    INIT_SND_CONTROL_BYTES(ctl, ctl_name, amp_pcm_write_datapath_params_get,
+            amp_pcm_write_datapath_params_put, pcm_write_datapath_params_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)
@@ -1870,6 +1911,8 @@
         /* Create sidetone control, enum values are TX backends */
         amp_create_pcm_sidetone_ctl(amp_priv, name, (*ctl_idx)++,
                         &be_tx_adi->dev_enum, idx, rx_adi);
+        amp_create_pcm_write_with_metadata_ctl(amp_priv, name, (*ctl_idx)++,
+                        idx, rx_adi);
     }
 
     return 0;
diff --git a/service/inc/private/agm/graph.h b/service/inc/private/agm/graph.h
index 9cea7d7..3564392 100644
--- a/service/inc/private/agm/graph.h
+++ b/service/inc/private/agm/graph.h
@@ -416,4 +416,6 @@
  */
 
 int32_t graph_enable_acdb_persistence(uint8_t enable_flag);
+
+int graph_set_media_config_datapath(struct graph_obj *gph_obj);
 #endif /*GPH_OBJ_H*/
diff --git a/service/inc/public/agm/agm_api.h b/service/inc/public/agm/agm_api.h
index e23d8cf..99fb5f3 100644
--- a/service/inc/public/agm/agm_api.h
+++ b/service/inc/public/agm/agm_api.h
@@ -60,6 +60,9 @@
 /**< true if buffer is marked as EOF */
 #define AGM_BUFF_FLAG_EOF 0x4
 
+/**< true if buffer contains media format */
+#define AGM_BUFF_FLAG_MEDIA_FORMAT 0x8
+
 /*Enables SRCM event in metadata on the read path*/
 #define AGM_SESSION_FLAG_INBAND_SRCM 0x1
 
@@ -1094,6 +1097,16 @@
 int agm_aif_group_set_media_config(uint32_t aif_group_id,
                           struct agm_group_media_config *media_config);
 
+/**
+ * \brief Write buffers containing codec params to session on datapath
+ *
+ * \param[in] session_id - Valid audio session id
+ * \param[in] buff: agm_buffer where data will be copied from
+ *
+ * \return 0 on success, error code otherwise
+ */
+int agm_session_write_datapath_params(uint32_t session_id, struct agm_buff *buff);
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/service/src/agm.c b/service/src/agm.c
index c6276de..2dbb010 100644
--- a/service/src/agm.c
+++ b/service/src/agm.c
@@ -848,3 +848,19 @@
                                             in_buffer_config,
                                             out_buffer_config);
 }
+
+int agm_session_write_datapath_params(uint32_t session_id, struct agm_buff *buff)
+{
+    struct session_obj *obj = NULL;
+    int ret = 0;
+    size_t consumed_size = 0;
+
+    ret = session_obj_get(session_id, &obj);
+    if (ret) {
+        AGM_LOGE("Error:%d retrieving session obj with session id=%d\n",
+                                                 ret, session_id);
+        return ret;
+    }
+
+    return session_obj_write_with_metadata(obj, buff, &consumed_size);
+}
diff --git a/service/src/graph.c b/service/src/graph.c
index 63f31a7..fb988b4 100644
--- a/service/src/graph.c
+++ b/service/src/graph.c
@@ -1934,3 +1934,49 @@
 {
     return gsl_enable_acdb_persistence(enable_flag);
 }
+
+static bool is_media_config_needed_on_datapath(enum agm_media_format format)
+{
+    bool ret = false;
+
+    switch (format) {
+    case AGM_FORMAT_MP3:
+    case AGM_FORMAT_AAC:
+    case AGM_FORMAT_FLAC:
+    case AGM_FORMAT_ALAC:
+    case AGM_FORMAT_APE:
+    case AGM_FORMAT_WMASTD:
+    case AGM_FORMAT_WMAPRO:
+        ret = true;
+        break;
+    default:
+        AGM_LOGE("Entered default, format %d", format);
+        break;
+    }
+    return ret;
+}
+
+int graph_set_media_config_datapath(struct graph_obj *graph_obj)
+{
+    int ret = 0;
+    struct listnode *node = NULL;
+    module_info_t *mod = NULL;
+    struct session_obj *sess_obj = graph_obj->sess_obj;
+
+    if (is_media_config_needed_on_datapath(sess_obj->out_media_config.format)) {
+        list_for_each(node, &graph_obj->tagged_mod_list) {
+            mod = node_to_item(node, module_info_t, list);
+            if (mod->tag == STREAM_INPUT_MEDIA_FORMAT) {
+                ret = mod->configure(mod, graph_obj);
+                if (ret != 0) {
+                    AGM_LOGE("Module configuration for miid %x, mid %x, tag %x, failed:%d\n",
+                              mod->miid, mod->mid, mod->tag, ret);
+                }
+            }
+        }
+    } else {
+        AGM_LOGD("Media configuration on dataptah is not needed for format %d",
+                 sess_obj->out_media_config.format);
+    }
+    return ret;
+}
diff --git a/service/src/graph_module.c b/service/src/graph_module.c
index fb8dc1f..5592d2b 100644
--- a/service/src/graph_module.c
+++ b/service/src/graph_module.c
@@ -1354,6 +1354,71 @@
     return ret;
 }
 
+static int configure_compress_shared_mem_ep_datapath(struct module_info *mod,
+                            struct graph_obj *graph_obj)
+{
+    int ret = 0;
+    struct session_obj *sess_obj = graph_obj->sess_obj;
+    struct media_format_t *media_fmt_hdr;
+    uint8_t *payload = NULL;
+    size_t payload_size = 0, real_fmt_id = 0;
+    struct agm_buff buffer = {0};
+    size_t consumed_size = 0;
+
+    if (is_format_bypassed(sess_obj->out_media_config.format) ||
+        sess_obj->stream_config.sess_mode == AGM_SESSION_NON_TUNNEL) {
+        AGM_LOGI("bypass shared mem ep config for format %x or sess_mode %d",
+                 sess_obj->out_media_config.format, sess_obj->stream_config.sess_mode);
+        return 0;
+    }
+
+    ret = get_media_fmt_id_and_size(sess_obj->out_media_config.format,
+                                    &payload_size, &real_fmt_id);
+    if (ret) {
+        AGM_LOGD("module is not configured for format: %d\n",
+                 sess_obj->out_media_config.format);
+        /* If ret is non-zero then shared memory module would be
+         * configured by client so return from here.
+         */
+        return 0;
+    }
+
+    payload_size = payload_size - sizeof(struct apm_module_param_data_t);
+    media_fmt_hdr = (struct media_format_t *) calloc(1, (size_t)payload_size);
+    if (!media_fmt_hdr) {
+        AGM_LOGE("Not enough memory for payload\n");
+        return -ENOMEM;
+    }
+
+
+    buffer.timestamp = 0x0;
+    buffer.flags = AGM_BUFF_FLAG_MEDIA_FORMAT;
+    buffer.size = payload_size;
+    buffer.addr = (uint8_t *)media_fmt_hdr;
+
+    ret =  set_compressed_media_format(sess_obj->out_media_config.format,
+                             media_fmt_hdr, sess_obj);
+    if (ret) {
+        AGM_LOGD("Shared mem EP is not configured for format: %d\n",
+                 sess_obj->out_media_config.format);
+        /* If ret is non-zero then shared memory module would be
+         * configured by client so return from here.
+         */
+        goto free_payload;
+    }
+
+    ret = graph_write(graph_obj, &buffer, &consumed_size);
+    if (ret != 0) {
+        ret = ar_err_get_lnx_err_code(ret);
+        AGM_LOGE("custom_config command for module %d failed with error %d",
+                      mod->tag, ret);
+    }
+
+free_payload:
+    free(media_fmt_hdr);
+    return ret;
+}
+
 int configure_pcm_shared_mem_ep(struct module_info *mod,
                             struct graph_obj *graph_obj)
 {
@@ -1459,8 +1524,12 @@
      */
     if (is_format_pcm(sess_obj->out_media_config.format))
         ret = configure_pcm_shared_mem_ep(mod, graph_obj);
-    else
-        ret = configure_compress_shared_mem_ep(mod, graph_obj);
+    else {
+        if (graph_obj->state != STARTED)
+            ret = configure_compress_shared_mem_ep(mod, graph_obj);
+        else
+            ret = configure_compress_shared_mem_ep_datapath(mod, graph_obj);
+    }
 
     if (ret)
         return ret;
diff --git a/service/src/session_obj.c b/service/src/session_obj.c
index 8407baa..303aad4 100644
--- a/service/src/session_obj.c
+++ b/service/src/session_obj.c
@@ -1996,7 +1996,7 @@
                  struct agm_media_config *media_config,
                  struct agm_buffer_config *buffer_config)
 {
-
+    int ret = 0;
     pthread_mutex_lock(&sess_obj->lock);
 
     sess_obj->stream_config = *stream_config;
@@ -2009,10 +2009,15 @@
         /*Playback session config*/
         sess_obj->out_media_config = *media_config;
         sess_obj->out_buffer_config = *buffer_config;
+        if (sess_obj->state == SESSION_STARTED) {
+            ret = graph_set_media_config_datapath(sess_obj->graph);
+            if (ret < 0)
+                AGM_LOGE("Failed to set media config on datapath ret %d", ret);
+        }
     }
 
     pthread_mutex_unlock(&sess_obj->lock);
-    return 0;
+    return ret;
 }
 
 int session_obj_prepare(struct session_obj *sess_obj)