hal : Modify the kernel buffer to 32ms.

 - Reduced the kernel buffer size to 32ms for deep buffer &
   pcm offload use cases
 - Handled Eos of DD/DDP Assoc stream to fix blocking during drain.
 - Adding support for AC4 stream playback.

Change-Id: Id159174d6ecf1424766d1471932d5403fd5ddc5e
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 3a34685..5b88274 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -48,7 +48,24 @@
  * DSP Latency (Calculated based on the Platform render latency)
 */
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 300
-#define PCM_OFFLOAD_PLAYBACK_LATENCY 248
+
+/* 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)
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#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
+
+/* In msec for 2 fragments of 32ms */
+#define QAF_PCM_OFFLOAD_PLAYBACK_LATENCY \
+              (QAF_PCM_OFFLOAD_BUFFER_DURATION * COMPRESS_OFFLOAD_NUM_FRAGMENTS)
+
+#define PCM_OFFLOAD_PLAYBACK_LATENCY \
+              (MS12_PCM_INPUT_BUFFER_LATENCY + QAF_PCM_OFFLOAD_PLAYBACK_LATENCY)
 
 /*
  * Buffer size for compress passthrough is 8192 bytes
@@ -80,7 +97,8 @@
  * Samples for 51.2ms = 51.2 x 1536/32 = 2457 samples.
  * Latency calculated similarly for DPP is 1365 samples.
  */
-#define TRANSCODE_LATENCY(buffer_size, frame_size, encoder_output_in_bytes) ((buffer_size * frame_size) / encoder_output_in_bytes)
+#define TRANSCODE_LATENCY(buffer_size, frame_size, encoder_output_in_bytes) \
+                          ((buffer_size * frame_size) / encoder_output_in_bytes)
 
 /*
  * QAF Latency to process buffers since out_write from primary HAL
@@ -88,6 +106,8 @@
 #define QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY 18
 #define QAF_PCM_OFFLOAD_PROCESSING_LATENCY 48
 
+#define QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1536
+
 #include <stdlib.h>
 #include <pthread.h>
 #include <errno.h>
@@ -109,7 +129,6 @@
 #include "sound/compress_params.h"
 
 #define QAF_OUTPUT_SAMPLING_RATE 48000
-#define PCM_OFFLOAD_BUFFER_SIZE 7680
 
 #ifdef QAF_DUMP_ENABLED
 FILE *fp_output_writer_hdmi = NULL;
@@ -137,6 +156,7 @@
           notify_event_callback_t event_callback, audio_event_id_t event_id);
     pthread_mutex_t lock;
     struct stream_out *stream_drain_main;
+    struct stream_out *stream_drain_assoc;
     struct stream_out *qaf_compr_offload_out;
     struct stream_out *qaf_compr_offload_out_mch;
     struct stream_out *qaf_compr_passthrough_out;
@@ -165,6 +185,8 @@
         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;
 
@@ -427,6 +449,33 @@
     return bytes;
 }
 
+static uint32_t qaf_get_pcm_offload_buffer_size(audio_offload_info_t* info)
+{
+    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 = MIN_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));
+
+    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)
 {
     int ret = 0;
@@ -450,7 +499,7 @@
     }
     // MS12 Latency + Kernel Latency + Dsp Latency
     if (qaf_mod->qaf_compr_offload_out != NULL) {
-        out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * PCM_OFFLOAD_BUFFER_SIZE \
+        out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * qaf_get_pcm_offload_buffer_size(&qaf_mod->qaf_compr_offload_out->info) \
                                        /(popcount(qaf_mod->qaf_compr_offload_out->channel_mask) * sizeof(short))) \
                                        +((platform_render_latency(qaf_mod->qaf_compr_offload_out->usecase) * qaf_mod->qaf_compr_offload_out->sample_rate) / 1000000LL);
     } else if (audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
@@ -537,15 +586,18 @@
     return status;
 }
 
-static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
+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);
+    ALOGV("%s stream_handle = %p , format = %x", __func__,
+                                          out->qaf_stream_handle, out->format);
 
     lock_output_stream(out);
     if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
-        status = qaf_mod->qaf_passthrough_out->stream.drain((struct audio_stream_out*)(qaf_mod->qaf_passthrough_out), type);
+        status = qaf_mod->qaf_passthrough_out->stream.drain(
+               (struct audio_stream_out*)(qaf_mod->qaf_passthrough_out), type);
         pthread_mutex_unlock(&out->lock);
         return status;
     }
@@ -555,8 +607,13 @@
         /* Stream stop will trigger EOS and on EOS_EVENT received
            from callback DRAIN_READY command is sent */
         status = audio_extn_qaf_stream_stop(out);
-        if (out->format != AUDIO_FORMAT_PCM_16_BIT)
-            qaf_mod->stream_drain_main = out;
+        if (out->format != AUDIO_FORMAT_PCM_16_BIT) {
+            if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
+                qaf_mod->stream_drain_assoc = out;
+            } else {
+                qaf_mod->stream_drain_main = out;
+            }
+        }
     }
     pthread_mutex_unlock(&out->lock);
     return status;
@@ -624,39 +681,47 @@
     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 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)
 {
 
 /*
  For SPKR:
- 1. Open pcm device if device_id passed to it SPKR and write the data to pcm device
+ 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_output_format
+ 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.
+ 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;
     audio_output_flags_t flags;
     struct qaf* qaf_module = (struct qaf* ) prv_data;
     struct audio_stream_out *bt_stream = NULL;
 
-    ALOGV("%s device 0x%X, %d in event = %d", __func__, device, __LINE__, event_id);
+    ALOGV("%s device 0x%X, %d in event = %d",
+                                          __func__, device, __LINE__, event_id);
 
     if (event_id == AUDIO_DATA_EVENT) {
-        ALOGVV("Device id %x %s %d, bytes to written %d", device, __func__,__LINE__, size);
+        ALOGVV("Device id %x %s %d, bytes to written %d",
+                                               device, __func__,__LINE__, size);
 
         if ((qaf_mod->qaf_passthrough_out != NULL) && qaf_mod->hdmi_connect) {
             pthread_mutex_lock(&qaf_module->lock);
             if (qaf_mod->qaf_compr_offload_out != NULL) {
-                adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                             (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+                adev_close_output_stream(
+                  (struct audio_hw_device *) qaf_mod->adev,
+                  (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
                 qaf_mod->qaf_compr_offload_out = NULL;
             }
             if (qaf_mod->qaf_compr_offload_out_mch) {
-                adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                             (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
+                adev_close_output_stream(
+                    (struct audio_hw_device *) qaf_mod->adev,
+                    (struct audio_stream_out *)
+                                          (qaf_mod->qaf_compr_offload_out_mch));
                 qaf_mod->qaf_compr_offload_out_mch = NULL;
             }
             pthread_mutex_unlock(&qaf_module->lock);
@@ -665,63 +730,88 @@
         } else {
             if (qaf_mod->qaf_passthrough_out != NULL) {
                 pthread_mutex_lock(&qaf_module->lock);
-                adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                            (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
+                adev_close_output_stream(
+                    (struct audio_hw_device *) qaf_mod->adev,
+                    (struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
                 qaf_mod->qaf_passthrough_out = NULL;
                 qaf_mod->main_output_active = false;
                 pthread_mutex_unlock(&qaf_module->lock);
             }
         }
         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))) {
+        if ((device ==
+                   (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD)) ||
+            (device ==
+                   (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
 
-            if (NULL == qaf_mod->qaf_compr_passthrough_out && qaf_mod->hdmi_connect) {
+            if (NULL == qaf_mod->qaf_compr_passthrough_out &&
+                                             qaf_mod->hdmi_connect) {
                 struct audio_config config;
                 audio_devices_t devices;
 
                 if (qaf_mod->qaf_compr_offload_out_mch) {
-                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
+                    adev_close_output_stream(
+                        (struct audio_hw_device *) qaf_mod->adev,
+                        (struct audio_stream_out *)
+                        (qaf_mod->qaf_compr_offload_out_mch));
                     qaf_mod->qaf_compr_offload_out_mch = NULL;
                 }
 
-                config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_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;
 
-                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;
+                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.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;
+                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_compr_passthrough_out), NULL);
+                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_compr_passthrough_out), NULL);
                 if (ret < 0) {
-                    ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
+                    ALOGE("%s: adev_open_output_stream failed with ret = %d!",
+                          __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
-                qaf_mod->qaf_compr_passthrough_out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->qaf_compr_passthrough_out->compr_config.fragments =
+                                                 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
             }
 
             if (!qaf_mod->passthrough_enabled)
                 qaf_mod->passthrough_enabled = 1;
 
-            if (qaf_mod->qaf_compr_passthrough_out)
-                ret = qaf_mod->qaf_compr_passthrough_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_passthrough_out, buf, size);
-        } else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) && ((qaf_mod->hdmi_connect) &&
-                   (qaf_mod->qaf_passthrough_out == NULL) && (qaf_mod->hdmi_sink_channels > 2))) {
+            if (qaf_mod->qaf_compr_passthrough_out) {
+                ret = qaf_mod->qaf_compr_passthrough_out->stream.write(
+                          (struct audio_stream_out *)
+                          qaf_mod->qaf_compr_passthrough_out, buf, size);
+            }
+        } else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+                   ((qaf_mod->hdmi_connect) &&
+                   (qaf_mod->qaf_passthrough_out == NULL) &&
+                   (qaf_mod->hdmi_sink_channels > 2))) {
             if (NULL == qaf_mod->qaf_compr_offload_out_mch) {
                 struct audio_config config;
                 audio_devices_t devices;
 
-                config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_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.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
@@ -730,79 +820,120 @@
                 devices = AUDIO_DEVICE_NONE;
 
                 if (qaf_mod->hdmi_sink_channels == 8) {
-                    config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
+                    config.offload_info.channel_mask = config.channel_mask =
+                                                      AUDIO_CHANNEL_OUT_7POINT1;
                 } else if (qaf_mod->hdmi_sink_channels == 6) {
-                    config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+                    config.offload_info.channel_mask = config.channel_mask =
+                                                      AUDIO_CHANNEL_OUT_5POINT1;
                 } else {
-                    config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+                    config.offload_info.channel_mask = config.channel_mask =
+                                                      AUDIO_CHANNEL_OUT_STEREO;
                 }
                 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                flags = AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+                flags = (AUDIO_OUTPUT_FLAG_DIRECT|
+                         AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
+                         AUDIO_OUTPUT_FLAG_DIRECT_PCM);
 
-                ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
-                                                 flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_offload_out_mch), NULL);
+                ret = adev_open_output_stream(
+                          (struct audio_hw_device *) qaf_mod->adev,
+                          QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices, flags,
+                          &config, (struct audio_stream_out **)
+                          &(qaf_mod->qaf_compr_offload_out_mch), NULL);
                 if (ret < 0) {
-                    ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
+                    ALOGE("%s: adev_open_output_stream failed with ret = %d!",
+                          __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
-                qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments =
+                                                 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->qaf_compr_offload_out_mch->compr_config.fragment_size =
+                          qaf_get_pcm_offload_buffer_size(&config.offload_info);
             }
 
-            if (qaf_mod->qaf_compr_offload_out_mch)
-                ret = qaf_mod->qaf_compr_offload_out_mch->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_offload_out_mch, buf, size);
+            if (qaf_mod->qaf_compr_offload_out_mch) {
+                ret = qaf_mod->qaf_compr_offload_out_mch->stream.write(
+                          (struct audio_stream_out *)
+                          qaf_mod->qaf_compr_offload_out_mch, buf, size);
+            }
         } else {
             bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
             if (bt_stream != NULL) {
                 if (qaf_mod->qaf_compr_offload_out) {
-                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+                    adev_close_output_stream(
+                        (struct audio_hw_device *) qaf_mod->adev,
+                        (struct audio_stream_out *)
+                        (qaf_mod->qaf_compr_offload_out));
                     qaf_mod->qaf_compr_offload_out = NULL;
                 }
 
                 audio_extn_bt_hal_out_write(qaf_mod->bt_hdl, buf, size);
             }
 
-            if (NULL == qaf_mod->qaf_compr_offload_out && bt_stream == NULL && qaf_mod->qaf_passthrough_out == NULL) {
+            if (NULL == qaf_mod->qaf_compr_offload_out && bt_stream == NULL &&
+                qaf_mod->qaf_passthrough_out == NULL) {
                 struct audio_config config;
                 audio_devices_t devices;
 
-                config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_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.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;
-                config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+                config.offload_info.channel_mask = config.channel_mask =
+                                                       AUDIO_CHANNEL_OUT_STEREO;
                 devices = AUDIO_DEVICE_OUT_SPEAKER;
-                flags = AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+                flags = (AUDIO_OUTPUT_FLAG_DIRECT|
+                         AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
+                         AUDIO_OUTPUT_FLAG_DIRECT_PCM);
 
                 /* TODO:: Need to Propagate errors to framework */
-                ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
-                                             flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_offload_out), NULL);
+                ret = adev_open_output_stream(
+                          (struct audio_hw_device *) qaf_mod->adev,
+                          QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
+                          flags, &config,
+                          (struct audio_stream_out **)
+                          &(qaf_mod->qaf_compr_offload_out), NULL);
                 if (ret < 0) {
-                    ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
+                    ALOGE("%s: adev_open_output_stream failed with ret = %d!",
+                          __func__, ret);
                     pthread_mutex_unlock(&qaf_module->lock);
                     return;
                 }
-                qaf_mod->qaf_compr_offload_out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-                qaf_mod->qaf_compr_offload_out->info.channel_mask = config.offload_info.channel_mask;
-                qaf_mod->qaf_compr_offload_out->info.format = config.offload_info.format;
-                qaf_mod->qaf_compr_offload_out->info.sample_rate = config.offload_info.sample_rate;
 
-                qaf_mod->qaf_compr_offload_out->stream.set_volume((struct audio_stream_out *)qaf_mod->qaf_compr_offload_out, qaf_mod->vol_left, qaf_mod->vol_right);
+                qaf_mod->qaf_compr_offload_out->compr_config.fragments =
+                                                 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+                qaf_mod->qaf_compr_offload_out->compr_config.fragment_size =
+                          qaf_get_pcm_offload_buffer_size(&config.offload_info);
+                qaf_mod->qaf_compr_offload_out->info.channel_mask =
+                                               config.offload_info.channel_mask;
+                qaf_mod->qaf_compr_offload_out->info.format =
+                                               config.offload_info.format;
+                qaf_mod->qaf_compr_offload_out->info.sample_rate =
+                                               config.offload_info.sample_rate;
+                qaf_mod->qaf_compr_offload_out->stream.set_volume(
+                      (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out,
+                      qaf_mod->vol_left, qaf_mod->vol_right);
             }
 
-            if (!qaf_mod->hdmi_connect && (qaf_mod->qaf_compr_passthrough_out || qaf_mod->qaf_compr_offload_out_mch)) {
+            if (!qaf_mod->hdmi_connect &&
+                (qaf_mod->qaf_compr_passthrough_out ||
+                 qaf_mod->qaf_compr_offload_out_mch)) {
                 qaf_mod->passthrough_enabled = 0;
                 if (qaf_mod->qaf_compr_passthrough_out) {
-                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
+                    adev_close_output_stream(
+                        (struct audio_hw_device *) qaf_mod->adev,
+                        (struct audio_stream_out *)
+                             (qaf_mod->qaf_compr_passthrough_out));
                     qaf_mod->qaf_compr_passthrough_out = NULL;
                 }
                 if (qaf_mod->qaf_compr_offload_out_mch) {
-                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
-                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
+                    adev_close_output_stream(
+                        (struct audio_hw_device *) qaf_mod->adev,
+                        (struct audio_stream_out *)
+                        (qaf_mod->qaf_compr_offload_out_mch));
                     qaf_mod->qaf_compr_offload_out_mch = NULL;
                 }
             }
@@ -811,18 +942,36 @@
              * TODO:: Since this is mixed data,
              * need to identify to which stream the error should be sent
              */
-            if (bt_stream == NULL && qaf_mod->qaf_compr_offload_out)
-                ret = qaf_mod->qaf_compr_offload_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_offload_out, buf, size);
+            if (bt_stream == NULL && qaf_mod->qaf_compr_offload_out) {
+                ret = qaf_mod->qaf_compr_offload_out->stream.write(
+                          (struct audio_stream_out *)
+                          qaf_mod->qaf_compr_offload_out, 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 || event_id == AUDIO_EOS_MAIN_AAC_EVENT) {
-        /* TODO:: Only MAIN Stream EOS Event is added, need to add ASSOC stream EOS Event */
+    } 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_drain_main;
-        if (out != NULL) {
+        struct stream_out *out_assoc = qaf_module->stream_drain_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) {
+            lock_output_stream(out_assoc);
+            out_assoc->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
+                                  out_assoc->offload_cookie);
+            pthread_mutex_unlock(&out_assoc->lock);
+            qaf_module->stream_drain_assoc = NULL;
+        } else if (out != NULL) {
             lock_output_stream(out);
-            out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->offload_cookie);
+            out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL,
+                                  out->offload_cookie);
             pthread_mutex_unlock(&out->lock);
             qaf_module->stream_drain_main = NULL;
             ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
@@ -908,6 +1057,7 @@
         status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_SYSTEM_TONE);
     } 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) {
@@ -1313,10 +1463,10 @@
 
     if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
         out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
-        out->config.period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
+        out->config.period_size = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
         out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
-        out->config.start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
-        out->config.avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
+        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;