audio: hal: Add support for registering adsp events

Add support for AHAL clients to register for adsp events
and receive event callbacks when an event is triggered by adsp.

CRs-Fixed: 2023812
Change-Id: Ie22efee6e859c3d819ed3939e164cb7baebab71b
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 5b88274..58b6e08 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -42,6 +42,20 @@
 #define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
 #define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
 #define QAF_DEFAULT_PASSTHROUGH_HANDLE 1003
+
+#define MAX_QAF_OUT 4
+
+#define QAF_OUT_TRANSCODE_PASSTHROUGH 0 /* transcode passthrough via MS12 */
+#define QAF_DEFAULT_PASSTHROUGH 1 /* passthrough without MS12 */
+#define QAF_OUT_OFFLOAD_MCH 2
+#define QAF_OUT_OFFLOAD 3
+
+#define MAX_QAF_IN 3
+
+#define QAF_IN_MAIN 0
+#define QAF_IN_ASSOC 1
+#define QAF_IN_PCM 2
+
 /*
  * MS12 Latency (Input Buffer Processing latency)+
  * Kernel Latency (Calculated based on the available offload buffer size) +
@@ -134,6 +148,13 @@
 FILE *fp_output_writer_hdmi = NULL;
 #endif
 
+struct qaf_adsp_hdlr_config_state {
+    struct audio_adsp_event event_params;
+    /* For holding client audio_adsp_event payload */
+    uint8_t event_payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN];
+    bool adsp_hdlr_config_valid;
+};
+
 struct qaf {
     struct audio_device *adev;
     audio_session_handle_t session_handle;
@@ -155,12 +176,12 @@
     void (*qaf_register_event_callback)(audio_session_handle_t session_handle, void *priv_data,
           notify_event_callback_t event_callback, audio_event_id_t event_id);
     pthread_mutex_t lock;
-    struct stream_out *stream_drain_main;
-    struct stream_out *stream_drain_assoc;
-    struct stream_out *qaf_compr_offload_out;
-    struct stream_out *qaf_compr_offload_out_mch;
-    struct stream_out *qaf_compr_passthrough_out;
-    struct stream_out *qaf_passthrough_out;
+
+    struct stream_out *stream[MAX_QAF_IN];
+    struct stream_out *qaf_out[MAX_QAF_OUT];
+
+    struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_IN];
+
     void *bt_hdl;
     bool hdmi_connect;
     int passthrough_enabled;
@@ -175,6 +196,16 @@
 static struct qaf *qaf_mod = NULL;
 static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair) __attribute__ ((unused));
 
+/* find index of input stream */
+static int get_input_stream_index(struct stream_out *out)
+{   int count = -1;
+    for (count = 0; count < MAX_QAF_IN; count++) {
+        if (out == qaf_mod->stream[count])
+            break;
+    }
+    return count;
+}
+
 static bool is_ms12_format(audio_format_t format)
 {
     if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)
@@ -225,7 +256,7 @@
 {
     struct stream_out *out = (struct stream_out *)cookie;
 
-    out->offload_callback(event, NULL, out->offload_cookie);
+    out->client_callback(event, NULL, out->client_cookie);
     return 0;
 }
 
@@ -235,18 +266,18 @@
 
     ALOGV("%s %d", __func__, __LINE__);
     if ((handle_id == QAF_DEFAULT_PASSTHROUGH_HANDLE) &&
-        (NULL == qaf_mod->qaf_passthrough_out)) {
+        (NULL == qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH])) {
         pthread_mutex_lock(&qaf_mod->lock);
         lock_output_stream(out);
         ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, handle_id, devices,
-                                         flags, config, (struct audio_stream_out **) &(qaf_mod->qaf_passthrough_out), NULL);
+                                         flags, config, (struct audio_stream_out **) &(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), NULL);
         if (ret < 0) {
             pthread_mutex_unlock(&out->lock);
             pthread_mutex_unlock(&qaf_mod->lock);
             ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
             return -EINVAL;
         }
-        qaf_mod->qaf_passthrough_out->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, (stream_callback_t) qaf_out_callback, out);
+        qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH], (stream_callback_t) qaf_out_callback, out);
         pthread_mutex_unlock(&out->lock);
         pthread_mutex_unlock(&qaf_mod->lock);
     }
@@ -288,12 +319,12 @@
           stream, out->usecase, use_case_table[out->usecase]);
 
     lock_output_stream(out);
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
         if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
             pthread_mutex_unlock(&out->lock);
             return status;
         }
-        status = qaf_mod->qaf_passthrough_out->stream.common.standby((struct audio_stream *) qaf_mod->qaf_passthrough_out);
+        status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.common.standby((struct audio_stream *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
         if (!out->standby) {
             out->standby = true;
         }
@@ -333,15 +364,15 @@
 static int qaf_out_set_volume(struct audio_stream_out *stream __unused, float left,
                           float right)
 {
-    /* For ms12 formats, qaf_mod->qaf_compr_offload_out is allocated during the first
+    /* For ms12 formats, qaf_mod->qaf_out[QAF_OUT_OFFLOAD] is allocated during the first
      * call of notify_event_callback(). Therefore, the volume levels set during session
      * open have to be cached and applied later */
     qaf_mod->vol_left = left;
     qaf_mod->vol_right = right;
 
-    if (qaf_mod->qaf_compr_offload_out != NULL) {
-        return qaf_mod->qaf_compr_offload_out->stream.set_volume(
-            (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out, left, right);
+    if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
+        return qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+            (struct audio_stream_out *)qaf_mod->qaf_out[QAF_OUT_OFFLOAD], left, right);
     }
     return -ENOSYS;
 }
@@ -390,14 +421,14 @@
     ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
     lock_output_stream(out);
 
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
         if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
             ALOGD(" %s : Drop data as compress passthrough session is going on", __func__);
             usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
                             out->stream.common.get_sample_rate(&out->stream.common));
             goto exit;
         }
-        ret = qaf_mod->qaf_passthrough_out->stream.write((struct audio_stream_out *)(qaf_mod->qaf_passthrough_out), buffer, bytes);
+        ret = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.write((struct audio_stream_out *)(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), buffer, bytes);
         pthread_mutex_unlock(&out->lock);
         return ret;
     }
@@ -498,15 +529,15 @@
         kvpairs = NULL;
     }
     // MS12 Latency + Kernel Latency + Dsp Latency
-    if (qaf_mod->qaf_compr_offload_out != NULL) {
-        out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * qaf_get_pcm_offload_buffer_size(&qaf_mod->qaf_compr_offload_out->info) \
-                                       /(popcount(qaf_mod->qaf_compr_offload_out->channel_mask) * sizeof(short))) \
-                                       +((platform_render_latency(qaf_mod->qaf_compr_offload_out->usecase) * qaf_mod->qaf_compr_offload_out->sample_rate) / 1000000LL);
+    if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
+        out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * qaf_get_pcm_offload_buffer_size(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info) \
+                                       /(popcount(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->channel_mask) * sizeof(short))) \
+                                       +((platform_render_latency(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->usecase) * qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->sample_rate) / 1000000LL);
     } else if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
         out->platform_latency = latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
-    } else if (NULL != qaf_mod->qaf_compr_passthrough_out) {
-        out->platform_latency = latency + ((qaf_mod->qaf_compr_passthrough_out->format == AUDIO_FORMAT_AC3) ? TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DD_ENCODER_OUTPUT_SIZE) : TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DDP_ENCODER_OUTPUT_SIZE)) \
-                                        + (COMPRESS_OFFLOAD_PLAYBACK_LATENCY *  qaf_mod->qaf_compr_passthrough_out->sample_rate/1000);
+    } else if (NULL != qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+        out->platform_latency = latency + ((qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->format == AUDIO_FORMAT_AC3) ? TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DD_ENCODER_OUTPUT_SIZE) : TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DDP_ENCODER_OUTPUT_SIZE)) \
+                                        + (COMPRESS_OFFLOAD_PLAYBACK_LATENCY *  qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate/1000);
     }
 
     if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
@@ -546,8 +577,8 @@
     int ret = -1;
     lock_output_stream(out);
 
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        ret = qaf_mod->qaf_passthrough_out->stream.get_presentation_position((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, frames, timestamp);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+        ret = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.get_presentation_position((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH], frames, timestamp);
         pthread_mutex_unlock(&out->lock);
         return ret;
     }
@@ -574,8 +605,8 @@
     ALOGE("%s", __func__);
 
     lock_output_stream(out);
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        status = qaf_mod->qaf_passthrough_out->stream.pause((struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+        status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.pause((struct audio_stream_out *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
         out->offload_state = OFFLOAD_STATE_PAUSED;
         pthread_mutex_unlock(&out->lock);
         return status;
@@ -595,26 +626,18 @@
                                           out->qaf_stream_handle, out->format);
 
     lock_output_stream(out);
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        status = qaf_mod->qaf_passthrough_out->stream.drain(
-               (struct audio_stream_out*)(qaf_mod->qaf_passthrough_out), type);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+        status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.drain(
+               (struct audio_stream_out*)(qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]), type);
         pthread_mutex_unlock(&out->lock);
         return status;
     }
 
 
-    if (out->offload_callback && out->qaf_stream_handle) {
+    if (out->client_callback && out->qaf_stream_handle)
         /* Stream stop will trigger EOS and on EOS_EVENT received
            from callback DRAIN_READY command is sent */
         status = audio_extn_qaf_stream_stop(out);
-        if (out->format != AUDIO_FORMAT_PCM_16_BIT) {
-            if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
-                qaf_mod->stream_drain_assoc = out;
-            } else {
-                qaf_mod->stream_drain_main = out;
-            }
-        }
-    }
     pthread_mutex_unlock(&out->lock);
     return status;
 }
@@ -635,8 +658,8 @@
     int status = -ENOSYS;
 
     lock_output_stream(out);
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        status = qaf_mod->qaf_passthrough_out->stream.flush((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+        status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.flush((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
         out->offload_state = OFFLOAD_STATE_IDLE;
         pthread_mutex_unlock(&out->lock);
         return status;
@@ -655,8 +678,8 @@
 
 
     lock_output_stream(out);
-    if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        latency = qaf_mod->qaf_passthrough_out->stream.get_latency((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+        latency = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.get_latency((struct audio_stream_out *)qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
         ALOGV("%s: latency = %u", __FUNCTION__, latency);
         pthread_mutex_unlock(&out->lock);
         return latency;
@@ -709,31 +732,31 @@
         ALOGVV("Device id %x %s %d, bytes to written %d",
                                                device, __func__,__LINE__, size);
 
-        if ((qaf_mod->qaf_passthrough_out != NULL) && qaf_mod->hdmi_connect) {
+        if ((qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] != NULL) && qaf_mod->hdmi_connect) {
             pthread_mutex_lock(&qaf_module->lock);
-            if (qaf_mod->qaf_compr_offload_out != NULL) {
+            if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL) {
                 adev_close_output_stream(
                   (struct audio_hw_device *) qaf_mod->adev,
-                  (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
-                qaf_mod->qaf_compr_offload_out = NULL;
+                  (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
             }
-            if (qaf_mod->qaf_compr_offload_out_mch) {
+            if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
                 adev_close_output_stream(
                     (struct audio_hw_device *) qaf_mod->adev,
                     (struct audio_stream_out *)
-                                          (qaf_mod->qaf_compr_offload_out_mch));
-                qaf_mod->qaf_compr_offload_out_mch = NULL;
+                                          (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
             }
             pthread_mutex_unlock(&qaf_module->lock);
             ALOGV("%s %d DROPPING DATA", __func__, __LINE__);
             return;
         } else {
-            if (qaf_mod->qaf_passthrough_out != NULL) {
+            if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] != NULL) {
                 pthread_mutex_lock(&qaf_module->lock);
                 adev_close_output_stream(
                     (struct audio_hw_device *) qaf_mod->adev,
-                    (struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
-                qaf_mod->qaf_passthrough_out = NULL;
+                    (struct audio_stream_out *) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
+                qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
                 qaf_mod->main_output_active = false;
                 pthread_mutex_unlock(&qaf_module->lock);
             }
@@ -744,17 +767,17 @@
             (device ==
                    (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
 
-            if (NULL == qaf_mod->qaf_compr_passthrough_out &&
+            if (NULL == qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] &&
                                              qaf_mod->hdmi_connect) {
                 struct audio_config config;
                 audio_devices_t devices;
 
-                if (qaf_mod->qaf_compr_offload_out_mch) {
+                if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
                     adev_close_output_stream(
                         (struct audio_hw_device *) qaf_mod->adev,
                         (struct audio_stream_out *)
-                        (qaf_mod->qaf_compr_offload_out_mch));
-                    qaf_mod->qaf_compr_offload_out_mch = NULL;
+                        (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
                 }
 
                 config.sample_rate = config.offload_info.sample_rate =
@@ -783,30 +806,30 @@
                           QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
                           flags, &config,
                           (struct audio_stream_out **)
-                          &(qaf_mod->qaf_compr_passthrough_out), NULL);
+                          &(qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]), NULL);
                 if (ret < 0) {
                     ALOGE("%s: adev_open_output_stream failed with ret = %d!",
                           __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
-                qaf_mod->qaf_compr_passthrough_out->compr_config.fragments =
+                qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
                                                  COMPRESS_OFFLOAD_NUM_FRAGMENTS;
             }
 
             if (!qaf_mod->passthrough_enabled)
                 qaf_mod->passthrough_enabled = 1;
 
-            if (qaf_mod->qaf_compr_passthrough_out) {
-                ret = qaf_mod->qaf_compr_passthrough_out->stream.write(
+            if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+                ret = qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
                           (struct audio_stream_out *)
-                          qaf_mod->qaf_compr_passthrough_out, buf, size);
+                          qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH], buf, size);
             }
         } else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                    ((qaf_mod->hdmi_connect) &&
-                   (qaf_mod->qaf_passthrough_out == NULL) &&
+                   (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL) &&
                    (qaf_mod->hdmi_sink_channels > 2))) {
-            if (NULL == qaf_mod->qaf_compr_offload_out_mch) {
+            if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
                 struct audio_config config;
                 audio_devices_t devices;
 
@@ -831,47 +854,78 @@
                 }
                 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
                 flags = (AUDIO_OUTPUT_FLAG_DIRECT|
-                         AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
                          AUDIO_OUTPUT_FLAG_DIRECT_PCM);
 
                 ret = adev_open_output_stream(
                           (struct audio_hw_device *) qaf_mod->adev,
                           QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices, flags,
                           &config, (struct audio_stream_out **)
-                          &(qaf_mod->qaf_compr_offload_out_mch), NULL);
+                          &(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]), NULL);
                 if (ret < 0) {
                     ALOGE("%s: adev_open_output_stream failed with ret = %d!",
                           __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
-                qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments =
+                if (qaf_mod->stream[QAF_IN_MAIN] && qaf_mod->stream[QAF_IN_MAIN]->client_callback != NULL)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback((struct audio_stream_out *)
+                                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+                                 qaf_mod->stream[QAF_IN_MAIN]->client_callback,
+                                 qaf_mod->stream[QAF_IN_MAIN]->client_cookie);
+                else if (qaf_mod->stream[QAF_IN_PCM] && qaf_mod->stream[QAF_IN_PCM]->client_callback != NULL)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback((struct audio_stream_out *)
+                                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+                                 qaf_mod->stream[QAF_IN_PCM]->client_callback,
+                                 qaf_mod->stream[QAF_IN_PCM]->client_cookie);
+
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
                                                  COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-                qaf_mod->qaf_compr_offload_out_mch->compr_config.fragment_size =
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
                           qaf_get_pcm_offload_buffer_size(&config.offload_info);
+
+                int index = -1;
+                if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
+                        index = (int)QAF_IN_MAIN;
+                else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
+                    index = (int)QAF_IN_PCM;
+                if (index >= 0) {
+                    if(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->standby)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+                          (struct audio_stream_out *)
+                          qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
+
+                    lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]);
+                    ret = audio_extn_out_set_param_data(
+                                qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH],
+                                AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+                                (audio_extn_param_payload *)
+                                &qaf_mod->adsp_hdlr_config[index].event_params);
+                    pthread_mutex_unlock(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->lock);
+
+                }
             }
 
-            if (qaf_mod->qaf_compr_offload_out_mch) {
-                ret = qaf_mod->qaf_compr_offload_out_mch->stream.write(
+            if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
+                ret = qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
                           (struct audio_stream_out *)
-                          qaf_mod->qaf_compr_offload_out_mch, buf, size);
+                          qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH], buf, size);
             }
         } else {
             bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
             if (bt_stream != NULL) {
-                if (qaf_mod->qaf_compr_offload_out) {
+                if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]) {
                     adev_close_output_stream(
                         (struct audio_hw_device *) qaf_mod->adev,
                         (struct audio_stream_out *)
-                        (qaf_mod->qaf_compr_offload_out));
-                    qaf_mod->qaf_compr_offload_out = NULL;
+                        (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
                 }
 
                 audio_extn_bt_hal_out_write(qaf_mod->bt_hdl, buf, size);
             }
 
-            if (NULL == qaf_mod->qaf_compr_offload_out && bt_stream == NULL &&
-                qaf_mod->qaf_passthrough_out == NULL) {
+            if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD] && bt_stream == NULL &&
+                qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL) {
                 struct audio_config config;
                 audio_devices_t devices;
 
@@ -884,57 +938,91 @@
                 config.format = AUDIO_FORMAT_PCM_16_BIT;
                 config.offload_info.channel_mask = config.channel_mask =
                                                        AUDIO_CHANNEL_OUT_STEREO;
-                devices = AUDIO_DEVICE_OUT_SPEAKER;
+                 if(qaf_mod->stream[QAF_IN_MAIN])
+                    devices = qaf_mod->stream[QAF_IN_MAIN]->devices;
+                else
+                    devices = qaf_mod->stream[QAF_IN_PCM]->devices;
                 flags = (AUDIO_OUTPUT_FLAG_DIRECT|
-                         AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
                          AUDIO_OUTPUT_FLAG_DIRECT_PCM);
 
+
                 /* TODO:: Need to Propagate errors to framework */
                 ret = adev_open_output_stream(
                           (struct audio_hw_device *) qaf_mod->adev,
                           QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
                           flags, &config,
                           (struct audio_stream_out **)
-                          &(qaf_mod->qaf_compr_offload_out), NULL);
+                          &(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]), NULL);
                 if (ret < 0) {
                     ALOGE("%s: adev_open_output_stream failed with ret = %d!",
                           __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
+                if (qaf_mod->stream[QAF_IN_MAIN] && qaf_mod->stream[QAF_IN_MAIN]->client_callback != NULL)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_callback((struct audio_stream_out *)
+                                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+                                 qaf_mod->stream[QAF_IN_MAIN]->client_callback,
+                                 qaf_mod->stream[QAF_IN_MAIN]->client_cookie);
+                else if (qaf_mod->stream[QAF_IN_PCM] && qaf_mod->stream[QAF_IN_PCM]->client_callback != NULL)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_callback((struct audio_stream_out *)
+                                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+                                 qaf_mod->stream[QAF_IN_PCM]->client_callback,
+                                 qaf_mod->stream[QAF_IN_PCM]->client_cookie);
 
-                qaf_mod->qaf_compr_offload_out->compr_config.fragments =
+
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
                                                  COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-                qaf_mod->qaf_compr_offload_out->compr_config.fragment_size =
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
                           qaf_get_pcm_offload_buffer_size(&config.offload_info);
-                qaf_mod->qaf_compr_offload_out->info.channel_mask =
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.channel_mask =
                                                config.offload_info.channel_mask;
-                qaf_mod->qaf_compr_offload_out->info.format =
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.format =
                                                config.offload_info.format;
-                qaf_mod->qaf_compr_offload_out->info.sample_rate =
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.sample_rate =
                                                config.offload_info.sample_rate;
-                qaf_mod->qaf_compr_offload_out->stream.set_volume(
-                      (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out,
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+                      (struct audio_stream_out *)qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
                       qaf_mod->vol_left, qaf_mod->vol_right);
+
+                int index = -1;
+                if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
+                    index = (int)QAF_IN_MAIN;
+                else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
+                    index = (int)QAF_IN_PCM;
+                if (index >= 0) {
+                    if(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->standby)
+                        qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.write(
+                          (struct audio_stream_out *)
+                          qaf_mod->qaf_out[QAF_OUT_OFFLOAD], NULL, 0);
+
+                    lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]);
+                    ret = audio_extn_out_set_param_data(
+                                qaf_mod->qaf_out[QAF_OUT_OFFLOAD],
+                                AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+                                (audio_extn_param_payload *)
+                                &qaf_mod->adsp_hdlr_config[index].event_params);
+                    pthread_mutex_unlock(&qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->lock);
+                }
             }
 
             if (!qaf_mod->hdmi_connect &&
-                (qaf_mod->qaf_compr_passthrough_out ||
-                 qaf_mod->qaf_compr_offload_out_mch)) {
+                (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] ||
+                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH])) {
                 qaf_mod->passthrough_enabled = 0;
-                if (qaf_mod->qaf_compr_passthrough_out) {
+                if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
                     adev_close_output_stream(
                         (struct audio_hw_device *) qaf_mod->adev,
                         (struct audio_stream_out *)
-                             (qaf_mod->qaf_compr_passthrough_out));
-                    qaf_mod->qaf_compr_passthrough_out = NULL;
+                             (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
+                    qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
                 }
-                if (qaf_mod->qaf_compr_offload_out_mch) {
+                if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
                     adev_close_output_stream(
                         (struct audio_hw_device *) qaf_mod->adev,
                         (struct audio_stream_out *)
-                        (qaf_mod->qaf_compr_offload_out_mch));
-                    qaf_mod->qaf_compr_offload_out_mch = NULL;
+                        (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]));
+                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
                 }
             }
 
@@ -942,10 +1030,10 @@
              * TODO:: Since this is mixed data,
              * need to identify to which stream the error should be sent
              */
-            if (bt_stream == NULL && qaf_mod->qaf_compr_offload_out) {
-                ret = qaf_mod->qaf_compr_offload_out->stream.write(
+            if (bt_stream == NULL && qaf_mod->qaf_out[QAF_OUT_OFFLOAD]) {
+                ret = qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.write(
                           (struct audio_stream_out *)
-                          qaf_mod->qaf_compr_offload_out, buf, size);
+                          qaf_mod->qaf_out[QAF_OUT_OFFLOAD], buf, size);
             }
         }
 
@@ -955,8 +1043,8 @@
                || event_id == AUDIO_EOS_MAIN_AAC_EVENT
                || event_id == AUDIO_EOS_MAIN_AC4_EVENT
                || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
-        struct stream_out *out = qaf_module->stream_drain_main;
-        struct stream_out *out_assoc = qaf_module->stream_drain_assoc;
+        struct stream_out *out = qaf_module->stream[QAF_IN_MAIN];
+        struct stream_out *out_assoc = qaf_module->stream[QAF_IN_ASSOC];
 
         /**
          * TODO:: Only DD/DDP Associate Eos is handled, need to add support
@@ -964,16 +1052,15 @@
          */
         if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT && out_assoc != NULL) {
             lock_output_stream(out_assoc);
-            out_assoc->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
-                                  out_assoc->offload_cookie);
+            out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
+                                  out_assoc->client_cookie);
             pthread_mutex_unlock(&out_assoc->lock);
-            qaf_module->stream_drain_assoc = NULL;
+            qaf_module->stream[QAF_IN_ASSOC] = NULL;
         } else if (out != NULL) {
             lock_output_stream(out);
-            out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
-                                  out->offload_cookie);
+            out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
             pthread_mutex_unlock(&out->lock);
-            qaf_module->stream_drain_main = NULL;
+            qaf_module->stream[QAF_IN_MAIN] = NULL;
             ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
         }
     }
@@ -1055,6 +1142,7 @@
     /* TODO to send appropriated flags when support for system tones is added */
     if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
         status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_SYSTEM_TONE);
+        qaf_mod->stream[QAF_IN_PCM] = out;
     } else if (input_config.format == AUDIO_FORMAT_AC3 ||
                input_config.format == AUDIO_FORMAT_E_AC3 ||
                input_config.format == AUDIO_FORMAT_AC4 ||
@@ -1067,12 +1155,14 @@
                     ALOGV("%s %d Open stream for Input with both Main and Associated stream contents with flag [%x] and stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
                     qaf_mod->main_output_active = true;
                     qaf_mod->assoc_output_active = true;
+                    qaf_mod->stream[QAF_IN_MAIN] = out;
                 }
             } else if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
                 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
                 if (status == 0) {
                     ALOGV("%s %d Open stream for Input with only Main flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
                     qaf_mod->main_output_active = true;
+                    qaf_mod->stream[QAF_IN_MAIN] = out;
                 }
             } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
                 ALOGE("%s %d Error main input is not active", __func__, __LINE__);
@@ -1082,6 +1172,7 @@
                 if (status == 0) {
                     ALOGV("%s %d Open stream for Local playback with flag [%x] stream handle [%p] ", __func__, __LINE__, flags, out->qaf_stream_handle);
                     qaf_mod->main_output_active = true;
+                    qaf_mod->stream[QAF_IN_MAIN] = out;
                 }
             }
         } else {
@@ -1097,6 +1188,7 @@
                     if (status == 0) {
                         ALOGV("%s %d Open stream for Input with only Associated flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
                         qaf_mod->assoc_output_active = true;
+                        qaf_mod->stream[QAF_IN_ASSOC] = out;
                     }
                 }
             } else {
@@ -1138,10 +1230,10 @@
     if ((!property_get_bool("audio.qaf.reencode", false)) &&
         property_get_bool("audio.qaf.passthrough", false)) {
         if (property_get_bool("audio.offload.passthrough", false)) {
-            if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect &&
+            if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect &&
                 (((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
                 ((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)))) {
-                status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
+                status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.resume((struct audio_stream_out*) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
                 if (!status)
                     out->offload_state = OFFLOAD_STATE_PLAYING;
                 pthread_mutex_unlock(&out->lock);
@@ -1151,13 +1243,13 @@
                     status = audio_extn_qaf_stream_open(out);
                     if (!status)
                         out->offload_state = OFFLOAD_STATE_PLAYING;
-                    out->offload_callback(STREAM_CBK_EVENT_WRITE_READY, NULL, out->offload_cookie);
+                    out->client_callback(STREAM_CBK_EVENT_WRITE_READY, NULL, out->client_cookie);
                 }
             }
         } else {
             if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
-                if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-                    status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
+                if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] && qaf_mod->hdmi_connect) {
+                    status = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]->stream.resume((struct audio_stream_out*) qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
                     if (!status)
                         out->offload_state = OFFLOAD_STATE_PLAYING;
                     pthread_mutex_unlock(&out->lock);
@@ -1177,20 +1269,16 @@
 {
     ALOGV("%s %d", __func__, __LINE__);
     if (qaf_mod != NULL) {
-        if (qaf_mod->qaf_compr_offload_out != NULL)
-            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
-        if (qaf_mod->qaf_compr_passthrough_out != NULL)
-            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
+        if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD] != NULL)
+            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_OFFLOAD]));
+        if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL)
+            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
 
-        if (qaf_mod->qaf_passthrough_out) {
-            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
-            qaf_mod->qaf_passthrough_out = NULL;
+        if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]) {
+            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]));
+            qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
         }
 
-        if (qaf_mod->qaf_lib != NULL) {
-            dlclose(qaf_mod->qaf_lib);
-            qaf_mod->qaf_lib = NULL;
-        }
         free(qaf_mod);
         qaf_mod = NULL;
     }
@@ -1270,8 +1358,8 @@
             break;
         }
         lock_output_stream(out);
-        if (send_callback && out->offload_callback) {
-            out->offload_callback(event, NULL, out->offload_cookie);
+        if (send_callback && out->client_callback) {
+            out->client_callback(event, NULL, out->client_cookie);
         }
         free(cmd);
     }
@@ -1321,7 +1409,7 @@
 
     ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
           __func__, out->usecase, use_case_table[out->usecase], kvpairs);
-    if ((NULL != qaf_mod->qaf_compr_offload_out)) {
+    if ((NULL != qaf_mod->qaf_out[QAF_OUT_OFFLOAD])) {
         if (qaf_mod->qaf_msmd_enabled) {
             if (qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect)
                 return 1;
@@ -1338,7 +1426,7 @@
                     val |= AUDIO_DEVICE_OUT_SPEAKER;
                     str_parms_add_int(new_parms, AUDIO_PARAMETER_STREAM_ROUTING, val);
                     new_kv_pairs = str_parms_to_str(new_parms);
-                    qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, new_kv_pairs);
+                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_out[QAF_OUT_OFFLOAD], new_kv_pairs);
                     free(new_kv_pairs);
                     str_parms_destroy(new_parms);
                 }
@@ -1346,7 +1434,7 @@
             str_parms_destroy(parms);
         } else {
             if (!(qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect))
-                qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, kvpairs);
+                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_out[QAF_OUT_OFFLOAD], kvpairs);
 
             parms = str_parms_create_str(kvpairs);
             if (!parms) {
@@ -1385,7 +1473,7 @@
             if (err >= 0) {
                 val = atoi(value);
                 if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
-                    (qaf_mod->qaf_passthrough_out == NULL)) {
+                    (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL)) {
                         audio_output_flags_t flags;
                         struct audio_config config;
                         audio_devices_t devices;
@@ -1414,7 +1502,120 @@
             str_parms_destroy(parms);
         }
     }
+    return ret;
+}
 
+bool audio_extn_is_qaf_stream(struct stream_out *out)
+{
+
+    return (audio_extn_qaf_is_enabled() && out && is_ms12_format(out->format));
+}
+
+/* API to send playback stream specific config parameters */
+int audio_extn_qaf_out_set_param_data(struct stream_out *out,
+                           audio_extn_param_id param_id,
+                           audio_extn_param_payload *payload)
+{
+    int ret = -EINVAL;
+    int count;
+    struct stream_out *new_out = NULL;
+    struct audio_adsp_event *adsp_event;
+
+    if (!out || !payload) {
+        ALOGE("%s:: Invalid Param",__func__);
+        return ret;
+    }
+
+    /* In qaf output render session may not be opened at this time.
+       to handle it store adsp_hdlr param info so that it can be
+       applied later after opening render session from ms12 callback
+    */
+    if (param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) {
+        count = get_input_stream_index(out);
+        if (count < 0) {
+            ALOGE("%s:: Invalid stream", __func__);
+            return ret;
+        }
+        adsp_event = (struct audio_adsp_event *)payload;
+
+        if (payload->adsp_event_params.payload_length
+                            <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
+            memcpy(qaf_mod->adsp_hdlr_config[count].event_payload,
+                   adsp_event->payload, adsp_event->payload_length);
+            qaf_mod->adsp_hdlr_config[count].event_params.payload =
+                   qaf_mod->adsp_hdlr_config[count].event_payload;
+            qaf_mod->adsp_hdlr_config[count].event_params.payload_length
+                   = adsp_event->payload_length;
+            qaf_mod->adsp_hdlr_config[count].adsp_hdlr_config_valid = true;
+        } else {
+            ALOGE("%s:: Invalid adsp event length %d", __func__,
+                   adsp_event->payload_length);
+            return ret;
+        }
+        ret = 0;
+    }
+
+   /* apply param for all active out sessions */
+   for (count = 0; count < MAX_QAF_OUT; count++) {
+       new_out = qaf_mod->qaf_out[count];
+       if (!new_out)
+           continue;
+
+       /*ADSP event is not supported for passthrough*/
+       if ((param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) &&
+           !(new_out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM))
+               continue;
+       if (new_out->standby)
+           new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
+       lock_output_stream(new_out);
+       ret = audio_extn_out_set_param_data(new_out, param_id, payload);
+       if(ret)
+           ALOGE("%s::audio_extn_out_set_param_data error %d", __func__, ret);
+       pthread_mutex_unlock(&new_out->lock);
+   }
+   return ret;
+}
+
+int audio_extn_qaf_out_get_param_data(struct stream_out *out,
+                             audio_extn_param_id param_id,
+                             audio_extn_param_payload *payload)
+{
+    int ret = -EINVAL;
+    struct stream_out *new_out = NULL;
+
+    if (!out || !payload) {
+        ALOGE("%s:: Invalid Param",__func__);
+        return ret;
+    }
+
+    if (!qaf_mod->hdmi_connect) {
+        ALOGE("%s:: hdmi not connected",__func__);
+        return ret;
+    }
+
+    /* get session which is routed to hdmi*/
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH])
+        new_out = qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH];
+    else if (qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH])
+        new_out = qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH];
+    else if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH])
+        new_out = qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH];
+    else if (qaf_mod->qaf_out[QAF_OUT_OFFLOAD])
+        new_out = qaf_mod->qaf_out[QAF_OUT_OFFLOAD];
+
+    if (!new_out) {
+        ALOGE("%s:: No out session active",__func__);
+        return ret;
+    }
+
+    if (new_out->standby)
+           new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
+
+    lock_output_stream(new_out);
+    ret = audio_extn_out_get_param_data(new_out, param_id, payload);
+    if(ret)
+        ALOGE("%s::audio_extn_out_get_param_data error %d", __func__, ret);
+    pthread_mutex_unlock(&new_out->lock);
     return ret;
 }
 
@@ -1485,14 +1686,15 @@
                                      struct audio_stream_out *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
+    int index;
 
     ALOGV("%s: enter:stream_handle(%p) format = %x", __func__, out, out->format);
-    if (qaf_mod->qaf_passthrough_out) {
-        ALOGD("%s %d closing stream handle %p", __func__, __LINE__, qaf_mod->qaf_passthrough_out);
+    if (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]) {
+        ALOGD("%s %d closing stream handle %p", __func__, __LINE__, qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]);
         pthread_mutex_lock(&qaf_mod->lock);
-        adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
+        adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH]));
         adev_close_output_stream(dev, stream);
-        qaf_mod->qaf_passthrough_out = NULL;
+        qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
         qaf_mod->main_output_active = false;
         pthread_mutex_unlock(&qaf_mod->lock);
         return;
@@ -1501,7 +1703,15 @@
     if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         qaf_destroy_offload_callback_thread(out);
     }
-    qaf_mod->stream_drain_main = NULL;
+
+    index = get_input_stream_index(out);
+    if (index < 0)
+        ALOGE("%s:: Invalid stream",__func__);
+    else
+        memset(&qaf_mod->adsp_hdlr_config[index], 0,
+                sizeof(struct qaf_adsp_hdlr_config_state));
+
+    qaf_mod->stream[index] = NULL;
     lock_output_stream(out);
     qaf_stream_close(out);
     pthread_mutex_unlock(&out->lock);