hal: Audio HAL / APM changes for HDMI passthrough

-Add support for HDMI passthrough for DD/DDP contents to HAL and
 APM.
-Add mixer control to set volume on volume module on passthrough
 COPP. The mixer control  takes zero volume for mute and unity
 volume for max volume.
-DDP content requires sample rate to be four times native sample
 rate. HAL sample rate is changed to four times native rate from
 start output stream. During rapid pause/resume offload thread
 calls standby when there is no active track and no activity for
 over a second. On resume start output steam is called and
 sample rate is converted to four times its current value.
 This results in session to be started with invalid sampling
 rate and playback failures.
-Add HDMI passthrough support for JOC format.
 Expose DDP/JOC as pass-through supported format if sink
 supports either DD or DDP. This is to allow support for
 pass-through convert based on edid data.
-Deep buffer music stream does not switch back to HDMI after
 ringtone playback ends. Ringtone, alarm, notification etc are
 played on speaker if HDMI pass-through is enabled. The
 decision is taken based on stream or strategy. The decision
 to change the device from HDMI to speaker is taken based on
 the stream type. When a patricular stream ends use the
 reference count instead of stream type.
-DAP is not turned on when switching from passthrough stream to
 deep buffer stream.DAP bypass call from HAL to DAP HAL expects
 integer pointer. Address of a bool variable is passed into the
 function. Corrupt value is set on driver instead of turn on/off
 causing random failures in DAP on/DAP bypass. Use same data type
 and use enumeration to make the function call readable.

CRs-Fixed: 761339
Change-Id: Ided9439ec5e87233a1fec3ff9f50a1e9ba4cb788
diff --git a/hal/Android.mk b/hal/Android.mk
index 797bcb7..1e0e52b 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -167,6 +167,10 @@
 endif
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH)),true)
+    LOCAL_CFLAGS += -DHDMI_PASSTHROUGH_ENABLED
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 8345c96..84192c7 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -270,7 +270,6 @@
 void audio_extn_dolby_set_endpoint(struct audio_device *adev);
 #endif
 
-
 #if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
 bool audio_extn_is_dolby_format(audio_format_t format);
 int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
@@ -288,6 +287,34 @@
 void audio_extn_ddp_set_parameters(struct audio_device *adev,
                                    struct str_parms *parms);
 void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
+
+#endif
+
+#ifndef HDMI_PASSTHROUGH_ENABLED
+#define audio_extn_dolby_update_passt_formats(adev, out)                   (0)
+#define audio_extn_dolby_update_passt_stream_configuration(adev, out)      (0)
+#define audio_extn_dolby_is_passt_convert_supported(adev, out)             (0)
+#define audio_extn_dolby_is_passt_supported(adev, out)                     (0)
+#define audio_extn_dolby_is_passthrough_stream(flags)                      (0)
+#define audio_extn_dolby_set_hdmi_config(adev, out)                        (0)
+#define audio_extn_dolby_get_passt_buffer_size(info)                       (0)
+#define audio_extn_dolby_set_passt_volume(out, mute)                       (0)
+#define audio_extn_dolby_set_passt_latency(out, latency)                   (0)
+#else
+int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
+                                          struct stream_out *out);
+bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
+                                                 struct stream_out *out);
+bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
+                                         struct stream_out *out);
+void audio_extn_dolby_update_passt_stream_configuration(struct audio_device *adev,
+                                                 struct stream_out *out);
+bool audio_extn_dolby_is_passthrough_stream(int flags);
+int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
+                                     struct stream_out *out);
+int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info);
+int audio_extn_dolby_set_passt_volume(struct stream_out *out, int mute);
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency);
 #endif
 
 #ifndef HFP_ENABLED
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index abbfe62..cdfa2a1 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -408,6 +408,118 @@
 }
 #endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
 
+#ifdef HDMI_PASSTHROUGH_ENABLED
+int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
+                                          struct stream_out *out) {
+    int32_t i = 0, ret = -ENOSYS;
+
+    if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3) ||
+        platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3)) {
+        out->supported_formats[i++] = AUDIO_FORMAT_AC3;
+        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
+        /* Reciever must support JOC and advertise, otherwise JOC is treated as DDP */
+        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
+        ret = 0;
+    }
+    ALOGV("%s: ret = %d", __func__, ret);
+    return ret;
+}
+
+bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
+                                                 struct stream_out *out) {
+
+    bool convert = false;
+    switch (out->format) {
+    case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
+        if (!platform_is_edid_supported_format(adev->platform,
+            AUDIO_FORMAT_E_AC3)) {
+            ALOGV("%s:PASSTHROUGH_CONVERT supported", __func__);
+            convert = true;
+        }
+        break;
+    default:
+        ALOGE("%s: PASSTHROUGH_CONVERT not supported for format 0x%x",
+              __func__, out->format);
+        break;
+    }
+    ALOGE("%s: convert %d", __func__, convert);
+    return convert;
+}
+
+bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
+                                         struct stream_out *out) {
+    bool passt = false;
+    switch (out->format) {
+    case AUDIO_FORMAT_E_AC3:
+        if (platform_is_edid_supported_format(adev->platform, out->format)) {
+            ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+            passt = true;
+        }
+        break;
+    case AUDIO_FORMAT_AC3:
+        if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)
+            || platform_is_edid_supported_format(adev->platform,
+            AUDIO_FORMAT_E_AC3)) {
+            ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+            passt = true;
+        }
+        break;
+    case AUDIO_FORMAT_E_AC3_JOC:
+         /* Check for DDP capability in edid for JOC contents.*/
+         if (platform_is_edid_supported_format(adev->platform,
+             AUDIO_FORMAT_E_AC3)) {
+             ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+             passt = true;
+         }
+    default:
+        ALOGV("%s:Passthrough not supported", __func__);
+    }
+    return passt;
+}
+
+void audio_extn_dolby_update_passt_stream_configuration(
+        struct audio_device *adev, struct stream_out *out) {
+    if (audio_extn_dolby_is_passt_supported(adev, out)) {
+        ALOGV("%s:PASSTHROUGH", __func__);
+        out->compr_config.codec->compr_passthr = PASSTHROUGH;
+    } else if (audio_extn_dolby_is_passt_convert_supported(adev, out)){
+        ALOGV("%s:PASSTHROUGH CONVERT", __func__);
+        out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
+    } else {
+        ALOGV("%s:NO PASSTHROUGH", __func__);
+        out->compr_config.codec->compr_passthr = LEGACY_PCM;
+    }
+}
+
+bool audio_extn_dolby_is_passthrough_stream(int flags) {
+
+    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+        return true;
+    return false;
+}
+
+int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
+                                                    struct stream_out *out) {
+    return platform_set_hdmi_config(out);
+}
+
+int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info) {
+    return platform_get_compress_passthrough_buffer_size(info);
+}
+
+int audio_extn_dolby_set_passt_volume(struct stream_out *out,  int mute) {
+    return platform_set_device_params(out, DEVICE_PARAM_MUTE_ID, mute);
+}
+
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency) {
+    return platform_set_device_params(out, DEVICE_PARAM_LATENCY_ID, latency);
+}
+#endif /* HDMI_PASSTHROUGH_ENABLED */
+
 #ifdef DS1_DOLBY_DAP_ENABLED
 void audio_extn_dolby_set_endpoint(struct audio_device *adev)
 {
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index cebba3f..7ab8cd4 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -64,12 +64,14 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
 #ifdef INCALL_MUSIC_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
 #endif
 #ifdef COMPRESS_VOIP_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
 #endif
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
 };
 
 const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -98,6 +100,7 @@
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
     STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
 #endif
 };
 
@@ -404,6 +407,7 @@
         ss_info = node_to_item(node_i, struct stream_sample_rate, list);
         if ((sample_rate <= ss_info->sample_rate) &&
             (bit_width == so_info->app_type_cfg.bit_width)) {
+
             app_type_cfg->app_type = so_info->app_type_cfg.app_type;
             app_type_cfg->sample_rate = ss_info->sample_rate;
             app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
@@ -509,7 +513,7 @@
         (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
         (!is_offload_usecase(usecase->id))) {
-        ALOGV("%s: a playback path where app type cfg is not required", __func__);
+        ALOGV("%s: a playback path where app type cfg is not required %d", __func__, usecase->id);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
@@ -548,8 +552,12 @@
 
     app_type_cfg[len++] = out->app_type_cfg.app_type;
     app_type_cfg[len++] = acdb_dev_id;
-    app_type_cfg[len++] = sample_rate;
-
+    if (((out->format == AUDIO_FORMAT_E_AC3) ||
+        (out->format == AUDIO_FORMAT_E_AC3_JOC)) &&
+        (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+        app_type_cfg[len++] = sample_rate * 4;
+    else
+        app_type_cfg[len++] = sample_rate;
     mixer_ctl_set_array(ctl, app_type_cfg, len);
     ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
            __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ce114da..7b8f697 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1277,8 +1277,9 @@
                 break;
             } else if (is_offload_usecase(usecase->id) &&
                        audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
-                ALOGD("%s: multi-channel(%x) compress offload playback is active, "
-                      "no change in HDMI channels", __func__, usecase->stream.out->channel_mask);
+                ALOGD("%s:multi-channel(%x) compress offload playback is active"
+                      ", no change in HDMI channels", __func__,
+                      usecase->stream.out->channel_mask);
                 ret = false;
                 break;
             }
@@ -1309,6 +1310,7 @@
         return 0;
     }
 
+    /*TODO: CHECK for passthrough don't set channel map for passthrough*/
     platform_set_hdmi_channels(adev->platform, channels);
     platform_set_edid_channels_configuration(adev->platform, channels);
     adev->cur_hdmi_channels = channels;
@@ -1356,7 +1358,8 @@
         return -EINVAL;
     }
 
-    if (is_offload_usecase(out->usecase)) {
+    if (is_offload_usecase(out->usecase) &&
+        !(audio_extn_dolby_is_passthrough_stream(out->flags))) {
         if (adev->visualizer_stop_output != NULL)
             adev->visualizer_stop_output(out->handle, out->pcm_device_id);
         if (adev->offload_effects_stop_output != NULL)
@@ -1372,6 +1375,15 @@
     list_remove(&uc_info->list);
     free(uc_info);
 
+    if (is_offload_usecase(out->usecase) &&
+        (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        (audio_extn_dolby_is_passthrough_stream(out->flags))) {
+        ALOGV("Disable passthrough , reset mixer to pcm");
+        /* NO_PASSTHROUGH */
+        out->compr_config.codec->compr_passthr = 0;
+        audio_extn_dolby_set_hdmi_config(adev, out);
+        audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
+    }
     /* Must be called after removing the usecase from list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
         check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
@@ -1409,7 +1421,7 @@
         ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
               __func__, out->pcm_device_id, out->usecase);
         ret = -EINVAL;
-        goto error_config;
+        goto error_open;
     }
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
@@ -1425,9 +1437,17 @@
     uc_info->devices = out->devices;
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
-
     /* This must be called before adding this usecase to the list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (is_offload_usecase(out->usecase)) {
+            if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+                ret = audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_BYPASS);
+                if(ret != 0) {
+                    goto error_open;
+                }
+                audio_extn_dolby_update_passt_stream_configuration(adev, out);
+            }
+        }
         property_get("audio.use.hdmi.sink.cap", prop_value, NULL);
         if (!strncmp("true", prop_value, 4)) {
             sink_channels = platform_edid_get_max_channels(out->dev->platform);
@@ -1435,13 +1455,17 @@
                    __func__, sink_channels);
             check_and_set_hdmi_channels(adev, sink_channels);
         } else {
-            if (is_offload_usecase(out->usecase))
-                check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
-            else
+            if (is_offload_usecase(out->usecase)) {
+                unsigned int ch_count =  out->compr_config.codec->ch_in;
+                if (audio_extn_dolby_is_passthrough_stream(out->flags))
+                    /* backend channel config for passthrough stream is stereo */
+                    ch_count = 2;
+                check_and_set_hdmi_channels(adev, ch_count);
+            } else
                 check_and_set_hdmi_channels(adev, out->config.channels);
         }
+        audio_extn_dolby_set_hdmi_config(adev, out);
     }
-
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
     select_devices(adev, out->usecase);
@@ -1498,11 +1522,12 @@
         if (audio_extn_is_dolby_format(out->format))
             audio_extn_dolby_send_ddp_endp_params(adev);
 #endif
-
-        if (adev->visualizer_start_output != NULL)
-            adev->visualizer_start_output(out->handle, out->pcm_device_id);
-        if (adev->offload_effects_start_output != NULL)
-            adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+        if (!(audio_extn_dolby_is_passthrough_stream(out->flags))) {
+            if (adev->visualizer_start_output != NULL)
+                adev->visualizer_start_output(out->handle, out->pcm_device_id);
+            if (adev->offload_effects_start_output != NULL)
+                adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+        }
     }
     ALOGV("%s: exit", __func__);
     return 0;
@@ -1891,6 +1916,28 @@
             str = strdup(keys);
         }
     }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
+    if (ret >= 0) {
+        value[0] = '\0';
+        i = 0;
+        first = true;
+        while (out->supported_formats[i] != 0) {
+            for (j = 0; j < ARRAY_SIZE(out_formats_name_to_enum_table); j++) {
+                if (out_formats_name_to_enum_table[j].value == out->supported_formats[i]) {
+                    if (!first) {
+                        strcat(value, "|");
+                    }
+                    strlcat(value, out_formats_name_to_enum_table[j].name, sizeof(value));
+                    first = false;
+                    break;
+                }
+            }
+            i++;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
+        str = str_parms_to_str(reply);
+    }
     str_parms_destroy(query);
     str_parms_destroy(reply);
     ALOGV("%s: exit: returns - %s", __func__, str);
@@ -1919,24 +1966,33 @@
         out->muted = (left == 0.0f);
         return 0;
     } else if (is_offload_usecase(out->usecase)) {
-        char mixer_ctl_name[128];
-        struct audio_device *adev = out->dev;
-        struct mixer_ctl *ctl;
-        int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+        if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+            /*
+             * Set mute or umute on HDMI passthrough stream.
+             * Only take left channel into account.
+             * Mute is 0 and unmute 1
+             */
+            audio_extn_dolby_set_passt_volume(out, (left == 0.0f));
+        } else {
+            char mixer_ctl_name[128];
+            struct audio_device *adev = out->dev;
+            struct mixer_ctl *ctl;
+            int pcm_device_id = platform_get_pcm_device_id(out->usecase,
                                                        PCM_PLAYBACK);
 
-        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
-                 "Compress Playback %d Volume", pcm_device_id);
-        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
-        if (!ctl) {
-            ALOGE("%s: Could not get ctl for mixer cmd - %s",
-                  __func__, mixer_ctl_name);
-            return -EINVAL;
+            snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+                     "Compress Playback %d Volume", pcm_device_id);
+            ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+            if (!ctl) {
+                ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                      __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+            volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+            volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+            mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+            return 0;
         }
-        volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
-        volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
-        mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
-        return 0;
     }
 
     return -ENOSYS;
@@ -2633,6 +2689,18 @@
             ret = -EINVAL;
             goto error_open;
         }
+
+        if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+            ((audio_extn_dolby_is_passthrough_stream(out->flags)))) {
+            ALOGV("read and update_pass through formats");
+            ret = audio_extn_dolby_update_passt_formats(adev, out);
+            if(ret != 0) {
+                goto error_open;
+            }
+            if(config->offload_info.format == 0)
+                config->offload_info.format = out->supported_formats[0];
+        }
+
         if (!is_supported_format(config->offload_info.format) &&
                 !audio_extn_is_dolby_format(config->offload_info.format)) {
             ALOGE("%s: Unsupported audio format", __func__);
@@ -2674,10 +2742,13 @@
                 get_snd_codec_id(config->offload_info.format);
         if (audio_is_offload_pcm(config->offload_info.format)) {
             out->compr_config.fragment_size =
-                       platform_get_pcm_offload_buffer_size(&config->offload_info);
+               platform_get_pcm_offload_buffer_size(&config->offload_info);
+        } else if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+            out->compr_config.fragment_size =
+               audio_extn_dolby_get_passt_buffer_size(&config->offload_info);
         } else {
             out->compr_config.fragment_size =
-                       platform_get_compress_offload_buffer_size(&config->offload_info);
+               platform_get_compress_offload_buffer_size(&config->offload_info);
         }
         out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
         out->compr_config.codec->sample_rate =
@@ -2688,6 +2759,8 @@
                 audio_channel_count_from_out_mask(config->channel_mask);
         out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
         out->bit_width = PCM_OUTPUT_BIT_WIDTH;
+        /*TODO: Do we need to change it for passthrough */
+        out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
 
         if (config->offload_info.format == AUDIO_FORMAT_AAC)
             out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
@@ -2761,6 +2834,9 @@
 
     ALOGV("%s devices %d,flags %x, format %x, out->sample_rate %d, out->bit_width %d",
            __func__, devices, flags, format, out->sample_rate, out->bit_width);
+    /* TODO remove this hardcoding and check why width is zero*/
+    if (out->bit_width == 0)
+        out->bit_width = 16;
     audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
                                                 devices, flags, format, out->sample_rate,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index eb5b351..3340230 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -48,6 +48,7 @@
 #define ACDB_DEV_TYPE_IN 2
 
 #define MAX_SUPPORTED_CHANNEL_MASKS 8
+#define MAX_SUPPORTED_FORMATS 3
 #define DEFAULT_HDMI_OUT_CHANNELS   2
 
 #define SND_CARD_STATE_OFFLINE 0
@@ -173,6 +174,7 @@
     audio_usecase_t usecase;
     /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
     audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+    audio_format_t supported_formats[MAX_SUPPORTED_FORMATS+1];
     bool muted;
     uint64_t written; /* total frames written, not cleared when entering standby */
     audio_io_handle_t handle;
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 458593c..e73fb93 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1109,7 +1109,7 @@
 }
 
 int platform_set_edid_channels_configuration(void *platform __unused,
-                                         int channels __unused)
+                                             int channels __unused)
 {
     return 0;
 }
@@ -1118,6 +1118,7 @@
 {
     return 0;
 }
+
 bool platform_is_edid_supported_format(void *platform __unused,
                                        int format __unused)
 {
@@ -1133,3 +1134,14 @@
 {
 
 }
+
+int platform_set_hdmi_config(struct stream_out *out __unused)
+{
+    return 0;
+}
+
+int platform_set_device_params(struct stream_out *out __unused,
+                                  int param __unused, int value __unused)
+{
+    return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 10e608b..e39c48e 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -71,6 +71,12 @@
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
 #define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
 
+/*
+ * Offload buffer size for compress passthrough
+ */
+#define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
+#define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
+
 #define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
 /*
  * This file will have a maximum of 38 bytes:
@@ -1204,6 +1210,7 @@
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
 
+    my_data->edid_info = NULL;
     return my_data;
 }
 
@@ -1211,6 +1218,11 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
 
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
@@ -3366,7 +3378,6 @@
 
 unsigned char platform_map_to_edid_format(int audio_format)
 {
-
     unsigned char format;
     switch (audio_format & AUDIO_FORMAT_MAIN_MASK) {
     case AUDIO_FORMAT_AC3:
@@ -3382,6 +3393,8 @@
         format = DOLBY_DIGITAL_PLUS;
         break;
     case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
+    case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
     default:
         ALOGV("%s:PCM", __func__);
         format =  LPCM;
@@ -3390,6 +3403,27 @@
     return format;
 }
 
+uint32_t platform_get_compress_passthrough_buffer_size(
+                                          audio_offload_info_t* info)
+{
+    uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+    if (!info->has_video)
+        fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+
+    return fragment_size;
+}
+
+void platform_reset_edid_info(void *platform) {
+
+    ALOGV("%s:", __func__);
+    struct platform_data *my_data = (struct platform_data *)platform;
+    if (my_data->edid_info) {
+        ALOGV("%s :free edid", __func__);
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+}
+
 bool platform_is_edid_supported_format(void *platform, int format)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -3403,10 +3437,16 @@
     info = (edid_audio_info *)my_data->edid_info;
     if (ret == 0 && info != NULL) {
         for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
-            if (info->audio_blocks_array[i].format_id == format_id)
+             /*
+              * To check
+              *  is there any special for CONFIG_HDMI_PASSTHROUGH_CONVERT
+              *  & DOLBY_DIGITAL_PLUS
+              */
+            if (info->audio_blocks_array[i].format_id == format_id) {
                 ALOGV("%s:platform_is_edid_supported_format true %x",
-                       __func__, format);
+                      __func__, format);
                 return true;
+            }
         }
     }
     ALOGV("%s:platform_is_edid_supported_format false %x",
@@ -3470,3 +3510,132 @@
         memset(my_data->edid_info, 0, sizeof(struct edid_audio_info));
     }
 }
+
+int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
+                      const char *mixer_val)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl = NULL;
+    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
+}
+
+int platform_set_hdmi_config(struct stream_out *out)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct audio_device *adev = out->dev;
+    const char *hdmi_format_ctrl = "HDMI RX Format";
+    const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
+    int sample_rate = out->sample_rate;
+    /*TODO: Add rules and check if this needs to be done.*/
+    if((is_offload_usecase(out->usecase)) &&
+        (out->compr_config.codec->compr_passthr == PASSTHROUGH ||
+        out->compr_config.codec->compr_passthr == PASSTHROUGH_CONVERT)) {
+        /* TODO: can we add mixer control for channels here avoid setting */
+        if ((out->format == AUDIO_FORMAT_E_AC3 ||
+            out->format == AUDIO_FORMAT_E_AC3_JOC) &&
+            (out->compr_config.codec->compr_passthr == PASSTHROUGH))
+            sample_rate = out->sample_rate * 4;
+        ALOGD("%s:HDMI compress format and samplerate %d, sample_rate %d",
+               __func__, out->sample_rate, sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "Compr");
+        switch (sample_rate) {
+            case 32000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_32");
+                break;
+            case 44100:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_44_1");
+                break;
+            case 96000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_96");
+                break;
+            case 176400:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_176_4");
+                break;
+            case 192000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_192");
+                break;
+            case 128000:
+                if (out->format != AUDIO_FORMAT_E_AC3) {
+                    platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_128");
+                    break;
+                } else
+                   ALOGW("Unsupported sample rate for E_AC3 32K");
+            default:
+            case 48000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+                break;
+        }
+    } else {
+        ALOGD("%s: HDMI pcm and samplerate %d", __func__,
+               out->sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "LPCM");
+        platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+    }
+
+    /*
+     * Deroute all the playback streams routed to HDMI so that
+     * the back end is deactivated. Note that backend will not
+     * be deactivated if any one stream is connected to it.
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:disable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            disable_audio_route(adev, usecase);
+        }
+    }
+
+    /*
+     * Enable all the streams disabled above. Now the HDMI backend
+     * will be activated with new channel configuration
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:enable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            enable_audio_route(adev, usecase);
+        }
+    }
+
+    return 0;
+}
+
+int platform_set_device_params(struct stream_out *out, int param, int value)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = "Device PP Params";
+    int ret = 0;
+    uint32_t set_values[] = {0,0};
+
+    set_values[0] = param;
+    set_values[1] = value;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto end;
+    }
+
+    ALOGV("%s: Setting device pp params param: %d, value %d mixer ctrl:%s",
+          __func__,param, value, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+end:
+    return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 1b80a13..9c944ff 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -346,4 +346,16 @@
     get_sample_rate_t get_sample_rate;
 };
 
+/* HDMI Passthrough defines */
+enum {
+    LEGACY_PCM = 0,
+    PASSTHROUGH,
+    PASSTHROUGH_CONVERT
+};
+/*
+ * ID for setting mute and lateny on the device side
+ * through Device PP Params mixer control.
+ */
+#define DEVICE_PARAM_MUTE_ID    0
+#define DEVICE_PARAM_LATENCY_ID 1
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 381901c..ab2cc9d 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -89,6 +89,7 @@
 struct audio_offload_info_t;
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info);
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
 int platform_get_usecase_index(const char * usecase);
@@ -106,5 +107,6 @@
 bool platform_is_edid_supported_format(void *platform, int format);
 void platform_cache_edid(void * platform);
 void platform_invalidate_edid(void * platform);
-
+int platform_set_hdmi_config(struct stream_out *out);
+int platform_set_device_params(struct stream_out *out, int param, int value);
 #endif // AUDIO_PLATFORM_API_H