QAF update to support multiple modules (Dolby MS12 and DTS M8)

CRs-fixed: 2036749
Change-Id: I60ad32f60e34d0ba32f77fae985f672c2155d548
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 58b6e08..ed66934 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -36,35 +36,18 @@
 #define ALOGVV(a...) do { } while(0)
 #endif
 
+#define DEBUG_MSG(arg,...) ALOGV("%s: %d:  " arg, __func__, __LINE__, ##__VA_ARGS__)
+#define ERROR_MSG(arg,...) ALOGE("%s: %d:  " arg, __func__, __LINE__, ##__VA_ARGS__)
+
 #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 2
-#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
-#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE 4608
+
 #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) +
- * DSP Latency (Calculated based on the Platform render latency)
-*/
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 300
 
-/* Used in calculating fragment size for pcm offload */
-#define QAF_PCM_OFFLOAD_BUFFER_DURATION 32 /*32 msecs */
 #define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
 
@@ -72,47 +55,36 @@
 #define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
 
 /* Pcm input node buffer size is 6144 bytes, i.e, 32msec for 48000 samplerate */
-#define MS12_PCM_INPUT_BUFFER_LATENCY 32
+#define QAF_MODULE_PCM_INPUT_BUFFER_LATENCY 32
 
-/* In msec for 2 fragments of 32ms */
-#define QAF_PCM_OFFLOAD_PLAYBACK_LATENCY \
-              (QAF_PCM_OFFLOAD_BUFFER_DURATION * COMPRESS_OFFLOAD_NUM_FRAGMENTS)
+#define MS12_PCM_OUT_FRAGMENT_SIZE 1536 //samples
 
-#define PCM_OFFLOAD_PLAYBACK_LATENCY \
-              (MS12_PCM_INPUT_BUFFER_LATENCY + QAF_PCM_OFFLOAD_PLAYBACK_LATENCY)
-
-/*
- * Buffer size for compress passthrough is 8192 bytes
- */
-#define COMPRESS_PASSTHROUGH_BUFFER_SIZE \
-     (COMPRESS_OFFLOAD_NUM_FRAGMENTS * COMPRESS_OFFLOAD_FRAGMENT_SIZE)
-/*
- * Frame size for DD/DDP is 1536 samples corresponding to 32ms.
- */
 #define DD_FRAME_SIZE 1536
+#define DDP_FRAME_SIZE DD_FRAME_SIZE
 /*
- * DD encoder output size for 32ms.
+ * DD encoder output size for one frame.
  */
 #define DD_ENCODER_OUTPUT_SIZE 2560
 /*
- * DDP encoder output size for 32ms.
+ * DDP encoder output size for one frame.
  */
 #define DDP_ENCODER_OUTPUT_SIZE 4608
 
+/*********TODO Need to get correct values.*************************/
+
+#define DTS_PCM_OUT_FRAGMENT_SIZE 1024 //samples
+
+#define DTS_FRAME_SIZE 1536
+#define DTSHD_FRAME_SIZE DTS_FRAME_SIZE
 /*
- * Frame size for DD/DDP is 1536 samples.
- * For a bit rate of 640 bps, DD encoder output size is 2560 bytes of
- * 32ms;
- * DDP encoder output size is 4608 bytes of 32 ms.
- * Kernel buffer buffer allocation for compress passthrough is
- * 2 x 2048 bytes = 4096 bytes
- * The Latency for DD (measured in samples) is calculated as:
- * Time taken to play 8192 bytes (for DD) = 4096 x 32/2560 = 51.2ms
- * Samples for 51.2ms = 51.2 x 1536/32 = 2457 samples.
- * Latency calculated similarly for DPP is 1365 samples.
+ * DTS encoder output size for one frame.
  */
-#define TRANSCODE_LATENCY(buffer_size, frame_size, encoder_output_in_bytes) \
-                          ((buffer_size * frame_size) / encoder_output_in_bytes)
+#define DTS_ENCODER_OUTPUT_SIZE 2560
+/*
+ * DTSHD encoder output size for one frame.
+ */
+#define DTSHD_ENCODER_OUTPUT_SIZE 4608
+/******************************************************************/
 
 /*
  * QAF Latency to process buffers since out_write from primary HAL
@@ -120,6 +92,7 @@
 #define QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY 18
 #define QAF_PCM_OFFLOAD_PROCESSING_LATENCY 48
 
+//TODO: Need to handle for DTS
 #define QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1536
 
 #include <stdlib.h>
@@ -142,6 +115,7 @@
 #include <qti_audio.h>
 #include "sound/compress_params.h"
 
+//TODO: Need to remove this.
 #define QAF_OUTPUT_SAMPLING_RATE 48000
 
 #ifdef QAF_DUMP_ENABLED
@@ -155,14 +129,42 @@
     bool adsp_hdlr_config_valid;
 };
 
-struct qaf {
-    struct audio_device *adev;
+//Types of MM module, currently supported by QAF.
+typedef enum {
+    MS12,
+    DTS_M8,
+    MAX_MM_MODULE_TYPE,
+    INVALID_MM_MODULE
+} mm_module_type;
+
+typedef enum {
+    QAF_OUT_TRANSCODE_PASSTHROUGH = 0, /* Transcode passthrough via MM module*/
+    QAF_OUT_OFFLOAD_MCH, /* Multi-channel PCM offload*/
+    QAF_OUT_OFFLOAD, /* PCM offload */
+
+    MAX_QAF_MODULE_OUT
+} mm_module_output_type;
+
+typedef enum {
+    QAF_IN_MAIN = 0, /* Single PID Main/Primary or Dual-PID stream */
+    QAF_IN_ASSOC, /* Associated/Secondary stream */
+    QAF_IN_PCM, /* PCM stream. */
+
+    MAX_QAF_MODULE_IN
+} mm_module_input_type;
+
+struct qaf_module {
     audio_session_handle_t session_handle;
     void *qaf_lib;
-    int (*qaf_audio_session_open)(audio_session_handle_t* session_handle, void *p_data, void* license_data);
+    int (*qaf_audio_session_open)(audio_session_handle_t* session_handle,
+                                  void *p_data,
+                                  void* license_data);
     int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
-    int (*qaf_audio_stream_open)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
-         audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags);
+    int (*qaf_audio_stream_open)(audio_session_handle_t session_handle,
+                                 audio_stream_handle_t* stream_handle,
+                                 audio_stream_config_t input_config,
+                                 audio_devices_t devices,
+                                 stream_type_t flags);
     int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
     int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
     int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
@@ -173,57 +175,151 @@
     int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
     int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
     int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
-    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;
+    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);
 
-    struct stream_out *stream[MAX_QAF_IN];
-    struct stream_out *qaf_out[MAX_QAF_OUT];
+    /*Input stream of MM module */
+    struct stream_out *stream_in[MAX_QAF_MODULE_IN];
+    /*Output Stream from MM module */
+    struct stream_out *stream_out[MAX_QAF_MODULE_OUT];
 
-    struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_IN];
+    struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_MODULE_IN];
 
+    //BT session handle.
     void *bt_hdl;
-    bool hdmi_connect;
-    int passthrough_enabled;
-    int hdmi_sink_channels;
-    bool main_output_active;
-    bool assoc_output_active;
-    bool qaf_msmd_enabled;
+
     float vol_left;
     float vol_right;
+    bool is_vol_set;
+    bool drain_received[MAX_QAF_MODULE_IN];
 };
 
-static struct qaf *qaf_mod = NULL;
-static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair) __attribute__ ((unused));
+struct qaf {
+    struct audio_device *adev;
 
-/* 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;
-}
+    pthread_mutex_t lock;
 
-static bool is_ms12_format(audio_format_t format)
+    bool hdmi_connect;
+    int hdmi_sink_channels;
+
+    //Flag to indicate if QAF transcode output stream is enabled from any mm module.
+    bool passthrough_enabled;
+    //Flag to indicate if QAF mch pcm output stream is enabled from any mm module.
+    bool mch_pcm_hdmi_enabled;
+
+    //Flag to indicate if msmd is supported.
+    bool qaf_msmd_enabled;
+
+    //Handle of QAF input stream, which is routed as QAF passthrough.
+    struct stream_out *passthrough_in;
+    //Handle of QAF passthrough stream.
+    struct stream_out *passthrough_out;
+
+    struct qaf_module qaf_mod[MAX_MM_MODULE_TYPE];
+};
+
+static int qaf_out_pause(struct audio_stream_out* stream);
+static int qaf_out_flush(struct audio_stream_out* stream);
+static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type);
+
+//Global handle of QAF. Access to this should be protected by mutex lock.
+static struct qaf *p_qaf = NULL;
+
+/* Gets the pointer to qaf module for the qaf input stream. */
+static struct qaf_module* get_qaf_module_for_input_stream(struct stream_out *out)
 {
-    if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)
-        return true;
-    if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3)
-        return true;
-    if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
-        return true;
-    if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
-        return true;
-    if((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC4)
-        return true;
-    if(format == AUDIO_FORMAT_PCM_16_BIT)
-        return true;
+    struct qaf_module *qaf_mod = NULL;
+    int i, j;
+    if (!p_qaf) return NULL;
 
-    return false;
+    for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+        for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+            if (p_qaf->qaf_mod[i].stream_in[j] == out) {
+                qaf_mod = &(p_qaf->qaf_mod[i]);
+                break;
+            }
+        }
+    }
+
+    return qaf_mod;
 }
 
+/* Finds the mm module input stream index for the QAF input stream. */
+static int get_input_stream_index(struct stream_out *out)
+{
+    int index = -1, j;
+    struct qaf_module* qaf_mod = NULL;
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if (!qaf_mod) return index;
+
+    for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+        if (qaf_mod->stream_in[j] == out) {
+            index = j;
+            break;
+        }
+    }
+
+    return index;
+}
+
+/* Finds the right mm module for the QAF input stream format. */
+static mm_module_type get_mm_module_for_format(audio_format_t format)
+{
+    int j;
+
+    DEBUG_MSG("Format 0x%x", format);
+
+    if (format == AUDIO_FORMAT_PCM_16_BIT) {
+        //If dts is not supported then alway support pcm with MS12
+        if (!property_get_bool("audio.qaf.dts_m8", false)) { //TODO: Need to add this property for DTS.
+            return MS12;
+        }
+
+        //If QAF passthrough is active then send the PCM stream to primary HAL.
+        if (!p_qaf->passthrough_out) {
+            /* Iff any stream is active in MS12 module then route PCM stream to it. */
+            for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+                if (p_qaf->qaf_mod[MS12].stream_in[j]) {
+                    return MS12;
+                }
+            }
+        }
+        return INVALID_MM_MODULE;
+    }
+
+    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+        case AUDIO_FORMAT_AC3:
+        case AUDIO_FORMAT_E_AC3:
+        case AUDIO_FORMAT_AAC:
+        case AUDIO_FORMAT_AAC_ADTS:
+        case AUDIO_FORMAT_AC4:
+            return MS12;
+        case AUDIO_FORMAT_DTS:
+        case AUDIO_FORMAT_DTS_HD:
+            return DTS_M8;
+        default:
+            return INVALID_MM_MODULE;
+    }
+}
+
+/* Gets the pcm output buffer size(in samples) for the mm module. */
+static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
+{
+    uint32_t pcm_output_buffer_size = 0;
+
+    if (qaf_mod == &p_qaf->qaf_mod[MS12]) {
+        pcm_output_buffer_size = MS12_PCM_OUT_FRAGMENT_SIZE;
+    } else if (qaf_mod == &p_qaf->qaf_mod[DTS_M8]) {
+        pcm_output_buffer_size = DTS_PCM_OUT_FRAGMENT_SIZE;
+    }
+
+    return pcm_output_buffer_size;
+}
+
+/* Acquire Mutex lock on output stream */
 static void lock_output_stream(struct stream_out *out)
 {
     pthread_mutex_lock(&out->pre_lock);
@@ -231,25 +327,80 @@
     pthread_mutex_unlock(&out->pre_lock);
 }
 
+/* Release Mutex lock on output stream */
+static void unlock_output_stream(struct stream_out *out)
+{
+    pthread_mutex_unlock(&out->lock);
+}
+
+/* Checks if stream can be routed as QAF passthrough or not. */
 static bool audio_extn_qaf_passthrough_enabled(struct stream_out *out)
 {
-    ALOGV("%s %d ", __func__, __LINE__);
-    if ((!property_get_bool("audio.qaf.reencode", false)) &&
-        property_get_bool("audio.qaf.passthrough", false)) {
-        if (property_get_bool("audio.offload.passthrough", false)) {
-            if (((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)) ||
-                ((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
-                ((out->format == AUDIO_FORMAT_DTS) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS)) ||
-                ((out->format == AUDIO_FORMAT_DTS_HD) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS_HD))) {
-                return true;
-            }
-        } else {
-            if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
-                return true;
+    DEBUG_MSG("Format 0x%x", out->format);
+    bool is_enabled = false;
+
+    if (!p_qaf) return false;
+
+    if ((!property_get_bool("audio.qaf.reencode", false))
+        && property_get_bool("audio.qaf.passthrough", false)) {
+
+        if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
+            is_enabled = true;
+        } else if (property_get_bool("audio.offload.passthrough", false)) {
+            switch (out->format) {
+                case AUDIO_FORMAT_AC3:
+                case AUDIO_FORMAT_E_AC3:
+                case AUDIO_FORMAT_DTS:
+                case AUDIO_FORMAT_DTS_HD: {
+                    is_enabled = true;
+                    break;
+                }
+                default:
+                    is_enabled = false;
+                break;
             }
         }
     }
-    return false;
+
+    return is_enabled;
+}
+
+/*Closes all pcm hdmi output from QAF. */
+static void close_all_pcm_hdmi_output()
+{
+    int i;
+    //Closing all the PCM HDMI output stream from QAF.
+    for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+        if (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]) {
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]));
+            p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
+        }
+
+        if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
+            && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
+            p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
+        }
+    }
+
+    p_qaf->mch_pcm_hdmi_enabled = 0;
+}
+
+static void close_all_hdmi_output()
+{
+    int k;
+    for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+        if (p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
+            p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
+        }
+    }
+    p_qaf->passthrough_enabled = 0;
+
+    close_all_pcm_hdmi_output();
 }
 
 static int qaf_out_callback(stream_callback_event_t event, void *param __unused, void *cookie)
@@ -260,56 +411,122 @@
     return 0;
 }
 
-static int create_output_stream(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices, int handle_id)
+/* Creates the QAF passthrough output stream. */
+static int create_qaf_passthrough_stream()
 {
-    int ret = 0;
+    DEBUG_MSG();
 
-    ALOGV("%s %d", __func__, __LINE__);
-    if ((handle_id == QAF_DEFAULT_PASSTHROUGH_HANDLE) &&
-        (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_out[QAF_DEFAULT_PASSTHROUGH]), NULL);
+    int ret = 0, k;
+    struct stream_out *out = p_qaf->passthrough_in;
+
+    if (!out) return -EINVAL;
+
+    pthread_mutex_lock(&p_qaf->lock);
+    lock_output_stream(out);
+
+    //Creating QAF passthrough output stream.
+    if (NULL == p_qaf->passthrough_out) {
+        audio_output_flags_t flags;
+        struct audio_config config;
+        audio_devices_t devices;
+
+        config.sample_rate = config.offload_info.sample_rate = out->sample_rate;
+        config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+        config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+        config.offload_info.format = out->format;
+        config.offload_info.bit_width = out->bit_width;
+        config.format = out->format;
+        config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
+
+        //Device is copied from the QAF passthrough input stream.
+        devices = out->devices;
+        flags = out->flags;
+
+        ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                      QAF_DEFAULT_PASSTHROUGH_HANDLE,
+                                      devices,
+                                      flags,
+                                      &config,
+                                      (struct audio_stream_out **)&(p_qaf->passthrough_out),
+                                      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;
+            ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+            unlock_output_stream(out);
+            return ret;
         }
-        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);
+        p_qaf->passthrough_in = out;
+        p_qaf->passthrough_out->stream.set_callback((struct audio_stream_out *)p_qaf->passthrough_out,
+                                                    (stream_callback_t) qaf_out_callback, out);
     }
+
+    unlock_output_stream(out);
+
+    //Since QAF-Passthrough is created, close other HDMI outputs.
+    close_all_hdmi_output();
+
+    pthread_mutex_unlock(&p_qaf->lock);
     return ret;
 }
 
+/* Closes the QAF passthrough output stream. */
+static void close_qaf_passthrough_stream()
+{
+    if (p_qaf->passthrough_out != NULL) { //QAF pasthroug is enabled. Close it.
+        pthread_mutex_lock(&p_qaf->lock);
+        adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                 (struct audio_stream_out *)(p_qaf->passthrough_out));
+        p_qaf->passthrough_out = NULL;
+        pthread_mutex_unlock(&p_qaf->lock);
+
+        if (p_qaf->passthrough_in->qaf_stream_handle) {
+            qaf_out_pause((struct audio_stream_out*)p_qaf->passthrough_in);
+            qaf_out_flush((struct audio_stream_out*)p_qaf->passthrough_in);
+            qaf_out_drain((struct audio_stream_out*)p_qaf->passthrough_in,
+                          (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
+        }
+    }
+}
+
+/* Sends a command to output stream offload thread. */
 static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
 {
+    DEBUG_MSG("command is %d", command);
+
     struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
 
     if (!cmd) {
-        ALOGE("failed to allocate mem for command 0x%x", command);
+        ERROR_MSG("failed to allocate mem for command 0x%x", command);
         return -ENOMEM;
     }
 
-    ALOGV("%s %d", __func__, command);
-
     cmd->cmd = command;
+
+    lock_output_stream(out);
     list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
     pthread_cond_signal(&out->qaf_offload_cond);
+    unlock_output_stream(out);
     return 0;
 }
 
+/* Stops a QAF module stream.*/
 static int audio_extn_qaf_stream_stop(struct stream_out *out)
 {
-    ALOGV("%s: %d start", __func__, __LINE__);
-    if (!qaf_mod->qaf_audio_stream_stop)
-        return -EINVAL;
+    int ret = 0;
+    DEBUG_MSG("Output Stream 0x%x", out);
 
-    return qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+    if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_stop)) {
+        return ret;
+    }
+
+    if (out->qaf_stream_handle) {
+        ret = qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
+    }
+
+    return ret;
 }
 
+/* Puts a QAF module stream in standby. */
 static int qaf_out_standby(struct audio_stream *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
@@ -319,70 +536,73 @@
           stream, out->usecase, use_case_table[out->usecase]);
 
     lock_output_stream(out);
-    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;
+
+    //If QAF passthrough is active then block standby on all the input streams of QAF mm modules.
+    if (p_qaf->passthrough_out) {
+        //If standby is received on QAF passthrough stream then forward it to primary HAL.
+        if (p_qaf->passthrough_in == out) {
+            status = p_qaf->passthrough_out->stream.common.standby(
+                    (struct audio_stream *)p_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;
-        }
-        pthread_mutex_unlock(&out->lock);
-        return status;
+    } else {
+        //If QAF passthrough stream is not active then stop the QAF module stream.
+        status = audio_extn_qaf_stream_stop(out);
     }
 
     if (!out->standby) {
         out->standby = true;
-        status = audio_extn_qaf_stream_stop(out);
     }
-    pthread_mutex_unlock(&out->lock);
+
+    unlock_output_stream(out);
     return status;
 }
 
-static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair)
-{
-    ALOGV("%s %d kvpair: %s", __func__, __LINE__, kv_pair);
-    if (!qaf_mod->qaf_audio_stream_set_param)
-        return -EINVAL;
-
-    return qaf_mod->qaf_audio_stream_set_param(out->qaf_stream_handle, kv_pair);
-}
-
-static int qaf_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
+/* Sets the volume to PCM output stream. */
+static int qaf_out_set_volume(struct audio_stream_out *stream, float left, float right)
 {
     int ret = 0;
-    ALOGVV("%s bytes = %d [%p]", __func__, bytes, out->qaf_stream_handle);
-    if (!qaf_mod->qaf_audio_stream_write)
-        return -EINVAL;
+    struct stream_out *out = (struct stream_out *)stream;
+    struct qaf_module *qaf_mod = NULL;
 
-    if (out->qaf_stream_handle)
-        ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+    DEBUG_MSG("Left %f, Right %f", left, right);
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if (!qaf_mod) {
+        return -EINVAL;
+    }
+
+    pthread_mutex_lock(&p_qaf->lock);
+    qaf_mod->vol_left = left;
+    qaf_mod->vol_right = right;
+    qaf_mod->is_vol_set = true;
+    pthread_mutex_unlock(&p_qaf->lock);
+
+    if (qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL) {
+        ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+                (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], left, right);
+    }
+
     return ret;
 }
 
-static int qaf_out_set_volume(struct audio_stream_out *stream __unused, float left,
-                          float right)
-{
-    /* 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_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;
-}
-
+/* Starts a QAF module stream. */
 static int qaf_stream_start(struct stream_out *out)
 {
-    if (!qaf_mod->qaf_audio_stream_start)
-        return -EINVAL;
+    int ret = -EINVAL;
+    struct qaf_module *qaf_mod = NULL;
 
-    return qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
+    DEBUG_MSG("Output Stream = %p", out);
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_start)) {
+        return -EINVAL;
+    }
+
+    if (out->qaf_stream_handle) {
+        ret = qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
+    }
+
+    return ret;
 }
 
 static int qaf_start_output_stream(struct stream_out *out)
@@ -411,116 +631,179 @@
     return qaf_stream_start(out);
 }
 
-static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer,
-                         size_t bytes)
+/* Sends input buffer to the QAF MM module. */
+static int qaf_module_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
+{
+    int ret = -EINVAL;
+    struct qaf_module *qaf_mod = NULL;
+    DEBUG_MSG("bytes = %d [%p]", bytes, out->qaf_stream_handle);
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_write)) {
+        return ret;
+    }
+
+    if (out->qaf_stream_handle) {
+        ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+    }
+    return ret;
+}
+
+/* Writes buffer to QAF input stream. */
+static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes)
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
     ssize_t ret = 0;
 
-    ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
+    DEBUG_MSG("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_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;
+    // If QAF passthrough is active then block writing data to QAF mm module.
+    if (p_qaf->passthrough_out) {
+        //If write is received for the QAF passthrough stream then send the buffer to primary HAL.
+        if (p_qaf->passthrough_in == out) {
+            ret = p_qaf->passthrough_out->stream.write(
+                    (struct audio_stream_out *)(p_qaf->passthrough_out),
+                    buffer,
+                    bytes);
+            if (ret > 0) out->standby = false;
         }
-        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);
+        unlock_output_stream(out);
         return ret;
-    }
-
-    if (out->standby) {
-        out->standby = false;
+    } else if (out->standby) {
         pthread_mutex_lock(&adev->lock);
         ret = qaf_start_output_stream(out);
         pthread_mutex_unlock(&adev->lock);
-        /* ToDo: If use case is compress offload should return 0 */
-        if (ret != 0) {
-            out->standby = true;
+        if (ret == 0) {
+            out->standby = false;
+        } else {
             goto exit;
         }
     }
 
-    if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+    if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
 
-    ret = qaf_write_input_buffer(out, buffer, bytes);
-    ALOGV("%s, ret [%d] ", __func__, (int)ret);
-    if (ret < 0) {
-        goto exit;
+    ret = qaf_module_write_input_buffer(out, buffer, bytes);
+    DEBUG_MSG("ret [%d]", (int)ret);
+
+    if (ret >= 0) {
+        bytes = ret;
+        out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
     }
-    out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
+
 
 exit:
-
-    pthread_mutex_unlock(&out->lock);
+    unlock_output_stream(out);
 
     if (ret < 0) {
         if (ret == -EAGAIN) {
-            ALOGV("No space available in ms12 driver, post msg to cb thread");
-            lock_output_stream(out);
+            DEBUG_MSG("No space available in mm module, post msg to cb thread");
             ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
-            pthread_mutex_unlock(&out->lock);
             bytes = 0;
-        }
-        if(ret == -ENOMEM || ret == -EPERM){
+        } else if (ret == -ENOMEM || ret == -EPERM) {
             if (out->pcm)
-                ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
+                ERROR_MSG("error %d, %s", (int)ret, pcm_get_error(out->pcm));
             qaf_out_standby(&out->stream.common);
-            usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
-                            out->stream.common.get_sample_rate(&out->stream.common));
+            usleep(bytes * 1000000
+                   / audio_stream_out_frame_size(stream)
+                   / out->stream.common.get_sample_rate(&out->stream.common));
         }
     }
     return bytes;
 }
 
-static uint32_t qaf_get_pcm_offload_buffer_size(audio_offload_info_t* info)
+/* Gets PCM offload buffer size for QAF module output. */
+static uint32_t qaf_get_pcm_offload_buffer_size(struct qaf_module *qaf_mod,
+                                                audio_offload_info_t* info)
 {
+    uint32_t samples_per_frame = get_pcm_output_buffer_size_samples(qaf_mod);
     uint32_t fragment_size = 0;
-    uint32_t bits_per_sample = 16;
-    uint32_t pcm_offload_time = QAF_PCM_OFFLOAD_BUFFER_DURATION;
 
-    //duration is set to 32 ms worth of stereo data at 48Khz
-    //with 16 bit per sample, modify this when the channel
-    //configuration is different
-    fragment_size = (pcm_offload_time
-                     * info->sample_rate
-                     * (bits_per_sample >> 3)
-                     * popcount(info->channel_mask))/1000;
-    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
+    fragment_size = (samples_per_frame * (info->bit_width >> 3) * popcount(info->channel_mask));
+
+    if (fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
-    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
+    else if (fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+
     // To have same PCM samples for all channels, the buffer size requires to
     // be multiple of (number of channels * bytes per sample)
     // For writes to succeed, the buffer must be written at address which is multiple of 32
-    fragment_size = ALIGN(fragment_size, ((bits_per_sample >> 3)* popcount(info->channel_mask) * 32));
+    fragment_size = ALIGN(fragment_size,
+                          ((info->bit_width >> 3) * popcount(info->channel_mask) * 32));
 
     ALOGI("Qaf PCM offload Fragment size to %d bytes", fragment_size);
 
     return fragment_size;
 }
 
-static int qaf_get_timestamp(struct stream_out *out, uint64_t *frames, struct timespec *timestamp)
+/* Gets buffer latency in samples. */
+static int get_buffer_latency(struct stream_out *out, uint32_t buffer_size, uint32_t *latency)
 {
-    int ret = 0;
+    unsigned long int samples_in_one_encoded_frame;
+    unsigned long int size_of_one_encoded_frame;
+
+    switch (out->format) {
+        case AUDIO_FORMAT_AC3:
+            samples_in_one_encoded_frame = DD_FRAME_SIZE;
+            size_of_one_encoded_frame = DD_ENCODER_OUTPUT_SIZE;
+        break;
+        case AUDIO_FORMAT_E_AC3:
+            samples_in_one_encoded_frame = DDP_FRAME_SIZE;
+            size_of_one_encoded_frame = DDP_ENCODER_OUTPUT_SIZE;
+        break;
+        case AUDIO_FORMAT_DTS:
+            samples_in_one_encoded_frame = DTS_FRAME_SIZE;
+            size_of_one_encoded_frame = DTS_ENCODER_OUTPUT_SIZE;
+        break;
+        case AUDIO_FORMAT_DTS_HD:
+            samples_in_one_encoded_frame = DTSHD_FRAME_SIZE;
+            size_of_one_encoded_frame = DTSHD_ENCODER_OUTPUT_SIZE;
+        break;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            samples_in_one_encoded_frame = 1;
+            size_of_one_encoded_frame = ((out->bit_width) >> 3) * popcount(out->channel_mask);
+        break;
+        default:
+            *latency = 0;
+            return (-EINVAL);
+    }
+
+    *latency = ((buffer_size * samples_in_one_encoded_frame) / size_of_one_encoded_frame);
+    return 0;
+}
+
+/* Returns the number of frames rendered to outside observer. */
+static int qaf_get_rendered_frames(struct stream_out *out, uint64_t *frames)
+{
+    int ret = 0, i;
     struct str_parms *parms;
     int value = 0;
-    int latency = 0;
+    int module_latency = 0;
+    uint32_t kernel_latency = 0;
+    uint32_t dsp_latency = 0;
     int signed_frames = 0;
     char* kvpairs = NULL;
+    struct qaf_module *qaf_mod = NULL;
 
-    ALOGV("%s out->format %d", __func__, out->format);
+    DEBUG_MSG("Output Format %d", out->format);
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_get_param)) {
+        return -EINVAL;
+    }
+
+    //Get MM module latency.
     kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "get_latency");
     if (kvpairs) {
         parms = str_parms_create_str(kvpairs);
-        ret = str_parms_get_int(parms, "get_latency", &latency);
+        ret = str_parms_get_int(parms, "get_latency", &module_latency);
         if (ret >= 0) {
             str_parms_destroy(parms);
             parms = NULL;
@@ -528,26 +811,54 @@
         free(kvpairs);
         kvpairs = NULL;
     }
-    // MS12 Latency + Kernel Latency + Dsp Latency
-    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_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);
+
+    //Get kernel Latency
+    for (i = MAX_QAF_MODULE_OUT - 1; i >= 0; i--) {
+        if (qaf_mod->stream_out[i] == NULL) {
+            continue;
+        } else {
+            unsigned int num_fragments = qaf_mod->stream_out[i]->compr_config.fragments;
+            uint32_t fragment_size = qaf_mod->stream_out[i]->compr_config.fragment_size;
+            uint32_t kernel_buffer_size = num_fragments * fragment_size;
+            get_buffer_latency(qaf_mod->stream_out[i], kernel_buffer_size, &kernel_latency);
+            break;
+        }
     }
 
-    if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
-       *frames = 0;
-       signed_frames = out->written - out->platform_latency;
-       // It would be unusual for this value to be negative, but check just in case ...
-       if (signed_frames >= 0) {
-           *frames = signed_frames;
-       }
-       clock_gettime(CLOCK_MONOTONIC, timestamp);
+    //Get DSP latency
+    if ((qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL)
+        || (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] != NULL)) {
+        unsigned int sample_rate = 0;
+
+        if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
+            sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
+        else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
+            sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
+
+        audio_usecase_t platform_latency =
+                platform_render_latency(qaf_mod->stream_out[QAF_OUT_OFFLOAD]->usecase);
+        dsp_latency = (platform_latency * sample_rate) / 1000000LL;
+    } else if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL) {
+        unsigned int sample_rate = 0;
+
+        sample_rate = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate; //TODO: How this sample rate can be used?
+        dsp_latency = (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * sample_rate) / 1000;
+    }
+
+    // MM Module Latency + Kernel Latency + DSP Latency
+    if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+        out->platform_latency = module_latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
+    } else {
+        out->platform_latency = (uint32_t)module_latency + kernel_latency + dsp_latency;
+    }
+
+    if (out->format & AUDIO_FORMAT_PCM_16_BIT) {
+        *frames = 0;
+        signed_frames = out->written - out->platform_latency;
+        // It would be unusual for this value to be negative, but check just in case ...
+        if (signed_frames >= 0) {
+            *frames = signed_frames;
+        }
     } else if (qaf_mod->qaf_audio_stream_get_param) {
         kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
         if (kvpairs) {
@@ -560,114 +871,173 @@
                 if (signed_frames >= 0) {
                     *frames = signed_frames;
                 }
-                clock_gettime(CLOCK_MONOTONIC, timestamp);
             }
             str_parms_destroy(parms);
         }
     } else {
         ret = -EINVAL;
     }
+
     return ret;
 }
 
 static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
-                                   uint64_t *frames, struct timespec *timestamp)
+                                             uint64_t *frames,
+                                             struct timespec *timestamp)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    int ret = -1;
-    lock_output_stream(out);
+    int ret = 0;
 
-    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);
+    DEBUG_MSG("Output Stream %p", stream);
+
+    //If QAF passthorugh output stream is active.
+    if (p_qaf->passthrough_out) {
+        if (p_qaf->passthrough_in == out) {
+            //If api is called for QAF passthorugh stream then call the primary HAL api to get the position.
+            pthread_mutex_lock(&p_qaf->lock);
+            ret = p_qaf->passthrough_out->stream.get_presentation_position(
+                    (struct audio_stream_out *)p_qaf->passthrough_out,
+                    frames,
+                    timestamp);
+            pthread_mutex_unlock(&p_qaf->lock);
+        } else {
+            //If api is called for other stream then return zero frames.
+            *frames = 0;
+            clock_gettime(CLOCK_MONOTONIC, timestamp);
+        }
         return ret;
     }
 
-    ret = qaf_get_timestamp(out, frames, timestamp);
-    pthread_mutex_unlock(&out->lock);
+    ret = qaf_get_rendered_frames(out, frames);
+    clock_gettime(CLOCK_MONOTONIC, timestamp);
 
     return ret;
 }
 
+/* Pause the QAF module input stream. */
 static int qaf_stream_pause(struct stream_out *out)
 {
-    ALOGV("%s: %d start", __func__, __LINE__);
-    if (!qaf_mod->qaf_audio_stream_pause)
-        return -EINVAL;
+    struct qaf_module *qaf_mod = NULL;
+    int ret = -EINVAL;
 
-    return qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if (!qaf_mod || !qaf_mod->qaf_audio_stream_pause) {
+        return -EINVAL;
+    }
+
+    if (out->qaf_stream_handle)
+        ret = qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
+
+    return ret;
 }
 
+/* Pause a QAF input stream. */
 static int qaf_out_pause(struct audio_stream_out* stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    int status = -ENOSYS;
-    ALOGE("%s", __func__);
+    int status = 0;
+    DEBUG_MSG("Output Stream %p", out);
 
     lock_output_stream(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;
+
+    //If QAF passthrough is enabled then block the pause on module stream.
+    if (p_qaf->passthrough_out) {
+        pthread_mutex_lock(&p_qaf->lock);
+        //If pause is received for QAF passthorugh stream then call the primary HAL api.
+        if (p_qaf->passthrough_in == out) {
+            status = p_qaf->passthrough_out->stream.pause(
+                    (struct audio_stream_out *)p_qaf->passthrough_out);
+            out->offload_state = OFFLOAD_STATE_PAUSED;
+        }
+        pthread_mutex_unlock(&p_qaf->lock);
+    } else {
+        //Pause the module input stream.
+        status = qaf_stream_pause(out);
     }
 
-    status = qaf_stream_pause(out);
-    pthread_mutex_unlock(&out->lock);
+    unlock_output_stream(out);
     return status;
 }
 
-static int qaf_out_drain(struct audio_stream_out* stream,
-                         audio_drain_type_t type)
+/* Drains a qaf input stream. */
+static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
 {
     struct stream_out *out = (struct stream_out *)stream;
     int status = 0;
-    ALOGV("%s stream_handle = %p , format = %x", __func__,
-                                          out->qaf_stream_handle, out->format);
+    DEBUG_MSG("Output Stream %p", out);
 
     lock_output_stream(out);
-    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 QAF passthrough is enabled then block the drain on module stream.
+    if (p_qaf->passthrough_out) {
+        pthread_mutex_lock(&p_qaf->lock);
+        //If drain is received for QAF passthorugh stream then call the primary HAL api.
+        if (p_qaf->passthrough_in == out) {
+            status = p_qaf->passthrough_out->stream.drain(
+                    (struct audio_stream_out *)p_qaf->passthrough_out, type);
+        }
+        pthread_mutex_unlock(&p_qaf->lock);
+    } else {
+        //Drain the module input stream.
+        /* 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 (status == 0) {
+            struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+            int index = get_input_stream_index(out);
+            if (qaf_mod && index >= 0) qaf_mod->drain_received[index] = true;
+        }
     }
 
-
-    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);
-    pthread_mutex_unlock(&out->lock);
+    unlock_output_stream(out);
     return status;
 }
 
+/* Flush the QAF module input stream. */
 static int audio_extn_qaf_stream_flush(struct stream_out *out)
 {
-    ALOGV("%s: %d exit", __func__, __LINE__);
-    if (!qaf_mod->qaf_audio_stream_flush)
-        return -EINVAL;
+    DEBUG_MSG("Output Stream %p", out);
+    int ret = -EINVAL;
+    struct qaf_module *qaf_mod = NULL;
 
-    return qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_flush)) {
+        return -EINVAL;
+    }
+
+    if (out->qaf_stream_handle)
+        ret = qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
+
+    return ret;
 }
 
+/* Flush the QAF input stream. */
 static int qaf_out_flush(struct audio_stream_out* stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    ALOGV("%s", __func__);
-    int status = -ENOSYS;
+    int status = 0;
 
+    DEBUG_MSG("Output Stream %p", out);
     lock_output_stream(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;
+
+    //If QAF passthrough is active then block the flush on module input streams.
+    if (p_qaf->passthrough_out) {
+        pthread_mutex_lock(&p_qaf->lock);
+        //If flush is received for the QAF passthrough stream then call the primary HAL api.
+        if (p_qaf->passthrough_in == out) {
+            status = p_qaf->passthrough_out->stream.flush(
+                    (struct audio_stream_out *)p_qaf->passthrough_out);
+            out->offload_state = OFFLOAD_STATE_IDLE;
+        }
+        pthread_mutex_unlock(&p_qaf->lock);
+    } else {
+        //Flush the module input stream.
+        status = audio_extn_qaf_stream_flush(out);
     }
 
-    status = audio_extn_qaf_stream_flush(out);
-    pthread_mutex_unlock(&out->lock);
-    ALOGV("%s Exit", __func__);
+    unlock_output_stream(out);
+    DEBUG_MSG("Exit");
     return status;
 }
 
@@ -675,354 +1045,395 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     uint32_t latency = 0;
+    struct qaf_module *qaf_mod = NULL;
+    DEBUG_MSG("Output Stream %p", out);
 
-
-    lock_output_stream(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;
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if (!qaf_mod) {
+        return 0;
     }
-    pthread_mutex_unlock(&out->lock);
 
-    if (is_offload_usecase(out->usecase)) {
-        latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+    //If QAF passthrough is active then block the get latency on module input streams.
+    if (p_qaf->passthrough_out) {
+        pthread_mutex_lock(&p_qaf->lock);
+        //If get latency is called for the QAF passthrough stream then call the primary HAL api.
+        if (p_qaf->passthrough_in == out) {
+            latency = p_qaf->passthrough_out->stream.get_latency(
+                    (struct audio_stream_out *)p_qaf->passthrough_out);
+        }
+        pthread_mutex_unlock(&p_qaf->lock);
     } else {
-        latency = PCM_OFFLOAD_PLAYBACK_LATENCY;
-    }
-
-    if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
-
         if (is_offload_usecase(out->usecase)) {
-            latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) + QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
+            latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
         } else {
-            latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) + QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
+            uint32_t sample_rate = 0;
+            latency = QAF_MODULE_PCM_INPUT_BUFFER_LATENCY; //Input latency
+
+            if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
+                sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
+            else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
+                sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
+
+            if (sample_rate) {
+                latency += (get_pcm_output_buffer_size_samples(qaf_mod) * 1000) / out->sample_rate;
+            }
+        }
+
+        if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+            if (is_offload_usecase(out->usecase)) {
+                latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
+                QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
+            } else {
+                latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
+                QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
+            }
         }
     }
-    ALOGV("%s: Latency %d", __func__, latency);
+
+    DEBUG_MSG("Latency %d", latency);
     return latency;
 }
 
-static void notify_event_callback(
-            audio_session_handle_t session_handle __unused, void *prv_data,
-            void *buf, audio_event_id_t event_id, int size, int device)
+static bool check_and_get_compressed_device_format(int device, int *format)
+{
+    switch (device) {
+        case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD):
+            *format = AUDIO_FORMAT_AC3;
+            return true;
+        case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP):
+            *format = AUDIO_FORMAT_E_AC3;
+            return true;
+        case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS):
+            *format = AUDIO_FORMAT_DTS;
+            return true;
+        case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS_HD):
+            *format = AUDIO_FORMAT_DTS_HD;
+            return true;
+        default:
+            return false;
+    }
+}
+
+/* Call back function for mm module. */
+static void notify_event_callback(audio_session_handle_t session_handle /*__unused*/,
+                                  void *prv_data,
+                                  void *buf,
+                                  audio_event_id_t event_id,
+                                  int size,
+                                  int device) //TODO: add media format as well.
 {
 
-/*
- For SPKR:
- 1. Open pcm device if device_id passed to it SPKR and write the data to
-    pcm device
+    /*
+     For SPKR:
+     1. Open pcm device if device_id passed to it SPKR and write the data to
+     pcm device
 
- For HDMI
- 1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format
- 2.create offload_callback thread to receive async events
- 3.Write the data to compress device. If not all the data is consumed by
-   the driver, add a command to offload_callback thread.
-*/
-    int ret;
+     For HDMI
+     1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format and write
+     data to the HDMI device.
+     */
+    int ret, i;
     audio_output_flags_t flags;
-    struct qaf* qaf_module = (struct qaf* ) prv_data;
+    struct qaf_module* qaf_mod = (struct qaf_module*)prv_data;
     struct audio_stream_out *bt_stream = NULL;
+    int format;
 
-    ALOGV("%s device 0x%X, %d in event = %d",
-                                          __func__, device, __LINE__, event_id);
+    DEBUG_MSG("Device 0x%X, Event = 0x%X", device, event_id);
+    pthread_mutex_lock(&p_qaf->lock);
 
     if (event_id == AUDIO_DATA_EVENT) {
-        ALOGVV("Device id %x %s %d, bytes to written %d",
-                                               device, __func__,__LINE__, size);
+        DEBUG_MSG("Device id 0x%X, bytes to write %d", device, size);
 
-        if ((qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] != NULL) && qaf_mod->hdmi_connect) {
-            pthread_mutex_lock(&qaf_module->lock);
-            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]));
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
-            }
-            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_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__);
+        if (p_qaf->passthrough_out != NULL) {
+            //If QAF passthrough is active then all the module output will be dropped.
+            pthread_mutex_unlock(&p_qaf->lock);
+            DEBUG_MSG("QAF-PSTH is active, DROPPING DATA!");
             return;
-        } else {
-            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_out[QAF_DEFAULT_PASSTHROUGH]);
-                qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
-                qaf_mod->main_output_active = false;
-                pthread_mutex_unlock(&qaf_module->lock);
+        }
+
+        if (check_and_get_compressed_device_format(device, &format)) {
+            /*
+             * CASE 1: Transcoded output of mm module.
+             * If HDMI is not connected then drop the data.
+             * Only one HDMI output can be supported from all the mm modules of QAF.
+             * Multi-Channel PCM HDMI output streams will be closed from all the mm modules.
+             * If transcoded output of other module is already enabled then this data will be dropped.
+             */
+
+            if (!p_qaf->hdmi_connect) {
+                DEBUG_MSG("HDMI not connected, DROPPING DATA!");
+                pthread_mutex_unlock(&p_qaf->lock);
+                return;
+            }
+
+            //Closing all the PCM HDMI output stream from QAF.
+            close_all_pcm_hdmi_output();
+
+            if (!p_qaf->passthrough_enabled
+                && !(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH])) {
+
+                struct audio_config config;
+                audio_devices_t devices;
+
+                //TODO: need to update the actual sample rate.
+                config.sample_rate = config.offload_info.sample_rate =
+                        QAF_OUTPUT_SAMPLING_RATE;
+                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+                config.format = config.offload_info.format = format;
+                //TODO: need to update the actual bit width.
+                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+                //TODO: What is the relevance of num of channels.
+                config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+                flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING
+                         | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
+                         | AUDIO_OUTPUT_FLAG_DIRECT);
+                devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+
+                ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                              QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE,
+                                              devices,
+                                              flags,
+                                              &config,
+                                              (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]),
+                                              NULL);
+                if (ret < 0) {
+                    ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+                    pthread_mutex_unlock(&p_qaf->lock);
+                    return;
+                }
+
+                if (format & AUDIO_COMPRESSED_OUT_DDP) {
+                    qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragment_size =
+                            COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE;
+                }
+                qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
+                        COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+
+                p_qaf->passthrough_enabled = true;
+            }
+
+            if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+                ret = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
+                        (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH],
+                        buf,
+                        size);
             }
         }
-        pthread_mutex_lock(&qaf_module->lock);
-        if ((device ==
-                   (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD)) ||
-            (device ==
-                   (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
+        else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+                   && (p_qaf->hdmi_connect)
+                   && (p_qaf->hdmi_sink_channels > 2)) {
 
-            if (NULL == qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] &&
-                                             qaf_mod->hdmi_connect) {
+            /* CASE 2: Multi-Channel PCM output to HDMI.
+             * If any other HDMI output is already enabled then this has to be dropped.
+             */
+            bool create_mch_out_stream = false;
+
+            if (p_qaf->passthrough_enabled) {
+                //Closing all the multi-Channel PCM HDMI output stream from QAF.
+                close_all_pcm_hdmi_output();
+
+                //If passthrough is active then pcm hdmi output has to be dropped.
+                pthread_mutex_unlock(&p_qaf->lock);
+                DEBUG_MSG("Compressed passthrough enabled, DROPPING DATA!");
+                return;
+            }
+
+            if (!p_qaf->mch_pcm_hdmi_enabled && !(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])) {
                 struct audio_config config;
                 audio_devices_t devices;
 
-                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_out[QAF_OUT_OFFLOAD_MCH]));
-                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
-                }
-
+                //TODO: need to update the actual sample rate.
                 config.sample_rate = config.offload_info.sample_rate =
-                                                       QAF_OUTPUT_SAMPLING_RATE;
+                        QAF_OUTPUT_SAMPLING_RATE;
                 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
                 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-
-                if (device ==
-                    (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP)) {
-                    config.format = config.offload_info.format =
-                                                           AUDIO_FORMAT_E_AC3;
-                } else {
-                    config.format = config.offload_info.format =
-                                                           AUDIO_FORMAT_AC3;
-                }
-
+                config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
+                //TODO: need to update the actual bit width.
                 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                config.offload_info.channel_mask = config.channel_mask =
-                                                      AUDIO_CHANNEL_OUT_5POINT1;
-                flags = (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
-                         AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM);
-                devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
 
-                ret = adev_open_output_stream(
-                          (struct audio_hw_device *) qaf_mod->adev,
-                          QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
-                          flags, &config,
-                          (struct audio_stream_out **)
-                          &(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_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_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
-                ret = qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
-                          (struct audio_stream_out *)
-                          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_out[QAF_DEFAULT_PASSTHROUGH] == NULL) &&
-                   (qaf_mod->hdmi_sink_channels > 2))) {
-            if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]) {
-                struct audio_config config;
-                audio_devices_t devices;
-
-                config.sample_rate = config.offload_info.sample_rate =
-                                                       QAF_OUTPUT_SAMPLING_RATE;
-                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-                config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
-                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                config.format = AUDIO_FORMAT_PCM_16_BIT;
-                devices = AUDIO_DEVICE_NONE;
-
-                if (qaf_mod->hdmi_sink_channels == 8) {
+                if (p_qaf->hdmi_sink_channels == 8) {
                     config.offload_info.channel_mask = config.channel_mask =
-                                                      AUDIO_CHANNEL_OUT_7POINT1;
-                } else if (qaf_mod->hdmi_sink_channels == 6) {
+                            AUDIO_CHANNEL_OUT_7POINT1;
+                } else if (p_qaf->hdmi_sink_channels == 6) {
                     config.offload_info.channel_mask = config.channel_mask =
-                                                      AUDIO_CHANNEL_OUT_5POINT1;
+                            AUDIO_CHANNEL_OUT_5POINT1;
                 } else {
                     config.offload_info.channel_mask = config.channel_mask =
-                                                      AUDIO_CHANNEL_OUT_STEREO;
+                            AUDIO_CHANNEL_OUT_STEREO;
                 }
-                devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                flags = (AUDIO_OUTPUT_FLAG_DIRECT|
-                         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_out[QAF_OUT_OFFLOAD_MCH]), NULL);
+                devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+
+                ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                              QAF_DEFAULT_COMPR_AUDIO_HANDLE,
+                                              devices,
+                                              flags,
+                                              &config,
+                                              (struct audio_stream_out **)&(qaf_mod->stream_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);
+                    ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+                    pthread_mutex_unlock(&p_qaf->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_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_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
-                          qaf_get_pcm_offload_buffer_size(&config.offload_info);
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
+                        COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
+                        qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+
+                p_qaf->mch_pcm_hdmi_enabled = true;
+
+                if (qaf_mod->stream_in[QAF_IN_MAIN]
+                    && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
+
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+                            (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+                            qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
+                            qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+                } else if (qaf_mod->stream_in[QAF_IN_PCM]
+                           && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
+
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+                            (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+                            qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
+                            qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
+                }
 
                 int index = -1;
                 if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
-                        index = (int)QAF_IN_MAIN;
+                    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);
+                    index = (int) QAF_IN_PCM;
 
-                    lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH]);
+                if (index >= 0) {
+                    if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->standby)
+                        qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+                                (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
+
+                    lock_output_stream(qaf_mod->stream_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);
+                            qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+                            AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+                            (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
+                    unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
 
                 }
             }
 
-            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_out[QAF_OUT_OFFLOAD_MCH], buf, size);
+            if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
+                ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
+                        (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+                        buf,
+                        size);
             }
-        } else {
+        }
+        else {
+            /* CASE 3: PCM output.
+             */
             bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
             if (bt_stream != NULL) {
-                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_out[QAF_OUT_OFFLOAD]));
-                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD] = NULL;
+                if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+                    adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                             (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
                 }
 
-                audio_extn_bt_hal_out_write(qaf_mod->bt_hdl, buf, size);
-            }
-
-            if (NULL == qaf_mod->qaf_out[QAF_OUT_OFFLOAD] && bt_stream == NULL &&
-                qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL) {
+                audio_extn_bt_hal_out_write(p_qaf->bt_hdl, buf, size);
+            } else if (NULL == qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
                 struct audio_config config;
                 audio_devices_t devices;
 
+                //TODO: need to update the actual sample rate.
                 config.sample_rate = config.offload_info.sample_rate =
-                                                       QAF_OUTPUT_SAMPLING_RATE;
+                        QAF_OUTPUT_SAMPLING_RATE;
                 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
                 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-                config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+                config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
+                //TODO: need to update the actual bit width.
                 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                config.format = AUDIO_FORMAT_PCM_16_BIT;
-                config.offload_info.channel_mask = config.channel_mask =
-                                                       AUDIO_CHANNEL_OUT_STEREO;
-                 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_DIRECT_PCM);
+                //TODO: need to update the actual num channels.
+                config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
 
+                if (qaf_mod->stream_in[QAF_IN_MAIN])
+                    devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
+                else
+                    devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
+
+                //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
+                if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
+                    if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+                        devices ^= AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                }
+                if (devices == 0) {
+                    devices = device;
+                }
+
+                flags = (AUDIO_OUTPUT_FLAG_DIRECT | 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_out[QAF_OUT_OFFLOAD]), NULL);
+                ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                              QAF_DEFAULT_COMPR_AUDIO_HANDLE,
+                                              devices,
+                                              flags,
+                                              &config,
+                                              (struct audio_stream_out **)&(qaf_mod->stream_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);
+                    ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
+                    pthread_mutex_unlock(&p_qaf->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);
 
+                if (qaf_mod->stream_in[QAF_IN_MAIN]
+                    && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
 
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
-                                                 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
-                          qaf_get_pcm_offload_buffer_size(&config.offload_info);
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.channel_mask =
-                                               config.offload_info.channel_mask;
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.format =
-                                               config.offload_info.format;
-                qaf_mod->qaf_out[QAF_OUT_OFFLOAD]->info.sample_rate =
-                                               config.offload_info.sample_rate;
-                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);
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+                            (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+                            qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
+                            qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+                } else if (qaf_mod->stream_in[QAF_IN_PCM]
+                           && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
+
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+                                                (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+                                                qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
+                                                qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
+                }
+
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
+                        COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
+                        qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+
+                if (qaf_mod->is_vol_set) {
+                    DEBUG_MSG("Setting Volume Left[%f], Right[%f]", qaf_mod->vol_left, qaf_mod->vol_right);
+                    qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
+                            (struct audio_stream_out *)qaf_mod->stream_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;
+                    index = (int) QAF_IN_MAIN;
                 else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
-                    index = (int)QAF_IN_PCM;
+                    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);
+                    if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]->standby) {
+                        qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
+                                (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], NULL, 0);
+                    }
 
-                    lock_output_stream(qaf_mod->qaf_out[QAF_OUT_OFFLOAD]);
+                    lock_output_stream(qaf_mod->stream_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_out[QAF_OUT_TRANSCODE_PASSTHROUGH] ||
-                 qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH])) {
-                qaf_mod->passthrough_enabled = 0;
-                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_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
-                    qaf_mod->qaf_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
-                }
-                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_out[QAF_OUT_OFFLOAD_MCH]));
-                    qaf_mod->qaf_out[QAF_OUT_OFFLOAD_MCH] = NULL;
+                            qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+                            AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
+                            (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
+                    unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
                 }
             }
 
@@ -1030,99 +1441,254 @@
              * TODO:: Since this is mixed data,
              * need to identify to which stream the error should be sent
              */
-            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_out[QAF_OUT_OFFLOAD], buf, size);
+            if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+                ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
+                        (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+                        buf,
+                        size);
             }
         }
 
-        ALOGVV("%s:%d stream write ret = %d", __func__, __LINE__, ret);
-        pthread_mutex_unlock(&qaf_module->lock);
-    } else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
+        DEBUG_MSG("Bytes written = %d", ret);
+    }
+    else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
                || 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[QAF_IN_MAIN];
-        struct stream_out *out_assoc = qaf_module->stream[QAF_IN_ASSOC];
+        struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
+        struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
+        bool *main_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
+        bool *assoc_drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
 
         /**
          * TODO:: Only DD/DDP Associate Eos is handled, need to add support
          * for other formats.
          */
-        if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT && out_assoc != NULL) {
+        if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+                && (out_assoc != NULL)
+                && (*assoc_drain_received)) {
+
             lock_output_stream(out_assoc);
-            out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
-                                  out_assoc->client_cookie);
-            pthread_mutex_unlock(&out_assoc->lock);
-            qaf_module->stream[QAF_IN_ASSOC] = NULL;
-        } else if (out != NULL) {
+            out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_assoc->client_cookie);
+            *assoc_drain_received = false;
+            unlock_output_stream(out_assoc);
+            DEBUG_MSG("sent associated DRAIN_READY");
+        } else if ((out != NULL) && (*main_drain_received)) {
             lock_output_stream(out);
             out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
-            pthread_mutex_unlock(&out->lock);
-            qaf_module->stream[QAF_IN_MAIN] = NULL;
-            ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
+            *main_drain_received = false;
+            unlock_output_stream(out);
+            DEBUG_MSG("sent main DRAIN_READY");
         }
     }
-    ALOGV("%s %d", __func__, __LINE__);
+#if 0
+    else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) { //TODO: For DTS
+        struct stream_out *out = NULL;
+        bool *drain_received = NULL;
+
+        if (event_id == AUDIO_MAIN_EOS_EVENT) {
+            out = qaf_mod->stream_in[QAF_IN_MAIN];
+            drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
+        } else {
+            out = qaf_mod->stream_in[QAF_IN_ASSOC];
+            drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
+        }
+
+        if ((out != NULL) && (*drain_received)) {
+            lock_output_stream(out);
+            out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
+            *drain_received = false;
+            unlock_output_stream(out);
+            DEBUG_MSG("sent DRAIN_READY");
+        }
+    }
+#endif
+
+    pthread_mutex_unlock(&p_qaf->lock);
+    return;
 }
 
-static int qaf_session_close()
+/* Close the mm module session. */
+static int qaf_session_close(struct qaf_module* qaf_mod)
 {
-    ALOGV("%s %d", __func__, __LINE__);
-    if (qaf_mod != NULL) {
-        if (!qaf_mod->qaf_audio_session_close)
-            return -EINVAL;
+    int j;
 
+    //Check if all streams are closed or not.
+    for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
+        if (qaf_mod->stream_in[j] != NULL) {
+            break;
+        }
+    }
+    if (j != MAX_QAF_MODULE_IN) {
+        return 0; //Some stream is already active, Can not close session.
+    }
+
+    if (qaf_mod->session_handle != NULL && qaf_mod->qaf_audio_session_close) {
         qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
         qaf_mod->session_handle = NULL;
-        pthread_mutex_destroy(&qaf_mod->lock);
+        qaf_mod->is_vol_set = false;
+        memset(qaf_mod->drain_received, 0, sizeof(qaf_mod->drain_received));
     }
+
+    for (j = 0; j < MAX_QAF_MODULE_OUT; j++) {
+        if (qaf_mod->stream_out[j]) {
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(qaf_mod->stream_out[j]));
+            qaf_mod->stream_out[j] = NULL;
+        }
+    }
+
+    DEBUG_MSG("Session Closed.");
+
     return 0;
 }
 
+/* Close the stream of QAF module. */
 static int qaf_stream_close(struct stream_out *out)
 {
-    int ret = 0;
-    ALOGV( "%s %d", __func__, __LINE__);
-    if (!qaf_mod->qaf_audio_stream_close)
+    int ret = -EINVAL;
+    struct qaf_module *qaf_mod = NULL;
+    int index = -1;
+    DEBUG_MSG("Flag [0x%x], Stream handle [%p]", out->flags, out->qaf_stream_handle);
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    index = get_input_stream_index(out);
+
+    if (!qaf_mod || !qaf_mod->qaf_audio_stream_close || index < 0) {
         return -EINVAL;
+    }
+
+    qaf_mod->stream_in[index] = NULL;
+    memset(&qaf_mod->adsp_hdlr_config[index], 0, sizeof(struct qaf_adsp_hdlr_config_state));
+
+    lock_output_stream(out);
     if (out->qaf_stream_handle) {
-        ALOGV( "%s %d output active flag is %x and stream handle %p", __func__, __LINE__, out->flags, out->qaf_stream_handle);
-        if ((out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) && (out->flags & AUDIO_OUTPUT_FLAG_MAIN)) { /* Close for Stream with Main and Associated Content*/
-            qaf_mod->main_output_active = false;
-            qaf_mod->assoc_output_active = false;
-        } else if (out->flags & AUDIO_OUTPUT_FLAG_MAIN) {/*Close for Main Stream*/
-            qaf_mod->main_output_active = false;
-            qaf_mod->assoc_output_active = false; /* TODO to remove resetting associated stream active flag when main stream is closed*/
-        } else if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) { /*Close for Associated Stream*/
-            qaf_mod->assoc_output_active = false;
-        } else { /*Close for Local Playback*/
-            qaf_mod->main_output_active = false;
-        }
         ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
         out->qaf_stream_handle = NULL;
     }
-    ALOGV( "%s %d", __func__, __LINE__);
+    unlock_output_stream(out);
+
+    //If all streams are closed then close the session.
+    qaf_session_close(qaf_mod);
+
+    DEBUG_MSG();
     return ret;
 }
 
-static int qaf_stream_open(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices)
+/* Open a MM module session with QAF. */
+static int audio_extn_qaf_session_open(mm_module_type mod_type)
 {
-    int status = 0;
     ALOGV("%s %d", __func__, __LINE__);
+    unsigned char* license_data = NULL;
+    device_license_config_t lic_config = {0};
+    int ret = -ENOSYS, size = 0;
+    char value[PROPERTY_VALUE_MAX] = {0};
+    struct qaf_module *qaf_mod = NULL;
 
-    if (!qaf_mod->qaf_audio_stream_open)
-        return -EINVAL;
+    if (mod_type >= MAX_MM_MODULE_TYPE || !(p_qaf->qaf_mod[mod_type].qaf_audio_session_open))
+        return -ENOTSUP; //Not supported by QAF module.
 
-    if (audio_extn_qaf_passthrough_enabled(out) && qaf_mod->hdmi_connect) {
-        ALOGV("%s %d passthrough is enabled", __func__, __LINE__);
-        status =  create_output_stream(out, config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
-        if (status < 0) {
-            ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, status);
+    pthread_mutex_lock(&p_qaf->lock);
+
+    qaf_mod = &(p_qaf->qaf_mod[mod_type]);
+
+    //If session is already opened then return.
+    if (qaf_mod->session_handle) {
+        DEBUG_MSG("Session is already opened.");
+        pthread_mutex_unlock(&p_qaf->lock);
+        return 0;
+    }
+
+    if (mod_type == MS12) {
+        //Getting the license
+        license_data = platform_get_license((struct audio_hw_device *)(p_qaf->adev->platform),
+                                            &size);
+        if (!license_data) {
+            ERROR_MSG("License data is not present.");
+            pthread_mutex_unlock(&p_qaf->lock);
             return -EINVAL;
         }
-        return 0;
+
+        lic_config.p_license = (unsigned char*)calloc(1, size);
+        if (lic_config.p_license == NULL) {
+            ERROR_MSG("Out of Memory");
+            ret = -ENOMEM;
+            goto exit;
+        }
+
+        lic_config.l_size = size;
+        memcpy(lic_config.p_license, license_data, size);
+
+        if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
+            lic_config.manufacturer_id = (unsigned long)atoi(value);
+        } else {
+            ERROR_MSG("audio.qaf.manufacturer id is not set");
+            ret = -EINVAL;
+            goto exit;
+        }
+    }
+
+    ret = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
+                                          (void *)(qaf_mod),
+                                          (void *)&lic_config);
+    if (ret < 0) {
+        ERROR_MSG("Error in session open %d", ret);
+        goto exit;
+    }
+
+    if (qaf_mod->session_handle == NULL) {
+        ERROR_MSG("Session handle is NULL.");
+        ret = -ENOMEM;
+        goto exit;
+    }
+
+    if (qaf_mod->qaf_register_event_callback)
+        qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
+                                             qaf_mod,
+                                             &notify_event_callback,
+                                             AUDIO_DATA_EVENT);
+
+    set_hdmi_configuration_to_module();
+
+exit:
+    if (license_data != NULL) {
+        free(license_data);
+        license_data = NULL;
+    }
+    if (lic_config.p_license != NULL) {
+        free(lic_config.p_license);
+        lic_config.p_license = NULL;
+    }
+
+    pthread_mutex_unlock(&p_qaf->lock);
+    return ret;
+}
+
+/* opens a stream in QAF module. */
+static int qaf_stream_open(struct stream_out *out,
+                           struct audio_config *config,
+                           audio_output_flags_t flags,
+                           audio_devices_t devices)
+{
+    int status = -EINVAL;
+    mm_module_type mmtype = get_mm_module_for_format(config->format);
+    struct qaf_module* qaf_mod = NULL;
+    DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
+
+    if (mmtype >= MAX_MM_MODULE_TYPE
+        || p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL
+        || p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+        ERROR_MSG("Unsupported Stream");
+        return -ENOTSUP;
+    }
+
+    //Open the module session, if not opened already.
+    status = audio_extn_qaf_session_open(mmtype);
+    qaf_mod = &(p_qaf->qaf_mod[mmtype]);
+
+    if ((status != 0) || (qaf_mod->session_handle == NULL)) {
+        ERROR_MSG("Failed to open session.");
+        return status;
     }
 
     audio_stream_config_t input_config;
@@ -1130,187 +1696,163 @@
     input_config.channels = popcount(config->channel_mask);
     input_config.format = config->format;
 
-    if ((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) {
-        input_config.format = AUDIO_FORMAT_AAC;
-    } else if((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS) {
-        input_config.format = AUDIO_FORMAT_AAC_ADTS;
+    if (input_config.format != AUDIO_FORMAT_PCM_16_BIT) {
+        input_config.format &= AUDIO_FORMAT_MAIN_MASK;
     }
 
-    ALOGV("%s %d audio_stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)\
-      ",__func__, __LINE__, input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
+    DEBUG_MSG("stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)",
+              input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
 
-    /* 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 ||
-               input_config.format == AUDIO_FORMAT_AAC ||
-               input_config.format == AUDIO_FORMAT_AAC_ADTS) {
-        if (qaf_mod->main_output_active == false) {
-            if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
-                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 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__);
+        //If PCM stream is already opened then fail this stream open.
+        if (qaf_mod->stream_in[QAF_IN_PCM]) {
+            ERROR_MSG("PCM input is already active.");
+            return -ENOTSUP;
+        }
+
+        //TODO: Flag can be system tone or external associated PCM.
+        status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+                                                &out->qaf_stream_handle,
+                                                input_config,
+                                                devices,
+                                                AUDIO_STREAM_SYSTEM_TONE);
+        qaf_mod->stream_in[QAF_IN_PCM] = out;
+    } else {
+        if (!qaf_mod->stream_in[QAF_IN_MAIN]) {
+            if ((!(flags & AUDIO_OUTPUT_FLAG_MAIN)) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
+                ERROR_MSG("Error main input is not active.");
                 return -EINVAL;
-            } else {
-                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 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;
-                }
+            }
+
+            status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+                                                    &out->qaf_stream_handle,
+                                                    input_config,
+                                                    devices,
+                                                    AUDIO_STREAM_MAIN);
+            if (status == 0) {
+                DEBUG_MSG("Open stream for Input with Main stream contents with flag [%x] and stream handle [%p]",
+                      flags, out->qaf_stream_handle);
+                qaf_mod->stream_in[QAF_IN_MAIN] = out;
             }
         } else {
             if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
-                ALOGE("%s %d Error main input is already active", __func__, __LINE__);
+                ERROR_MSG("Error main input is already active");
                 return -EINVAL;
-            } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
-                if (qaf_mod->assoc_output_active) {
-                    ALOGE("%s %d Error assoc input is already active", __func__, __LINE__);
-                    return -EINVAL;
-                } else {
-                    status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
-                    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 if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)
+                       && (!qaf_mod->stream_in[QAF_IN_ASSOC])) {
+                status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
+                                                        &out->qaf_stream_handle,
+                                                        input_config,
+                                                        devices,
+                                                        AUDIO_STREAM_ASSOCIATED);
+                if (status == 0) {
+                    DEBUG_MSG("Open stream for Input with only Associated flag [%x] stream handle [%p]",
+                          flags, out->qaf_stream_handle);
+                    qaf_mod->stream_in[QAF_IN_ASSOC] = out;
                 }
             } else {
-                ALOGE("%s %d Error main input is already active", __func__, __LINE__);
-                return -EINVAL;
+                ERROR_MSG("Invalid flag or associated is already active");
+                status = -EINVAL;
             }
         }
     }
 
+    if (status != 0) {
+        //If no stream is active then close the session.
+        qaf_session_close(qaf_mod);
+        return status;
+    }
+
+    //If Device is HDMI, QAF passthrough is enabled and there is no previous QAF passthrough input stream.
+    if ((!p_qaf->passthrough_in)
+        && (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+        && audio_extn_qaf_passthrough_enabled(out)) {
+        //Assign the QAF passthrough input stream.
+        p_qaf->passthrough_in = out;
+
+        //If HDMI is connected and format is supported by HDMI then create QAF passthrough output stream.
+        if (p_qaf->hdmi_connect
+            && platform_is_edid_supported_format(p_qaf->adev->platform, out->format)) {
+            status = create_qaf_passthrough_stream();
+            if (status < 0) {
+                qaf_stream_close(out);
+                ERROR_MSG("QAF passthrough stream creation failed with error %d", status);
+                return status;
+            }
+        }
+        /*Else: since QAF passthrough input stream is already initialized,
+         * when hdmi is connected
+         * then qaf passthrough output stream will be created.
+         */
+    }
+
+    DEBUG_MSG();
     return status;
 }
 
-static int audio_extn_qaf_stream_open(struct stream_out *out)
-{
-    int status = -ENOSYS;
-    struct audio_config config;
-    audio_devices_t devices;
-
-    config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
-    config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-    config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-    config.offload_info.format = out->format;
-    config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-    config.format = out->format;
-    config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
-
-    devices = AUDIO_DEVICE_OUT_SPEAKER;
-    status = qaf_stream_open(out, &config, out->flags, devices);
-    ALOGV("%s %d status %d", __func__, __LINE__, status);
-    return status;
-}
-
+/* Resume a QAF stream. */
 static int qaf_out_resume(struct audio_stream_out* stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    int status = -ENOSYS;
-    ALOGV("%s", __func__);
+    int status = 0;
+    DEBUG_MSG("Output Stream %p", out);
+
+
     lock_output_stream(out);
-    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_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_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);
-                return status;
-            } else {
-                if ((out->format == AUDIO_FORMAT_E_AC3) || (out->format == AUDIO_FORMAT_AC3)) {
-                    status = audio_extn_qaf_stream_open(out);
-                    if (!status)
-                        out->offload_state = OFFLOAD_STATE_PLAYING;
-                    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_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);
-                    return status;
-                }
-            }
+
+    //If QAF passthrough is active then block the resume on module input streams.
+    if (p_qaf->passthrough_out) {
+        //If resume is received for the QAF passthrough stream then call the primary HAL api.
+        pthread_mutex_lock(&p_qaf->lock);
+        if (p_qaf->passthrough_in == out) {
+            status = p_qaf->passthrough_out->stream.resume(
+                    (struct audio_stream_out*)p_qaf->passthrough_out);
+            if (!status) out->offload_state = OFFLOAD_STATE_PLAYING;
         }
+        pthread_mutex_unlock(&p_qaf->lock);
+    } else {
+        //Flush the module input stream.
+        status = qaf_stream_start(out);
     }
 
-    status = qaf_stream_start(out);
-    pthread_mutex_unlock(&out->lock);
-    ALOGD("%s Exit", __func__);
+    unlock_output_stream(out);
+
+    DEBUG_MSG();
     return status;
 }
 
-static int qaf_deinit()
-{
-    ALOGV("%s %d", __func__, __LINE__);
-    if (qaf_mod != 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_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_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;
-        }
-
-        free(qaf_mod);
-        qaf_mod = NULL;
-    }
-    return 0;
-}
-
+/* Offload thread for QAF output streams. */
 static void *qaf_offload_thread_loop(void *context)
 {
-    struct stream_out *out = (struct stream_out *) context;
+    struct stream_out *out = (struct stream_out *)context;
     struct listnode *item;
     int ret = 0;
     struct str_parms *parms = NULL;
     int value = 0;
     char* kvpairs = NULL;
+    struct qaf_module *qaf_mod = NULL;
+
+    qaf_mod = get_qaf_module_for_input_stream(out);
+
+    if (!qaf_mod) return NULL;
 
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
     set_sched_policy(0, SP_FOREGROUND);
     prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
 
-    ALOGV("%s", __func__);
     lock_output_stream(out);
+
+    DEBUG_MSG();
     for (;;) {
         struct offload_cmd *cmd = NULL;
         stream_callback_event_t event;
         bool send_callback = false;
 
-        ALOGV("%s qaf_offload_cmd_list %d",
-              __func__, list_empty(&out->qaf_offload_cmd_list));
+        DEBUG_MSG("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
         if (list_empty(&out->qaf_offload_cmd_list)) {
-            ALOGV("%s SLEEPING", __func__);
+            DEBUG_MSG("SLEEPING");
             pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
-            ALOGV("%s RUNNING", __func__);
+            DEBUG_MSG("RUNNING");
             continue;
         }
 
@@ -1323,80 +1865,91 @@
             break;
         }
 
-        pthread_mutex_unlock(&out->lock);
+        unlock_output_stream(out);
+
         send_callback = false;
-        switch(cmd->cmd) {
-        case OFFLOAD_CMD_WAIT_FOR_BUFFER:
-            ALOGV("wait for ms12 buffer availability");
-            while (1) {
-                kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "buf_available");
-                if (kvpairs) {
-                    parms = str_parms_create_str(kvpairs);
-                    ret = str_parms_get_int(parms, "buf_available", &value);
-                    if (ret >= 0) {
-                        if (value >= (int)out->compr_config.fragment_size) {
-                            ALOGV("%s buffer available", __func__);
-                            str_parms_destroy(parms);
-                            parms = NULL;
-                            break;
-                        } else {
-                            ALOGV("%s sleep", __func__);
-                            str_parms_destroy(parms);
-                            parms = NULL;
-                            usleep(10000);
+        switch (cmd->cmd) {
+            case OFFLOAD_CMD_WAIT_FOR_BUFFER: {
+                DEBUG_MSG("wait for buffer availability");
+
+                while (1) {
+                    kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle,
+                                                                  "buf_available");
+                    if (kvpairs) {
+                        parms = str_parms_create_str(kvpairs);
+                        ret = str_parms_get_int(parms, "buf_available", &value);
+                        if (ret >= 0) {
+                            if (value >= (int)out->compr_config.fragment_size) {
+                                DEBUG_MSG("buffer available");
+                                str_parms_destroy(parms);
+                                parms = NULL;
+                                break;
+                            } else {
+                                DEBUG_MSG("sleep");
+                                str_parms_destroy(parms);
+                                parms = NULL;
+                                usleep(10000);
+                            }
                         }
+                        free(kvpairs);
+                        kvpairs = NULL;
                     }
-                    free(kvpairs);
-                    kvpairs = NULL;
                 }
+                send_callback = true;
+                event = STREAM_CBK_EVENT_WRITE_READY;
+                break;
             }
-            send_callback = true;
-            event = STREAM_CBK_EVENT_WRITE_READY;
-            break;
-        default:
-            ALOGV("%s unknown command received: %d", __func__, cmd->cmd);
+            default:
+                DEBUG_MSG("unknown command received: %d", cmd->cmd);
             break;
         }
+
         lock_output_stream(out);
+
         if (send_callback && out->client_callback) {
             out->client_callback(event, NULL, out->client_cookie);
         }
+
         free(cmd);
     }
 
     while (!list_empty(&out->qaf_offload_cmd_list)) {
         item = list_head(&out->qaf_offload_cmd_list);
         list_remove(item);
-        free(node_to_item(item, struct offload_cmd, node));
+        free (node_to_item( item, struct offload_cmd, node));
     }
-    pthread_mutex_unlock(&out->lock);
+    unlock_output_stream(out);
 
     return NULL;
 }
 
+/* Create the offload callback thread for QAF output stream. */
 static int qaf_create_offload_callback_thread(struct stream_out *out)
 {
-    ALOGV("%s", __func__);
-    pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *) NULL);
+    DEBUG_MSG("Output Stream %p", out);
+    lock_output_stream(out);
+    pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *)NULL);
     list_init(&out->qaf_offload_cmd_list);
-    pthread_create(&out->qaf_offload_thread, (const pthread_attr_t *) NULL,
-                    qaf_offload_thread_loop, out);
+    pthread_create(&out->qaf_offload_thread,
+                   (const pthread_attr_t *)NULL,
+                   qaf_offload_thread_loop,
+                   out);
+    unlock_output_stream(out);
     return 0;
 }
 
+/* Destroy the offload callback thread of QAF output stream. */
 static int qaf_destroy_offload_callback_thread(struct stream_out *out)
 {
-    ALOGV("%s", __func__);
-    lock_output_stream(out);
+    DEBUG_MSG("Output Stream %p", out);
     qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
-    pthread_mutex_unlock(&out->lock);
 
-    pthread_join(out->qaf_offload_thread, (void **) NULL);
+    pthread_join(out->qaf_offload_thread, (void **)NULL);
     pthread_cond_destroy(&out->qaf_offload_cond);
-
     return 0;
 }
 
+/* Sets the stream set parameters (device routing information). */
 static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
 {
     struct str_parms *parms, *new_parms;
@@ -1406,241 +1959,238 @@
     struct stream_out *out = (struct stream_out *)stream;
     int ret = 0;
     int err = 0;
+    struct qaf_module *qaf_mod = NULL;
 
-    ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
-          __func__, out->usecase, use_case_table[out->usecase], kvpairs);
-    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;
+    DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
 
-            parms = str_parms_create_str(kvpairs);
-            err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    parms = str_parms_create_str(kvpairs);
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (err < 0)
+        return err;
+    val = atoi(value);
 
-            /* usecase : hdmi sink which supports only 2-channel pcm */
-            if (err >= 0) {
-                val = atoi(value);
-                if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
-                        ((qaf_mod->hdmi_sink_channels == 2) && !(qaf_mod->passthrough_enabled))) {
-                    new_parms = str_parms_create();
-                    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_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);
-                }
+    qaf_mod = get_qaf_module_for_input_stream(out);
+    if (!qaf_mod) return (-EINVAL);
+
+    //TODO: HDMI is connected but user doesn't want HDMI output, close both HDMI outputs.
+
+    /* Setting new device information to the mm module input streams.
+     * This is needed if QAF module output streams are not created yet.
+     */
+    if (qaf_mod->stream_in[QAF_IN_MAIN] == out || qaf_mod->stream_in[QAF_IN_ASSOC] == out) {
+        qaf_mod->stream_in[QAF_IN_MAIN]->devices = val;
+    } else {
+        out->devices = val;
+    }
+
+    if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
+        //If device is BT then open the BT stream if not already opened.
+        if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL
+             && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
+            ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
+                                                       QAF_OUTPUT_SAMPLING_RATE,
+                                                       AUDIO_CHANNEL_OUT_STEREO,
+                                                       CODEC_BACKEND_DEFAULT_BIT_WIDTH);
+            if (ret != 0) {
+                ERROR_MSG("BT Output stream open failure!");
             }
-            str_parms_destroy(parms);
-        } else {
-            if (!(qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect))
-                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) {
-                ALOGE("str_parms_create_str failed!");
-            } else {
-                err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
-                if (err >= 0) {
-                    val = atoi(value);
-                    if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) { //BT routing
-                        if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
-                            ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
-                                    QAF_OUTPUT_SAMPLING_RATE,
-                                    AUDIO_CHANNEL_OUT_STEREO,
-                                    CODEC_BACKEND_DEFAULT_BIT_WIDTH);
-                            if (ret != 0) {
-                                ALOGE("%s: BT Output stream open failure!", __FUNCTION__);
-                            }
-                        }
-                    } else if (val != 0) {
-                        if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl)!= NULL) {
-                            audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
-                        }
-                    }
-                }
-                str_parms_destroy(parms);
-            }
+        }
+    } else if (val != 0) {
+        //If device is not BT then close the BT stream if already opened.
+        if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
+            audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
         }
     }
 
-    if (audio_extn_qaf_passthrough_enabled(out)) {
-        parms = str_parms_create_str(kvpairs);
-        if (!parms) {
-            ALOGE("str_parms_create_str failed!");
-        } else {
-            err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
-            if (err >= 0) {
-                val = atoi(value);
-                if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
-                    (qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] == NULL)) {
-                        audio_output_flags_t flags;
-                        struct audio_config config;
-                        audio_devices_t devices;
+    if (p_qaf->passthrough_in == out) { //Device routing is received for QAF passthrough stream.
 
-                        config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
-                        config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-                        config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-                        config.offload_info.format = out->format;
-                        config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                        config.format = out->format;
-                        config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
+        if (!(val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { //HDMI route is disabled.
 
-                        devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                        flags = out->flags;
+            //If QAF pasthrough output is enabled. Close it.
+            close_qaf_passthrough_stream();
 
-                        if (out->qaf_stream_handle) {
-                            qaf_out_pause((struct audio_stream_out*)out);
-                            qaf_out_flush((struct audio_stream_out*)out);
-                            qaf_out_drain((struct audio_stream_out*)out, (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
-                            qaf_stream_close(out);
-                        }
-                        create_output_stream(out, &config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
-                        qaf_mod->main_output_active = true;
-                }
+            //Send the routing information to mm module pcm output.
+            if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+                ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
+                        (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
             }
-            str_parms_destroy(parms);
+            //else: device info is updated in the input streams.
+        } else { //HDMI route is enabled.
+
+            //create the QAf passthrough stream, if not created already.
+            ret = create_qaf_passthrough_stream();
+
+            if (p_qaf->passthrough_out != NULL) { //If QAF passthrough out is enabled then send routing information.
+                ret = p_qaf->passthrough_out->stream.common.set_parameters(
+                        (struct audio_stream *)p_qaf->passthrough_out, kvpairs);
+            }
         }
+    } else {
+        //Send the routing information to mm module pcm output.
+        if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+            ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
+                    (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
+        }
+        //else: device info is updated in the input streams.
     }
+    str_parms_destroy(parms);
+
     return ret;
 }
 
+/* Checks if a stream is QAF stream or not. */
 bool audio_extn_is_qaf_stream(struct stream_out *out)
 {
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
 
-    return (audio_extn_qaf_is_enabled() && out && is_ms12_format(out->format));
+    if (qaf_mod) {
+        return true;
+    }
+    return false;
 }
 
 /* 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)
+                                       audio_extn_param_id param_id,
+                                       audio_extn_param_payload *payload)
 {
     int ret = -EINVAL;
-    int count;
+    int index;
     struct stream_out *new_out = NULL;
     struct audio_adsp_event *adsp_event;
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
 
-    if (!out || !payload) {
-        ALOGE("%s:: Invalid Param",__func__);
+    if (!out || !qaf_mod || !payload) {
+        ERROR_MSG("Invalid Param");
         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
-    */
+     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__);
+        index = get_input_stream_index(out);
+        if (index < 0) {
+            ERROR_MSG("Invalid stream");
             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__,
+        if (payload->adsp_event_params.payload_length <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
+            pthread_mutex_lock(&p_qaf->lock);
+            memcpy(qaf_mod->adsp_hdlr_config[index].event_payload,
+                   adsp_event->payload,
                    adsp_event->payload_length);
+            qaf_mod->adsp_hdlr_config[index].event_params.payload =
+                    qaf_mod->adsp_hdlr_config[index].event_payload;
+            qaf_mod->adsp_hdlr_config[index].event_params.payload_length =
+                    adsp_event->payload_length;
+            qaf_mod->adsp_hdlr_config[index].adsp_hdlr_config_valid = true;
+            pthread_mutex_unlock(&p_qaf->lock);
+        } else {
+            ERROR_MSG("Invalid adsp event length %d", 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;
+    /* apply param for all active out sessions */
+    for (index = 0; index < MAX_QAF_MODULE_OUT; index++) {
+        new_out = qaf_mod->stream_out[index];
+        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;
+        /*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)
+            ERROR_MSG("audio_extn_out_set_param_data error %d", ret);
+        unlock_output_stream(new_out);
+    }
+    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;
+    int ret = -EINVAL, i;
+    struct stream_out *new_out;
+    struct audio_usecase *uc_info;
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
 
-    if (!out || !payload) {
-        ALOGE("%s:: Invalid Param",__func__);
+    if (!out || !qaf_mod || !payload) {
+        ERROR_MSG("Invalid Param");
         return ret;
     }
 
-    if (!qaf_mod->hdmi_connect) {
-        ALOGE("%s:: hdmi not connected",__func__);
+    if (!p_qaf->hdmi_connect) {
+        ERROR_MSG("hdmi not connected");
         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 (p_qaf->passthrough_out)
+        new_out = p_qaf->passthrough_out;
+    else {
+        for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
+            if (qaf_mod->stream_out[i]) {
+                new_out = qaf_mod->stream_out[i];
+                break;
+            }
+        }
+    }
 
     if (!new_out) {
-        ALOGE("%s:: No out session active",__func__);
+        ERROR_MSG("No stream active.");
         return ret;
     }
 
     if (new_out->standby)
-           new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
+        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);
+    if (ret)
+        ERROR_MSG("audio_extn_out_get_param_data error %d", ret);
+    unlock_output_stream(new_out);
+
     return ret;
 }
 
+/* To open a stream with QAF. */
 int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
-                                   audio_io_handle_t handle,
-                                   audio_devices_t devices,
-                                   audio_output_flags_t flags,
-                                   struct audio_config *config,
-                                   struct audio_stream_out **stream_out,
-                                   const char *address __unused)
+                                      audio_io_handle_t handle,
+                                      audio_devices_t devices,
+                                      audio_output_flags_t flags,
+                                      struct audio_config *config,
+                                      struct audio_stream_out **stream_out,
+                                      const char *address)
 {
     int ret = 0;
     struct stream_out *out;
 
     ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
     if (*stream_out == NULL) {
-        goto error_open;
-    }
-
-    if ( false == is_ms12_format(config->format) ) {
-        ALOGV("%s: exiting qaf for non-ms12 format %x", __func__, config->format);
+        ERROR_MSG("Stream open failed %d", ret);
         return ret;
     }
 
-    out = (struct stream_out *) *stream_out;
+    out = (struct stream_out *)*stream_out;
+
+    ret = qaf_stream_open(out, config, flags, devices);
+    if (ret == -ENOTSUP) {
+        //Stream not supported by QAF, Bypass QAF.
+        return 0;
+    } else if (ret < 0) {
+        ERROR_MSG("Error opening QAF stream err[%d]!", ret);
+        adev_close_output_stream(dev, *stream_out);
+        return ret;
+    }
 
     /* Override function pointers based on qaf definitions */
     out->stream.set_volume = qaf_out_set_volume;
@@ -1655,13 +2205,8 @@
     out->stream.write = qaf_out_write;
     out->stream.get_presentation_position = qaf_out_get_presentation_position;
     out->platform_latency = 0;
-    ret = qaf_stream_open(out, config, flags, devices);
-    if (ret < 0) {
-        ALOGE("%s, Error opening QAF stream err[%d]!", __func__, ret);
-        adev_close_output_stream(dev, *stream_out);
-        goto error_open;
-    }
 
+    /*TODO: Need to handle this for DTS*/
     if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
         out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
         out->config.period_size = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
@@ -1669,57 +2214,52 @@
         out->config.start_threshold = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
         out->config.avail_min = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
     }
-
     *stream_out = &out->stream;
     if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         qaf_create_offload_callback_thread(out);
     }
-    ALOGV("%s: exit", __func__);
+
+    DEBUG_MSG("Exit");
     return 0;
-error_open:
-    *stream_out = NULL;
-    ALOGD("%s: exit: ret %d", __func__, ret);
-    return ret;
 }
 
+/* Close a QAF stream. */
 void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
-                                     struct audio_stream_out *stream)
+                                        struct audio_stream_out *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    int index;
+    struct qaf_module* qaf_mod = get_qaf_module_for_input_stream(out);
 
-    ALOGV("%s: enter:stream_handle(%p) format = %x", __func__, out, out->format);
-    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_out[QAF_DEFAULT_PASSTHROUGH]));
-        adev_close_output_stream(dev, stream);
-        qaf_mod->qaf_out[QAF_DEFAULT_PASSTHROUGH] = NULL;
-        qaf_mod->main_output_active = false;
-        pthread_mutex_unlock(&qaf_mod->lock);
-        return;
+    if (!qaf_mod) return;
+
+    DEBUG_MSG("stream_handle(%p) format = %x", out, out->format);
+
+    //If close is received for QAF passthrough stream then close the QAF passthrough output.
+    if (p_qaf->passthrough_in == out) {
+        if (p_qaf->passthrough_out) {
+            ALOGD("%s %d closing stream handle %p", __func__, __LINE__, p_qaf->passthrough_out);
+            pthread_mutex_lock(&p_qaf->lock);
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(p_qaf->passthrough_out));
+            pthread_mutex_unlock(&p_qaf->lock);
+            p_qaf->passthrough_out = NULL;
+        }
+
+        p_qaf->passthrough_in = NULL;
     }
 
     if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         qaf_destroy_offload_callback_thread(out);
     }
 
-    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);
 
     adev_close_output_stream(dev, stream);
-    ALOGV("%s: exit", __func__);
+
+    DEBUG_MSG("Exit");
 }
 
+/* Check if QAF is supported or not. */
 bool audio_extn_qaf_is_enabled()
 {
     bool prop_enabled = false;
@@ -1729,322 +2269,413 @@
     return (prop_enabled);
 }
 
-int audio_extn_qaf_session_open(struct qaf *qaf_mod,
-                                device_license_config_t* lic_config)
+/* Query HDMI EDID and sets module output accordingly.*/
+void set_hdmi_configuration_to_module()
 {
-    ALOGV("%s %d", __func__, __LINE__);
-    int status = -ENOSYS;
-
-    pthread_mutex_init(&qaf_mod->lock, (const pthread_mutexattr_t *) NULL);
-
-    if (!qaf_mod->qaf_audio_session_open)
-       return -EINVAL;
-
-    status = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
-                                             (void *)(qaf_mod), (void *)lic_config);
-    if(status < 0)
-        return status;
-
-    if (qaf_mod->session_handle == NULL) {
-        ALOGE("%s %d QAF wrapper session handle is NULL", __func__, __LINE__);
-        return -ENOMEM;
-    }
-    if (qaf_mod->qaf_register_event_callback)
-        qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
-                                             qaf_mod, &notify_event_callback,
-                                             AUDIO_DATA_EVENT);
-
-    if (property_get_bool("audio.qaf.msmd", false)) {
-        qaf_mod->qaf_msmd_enabled = 1;
-    }
-
-    return status;
-}
-
-char* audio_extn_qaf_stream_get_param(struct stream_out *out __unused, const char *kv_pair __unused)
-{
-   return NULL;
-}
-
-int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
-{
-    int status = 0, val = 0, channels = 0;
-    char *format_params, *kv_parirs;
+    int channels = 0;
+    char *format_params;
     struct str_parms *qaf_params;
-    char value[32];
     char prop_value[PROPERTY_VALUE_MAX];
     bool passth_support = false;
 
-    ALOGV("%s %d ", __func__, __LINE__);
-    if (!qaf_mod || !qaf_mod->qaf_audio_session_set_param) {
+    DEBUG_MSG("Entry");
+
+    if (!p_qaf) {
+        return;
+    }
+
+    if (!p_qaf->hdmi_connect) {
+        DEBUG_MSG("HDMI is not connected.");
+        return;
+    }
+
+    p_qaf->hdmi_sink_channels = 0;
+
+    //QAF re-encoding and DSP offload passthrough is supported.
+    if (property_get_bool("audio.offload.passthrough", false)
+            && property_get_bool("audio.qaf.reencode", false)) {
+
+        //If MS12 session is active.
+        if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
+
+            bool do_setparam = false;
+            qaf_params = str_parms_create();
+            property_get("audio.qaf.hdmi.out", prop_value, NULL);
+
+            if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_E_AC3)
+                    && (strncmp(prop_value, "ddp", 3) == 0)) {
+                do_setparam = true;
+                if (qaf_params) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                      AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
+                }
+            } else if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_AC3)) {
+                do_setparam = true;
+                if (qaf_params) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                      AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
+                }
+            }
+
+            if (do_setparam) {
+                if (p_qaf->qaf_msmd_enabled) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
+                } else {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                }
+                format_params = str_parms_to_str(qaf_params);
+
+                p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
+                                                                 format_params);
+
+                passth_support = true;
+            }
+            str_parms_destroy(qaf_params);
+        }
+
+        //DTS_M8 session is active.
+        if (p_qaf->qaf_mod[DTS_M8].session_handle
+                && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
+
+            bool do_setparam = false;
+            qaf_params = str_parms_create();
+#if 0 //TODO: Need to enable with DTS_M8 wrapper.
+            if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_DTS)) {
+                do_setparam = true;
+                if (qaf_params) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                      AUDIO_QAF_PARAMETER_VALUE_REENCODE_DTS);
+                }
+            }
+#endif
+
+            if (do_setparam) {
+                if (p_qaf->qaf_msmd_enabled) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
+                } else {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                }
+                format_params = str_parms_to_str(qaf_params);
+
+                p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
+                                                                   format_params);
+
+                passth_support = true;
+            }
+            str_parms_destroy(qaf_params);
+        }
+    }
+
+    //Compressed passthrough is not enabled.
+    if (!passth_support) {
+
+        channels = platform_edid_get_max_channels(p_qaf->adev->platform);
+
+        qaf_params = str_parms_create();
+        switch (channels) {
+            case 8:
+                DEBUG_MSG("Switching Qaf output to 7.1 channels");
+                str_parms_add_str(qaf_params,
+                                  AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+                                  AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
+                if (p_qaf->qaf_msmd_enabled) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+                } else {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                }
+                p_qaf->hdmi_sink_channels = channels;
+                break;
+            case 6:
+                DEBUG_MSG("Switching Qaf output to 5.1 channels");
+                str_parms_add_str(qaf_params,
+                                  AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+                                  AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
+                if (p_qaf->qaf_msmd_enabled) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+                } else {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                }
+                p_qaf->hdmi_sink_channels = channels;
+                break;
+            default:
+                DEBUG_MSG("Switching Qaf output to default channels");
+                str_parms_add_str(qaf_params,
+                                  AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+                                  AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
+                if (p_qaf->qaf_msmd_enabled) {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
+                } else {
+                    str_parms_add_str(qaf_params,
+                                      AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                      AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+                }
+                p_qaf->hdmi_sink_channels = 2;
+                break;
+        }
+
+        format_params = str_parms_to_str(qaf_params);
+
+        if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
+            p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
+                                                             format_params);
+        }
+        if (p_qaf->qaf_mod[DTS_M8].session_handle
+                && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
+            p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
+                                                               format_params);
+        }
+
+        str_parms_destroy(qaf_params);
+    }
+    DEBUG_MSG("Exit");
+}
+
+/* QAF set parameter function. For Device connect and disconnect. */
+int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    int status = 0, val = 0, k;
+    char *format_params, *kv_parirs;
+    struct str_parms *qaf_params;
+    char value[32];
+
+    DEBUG_MSG("Entry");
+
+    if (!p_qaf) {
         return -EINVAL;
     }
 
     status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+
     if (status >= 0) {
         val = atoi(value);
-        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-            if (property_get_bool("audio.offload.passthrough", false) &&
-                property_get_bool("audio.qaf.reencode", false)) {
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is connected.
 
-                qaf_params = str_parms_create();
-                property_get("audio.qaf.hdmi.out", prop_value, NULL);
-                if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3) &&
-                                                          (strncmp(prop_value, "ddp", 3) == 0)) {
-                    passth_support = true;
-                    if (qaf_params) {
-                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
-                                              AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
-                    }
-                } else if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)) {
-                    passth_support = true;
-                    if (qaf_params) {
-                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
-                                              AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
-                    }
+            p_qaf->hdmi_connect = 1;
+            p_qaf->hdmi_sink_channels = 0;
+
+            if (p_qaf->passthrough_in) { //If QAF passthrough is already initialized.
+                lock_output_stream(p_qaf->passthrough_in);
+                if (platform_is_edid_supported_format(adev->platform,
+                                                      p_qaf->passthrough_in->format)) {
+                    //If passthrough format is supported by HDMI then create the QAF passthrough output if not created already.
+                    create_qaf_passthrough_stream();
+                    //Ignoring the returned error, If error then QAF passthrough is disabled.
+                } else {
+                    //If passthrough format is not supported by HDMI then close the QAF passthrough output if already created.
+                    close_qaf_passthrough_stream();
                 }
-
-                if (passth_support) {
-                    qaf_mod->passthrough_enabled = 1;
-                    if (qaf_mod->qaf_msmd_enabled) {
-                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
-                    } else {
-                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                              AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
-                    }
-                    format_params = str_parms_to_str(qaf_params);
-
-                    qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
-                }
-                str_parms_destroy(qaf_params);
+                unlock_output_stream(p_qaf->passthrough_in);
             }
 
-            if (!passth_support) {
-                channels = platform_edid_get_max_channels(adev->platform);
+            set_hdmi_configuration_to_module();
 
-                qaf_params = str_parms_create();
-                switch (channels) {
-                    case 8:
-                          ALOGV("%s: Switching Qaf output to 7.1 channels", __func__);
-                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
-                                                AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
-                          if (qaf_mod->qaf_msmd_enabled) {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
-                          } else {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
-                          }
-                          qaf_mod->hdmi_sink_channels = channels;
-                          break;
-                    case 6:
-                          ALOGV("%s: Switching Qaf output to 5.1 channels", __func__);
-                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
-                                                AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
-                          if (qaf_mod->qaf_msmd_enabled) {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
-                          } else {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
-                          }
-                          qaf_mod->hdmi_sink_channels = channels;
-                          break;
-                    default:
-                          ALOGV("%s: Switching Qaf output to default channels", __func__);
-                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
-                                                AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
-                          if (qaf_mod->qaf_msmd_enabled) {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
-                          } else {
-                              str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                                    AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
-                          }
-                          qaf_mod->hdmi_sink_channels = 2;
-                        break;
-                }
-
-                format_params = str_parms_to_str(qaf_params);
-                qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
-                str_parms_destroy(qaf_params);
-            }
-            qaf_mod->hdmi_connect = 1;
         } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
-            ALOGV("%s: Opening a2dp output...", __FUNCTION__);
-            status = audio_extn_bt_hal_load(&qaf_mod->bt_hdl);
-            if(status != 0) {
-                ALOGE("%s:Error opening BT module", __FUNCTION__);
-                return status;
+            for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+                if (!p_qaf->qaf_mod[k].bt_hdl) {
+                    DEBUG_MSG("Opening a2dp output...");
+                    status = audio_extn_bt_hal_load(&p_qaf->qaf_mod[k].bt_hdl);
+                    if (status != 0) {
+                        ERROR_MSG("Error opening BT module");
+                        return status;
+                    }
+                }
             }
         }
+        //TODO else if: Need to consider other devices.
     }
 
     status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
     if (status >= 0) {
         val = atoi(value);
-        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-            qaf_params = str_parms_create();
-            str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
-                                  AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
-            str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
-                                  AUDIO_QAF_PARAMETER_VALUE_PCM);
-            qaf_mod->hdmi_sink_channels = 0;
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is disconnected.
 
-            qaf_mod->passthrough_enabled = 0;
-            qaf_mod->hdmi_connect = 0;
+            qaf_params = str_parms_create();
+            str_parms_add_str(qaf_params,
+                              AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                              AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+            str_parms_add_str(qaf_params,
+                              AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                              AUDIO_QAF_PARAMETER_VALUE_PCM);
+            p_qaf->hdmi_sink_channels = 0;
+
+            p_qaf->passthrough_enabled = 0;
+            p_qaf->mch_pcm_hdmi_enabled = 0;
+            p_qaf->hdmi_connect = 0;
+
             format_params = str_parms_to_str(qaf_params);
-            qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
+
+            for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+                if (p_qaf->qaf_mod[k].session_handle
+                    && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
+                    p_qaf->qaf_mod[k].qaf_audio_session_set_param(
+                            p_qaf->qaf_mod[k].session_handle, format_params);
+                }
+            }
+            close_all_hdmi_output();
+
             str_parms_destroy(qaf_params);
+            close_qaf_passthrough_stream();
         } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
-            ALOGV("%s: Closing a2dp output...", __FUNCTION__);
-            audio_extn_bt_hal_unload(qaf_mod->bt_hdl);
+            DEBUG_MSG("Closing a2dp output...");
+            for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+                if (p_qaf->qaf_mod[k].bt_hdl) {
+                    audio_extn_bt_hal_unload(p_qaf->qaf_mod[k].bt_hdl);
+                    p_qaf->qaf_mod[k].bt_hdl = NULL;
+                }
+            }
+        }
+        //TODO else if: Need to consider other devices.
+    }
+
+    for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
+        kv_parirs = str_parms_to_str(parms);
+        if (p_qaf->qaf_mod[k].session_handle && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
+            p_qaf->qaf_mod[k].qaf_audio_session_set_param(
+                    p_qaf->qaf_mod[k].session_handle, kv_parirs);
         }
     }
 
-    kv_parirs = str_parms_to_str(parms);
-    qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, kv_parirs);
-
+    DEBUG_MSG("Exit");
     return status;
 }
 
-char* audio_extn_qaf_get_param(struct audio_device *adev __unused, const char *kv_pair __unused)
+/* Create the QAF. */
+int audio_extn_qaf_init(struct audio_device *adev)
 {
+    DEBUG_MSG("Entry");
+
+    p_qaf = calloc(1, sizeof(struct qaf));
+    if (p_qaf == NULL) {
+        ERROR_MSG("Out of memory");
+        return -ENOMEM;
+    }
+
+    p_qaf->adev = adev;
+
+    if (property_get_bool("audio.qaf.msmd", false)) {
+        p_qaf->qaf_msmd_enabled = 1;
+    }
+    pthread_mutex_init(&p_qaf->lock, (const pthread_mutexattr_t *) NULL);
+
+    int i = 0;
+
+    for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+        char value[PROPERTY_VALUE_MAX] = {0};
+        char lib_name[PROPERTY_VALUE_MAX] = {0};
+        struct qaf_module *qaf_mod = &(p_qaf->qaf_mod[i]);
+
+        if (i == MS12) {
+            property_get("audio.qaf.library", value, NULL);
+        } else if (i == DTS_M8) {
+            property_get("audio.qaf.m8.library", value, NULL);
+        } else {
+            continue;
+        }
+
+        snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
+
+        qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
+        if (qaf_mod->qaf_lib == NULL) {
+            ERROR_MSG("DLOPEN failed for %s", lib_name);
+            continue;
+        }
+
+        DEBUG_MSG("DLOPEN successful for %s", lib_name);
+        qaf_mod->qaf_audio_session_open =
+                    (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_session_open");
+        qaf_mod->qaf_audio_session_close =
+                    (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_session_close");
+        qaf_mod->qaf_audio_stream_open =
+                    (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
+                     audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_open");
+        qaf_mod->qaf_audio_stream_close =
+                    (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_close");
+        qaf_mod->qaf_audio_stream_set_param =
+                    (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_set_param");
+        qaf_mod->qaf_audio_session_set_param =
+                    (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_session_set_param");
+        qaf_mod->qaf_audio_stream_get_param =
+                    (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_get_param");
+        qaf_mod->qaf_audio_session_get_param =
+                    (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_session_get_param");
+        qaf_mod->qaf_audio_stream_start =
+                    (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_start");
+        qaf_mod->qaf_audio_stream_stop =
+                    (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_stop");
+        qaf_mod->qaf_audio_stream_pause =
+                    (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_pause");
+        qaf_mod->qaf_audio_stream_flush =
+                    (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_flush");
+        qaf_mod->qaf_audio_stream_write =
+                    (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
+                                                                     "audio_stream_write");
+        qaf_mod->qaf_register_event_callback =
+                    (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
+                     audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
+                                                                     "register_event_callback");
+    }
+
+    DEBUG_MSG("Exit");
     return 0;
 }
 
-int audio_extn_qaf_init(struct audio_device *adev)
-{
-    char value[PROPERTY_VALUE_MAX] = {0};
-    char lib_name[PROPERTY_VALUE_MAX] = {0};
-    unsigned char* license_data = NULL;
-    device_license_config_t* lic_config = NULL;
-    ALOGV("%s %d", __func__, __LINE__);
-    int ret = 0, size = 0;
-
-    qaf_mod = malloc(sizeof(struct qaf));
-    if(qaf_mod == NULL) {
-        ALOGE("%s, out of memory", __func__);
-        ret = -ENOMEM;
-        goto done;
-    }
-    memset(qaf_mod, 0, sizeof(struct qaf));
-    lic_config = (device_license_config_t*) calloc(1, sizeof(device_license_config_t));
-    if(lic_config == NULL) {
-        ALOGE("%s, out of memory", __func__);
-        ret = -ENOMEM;
-        goto done;
-    }
-    qaf_mod->adev = adev;
-    property_get("audio.qaf.library", value, NULL);
-    snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
-
-    qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
-    if (qaf_mod->qaf_lib == NULL) {
-        ALOGE("%s: DLOPEN failed for %s", __func__, lib_name);
-        ret = -EINVAL;
-        goto done;
-    }
-
-    ALOGV("%s: DLOPEN successful for %s", __func__, lib_name);
-    qaf_mod->qaf_audio_session_open =
-                (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_session_open");
-    qaf_mod->qaf_audio_session_close =
-                (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_session_close");
-    qaf_mod->qaf_audio_stream_open =
-                (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
-                 audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_open");
-    qaf_mod->qaf_audio_stream_close =
-                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_close");
-    qaf_mod->qaf_audio_stream_set_param =
-                (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_set_param");
-    qaf_mod->qaf_audio_session_set_param =
-                (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_session_set_param");
-    qaf_mod->qaf_audio_stream_get_param =
-                (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_get_param");
-    qaf_mod->qaf_audio_session_get_param =
-                (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_session_get_param");
-    qaf_mod->qaf_audio_stream_start =
-                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_start");
-    qaf_mod->qaf_audio_stream_stop =
-                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_stop");
-    qaf_mod->qaf_audio_stream_pause =
-                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_pause");
-    qaf_mod->qaf_audio_stream_flush =
-                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_flush");
-    qaf_mod->qaf_audio_stream_write =
-                (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
-                                                                 "audio_stream_write");
-    qaf_mod->qaf_register_event_callback =
-                (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
-                 audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
-                                                                 "register_event_callback");
-
-    license_data = platform_get_license((struct audio_hw_device *)(qaf_mod->adev->platform), &size);
-    if (!license_data) {
-        ALOGE("License is not present");
-        ret = -EINVAL;
-        goto done;
-    }
-    lic_config->p_license = (unsigned char* ) calloc(1, size);
-     if(lic_config->p_license == NULL) {
-        ALOGE("%s, out of memory", __func__);
-        ret = -ENOMEM;
-        goto done;
-    }
-    lic_config->l_size = size;
-    memcpy(lic_config->p_license, license_data, size);
-
-    if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
-        lic_config->manufacturer_id = (unsigned long) atoi (value);
-    } else {
-        ALOGE("audio.qaf.manufacturer id is not set");
-        ret = -EINVAL;
-        goto done;
-    }
-
-    ret = audio_extn_qaf_session_open(qaf_mod, lic_config);
-done:
-    if (license_data != NULL) {
-        free(license_data);
-        license_data = NULL;
-    }
-    if (lic_config->p_license != NULL) {
-        free(lic_config->p_license);
-        lic_config->p_license = NULL;
-    }
-    if (lic_config != NULL) {
-        free(lic_config);
-        lic_config = NULL;
-    }
-    if (ret != 0) {
-        if (qaf_mod->qaf_lib != NULL) {
-            dlclose(qaf_mod->qaf_lib);
-            qaf_mod->qaf_lib = NULL;
-        }
-        if (qaf_mod != NULL) {
-            free(qaf_mod);
-            qaf_mod = NULL;
-        }
-    }
-    return ret;
-}
-
+/* Tear down the qaf extension. */
 void audio_extn_qaf_deinit()
 {
-    qaf_session_close();
-    qaf_deinit();
+    int i;
+    DEBUG_MSG("Entry");
+
+    if (p_qaf != NULL) {
+        for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
+            qaf_session_close(&p_qaf->qaf_mod[i]);
+
+            if (p_qaf->qaf_mod[i].qaf_lib != NULL) {
+                dlclose(p_qaf->qaf_mod[i].qaf_lib);
+                p_qaf->qaf_mod[i].qaf_lib = NULL;
+            }
+        }
+        if (p_qaf->passthrough_out) {
+            adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                     (struct audio_stream_out *)(p_qaf->passthrough_out));
+            p_qaf->passthrough_out = NULL;
+        }
+
+        pthread_mutex_destroy(&p_qaf->lock);
+        free(p_qaf);
+        p_qaf = NULL;
+    }
+    DEBUG_MSG("Exit");
 }