audio: hal: changes to support compressed input for transcode loopback

- Support compressed input format in transcode loopback extension
- Support compressed input format in target platform
- Test application changes to support pcm and compressed input formats

CRs-Fixed: 2061945
Change-Id: I693594164e05c09ffece8fa705149c7b45c2e5d3
Signed-off-by: Siddartha Shaik <sshaik@codeaurora.org>
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 6325ab6..d0c3395 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -906,8 +906,8 @@
                                     const struct audio_port_config *config);
 int audio_extn_hw_loopback_get_audio_port(struct audio_hw_device *dev,
                                     struct audio_port *port_in);
-int audio_extn_loopback_init(struct audio_device *adev);
-void audio_extn_loopback_deinit(struct audio_device *adev);
+int audio_extn_hw_loopback_init(struct audio_device *adev);
+void audio_extn_hw_loopback_deinit(struct audio_device *adev);
 #else
 static int __unused audio_extn_hw_loopback_create_audio_patch(struct audio_hw_device *dev __unused,
                                      unsigned int num_sources __unused,
@@ -933,11 +933,11 @@
 {
     return -ENOSYS;
 }
-static int __unused audio_extn_loopback_init(struct audio_device *adev __unused)
+static int __unused audio_extn_hw_loopback_init(struct audio_device *adev __unused)
 {
     return -ENOSYS;
 }
-static void __unused audio_extn_loopback_deinit(struct audio_device *adev __unused)
+static void __unused audio_extn_hw_loopback_deinit(struct audio_device *adev __unused)
 {
 }
 #endif
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index 8e577c2..5b67284 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -251,9 +251,14 @@
     disable_snd_device(adev, uc_info->out_snd_device);
     disable_snd_device(adev, uc_info->in_snd_device);
 
+    /* 4. Reset backend device to default state */
+    platform_invalidate_backend_config(adev->platform,uc_info->in_snd_device);
+
     list_remove(&uc_info->list);
     free(uc_info);
 
+    adev->active_input = get_next_active_input(adev);
+
     if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format) && inout->ip_hdlr_handle) {
         ret = audio_extn_ip_hdlr_intf_close(inout->ip_hdlr_handle, true, inout);
         if (ret < 0)
@@ -284,6 +289,7 @@
     if (event == AUDIO_EXTN_STREAM_CBK_EVENT_ERROR) {
         pthread_mutex_lock(&audio_loopback_mod->lock);
         release_loopback_session(cookie);
+        audio_loopback_mod->patch_db.num_patches--;
         pthread_mutex_unlock(&audio_loopback_mod->lock);
     }
     return 0;
@@ -305,6 +311,7 @@
                                                     loopback_sink;
     struct stream_inout *inout =  &active_loopback_patch->patch_stream;
     struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
+    struct stream_in loopback_source_stream;
 
     ALOGD("%s: Create loopback session begin", __func__);
 
@@ -324,6 +331,16 @@
 
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
+    loopback_source_stream.source = AUDIO_SOURCE_UNPROCESSED;
+    loopback_source_stream.device = inout->in_config.devices;
+    loopback_source_stream.channel_mask = inout->in_config.channel_mask;
+    loopback_source_stream.bit_width = inout->in_config.bit_width;
+    loopback_source_stream.sample_rate = inout->in_config.sample_rate;
+    loopback_source_stream.format = inout->in_config.format;
+
+    memcpy(&loopback_source_stream.usecase, uc_info,
+           sizeof(struct audio_usecase));
+    adev->active_input = &loopback_source_stream;
     select_devices(adev, uc_info->id);
 
     pcm_dev_asm_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
@@ -579,10 +596,11 @@
         }
     }
 
-    if (patch_found) {
+    if (patch_found && (audio_loopback_mod->patch_db.num_patches > 0)) {
         active_loopback_patch = &(audio_loopback_mod->patch_db.loopback_patch[
                                 patch_index]);
         status = release_loopback_session(active_loopback_patch);
+        audio_loopback_mod->patch_db.num_patches--;
     } else {
         ALOGE("%s, Requested Patch handle does not exist", __func__);
         status = -1;
@@ -715,7 +733,7 @@
 }
 
 /* Loopback extension initialization, part of hal init sequence */
-int audio_extn_loopback_init(struct audio_device *adev)
+int audio_extn_hw_loopback_init(struct audio_device *adev)
 {
     ALOGV("%s Audio loopback extension initializing", __func__);
     int ret = 0, size = 0;
@@ -764,7 +782,7 @@
     return ret;
 }
 
-void audio_extn_loopback_deinit(struct audio_device *adev)
+void audio_extn_hw_loopback_deinit(struct audio_device *adev)
 {
     ALOGV("%s Audio loopback extension de-initializing", __func__);
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ac7e16d..51d34b0 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1562,6 +1562,7 @@
     struct audio_usecase *vc_usecase = NULL;
     struct audio_usecase *voip_usecase = NULL;
     struct audio_usecase *hfp_usecase = NULL;
+    struct stream_out stream_out;
     audio_usecase_t hfp_ucid;
     int status = 0;
 
@@ -1589,8 +1590,13 @@
             ALOGE("%s: stream.inout is NULL", __func__);
             return -EINVAL;
         }
-        out_snd_device = usecase->stream.inout->out_config.devices;
-        in_snd_device = usecase->stream.inout->in_config.devices;
+        stream_out.devices = usecase->stream.inout->out_config.devices;
+        stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
+        stream_out.format = usecase->stream.inout->out_config.format;
+        stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
+        out_snd_device = platform_get_output_snd_device(adev->platform,
+                                                        &stream_out);
+        in_snd_device = platform_get_input_snd_device(adev->platform, AUDIO_DEVICE_NONE);
         usecase->devices = (out_snd_device | in_snd_device);
     } else {
         /*
@@ -5546,7 +5552,7 @@
         qahwi_deinit(device);
         audio_extn_adsp_hdlr_deinit();
         audio_extn_snd_mon_deinit();
-        audio_extn_loopback_deinit(adev);
+        audio_extn_hw_loopback_deinit(adev);
         if (adev->device_cfg_params) {
             free(adev->device_cfg_params);
             adev->device_cfg_params = NULL;
@@ -5733,7 +5739,7 @@
     audio_extn_init(adev);
     audio_extn_listen_init(adev, adev->snd_card);
     audio_extn_gef_init(adev);
-    audio_extn_loopback_init(adev);
+    audio_extn_hw_loopback_init(adev);
 
     if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
         adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index becd247..cfb5486 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -223,6 +223,7 @@
     uint32_t sample_rate;
     uint32_t bit_width;
     uint32_t channels;
+    uint32_t format;
     char     *bitwidth_mixer_ctl;
     char     *samplerate_mixer_ctl;
     char     *channels_mixer_ctl;
@@ -1421,6 +1422,7 @@
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = strdup("bt-sco-wb");
+    backend_tag_table[SND_DEVICE_IN_HDMI_MIC] = strdup("hdmi-mic");
     backend_tag_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
     backend_tag_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
     backend_tag_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
@@ -2419,6 +2421,7 @@
         my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
         if (idx > MAX_RX_CODEC_BACKENDS)
             my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
+        my_data->current_backend_cfg[idx].format = AUDIO_FORMAT_PCM;
         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
@@ -2515,6 +2518,13 @@
     my_data->current_backend_cfg[DISP_PORT_RX_BACKEND].channels_mixer_ctl =
         strdup("Display Port RX Channels");
 
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].bitwidth_mixer_ctl =
+        strdup("QUAT_MI2S_TX Format");
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].samplerate_mixer_ctl =
+        strdup("QUAT_MI2S_TX SampleRate");
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].channels_mixer_ctl =
+        strdup("QUAT_MI2S_TX Channels");
+
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
                                              my_data->codec_version);
@@ -3137,6 +3147,8 @@
                         port = USB_AUDIO_TX_BACKEND;
                 else if (strstr(backend_tag_table[snd_device], "bt-sco") != NULL)
                         port = BT_SCO_TX_BACKEND;
+                else if (strcmp(backend_tag_table[snd_device], "hdmi-mic") == 0)
+                        port = HDMI_TX_BACKEND;
         }
     } else {
         ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
@@ -5423,7 +5435,7 @@
         ret = 0;
     }
 
-    bool set_ext_disp_format = false;
+    bool set_ext_disp_format = false, set_mi2s_tx_data_format = false;
     char *ext_disp_format = NULL;
 
     if (backend_idx == HDMI_RX_BACKEND) {
@@ -5432,10 +5444,32 @@
     } else if (backend_idx == DISP_PORT_RX_BACKEND) {
         ext_disp_format = "Display Port RX Format";
         set_ext_disp_format = true;
+    } else if (backend_idx == HDMI_TX_BACKEND) {
+        ext_disp_format = "QUAT MI2S TX Format";
+        set_mi2s_tx_data_format = true;
     } else {
         ALOGV("%s: Format doesnt have to be set", __func__);
     }
 
+    format = format & AUDIO_FORMAT_MAIN_MASK;
+    /* Set data format only if there is a change from PCM to compressed
+       and vice versa */
+    if (set_mi2s_tx_data_format && (format ^ my_data->current_backend_cfg[backend_idx].format)) {
+        struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, ext_disp_format);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                  __func__, ext_disp_format);
+            return -EINVAL;
+        }
+        if (format == AUDIO_FORMAT_PCM) {
+            ALOGE("%s:MI2S data format LPCM", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "LPCM");
+        } else {
+            ALOGE("%s:MI2S data format Compr", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "Compr");
+        }
+        my_data->current_backend_cfg[backend_idx].format = format;
+    }
     if (set_ext_disp_format) {
         struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, ext_disp_format);
         if (!ctl) {
@@ -5878,15 +5912,17 @@
     unsigned int bit_width;
     unsigned int sample_rate;
     unsigned int channels;
+    unsigned int format;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
 
     bit_width = backend_cfg->bit_width;
     sample_rate = backend_cfg->sample_rate;
     channels = backend_cfg->channels;
+    format = backend_cfg->format;
 
     ALOGI("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
-          "sample rate: %d, channels %d",__func__,backend_idx, bit_width,
-          sample_rate, channels);
+          "sample rate: %d, channels %d format %d",__func__,backend_idx, bit_width,
+          sample_rate, channels,format);
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
@@ -5937,15 +5973,17 @@
     // is not same as current backend comfiguration
     if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
         (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
-        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        (channels != my_data->current_backend_cfg[backend_idx].channels) ||
+        ((format & AUDIO_FORMAT_MAIN_MASK) != my_data->current_backend_cfg[backend_idx].format)) {
         backend_cfg->bit_width = bit_width;
         backend_cfg->sample_rate= sample_rate;
         backend_cfg->channels = channels;
+        backend_cfg->format = format & AUDIO_FORMAT_MAIN_MASK;
         backend_change = true;
         ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
-              "new sample rate: %d new channel: %d",
+              "new sample rate: %d new channel: %d new format: %d",
               __func__, backend_cfg->bit_width,
-              backend_cfg->sample_rate, backend_cfg->channels);
+              backend_cfg->sample_rate, backend_cfg->channels, backend_cfg->format);
     }
 
     return backend_change;
@@ -5978,11 +6016,12 @@
         backend_cfg.channels = 1;
     }
 
-    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, channel %d"
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, channel %d format %d"
           ", backend_idx %d usecase = %d device (%s)", __func__,
           backend_cfg.bit_width,
           backend_cfg.sample_rate,
           backend_cfg.channels,
+          backend_cfg.format,
           backend_idx, usecase->id,
           platform_get_snd_device_name(snd_device));
     if (platform_check_capture_codec_backend_cfg(adev, backend_idx,
@@ -6583,6 +6622,27 @@
     platform_get_edid_info(platform);
 }
 
+void platform_invalidate_backend_config(void * platform,snd_device_t snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct audio_backend_cfg backend_cfg;
+    int backend_idx;
+
+    backend_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    backend_cfg.channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    backend_cfg.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    backend_cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    backend_cfg.passthrough_enabled = false;
+
+    backend_idx = platform_get_backend_index(snd_device);
+    platform_set_codec_backend_cfg(adev, snd_device, backend_cfg);
+    my_data->current_backend_cfg[backend_idx].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    my_data->current_backend_cfg[backend_idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    my_data->current_backend_cfg[backend_idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    my_data->current_backend_cfg[backend_idx].format = AUDIO_FORMAT_PCM_16_BIT;
+}
+
 void platform_invalidate_hdmi_config(void * platform)
 {
     //reset ext display EDID info
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 17bd8f2..6aa4dc1 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -252,6 +252,7 @@
     DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
     USB_AUDIO_TX_BACKEND,
     BT_SCO_TX_BACKEND,
+    HDMI_TX_BACKEND,
     MAX_CODEC_BACKENDS
 };
 
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index e08e21b..98b275b 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -197,6 +197,7 @@
     uint32_t sample_rate;
     uint32_t bit_width;
     uint32_t channels;
+    uint32_t format;
     char     *bitwidth_mixer_ctl;
     char     *samplerate_mixer_ctl;
     char     *channels_mixer_ctl;
@@ -1266,6 +1267,7 @@
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = strdup("bt-sco-wb");
+    backend_tag_table[SND_DEVICE_IN_HDMI_MIC] = strdup("hdmi-mic");
     backend_tag_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
     backend_tag_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
     backend_tag_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
@@ -2202,6 +2204,7 @@
         my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
         if (idx > MAX_RX_CODEC_BACKENDS)
             my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
+        my_data->current_backend_cfg[idx].format = AUDIO_FORMAT_PCM;
         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
@@ -2273,6 +2276,13 @@
     my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].channels_mixer_ctl =
         strdup("USB_AUDIO_TX Channels");
 
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].bitwidth_mixer_ctl =
+        strdup("QUAT_MI2S_TX Format");
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].samplerate_mixer_ctl =
+        strdup("QUAT_MI2S_TX SampleRate");
+    my_data->current_backend_cfg[HDMI_TX_BACKEND].channels_mixer_ctl =
+        strdup("QUAT_MI2S_TX Channels");
+
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
                                              my_data->codec_version);
@@ -2903,6 +2913,8 @@
                         port = USB_AUDIO_TX_BACKEND;
                 else if (strstr(backend_tag_table[snd_device], "bt-sco") != NULL)
                         port = BT_SCO_TX_BACKEND;
+                else if (strcmp(backend_tag_table[snd_device], "hdmi-mic") == 0)
+                        port = HDMI_TX_BACKEND;
         }
     } else {
         ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
@@ -5146,9 +5158,9 @@
         format = adev_device_cfg_ptr->dev_cfg_params.format;
     }
 
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d format %d"
           ", backend_idx %d device (%s)", __func__,  bit_width,
-          sample_rate, channels, backend_idx,
+          sample_rate, channels, format, backend_idx,
           platform_get_snd_device_name(snd_device));
 
     if ((my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl) &&
@@ -5296,7 +5308,7 @@
         ret = 0;
     }
 
-    bool set_ext_disp_format = false;
+    bool set_ext_disp_format = false, set_mi2s_tx_data_format = false;
     char *ext_disp_format = NULL;
 
     if (backend_idx == HDMI_RX_BACKEND) {
@@ -5305,10 +5317,32 @@
     } else if (backend_idx == DISP_PORT_RX_BACKEND) {
         ext_disp_format = "Display Port RX Format";
         set_ext_disp_format = true;
+    } else if (backend_idx == HDMI_TX_BACKEND) {
+        ext_disp_format = "QUAT MI2S TX Format";
+        set_mi2s_tx_data_format = true;
     } else {
         ALOGV("%s: Format doesnt have to be set", __func__);
     }
 
+    format = format & AUDIO_FORMAT_MAIN_MASK;
+    /* Set data format only if there is a change from PCM to compressed
+       and vice versa */
+    if (set_mi2s_tx_data_format && (format ^ my_data->current_backend_cfg[backend_idx].format)) {
+        struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, ext_disp_format);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                  __func__, ext_disp_format);
+            return -EINVAL;
+        }
+        if (format == AUDIO_FORMAT_PCM) {
+            ALOGE("%s:MI2S data format LPCM", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "LPCM");
+        } else {
+            ALOGE("%s:MI2S data format Compr", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "Compr");
+        }
+        my_data->current_backend_cfg[backend_idx].format = format;
+    }
     if (set_ext_disp_format) {
         struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, ext_disp_format);
         if (!ctl) {
@@ -5725,15 +5759,17 @@
     unsigned int bit_width;
     unsigned int sample_rate;
     unsigned int channels;
+    unsigned int format;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
 
     bit_width = backend_cfg->bit_width;
     sample_rate = backend_cfg->sample_rate;
     channels = backend_cfg->channels;
+    format = backend_cfg->format;
 
     ALOGI("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
-          "sample rate: %d, channels %d",__func__,backend_idx, bit_width,
-          sample_rate, channels);
+          "sample rate: %d, channels %d format %d",__func__,backend_idx, bit_width,
+          sample_rate, channels,format);
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
@@ -5785,15 +5821,17 @@
     // is not same as current backend comfiguration
     if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
         (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
-        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        (channels != my_data->current_backend_cfg[backend_idx].channels) ||
+        ((format & AUDIO_FORMAT_MAIN_MASK) != my_data->current_backend_cfg[backend_idx].format)) {
         backend_cfg->bit_width = bit_width;
         backend_cfg->sample_rate= sample_rate;
         backend_cfg->channels = channels;
+        backend_cfg->format = format & AUDIO_FORMAT_MAIN_MASK;
         backend_change = true;
         ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
-              "new sample rate: %d new channel: %d",
+              "new sample rate: %d new channel: %d new format: %d",
               __func__, backend_cfg->bit_width,
-              backend_cfg->sample_rate, backend_cfg->channels);
+              backend_cfg->sample_rate, backend_cfg->channels, backend_cfg->format);
     }
 
     return backend_change;
@@ -5826,11 +5864,12 @@
         backend_cfg.channels = 1;
     }
 
-    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, channel %d"
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, channel %d format %d"
           ", backend_idx %d usecase = %d device (%s)", __func__,
           backend_cfg.bit_width,
           backend_cfg.sample_rate,
           backend_cfg.channels,
+          backend_cfg.format,
           backend_idx, usecase->id,
           platform_get_snd_device_name(snd_device));
     if (platform_check_capture_codec_backend_cfg(adev, backend_idx,
@@ -6447,6 +6486,27 @@
     platform_get_edid_info(platform);
 }
 
+void platform_invalidate_backend_config(void * platform,snd_device_t snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct audio_backend_cfg backend_cfg;
+    int backend_idx;
+
+    backend_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    backend_cfg.channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    backend_cfg.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    backend_cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    backend_cfg.passthrough_enabled = false;
+
+    backend_idx = platform_get_backend_index(snd_device);
+    platform_set_codec_backend_cfg(adev, snd_device, backend_cfg);
+    my_data->current_backend_cfg[backend_idx].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    my_data->current_backend_cfg[backend_idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    my_data->current_backend_cfg[backend_idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    my_data->current_backend_cfg[backend_idx].format = AUDIO_FORMAT_PCM_16_BIT;
+}
+
 void platform_invalidate_hdmi_config(void * platform)
 {
     //reset ext display EDID info
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 9695e36..06f2cdc 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -249,6 +249,7 @@
     DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
     USB_AUDIO_TX_BACKEND,
     BT_SCO_TX_BACKEND,
+    HDMI_TX_BACKEND,
     MAX_CODEC_BACKENDS
 };
 
diff --git a/hal/platform_api.h b/hal/platform_api.h
index c7787a2..3c31c56 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -207,6 +207,7 @@
 int platform_get_backend_index(snd_device_t snd_device);
 int platform_get_ext_disp_type(void *platform);
 void platform_invalidate_hdmi_config(void *platform);
+void platform_invalidate_backend_config(void * platform,snd_device_t snd_device);
 
 int platform_send_audio_cal(void* platform, int acdb_dev_id, int acdb_device_type,
     int app_type, int topology_id, int sample_rate, uint32_t module_id, uint32_t param_id,
diff --git a/qahw_api/test/trans_loopback_test.c b/qahw_api/test/trans_loopback_test.c
index c0435c7..0fc2f08 100644
--- a/qahw_api/test/trans_loopback_test.c
+++ b/qahw_api/test/trans_loopback_test.c
@@ -33,8 +33,12 @@
 #include <linux/netlink.h>
 #include <pthread.h>
 #include <poll.h>
+#include <stdlib.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <string.h>
+#include <signal.h>
+#include <errno.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
@@ -42,17 +46,20 @@
 #include <utils/Log.h>
 
 #include <cutils/list.h>
-#include <hardware/audio.h>
-#include <system/audio.h>
 #include "qahw_api.h"
 #include "qahw_defs.h"
 
+static int sock_event_fd = -1;
+
+pthread_t data_event_th = -1;
+pthread_attr_t data_event_attr;
 
 typedef struct tlb_hdmi_config {
     int hdmi_conn_state;
     int hdmi_audio_state;
     int hdmi_sample_rate;
     int hdmi_num_channels;
+    int hdmi_data_format;
 } tlb_hdmi_config_t;
 
 const char tlb_hdmi_in_audio_sys_path[] =
@@ -70,11 +77,15 @@
 "/sys/devices/virtual/switch/channels/state";
 const char tlb_hdmi_in_audio_channel_dev_path[] =
 "/devices/virtual/switch/channels";
+const char tlb_hdmi_in_audio_format_sys_path[] =
+"/sys/devices/virtual/switch/audio_format/state";
+const char tlb_hdmi_in_audio_format_dev_path[] =
+"/devices/virtual/switch/audio_format";
 
 qahw_module_handle_t *primary_hal_handle = NULL;
 
 FILE * log_file = NULL;
-volatile bool stop_playback = false;
+volatile bool stop_loopback = false;
 const char *log_filename = NULL;
 
 #define TRANSCODE_LOOPBACK_SOURCE_PORT_ID 0x4C00
@@ -82,6 +93,8 @@
 
 #define MAX_MODULE_NAME_LENGTH  100
 
+#define DEV_NODE_CHECK(node_name,node_id) strncmp(node_name,node_id,strlen(node_name))
+
 typedef enum source_port_type {
     SOURCE_PORT_NONE,
     SOURCE_PORT_HDMI,
@@ -89,16 +102,34 @@
     SOURCE_PORT_MIC
 } source_port_type_t;
 
+typedef enum source_port_state {
+    SOURCE_PORT_INACTIVE=0,
+    SOURCE_PORT_ACTIVE,
+    SOURCE_PORT_CONFIG_CHANGED
+} source_port_state_t;
+
+typedef struct source_port_config {
+    source_port_type_t source_port_type;
+    source_port_state_t source_port_state;
+    union {
+        tlb_hdmi_config_t hdmi_in_port_config;
+    } port_config;
+} source_port_config_t;
 typedef struct trnscode_loopback_config {
     qahw_module_handle_t *hal_handle;
     audio_devices_t devices;
     struct audio_port_config source_config;
     struct audio_port_config sink_config;
     audio_patch_handle_t patch_handle;
+    source_port_config_t source_port_config;
 } transcode_loopback_config_t;
 
 transcode_loopback_config_t g_trnscode_loopback_config;
 
+void break_signal_handler(int signal __attribute__((unused)))
+{
+   stop_loopback = true;
+}
 
 void init_transcode_loopback_config(transcode_loopback_config_t **p_transcode_loopback_config)
 {
@@ -143,6 +174,11 @@
     /* Init patch handle */
     g_trnscode_loopback_config.patch_handle = AUDIO_PATCH_HANDLE_NONE;
 
+    memset(&g_trnscode_loopback_config.source_port_config,0,sizeof(source_port_config_t));
+    g_trnscode_loopback_config.source_port_config.source_port_type = SOURCE_PORT_HDMI;
+    g_trnscode_loopback_config.source_port_config.source_port_state = SOURCE_PORT_INACTIVE;
+
+    poll_data_event_init();
     *p_transcode_loopback_config = &g_trnscode_loopback_config;
 
     fprintf(log_file,"\nDone Initializing global transcode loopback config\n");
@@ -192,71 +228,114 @@
 int read_and_set_source_config(source_port_type_t source_port_type,
                                struct audio_port_config *dest_port_config)
 {
-    int rc=0, channels = 2;
+    int rc=0;
     tlb_hdmi_config_t hdmi_config = {0};
     switch(source_port_type)
     {
-    case SOURCE_PORT_HDMI :
-    read_data_from_fd(tlb_hdmi_in_audio_sys_path, &hdmi_config.hdmi_conn_state);
-    read_data_from_fd(tlb_hdmi_in_audio_state_sys_path,
-                      &hdmi_config.hdmi_audio_state);
-    read_data_from_fd(tlb_hdmi_in_audio_sample_rate_sys_path,
-                      &hdmi_config.hdmi_sample_rate);
-    read_data_from_fd(tlb_hdmi_in_audio_channel_sys_path,
-                      &hdmi_config.hdmi_num_channels);
-
-    channels = actual_channels_from_audio_infoframe(hdmi_config.hdmi_num_channels);
-    fprintf(log_file,"\nHDMI In state: %d, audio_state: %d, samplerate: %d, channels: %d\n",
-            hdmi_config.hdmi_conn_state, hdmi_config.hdmi_audio_state,
-            hdmi_config.hdmi_sample_rate, channels);
-
-    ALOGD("HDMI In state: %d, audio_state: %d, samplerate: %d, channels: %d",
-           hdmi_config.hdmi_conn_state, hdmi_config.hdmi_audio_state,
-           hdmi_config.hdmi_sample_rate, channels);
-
-        dest_port_config->sample_rate = hdmi_config.hdmi_sample_rate;
-        switch(channels) {
-        case 2 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
-            break;
-        case 3 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_2POINT1;
-            break;
-        case 4 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_QUAD;
-            break;
-        case 5 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_PENTA;
-            break;
-        case 6 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
-            break;
-        case 7 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_6POINT1;
-            break;
-        case 8 :
-            dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
-            break;
+        case SOURCE_PORT_HDMI :
+            read_data_from_fd(tlb_hdmi_in_audio_sys_path, &hdmi_config.hdmi_conn_state);
+            read_data_from_fd(tlb_hdmi_in_audio_state_sys_path,
+                              &hdmi_config.hdmi_audio_state);
+            read_data_from_fd(tlb_hdmi_in_audio_sample_rate_sys_path,
+                              &hdmi_config.hdmi_sample_rate);
+            read_data_from_fd(tlb_hdmi_in_audio_channel_sys_path,
+                              &hdmi_config.hdmi_num_channels);
+            read_data_from_fd(tlb_hdmi_in_audio_format_sys_path,
+                              &hdmi_config.hdmi_data_format);
+        break;
         default :
-            fprintf(log_file,"\nUnsupported number of channels in source port %d\n",
-                    channels);
+            fprintf(log_file,"\nUnsupported port type, cannot set configuration\n");
             rc = -1;
-            break;
-        }
+        break;
+    }
+
+    hdmi_config.hdmi_num_channels = actual_channels_from_audio_infoframe(hdmi_config.hdmi_num_channels);
+
+    if(hdmi_config.hdmi_data_format) {
+        if(!( hdmi_config.hdmi_num_channels == 2 || hdmi_config.hdmi_num_channels == 8 )) {
+                transcode_loopback_config->source_port_config.source_port_state = SOURCE_PORT_INACTIVE;
+                return rc;
+            }
+    }
+    dest_port_config->sample_rate = hdmi_config.hdmi_sample_rate;
+    switch(hdmi_config.hdmi_num_channels) {
+    case 2 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+        break;
+    case 3 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_2POINT1;
+        break;
+    case 4 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_QUAD;
+        break;
+    case 5 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_PENTA;
+        break;
+    case 6 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
+    case 7 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_6POINT1;
+        break;
+    case 8 :
+        dest_port_config->channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
         break;
     default :
-        fprintf(log_file,"\nUnsupported port type, cannot set configuration\n");
+        fprintf(log_file,"\nUnsupported number of channels in source port %d\n",
+                hdmi_config.hdmi_num_channels);
         rc = -1;
         break;
     }
+    switch(hdmi_config.hdmi_data_format) {
+    case 0 :
+        // TODO : HDMI driver detecting as 0 for compressed also as of now
+        //dest_port_config->format = AUDIO_FORMAT_AC3;
+        dest_port_config->format = AUDIO_FORMAT_PCM_16_BIT;
+        break;
+    case 1 :
+        dest_port_config->format = AUDIO_FORMAT_AC3;
+        break;
+    default :
+        fprintf(log_file,"\nUnsupported data format in source port %d\n",
+                hdmi_config.hdmi_data_format);
+        rc = -1;
+        break;
+    }
+
+    fprintf(log_file,"\nExisting HDMI In state: %d, audio_state: %d, samplerate: %d, channels: %d, format: %d\n",
+            transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config.hdmi_conn_state, transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config.hdmi_audio_state,
+            transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config.hdmi_sample_rate, transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config.hdmi_num_channels,
+            transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config.hdmi_data_format);
+
+    fprintf(log_file,"\nSource port connection_state: %d, audio_state: %d, samplerate: %d, channels: %d, format: %d\n",
+            hdmi_config.hdmi_conn_state, hdmi_config.hdmi_audio_state,
+            hdmi_config.hdmi_sample_rate, hdmi_config.hdmi_num_channels,
+            hdmi_config.hdmi_data_format);
+
+    if( rc == 0 ) {
+        if(hdmi_config.hdmi_audio_state)
+        {
+            if(memcmp(&hdmi_config,&(transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config),sizeof(tlb_hdmi_config_t))) {
+                transcode_loopback_config->source_port_config.source_port_state = SOURCE_PORT_CONFIG_CHANGED;
+            } else {
+                    transcode_loopback_config->source_port_config.source_port_state = SOURCE_PORT_ACTIVE;
+            }
+        } else {
+                transcode_loopback_config->source_port_config.source_port_state = SOURCE_PORT_INACTIVE;
+        }
+        memcpy(&(transcode_loopback_config->source_port_config.port_config.hdmi_in_port_config),&hdmi_config,sizeof(tlb_hdmi_config_t));
+    }
     return rc;
 }
 
 void stop_transcode_loopback(
             transcode_loopback_config_t *transcode_loopback_config)
 {
-    qahw_release_audio_patch(transcode_loopback_config->hal_handle,
-                             transcode_loopback_config->patch_handle);
+    fprintf(log_file,"\nStopping current loopback session\n");
+    if(transcode_loopback_config->patch_handle != AUDIO_PATCH_HANDLE_NONE)
+        qahw_release_audio_patch(transcode_loopback_config->hal_handle,
+                                 transcode_loopback_config->patch_handle);
+    transcode_loopback_config->patch_handle = AUDIO_PATCH_HANDLE_NONE;
 }
 
 int create_run_transcode_loopback(
@@ -267,6 +346,10 @@
 
 
     fprintf(log_file,"\nCreating audio patch\n");
+    if (transcode_loopback_config->patch_handle != AUDIO_PATCH_HANDLE_NONE) {
+        fprintf(log_file,"\nPatch already existing, release the patch before opening a new patch\n");
+        return rc;
+    }
     rc = qahw_create_audio_patch(module_handle,
                         1,
                         &transcode_loopback_config->source_config,
@@ -277,14 +360,14 @@
     return rc;
 }
 
-static audio_hw_device_t *load_hal(audio_devices_t dev)
+static qahw_module_handle_t *load_hal(audio_devices_t dev)
 {
     if (primary_hal_handle == NULL) {
         primary_hal_handle = qahw_load_module(QAHW_MODULE_ID_PRIMARY);
         if (primary_hal_handle == NULL) {
             fprintf(stderr,"failure in Loading primary HAL\n");
             goto exit;
-		}
+        }
     }
 
 exit:
@@ -303,28 +386,152 @@
     return 1;
 }
 
+
+int poll_data_event_init()
+{
+    struct sockaddr_nl sock_addr;
+    int sz = (64*1024);
+    int soc;
+
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    sock_addr.nl_family = AF_NETLINK;
+    sock_addr.nl_pid = getpid();
+    sock_addr.nl_groups = 0xffffffff;
+
+    soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (soc < 0) {
+        return 0;
+    }
+
+    setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+    if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+        close(soc);
+        return 0;
+    }
+
+    sock_event_fd = soc;
+
+    return (soc > 0);
+}
+
+void source_data_event_handler(transcode_loopback_config_t *transcode_loopback_config)
+{
+    int status =0;
+    source_port_type_t source_port_type = transcode_loopback_config->source_port_config.source_port_type;
+    status = read_and_set_source_config(source_port_type,&transcode_loopback_config->source_config);
+
+    if ( status )
+    {
+        fprintf(log_file,"\nFailure in source port configuration with status: %d\n", status);
+        return;
+    }
+
+    fprintf(log_file,"\nSource port state : %d\n", transcode_loopback_config->source_port_config.source_port_state);
+
+    if(transcode_loopback_config->source_port_config.source_port_state == SOURCE_PORT_CONFIG_CHANGED) {
+        fprintf(log_file,"\nAudio state changed, Create and start transcode loopback session begin\n");
+        stop_transcode_loopback(transcode_loopback_config);
+        status = create_run_transcode_loopback(transcode_loopback_config);
+        if(status)
+        {
+            fprintf(log_file,"\nCreate audio patch failed with status %d\n",status);
+            stop_transcode_loopback(transcode_loopback_config);
+        }
+    } else if(transcode_loopback_config->source_port_config.source_port_state == SOURCE_PORT_INACTIVE) {
+        stop_transcode_loopback(transcode_loopback_config);
+    }
+}
+
+void process_loopback_data(void *ptr)
+{
+    char buffer[64*1024];
+    struct pollfd fds;
+    int i, count, status;
+    int j;
+    char *dev_path = NULL;
+    char *switch_state = NULL;
+    char *switch_name = NULL;
+    transcode_loopback_config_t *transcode_loopback_config = &g_trnscode_loopback_config;
+
+    fprintf(log_file,"\nEvent thread loop\n");
+    source_data_event_handler(transcode_loopback_config);
+    while(1) {
+
+        fds.fd = sock_event_fd;
+        fds.events = POLLIN;
+        fds.revents = 0;
+        i = poll(&fds, 1, -1);
+
+        if (i > 0 && (fds.revents & POLLIN)) {
+            count = recv(sock_event_fd, buffer, (64*1024), 0 );
+            if (count > 0) {
+                buffer[count] = '\0';
+                j = 0;
+                while(j < count) {
+                    if (strncmp(&buffer[j], "DEVPATH=", 8) == 0) {
+                        dev_path = &buffer[j+8];
+                        j += 8;
+                        continue;
+                    } else if (strncmp(&buffer[j], "SWITCH_NAME=", 12) == 0) {
+                        switch_name = &buffer[j+12];
+                        j += 12;
+                        continue;
+                    } else if (strncmp(&buffer[j], "SWITCH_STATE=", 13) == 0) {
+                        switch_state = &buffer[j+13];
+                        j += 13;
+                        continue;
+                    }
+                    j++;
+                }
+                fprintf(log_file,"devpath = %s, switch_name = %s \n",
+                                         dev_path, switch_name);
+
+                if((DEV_NODE_CHECK(tlb_hdmi_in_audio_dev_path, dev_path) == 0)  || (DEV_NODE_CHECK(tlb_hdmi_in_audio_sample_rate_dev_path, dev_path) == 0)
+                || (DEV_NODE_CHECK(tlb_hdmi_in_audio_state_dev_path, dev_path) == 0)
+                || (DEV_NODE_CHECK(tlb_hdmi_in_audio_channel_dev_path, dev_path) == 0)
+                || (DEV_NODE_CHECK(tlb_hdmi_in_audio_format_dev_path, dev_path) == 0)) {
+                    source_data_event_handler(transcode_loopback_config);
+                }
+            }
+        } else {
+            ALOGD("NO Data\n");
+        }
+    }
+    fprintf(log_file,"\nEvent thread loop exit\n");
+    pthread_exit(0);
+}
+
 int main(int argc, char *argv[]) {
 
-    int status = 0,play_duration_in_seconds = 30;
+    int status = 0;
+    uint32_t play_duration_in_seconds = 30,play_duration_elapsed_msec = 0,play_duration_in_msec = 0;
     source_port_type_t source_port_type = SOURCE_PORT_NONE;
     log_file = stdout;
 
+    fprintf(log_file,"\nUsage : trans_loopback_test <optional : duration_in_seconds>\n");
     fprintf(log_file,"\nTranscode loopback test begin\n");
+    play_duration_in_seconds = 600;
     if (argc == 2) {
         play_duration_in_seconds = atoi(argv[1]);
         if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
             fprintf(log_file,
-                    "\nPlayback duration %s invalid or unsupported(range : 1 to 3600 )\n",
+                    "\nPlayback duration %s invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
                     argv[1]);
-            goto usage;
+            play_duration_in_seconds = 600;
         }
-    } else {
-        goto usage;
     }
+    play_duration_in_msec = play_duration_in_seconds * 1000;
 
     transcode_loopback_config_t    *transcode_loopback_config = NULL;
     transcode_loopback_config_t *temp = NULL;
 
+    /* Register the SIGINT to close the App properly */
+    if (signal(SIGINT, break_signal_handler) == SIG_ERR) {
+        fprintf(log_file, "Failed to register SIGINT:%d\n",errno);
+        fprintf(stderr, "Failed to register SIGINT:%d\n",errno);
+    }
+
     /* Initialize global transcode loopback struct */
     init_transcode_loopback_config(&temp);
     transcode_loopback_config = &g_trnscode_loopback_config;
@@ -339,39 +546,32 @@
     transcode_loopback_config->hal_handle = primary_hal_handle;
     fprintf(log_file,"\nLoading HAL for loopback usecase done\n");
 
-    /* Configuration assuming source port is HDMI */
-    {
-        source_port_type = SOURCE_PORT_HDMI;
-        fprintf(log_file,"\nSet port config being\n");
-        status = read_and_set_source_config(source_port_type,&transcode_loopback_config->source_config);
-        fprintf(log_file,"\nSet port config end\n");
+    pthread_attr_init(&data_event_attr);
+    fprintf(log_file,"\nData thread init done\n");
+    pthread_attr_setdetachstate(&data_event_attr, PTHREAD_CREATE_JOINABLE);
+    fprintf(log_file,"\nData thread setdetachstate done\n");
 
-        if (status != 0) {
-            fprintf(log_file,"\nFailed to set port config, exiting\n");
-            goto exit_transcode_loopback_test;
+    fprintf(log_file,"\nData thread create\n");
+    pthread_create(&data_event_th, &data_event_attr,
+                       (void *) process_loopback_data, NULL);
+    fprintf(log_file,"\nMain thread loop\n");
+    while(!stop_loopback) {
+        usleep(100*1000);
+        play_duration_elapsed_msec += 100;
+        if(play_duration_in_msec <= play_duration_elapsed_msec)
+        {
+            fprintf(log_file,"\nElapsed set playback duration %d seconds, exiting test\n",play_duration_in_msec/1000);
+            break;
         }
     }
-
-    /* Open transcode loopback session */
-    fprintf(log_file,"\nCreate and start transcode loopback session begin\n");
-    status = create_run_transcode_loopback(transcode_loopback_config);
-    fprintf(log_file,"\nCreate and start transcode loopback session end\n");
-
-    /* If session opened successfully, run for a duration and close session */
-    if (status == 0) {
-        fprintf(log_file,"\nSleeping for %d seconds for loopback session to run\n",
-                play_duration_in_seconds);
-        usleep(play_duration_in_seconds*1000*1000);
-
-        fprintf(log_file,"\nStop transcode loopback session begin\n");
-        stop_transcode_loopback(transcode_loopback_config);
-        fprintf(log_file,"\nStop transcode loopback session end\n");
-    } else {
-        fprintf(log_file,"\nEncountered error %d in creating transcode loopback session\n",
-              status);
-    }
+    fprintf(log_file,"\nMain thread loop exit\n");
 
 exit_transcode_loopback_test:
+    stop_transcode_loopback(transcode_loopback_config);
+    fprintf(log_file,"\nCancelling loopback thread\n");
+    pthread_cancel(data_event_th);
+    fprintf(log_file,"\nJoining loopback thread\n");
+    pthread_join(data_event_th, NULL);
     fprintf(log_file,"\nUnLoading HAL for loopback usecase begin\n");
     unload_hals();
     fprintf(log_file,"\nUnLoading HAL for loopback usecase end\n");