Modify not to destroy handle inside of the resource release callback
[platform/core/multimedia/libmm-wfd.git] / src / mm_wfd_sink_priv.c
old mode 100755 (executable)
new mode 100644 (file)
index dc17608..5244044
@@ -23,7 +23,8 @@
 #include <gst/gst.h>
 #include <gst/video/videooverlay.h>
 #include <Elementary.h>
-#include <Ecore_Wayland.h>
+#include <Ecore_Wl2.h>
+#include <sys/syscall.h>
 
 #include "mm_wfd_sink_util.h"
 #include "mm_wfd_sink_priv.h"
 #include "mm_wfd_sink_dlog.h"
 #include "mm_wfd_sink_enum.h"
 #include "mm_wfd_sink_wayland.h"
+#include "mm_wfd_sink_config.h"
+
+#define PRINT_WFD_REF_COUNT(wfd_sink)\
+       do {\
+               wfd_sink_debug("PRINT WFD REF COUNT");\
+               __mm_wfd_sink_print_ref_count(wfd_sink);\
+       } while (0);
 
 /* gstreamer */
 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
-static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
-
-/* state */
-static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd);
-static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
+static gboolean _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data);
 
 /* util */
 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
-static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution);
 
-int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
+static int
+__resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
+               void *user_data)
+{
+       mm_wfd_sink_t *wfdsink = NULL;
+       MMWFDSinkResourceType res_idx = MM_WFD_SINK_RESOURCE_TYPE_MAX;
+
+       wfd_sink_debug_fenter();
+
+       if (!user_data) {
+               wfd_sink_error("user_data is null");
+               return FALSE;
+       }
+
+       wfdsink = (mm_wfd_sink_t *)user_data;
+
+       wfdsink->interrupted_by_resource = TRUE;
+
+       wfd_sink_debug("resource is interrupted. resource would be released after destroying");
+
+       MMWFDSINK_CMD_LOCK(wfdsink);
+       if (_mm_wfd_sink_disconnect(wfdsink) != MM_ERROR_NONE)
+               wfd_sink_error("failed to disconnect");
+
+       if (_mm_wfd_sink_unprepare(wfdsink) != MM_ERROR_NONE)
+               wfd_sink_error("failed to unprepare");
+       for (res_idx = MM_WFD_SINK_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MM_WFD_SINK_RESOURCE_TYPE_MAX; res_idx++) {
+               wfdsink->hw_resource[res_idx] = NULL;
+       }
+       MMWFDSINK_CMD_UNLOCK(wfdsink);
+
+       wfd_sink_debug_fleave();
+       return TRUE; /* release all the resources */
+}
+
+static int __mm_wfd_sink_acquire_hw_resource (mm_wfd_sink_t* wfd_sink, MMWFDSinkResourceType type)
+{
+       int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
+
+       switch (type) {
+               case MM_WFD_SINK_RESOURCE_TYPE_VIDEO_DECODER:
+                       rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
+                       break;
+               case MM_WFD_SINK_RESOURCE_TYPE_VIDEO_OVERLAY:
+                       rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
+                       break;
+               default:
+                       wfd_sink_error("invalid wfd sink resource type %d", type);
+                       return MM_ERROR_WFD_INTERNAL;
+       }
+
+       if (wfd_sink->hw_resource[type] != NULL) {
+               wfd_sink_debug("[%d type] resource was already acquired", type);
+               return MM_ERROR_NONE;
+       }
+
+       wfd_sink_debug("mark for acquire [%d type] resource", type);
+       rm_ret = mm_resource_manager_mark_for_acquire(wfd_sink->resource_manager,
+                       rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &wfd_sink->hw_resource[type]);
+       if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+               wfd_sink_error("failed to mark resource for acquire, ret(0x%x)", rm_ret);
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       rm_ret = mm_resource_manager_commit(wfd_sink->resource_manager);
+       if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+               wfd_sink_error("failed to commit of resource, ret(0x%x)", rm_ret);
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       wfd_sink_debug_fleave();
+       return MM_ERROR_NONE;
+}
+
+static int __mm_wfd_sink_release_hw_resource(mm_wfd_sink_t *wfd_sink, MMWFDSinkResourceType type)
+{
+       int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       if (wfd_sink->hw_resource[type] == NULL) {
+               wfd_sink_debug("there is no acquired [%d type] resource", type);
+               return MM_ERROR_NONE;
+       }
+
+       wfd_sink_debug("mark for release [%d type] resource", type);
+       rm_ret = mm_resource_manager_mark_for_release(wfd_sink->resource_manager, wfd_sink->hw_resource[type]);
+       if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+               wfd_sink_error("failed to mark resource for release, ret(0x%x)", rm_ret);
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       wfd_sink->hw_resource[type] = NULL;
+
+       rm_ret = mm_resource_manager_commit(wfd_sink->resource_manager);
+       if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+               wfd_sink_error("failed to commit of resource, ret(0x%x)", rm_ret);
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       wfd_sink_debug_fleave();
+       return MM_ERROR_NONE;
+}
+
+int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink, const char *ini_path)
 {
        int result = MM_ERROR_NONE;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
+       if (ini_path == NULL) {
+               ini_path = MM_WFD_SINK_INI_DEFAULT_PATH;
+               wfd_sink_debug("The wfd ini file path is set as defalut[%s]", ini_path);
+       }
 
        mm_wfd_sink_t *new_wfd_sink = NULL;
 
@@ -69,6 +176,15 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
                return MM_ERROR_WFD_NO_FREE_SPACE;
        }
 
+       /* initialize resource manager */
+       if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
+               __resource_release_cb, new_wfd_sink, &new_wfd_sink->resource_manager)
+               != MM_RESOURCE_MANAGER_ERROR_NONE) {
+               wfd_sink_error("failed to initialize resource manager");
+               MMWFDSINK_FREEIF(new_wfd_sink);
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
        /* Initialize gstreamer related */
        new_wfd_sink->attrs = 0;
 
@@ -114,18 +230,25 @@ int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
        /* Initialize video resolution */
        new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
 
+       /* Initialize coulped sink information */
+       new_wfd_sink->coupled_sink_address = NULL;
+       new_wfd_sink->coupled_sink_status = MM_WFD_COUPLED_SINK_STATUS_NOT_COUPLED;
+
+       /* In case of R2 sink, it would be TRUE */
+       new_wfd_sink->is_coupled_sink_supported = FALSE;
+
        /* construct attributes */
        new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
        if (!new_wfd_sink->attrs) {
-               MMWFDSINK_FREEIF(new_wfd_sink);
+               result = MM_ERROR_WFD_INTERNAL;
                wfd_sink_error("failed to set attribute");
-               return MM_ERROR_WFD_INTERNAL;
+               goto fail_to_attrs;
        }
 
        /* load ini for initialize */
-       result = mm_wfd_sink_ini_load(&new_wfd_sink->ini);
+       result = mm_wfd_sink_ini_load(&new_wfd_sink->ini, ini_path);
        if (result != MM_ERROR_NONE) {
-               wfd_sink_error("failed to load ini file");
+               wfd_sink_error("failed to load ini file[%s]", ini_path);
                goto fail_to_load_ini;
        }
        new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
@@ -159,6 +282,8 @@ fail_to_init:
        mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
 fail_to_load_ini:
        _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
+fail_to_attrs:
+       mm_resource_manager_destroy(new_wfd_sink->resource_manager);
        MMWFDSINK_FREEIF(new_wfd_sink);
 
        *wfd_sink = NULL;
@@ -240,15 +365,16 @@ int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
 
        wfd_sink_debug_fenter();
 
-       wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"), MM_ERROR_WFD_INVALID_ARGUMENT);
+       wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
+                                                               MM_ERROR_WFD_INVALID_ARGUMENT);
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        /* check current wi-fi display sink state */
        MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
@@ -303,16 +429,16 @@ int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        /* check current wi-fi display sink state */
        MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
 
-       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL);
+       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-pause", NULL);
 
        wfd_sink_debug_fleave();
 
@@ -326,16 +452,16 @@ int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        /* check current wi-fi display sink state */
        MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
 
-       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL);
+       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-resume", NULL);
 
        wfd_sink_debug_fleave();
 
@@ -349,11 +475,11 @@ int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        /* check current wi-fi display sink state */
        MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
@@ -361,7 +487,7 @@ int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
        WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
        WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
 
-       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL);
+       g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-close", NULL);
 
        wfd_sink_debug_fleave();
 
@@ -394,6 +520,16 @@ int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
        /* set state */
        __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NULL);
 
+       if (!wfd_sink->interrupted_by_resource) {
+               int rm_ret = MM_ERROR_NONE;
+               MMWFDSinkResourceType res_idx = MM_WFD_SINK_RESOURCE_TYPE_MAX;
+
+               for (res_idx = MM_WFD_SINK_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MM_WFD_SINK_RESOURCE_TYPE_MAX; res_idx++) {
+                       rm_ret = __mm_wfd_sink_release_hw_resource(wfd_sink, res_idx);
+                       if (rm_ret != MM_ERROR_NONE)
+                               wfd_sink_error("failed to release [%d] resources", res_idx);
+               }
+       }
        wfd_sink_debug_fleave();
 
        return result;
@@ -416,12 +552,21 @@ int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
        /* release attributes */
        _mmwfd_deconstruct_attribute(wfd_sink->attrs);
 
+       /* release the others */
+       g_free(wfd_sink->coupled_sink_address);
+
+       /* release resource manager */
+       if (MM_ERROR_NONE != mm_resource_manager_destroy(wfd_sink->resource_manager)) {
+               result = MM_ERROR_WFD_INTERNAL;
+               wfd_sink_error("failed to destroy resource manager");
+       }
+
+       /* release manager thread  */
        if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
+               result = MM_ERROR_WFD_INTERNAL;
                wfd_sink_error("failed to release manager");
-               return MM_ERROR_WFD_INTERNAL;
        }
 
-
        /* set state */
        __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NONE);
 
@@ -493,13 +638,13 @@ static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug("initializing gstreamer with following parameter");
        wfd_sink_debug("argc : %d", *argc);
 
-       for (i = 0; i < *argc; i++) {
+       for (i = 0; i < *argc; i++)
                wfd_sink_debug("argv[%d] : %s", i, argv[i]);
-       }
 
        /* initializing gstreamer */
        if (!gst_init_check(argc, &argv, &err)) {
-               wfd_sink_error("failed to initialize gstreamer: %s", err ? err->message : "unknown error occurred");
+               wfd_sink_error("failed to initialize gstreamer: %s",
+                                               err ? err->message : "unknown error occurred");
                if (err)
                        g_error_free(err);
 
@@ -507,9 +652,9 @@ static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
        }
 
        /* release */
-       for (i = 0; i < *argc; i++) {
+       for (i = 0; i < *argc; i++)
                MMWFDSINK_FREEIF(argv[i]);
-       }
+
        MMWFDSINK_FREEIF(argv);
        MMWFDSINK_FREEIF(argc);
 
@@ -524,281 +669,525 @@ _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
        GstBusSyncReply ret = GST_BUS_PASS;
 
        wfd_sink_return_val_if_fail(message &&
-                                               GST_IS_MESSAGE(message) &&
-                                               GST_MESSAGE_SRC(message),
-                                               GST_BUS_DROP);
+                                                               GST_IS_MESSAGE(message) &&
+                                                               GST_MESSAGE_SRC(message),
+                                                               GST_BUS_DROP);
+
+       wfd_sink_debug("get message %p, %s from %p, %s", message,
+                                       GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC(message), GST_MESSAGE_SRC_NAME(message));
 
        switch (GST_MESSAGE_TYPE(message)) {
-               case GST_MESSAGE_TAG:
-                       break;
-               case GST_MESSAGE_DURATION:
-                       break;
-               case GST_MESSAGE_STATE_CHANGED: {
-                               /* we only handle state change messages from pipeline */
-                               if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
-                                       ret = GST_BUS_DROP;
-                       }
-                       break;
-               case GST_MESSAGE_ASYNC_DONE: {
-                               if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
-                                       ret = GST_BUS_DROP;
-                       }
-                       break;
-               default:
-                       break;
+       case GST_MESSAGE_TAG:
+               break;
+       case GST_MESSAGE_DURATION:
+               break;
+       case GST_MESSAGE_STATE_CHANGED:
+               /* we only handle state change messages from pipeline */
+               if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
+                       _mm_wfd_sink_msg_callback(bus, message, data);
+
+               ret = GST_BUS_DROP;
+               break;
+       case GST_MESSAGE_ASYNC_DONE:
+               if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
+                       _mm_wfd_sink_msg_callback(bus, message, data);
+
+               ret = GST_BUS_DROP;
+               break;
+       default:
+               break;
+       }
+
+       if (ret == GST_BUS_DROP) {
+               gst_message_unref(message);
+               message = NULL;
        }
 
        return ret;
 }
 
+int __mm_wfd_sink_activate_audio_stream(mm_wfd_sink_t *wfd_sink)
+{
+       GstElement *valve = NULL;
+       GstPad *sinkpad = NULL;
+       GstPad *srcpad = NULL;
+       int result = MM_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
+       srcpad = gst_element_get_static_pad(valve, "src");
+       if (!srcpad) {
+               wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
+               goto error;
+       }
+
+       if (gst_pad_is_linked(srcpad)) {
+               wfd_sink_debug("%s:%s is already linked",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
+               goto done;
+       }
+
+       result = __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad);
+       if (MM_ERROR_NONE != result) {
+               wfd_sink_error("failed to prepare audio pipeline....");
+               goto error;
+       }
+
+       wfd_sink_debug("try to link %s:%s and %s:%s",
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+       if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+               wfd_sink_error("failed to link %s:%s and %s:%s",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+               goto error;
+       }
+
+       if (sinkpad != NULL) {
+               gst_object_unref(GST_OBJECT(sinkpad));
+               sinkpad = NULL;
+       }
+
+done:
+       if (srcpad != NULL) {
+               gst_object_unref(GST_OBJECT(srcpad));
+               srcpad = NULL;
+       }
+       /* drop all the audio buffers using valve */
+       g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
+
+       wfd_sink_debug_fleave();
+
+       return MM_ERROR_NONE;
+
+error:
+       if (srcpad != NULL) {
+               gst_object_unref(GST_OBJECT(srcpad));
+               srcpad = NULL;
+       }
+
+       if (sinkpad != NULL) {
+               gst_object_unref(GST_OBJECT(sinkpad));
+               sinkpad = NULL;
+       }
+
+       wfd_sink_debug_fleave();
+       return MM_ERROR_WFD_INTERNAL;
+}
+
+int __mm_wfd_sink_activate_video_stream(mm_wfd_sink_t *wfd_sink)
+{
+       GstElement *valve = NULL;
+       GstPad *sinkpad = NULL;
+       GstPad *srcpad = NULL;
+       int result = MM_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
+       srcpad = gst_element_get_static_pad(valve, "src");
+       if (!srcpad) {
+               wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
+               goto error;
+       }
+
+       if (gst_pad_is_linked(srcpad)) {
+               wfd_sink_debug("%s:%s is already linked",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
+               goto done;
+       }
+
+       result = __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad);
+       if (MM_ERROR_NONE != result) {
+               wfd_sink_error("failed to prepare video pipeline....");
+               goto error;
+       }
+
+       wfd_sink_debug("try to link %s:%s and %s:%s",
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+       if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+               wfd_sink_error("failed to link %s:%s and %s:%s",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+               goto error;
+       }
+       if (sinkpad != NULL) {
+               gst_object_unref(GST_OBJECT(sinkpad));
+               sinkpad = NULL;
+       }
+
+done:
+       if (srcpad != NULL) {
+               gst_object_unref(GST_OBJECT(srcpad));
+               srcpad = NULL;
+       }
+       /* drop all the video buffers using valve */
+       g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
+
+       wfd_sink_debug_fleave();
+
+       return MM_ERROR_NONE;
+
+error:
+       if (srcpad != NULL) {
+               gst_object_unref(GST_OBJECT(srcpad));
+               srcpad = NULL;
+       }
+
+       if (sinkpad != NULL) {
+               gst_object_unref(GST_OBJECT(sinkpad));
+               sinkpad = NULL;
+       }
+
+       wfd_sink_debug_fleave();
+       return MM_ERROR_WFD_INTERNAL;
+}
+
+int __mm_wfd_sink_deactivate_audio_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
+{
+       int ret = MM_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       /* drop all the audio buffers using valve */
+       g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst), "drop", TRUE, NULL);
+
+       if (unprepare) {
+               /* unprepare audio pipeline */
+               ret = __mm_wfd_sink_unprepare_audio_pipeline(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to unprepare audio pipeline...");
+                       return MM_ERROR_WFD_INTERNAL;
+               }
+       }
+
+       wfd_sink_debug_fleave();
+
+       return MM_ERROR_NONE;
+}
+
+int __mm_wfd_sink_deactivate_video_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
+{
+       int ret = MM_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       /* drop all the video buffers using valve */
+       g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst), "drop", TRUE, NULL);
+
+       if (unprepare) {
+               /* unprepare video pipeline */
+               ret = __mm_wfd_sink_unprepare_video_pipeline(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to unprepare video pipeline...");
+                       return MM_ERROR_WFD_INTERNAL;
+               }
+       }
+
+       wfd_sink_debug_fleave();
+
+       return MM_ERROR_NONE;
+
+}
+
 static gboolean
 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
 {
        mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
        const GstStructure *message_structure = gst_message_get_structure(msg);
        gboolean ret = TRUE;
+       gchar *getname = NULL;
 
        wfd_sink_return_val_if_fail(wfd_sink, FALSE);
        wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
 
-       wfd_sink_debug("got %s from %s",
+       wfd_sink_debug("got %s(%d) from %s",
                                        GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
+                                       GST_MESSAGE_TYPE(msg),
                                        GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
 
        switch (GST_MESSAGE_TYPE(msg)) {
-               case GST_MESSAGE_ERROR: {
-                               GError *error = NULL;
-                               gchar *debug = NULL;
-
-                               /* get error code */
-                               gst_message_parse_error(msg, &error, &debug);
+       case GST_MESSAGE_ERROR: {
+                       GError *error = NULL;
+                       gchar *debug = NULL;
 
-                               wfd_sink_error("error : %s", error->message);
-                               wfd_sink_error("debug : %s", debug);
-
-                               MMWFDSINK_FREEIF(debug);
-                               g_error_free(error);
-                       }
-                       break;
+                       /* get error code */
+                       gst_message_parse_error(msg, &error, &debug);
 
-               case GST_MESSAGE_WARNING: {
-                               char *debug = NULL;
-                               GError *error = NULL;
+                       wfd_sink_error("error : %s", error->message);
+                       wfd_sink_error("debug : %s", debug);
 
-                               gst_message_parse_warning(msg, &error, &debug);
+                       MMWFDSINK_FREEIF(debug);
+                       g_error_free(error);
+               }
+               break;
 
-                               wfd_sink_warning("warning : %s", error->message);
-                               wfd_sink_warning("debug : %s", debug);
+       case GST_MESSAGE_WARNING: {
+                       char *debug = NULL;
+                       GError *error = NULL;
 
-                               MMWFDSINK_FREEIF(debug);
-                               g_error_free(error);
-                       }
-                       break;
+                       gst_message_parse_warning(msg, &error, &debug);
 
-               case GST_MESSAGE_STATE_CHANGED: {
-                               const GValue *voldstate, *vnewstate, *vpending;
-                               GstState oldstate, newstate, pending;
-                               const GstStructure *structure;
-
-                               /* we only handle messages from pipeline */
-                               if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
-                                       break;
-
-                               /* get state info from msg */
-                               structure = gst_message_get_structure(msg);
-                               if (structure == NULL)
-                                       break;
-
-                               voldstate = gst_structure_get_value(structure, "old-state");
-                               vnewstate = gst_structure_get_value(structure, "new-state");
-                               vpending = gst_structure_get_value(structure, "pending-state");
-                               if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
-                                       break;
-
-                               oldstate = (GstState)voldstate->data[0].v_int;
-                               newstate = (GstState)vnewstate->data[0].v_int;
-                               pending = (GstState)vpending->data[0].v_int;
-
-                               wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
-                                                       GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
-                                                       gst_element_state_get_name((GstState)oldstate),
-                                                       gst_element_state_get_name((GstState)newstate),
-                                                       gst_element_state_get_name((GstState)pending));
-
-                               if (oldstate == newstate) {
-                                       wfd_sink_debug("pipeline reports state transition to old state");
-                                       break;
-                               }
+                       wfd_sink_error("warning : %s", error->message);
+                       wfd_sink_error("debug : %s", debug);
 
-                               switch (newstate) {
-                                       case GST_STATE_VOID_PENDING:
-                                       case GST_STATE_NULL:
-                                       case GST_STATE_READY:
-                                       case GST_STATE_PAUSED:
-                                       case GST_STATE_PLAYING:
-                                       default:
-                                               break;
-                               }
+                       MMWFDSINK_FREEIF(debug);
+                       g_error_free(error);
+               }
+               break;
+
+       case GST_MESSAGE_STATE_CHANGED: {
+                       const GValue *voldstate, *vnewstate, *vpending;
+                       GstState oldstate, newstate, pending;
+                       const GstStructure *structure;
+
+                       /* get state info from msg */
+                       structure = gst_message_get_structure(msg);
+                       if (structure == NULL)
+                               break;
+
+                       voldstate = gst_structure_get_value(structure, "old-state");
+                       vnewstate = gst_structure_get_value(structure, "new-state");
+                       vpending = gst_structure_get_value(structure, "pending-state");
+                       if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
+                               break;
+
+                       oldstate = (GstState)voldstate->data[0].v_int;
+                       newstate = (GstState)vnewstate->data[0].v_int;
+                       pending = (GstState)vpending->data[0].v_int;
+
+                       wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
+                                               GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
+                                               gst_element_state_get_name((GstState)oldstate),
+                                               gst_element_state_get_name((GstState)newstate),
+                                               gst_element_state_get_name((GstState)pending));
+
+                       /* we only handle messages from pipeline */
+                       if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
+                               break;
+
+                       if (oldstate == newstate) {
+                               wfd_sink_debug("pipeline reports state transition to old state");
+                               break;
                        }
-                       break;
 
-               case GST_MESSAGE_CLOCK_LOST: {
-                               GstClock *clock = NULL;
-                               gst_message_parse_clock_lost(msg, &clock);
-                               wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
+                       switch (newstate) {
+                       case GST_STATE_VOID_PENDING:
+                       case GST_STATE_NULL:
+                       case GST_STATE_READY:
+                       case GST_STATE_PAUSED:
+                       case GST_STATE_PLAYING:
+                       default:
+                               break;
                        }
-                       break;
+               }
+               break;
 
-               case GST_MESSAGE_NEW_CLOCK: {
-                               GstClock *clock = NULL;
-                               gst_message_parse_new_clock(msg, &clock);
-                               if (!clock)
-                                       break;
-
-                               if (wfd_sink->clock) {
-                                       if (wfd_sink->clock != clock)
-                                               wfd_sink_debug("clock is changed! [%s] -->[%s]",
-                                                               GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
-                                                               GST_STR_NULL(GST_OBJECT_NAME(clock)));
-                                       else
-                                               wfd_sink_debug("same clock is selected again! [%s]",
-                                                               GST_STR_NULL(GST_OBJECT_NAME(clock)));
-                               } else {
-                                       wfd_sink_debug("new clock [%s] was selected in the pipeline",
+       case GST_MESSAGE_CLOCK_LOST: {
+                       GstClock *clock = NULL;
+                       gst_message_parse_clock_lost(msg, &clock);
+                       wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
+                                       (clock ? GST_OBJECT_NAME(clock) : "NULL"));
+               }
+               break;
+
+       case GST_MESSAGE_NEW_CLOCK: {
+                       GstClock *clock = NULL;
+                       gst_message_parse_new_clock(msg, &clock);
+                       if (!clock)
+                               break;
+
+                       if (wfd_sink->clock) {
+                               if (wfd_sink->clock != clock)
+                                       wfd_sink_debug("clock is changed! [%s] -->[%s]",
+                                                                       GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
+                                                                       GST_STR_NULL(GST_OBJECT_NAME(clock)));
+                               else
+                                       wfd_sink_debug("same clock is selected again! [%s]",
+                                                                       GST_STR_NULL(GST_OBJECT_NAME(clock)));
+                       } else {
+                               wfd_sink_debug("new clock [%s] was selected in the pipeline",
                                                                (GST_STR_NULL(GST_OBJECT_NAME(clock))));
-                               }
-
-                               wfd_sink->clock = clock;
                        }
-                       break;
 
-               case GST_MESSAGE_APPLICATION: {
-                               const gchar *message_structure_name;
+                       wfd_sink->clock = clock;
+               }
+               break;
 
-                               message_structure_name = gst_structure_get_name(message_structure);
-                               if (!message_structure_name)
-                                       break;
+       case GST_MESSAGE_APPLICATION: {
+                       const gchar *message_structure_name;
 
-                               wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
-                       }
-                       break;
+                       message_structure_name = gst_structure_get_name(message_structure);
+                       if (!message_structure_name)
+                               break;
 
-               case GST_MESSAGE_ELEMENT: {
-                               const gchar *structure_name = NULL;
-
-                               structure_name = gst_structure_get_name(message_structure);
-                               if (structure_name) {
-                                       wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
-                                       if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
-                                               wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
-                                               MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                               MM_ERROR_WFD_INTERNAL,
-                                                                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                       } else if (g_strrstr(structure_name, "GstWFDSrcSessionTimeout")) {
-                                               wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
-                                               MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                               MM_ERROR_WFD_INTERNAL,
-                                                                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                       }
+                       wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
+               }
+               break;
+
+       case GST_MESSAGE_ELEMENT: {
+                       const gchar *structure_name = NULL;
+
+                       structure_name = gst_structure_get_name(message_structure);
+                       if (structure_name) {
+                               wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
+                               if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
+                                       wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
+                                                                       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                                       MM_ERROR_WFD_INTERNAL,
+                                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else if (g_strrstr(structure_name, "GstWFDSessionTimeout")) {
+                                       wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
+                                       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                                       MM_ERROR_WFD_INTERNAL,
+                                                                       MM_WFD_SINK_STATE_DISCONNECTED);
                                }
                        }
-                       break;
-
-               case GST_MESSAGE_PROGRESS: {
-                               GstProgressType type = GST_PROGRESS_TYPE_ERROR;
-                               gchar *category = NULL, *text = NULL;
-
-                               gst_message_parse_progress(msg, &type, &category, &text);
-                               wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
-
-                               switch (type) {
-                                       case GST_PROGRESS_TYPE_START:
-                                               break;
-                                       case GST_PROGRESS_TYPE_COMPLETE:
-                                               if (category && !strcmp(category, "open"))
-                                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_CONNECTED);
-                                               else if (category && !strcmp(category, "play")) {
-                                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PLAYING);
-                                                       /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
-                                               } else if (category && !strcmp(category, "pause"))
-                                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PAUSED);
-                                               else if (category && !strcmp(category, "close"))
-                                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
-                                               break;
-                                       case GST_PROGRESS_TYPE_CANCELED:
-                                               break;
-                                       case GST_PROGRESS_TYPE_ERROR:
-                                               if (category && !strcmp(category, "open")) {
-                                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
-                                                       /*_mm_wfd_sink_disconnect (wfd_sink); */
-                                                       MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                       MM_ERROR_WFD_INTERNAL,
-                                                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                               } else if (category && !strcmp(category, "play")) {
-                                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
-                                                       /*_mm_wfd_sink_disconnect (wfd_sink); */
+               }
+               break;
+
+       case GST_MESSAGE_PROGRESS: {
+                       GstProgressType type = GST_PROGRESS_TYPE_ERROR;
+                       gchar *category = NULL, *text = NULL;
+
+                       gst_message_parse_progress(msg, &type, &category, &text);
+                       wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
+
+                       switch (type) {
+                       case GST_PROGRESS_TYPE_START:
+                               break;
+                       case GST_PROGRESS_TYPE_COMPLETE:
+                               if (category && !strcmp(category, "open")) {
+                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_CONNECTED);
+                               } else if (category && !strcmp(category, "play")) {
+                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PLAYING);
+                                       /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
+                               } else if (category && !strcmp(category, "pause")) {
+                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PAUSED);
+                               } else if (category && !strcmp(category, "close")) {
+                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
+                               } else if (category && !strcmp(category, "coupling")) {
+                                       wfd_sink->coupled_sink_status = MM_WFD_COUPLED_SINK_STATUS_COUPLED;
+                                       wfd_sink->coupled_sink_address = g_strdup(text);
+                                       wfd_sink_debug("coupling info [%d : %s]", wfd_sink->coupled_sink_status, wfd_sink->coupled_sink_address);
+                                       __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
+                               }
+                               break;
+                       case GST_PROGRESS_TYPE_CANCELED:
+                               break;
+                       case GST_PROGRESS_TYPE_ERROR:
+                               if (category && !strcmp(category, "open")) {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
+                                       /*_mm_wfd_sink_disconnect (wfd_sink); */
+                                       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else if (category && !strcmp(category, "play")) {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
+                                       /*_mm_wfd_sink_disconnect (wfd_sink); */
+                                       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                               MM_ERROR_WFD_INTERNAL,
+                                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else if (category && !strcmp(category, "pause")) {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
+                                       /*_mm_wfd_sink_disconnect (wfd_sink); */
                                                        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                       MM_ERROR_WFD_INTERNAL,
-                                                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                               } else if (category && !strcmp(category, "pause")) {
-                                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else if (category && !strcmp(category, "close")) {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
                                                        /*_mm_wfd_sink_disconnect (wfd_sink); */
                                                        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                       MM_ERROR_WFD_INTERNAL,
-                                                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                               } else if (category && !strcmp(category, "close")) {
-                                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else if (category && !strcmp(category, "coupling")) {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
                                                        /*_mm_wfd_sink_disconnect (wfd_sink); */
                                                        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                                                                       MM_ERROR_WFD_INTERNAL,
-                                                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
-                                               } else {
-                                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
-                                               }
-                                               break;
-                                       default:
-                                               wfd_sink_error("progress message has no type");
-                                               return ret;
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+                               } else {
+                                       wfd_sink_error("got error : %s", GST_STR_NULL(text));
                                }
-
-                               MMWFDSINK_FREEIF(category);
-                               MMWFDSINK_FREEIF(text);
+                               break;
+                       default:
+                               wfd_sink_error("progress message has no type");
+                               return ret;
                        }
-                       break;
-               case GST_MESSAGE_ASYNC_START:
-                       wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
-                       break;
-               case GST_MESSAGE_ASYNC_DONE:
-                       wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
-                       break;
-               case GST_MESSAGE_UNKNOWN:
-               case GST_MESSAGE_INFO:
-               case GST_MESSAGE_TAG:
-               case GST_MESSAGE_BUFFERING:
-               case GST_MESSAGE_EOS:
-               case GST_MESSAGE_STATE_DIRTY:
-               case GST_MESSAGE_STEP_DONE:
-               case GST_MESSAGE_CLOCK_PROVIDE:
-               case GST_MESSAGE_STRUCTURE_CHANGE:
-               case GST_MESSAGE_STREAM_STATUS:
-               case GST_MESSAGE_SEGMENT_START:
-               case GST_MESSAGE_SEGMENT_DONE:
-               case GST_MESSAGE_DURATION:
-               case GST_MESSAGE_LATENCY:
-               case GST_MESSAGE_REQUEST_STATE:
-               case GST_MESSAGE_STEP_START:
-               case GST_MESSAGE_QOS:
-               case GST_MESSAGE_ANY:
-                       break;
-               default:
-                       wfd_sink_debug("unhandled message");
-                       break;
+
+                       MMWFDSINK_FREEIF(category);
+                       MMWFDSINK_FREEIF(text);
+               }
+               break;
+
+       case GST_MESSAGE_ASYNC_START:
+               getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
+               wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", getname);
+               MMWFDSINK_FREEIF(getname);
+               break;
+       case GST_MESSAGE_ASYNC_DONE:
+               getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
+               wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", getname);
+               MMWFDSINK_FREEIF(getname);
+               break;
+       case GST_MESSAGE_UNKNOWN:
+       case GST_MESSAGE_INFO:
+       case GST_MESSAGE_TAG:
+       case GST_MESSAGE_BUFFERING:
+       case GST_MESSAGE_EOS:
+       case GST_MESSAGE_STATE_DIRTY:
+       case GST_MESSAGE_STEP_DONE:
+       case GST_MESSAGE_CLOCK_PROVIDE:
+       case GST_MESSAGE_STRUCTURE_CHANGE:
+       case GST_MESSAGE_STREAM_STATUS:
+       case GST_MESSAGE_SEGMENT_START:
+       case GST_MESSAGE_SEGMENT_DONE:
+       case GST_MESSAGE_DURATION:
+       case GST_MESSAGE_LATENCY:
+       case GST_MESSAGE_REQUEST_STATE:
+       case GST_MESSAGE_STEP_START:
+       case GST_MESSAGE_QOS:
+       case GST_MESSAGE_ANY:
+               break;
+       default:
+               wfd_sink_debug("unhandled message");
+               break;
        }
 
        return ret;
 }
 
-static int
+int
 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
 {
        GList *bucket = element_bucket;
@@ -819,14 +1208,14 @@ __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket,
 
                        if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
                                wfd_sink_error("failed to add element [%s] to bin [%s]",
-                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
-                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
                                return 0;
                        }
 
                        wfd_sink_debug("add element [%s] to bin [%s]",
-                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
-                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
+                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
+                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
 
                        successful_add_count++;
                }
@@ -837,7 +1226,7 @@ __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket,
        return successful_add_count;
 }
 
-static int
+int
 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
 {
        GList *bucket = element_bucket;
@@ -858,13 +1247,13 @@ __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
                if (element && element->gst) {
                        if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
                                wfd_sink_debug("linking [%s] to [%s] success",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
                                successful_link_count++;
                        } else {
                                wfd_sink_error("linking [%s] to [%s] failed",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
+                                                               GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
                                return -1;
                        }
                }
@@ -877,7 +1266,7 @@ __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
        return successful_link_count;
 }
 
-static int
+int
 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
 {
        MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
@@ -891,98 +1280,89 @@ __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
        cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
 
        switch (cmd) {
-               case MM_WFD_SINK_COMMAND_CREATE: {
-                               if (cur_state != MM_WFD_SINK_STATE_NONE)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_PREPARE: {
-                               if (cur_state == MM_WFD_SINK_STATE_PREPARED)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_NULL)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_CONNECT: {
-                               if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_START: {
-                               if (cur_state == MM_WFD_SINK_STATE_PLAYING)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_PAUSE: {
-                               if (cur_state == MM_WFD_SINK_STATE_PAUSED)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_RESUME: {
-                               if (cur_state == MM_WFD_SINK_STATE_PLAYING)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_DISCONNECT: {
-                               if (cur_state == MM_WFD_SINK_STATE_NONE ||
-                                   cur_state == MM_WFD_SINK_STATE_NULL ||
-                                   cur_state == MM_WFD_SINK_STATE_PREPARED ||
-                                   cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
-                                       goto no_operation;
-                               else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
-                                       cur_state != MM_WFD_SINK_STATE_CONNECTED &&
-                                       cur_state != MM_WFD_SINK_STATE_PAUSED)
-                                       goto invalid_state;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
-                       }
-                       break;
-
-               case MM_WFD_SINK_COMMAND_UNPREPARE: {
-                               if (cur_state == MM_WFD_SINK_STATE_NONE ||
-                                   cur_state == MM_WFD_SINK_STATE_NULL)
-                                       goto no_operation;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
-                       }
-                       break;
+       case MM_WFD_SINK_COMMAND_CREATE:
+               if (cur_state != MM_WFD_SINK_STATE_NONE)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
+               break;
+
+       case MM_WFD_SINK_COMMAND_PREPARE:
+               if (cur_state == MM_WFD_SINK_STATE_PREPARED)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_NULL)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
+               break;
+
+       case MM_WFD_SINK_COMMAND_CONNECT:
+               if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
+               break;
+
+       case MM_WFD_SINK_COMMAND_START:
+               if (cur_state == MM_WFD_SINK_STATE_PLAYING)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
+               break;
+
+       case MM_WFD_SINK_COMMAND_PAUSE:
+               if (cur_state == MM_WFD_SINK_STATE_PAUSED)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
+               break;
+
+       case MM_WFD_SINK_COMMAND_RESUME:
+               if (cur_state == MM_WFD_SINK_STATE_PLAYING)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
+               break;
+
+       case MM_WFD_SINK_COMMAND_DISCONNECT:
+               if (cur_state == MM_WFD_SINK_STATE_NONE ||
+                   cur_state == MM_WFD_SINK_STATE_NULL ||
+                   cur_state == MM_WFD_SINK_STATE_PREPARED ||
+                   cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
+                       goto no_operation;
+               else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
+                       cur_state != MM_WFD_SINK_STATE_CONNECTED &&
+                       cur_state != MM_WFD_SINK_STATE_PAUSED)
+                       goto invalid_state;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
+               break;
+
+       case MM_WFD_SINK_COMMAND_UNPREPARE:
+               if (cur_state == MM_WFD_SINK_STATE_NONE ||
+                   cur_state == MM_WFD_SINK_STATE_NULL)
+                       goto no_operation;
+
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
+               break;
+
+       case MM_WFD_SINK_COMMAND_DESTROY:
+               if (cur_state == MM_WFD_SINK_STATE_NONE)
+                       goto no_operation;
 
-               case MM_WFD_SINK_COMMAND_DESTROY: {
-                               if (cur_state == MM_WFD_SINK_STATE_NONE)
-                                       goto no_operation;
-
-                               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
-                       }
-                       break;
+               MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
+               break;
 
-               default:
-                       break;
+       default:
+               break;
        }
 
        wfd_sink->cmd = cmd;
@@ -997,11 +1377,11 @@ no_operation:
 
        /* ERRORS */
 invalid_state:
-       wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
+       wfd_sink_error("current state[%s] is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
        return MM_ERROR_WFD_INVALID_STATE;
 }
 
-static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
+int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
 {
        wfd_sink_debug_fenter();
 
@@ -1020,10 +1400,10 @@ static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType s
        if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
                MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
 
-       /* poset state message to application */
+       /* post state message to application */
        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                               MM_ERROR_NONE,
-                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
+                                                       MM_ERROR_NONE,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
 
        /* print state */
        MMWFDSINK_PRINT_STATE(wfd_sink);
@@ -1033,7 +1413,7 @@ static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType s
        return MM_ERROR_NONE;
 }
 
-static int
+int
 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
 {
        GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
@@ -1043,12 +1423,13 @@ __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboole
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
-       wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING, MM_ERROR_WFD_INVALID_ARGUMENT);
+       wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING,
+                                                               MM_ERROR_WFD_INVALID_ARGUMENT);
 
        wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
 
@@ -1061,7 +1442,8 @@ __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboole
        if (!async) {
                wfd_sink_debug("wait for changing state is completed ");
 
-               result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
+               result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
+                                                                               &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
                if (result == GST_STATE_CHANGE_FAILURE) {
                        wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
 
@@ -1073,8 +1455,8 @@ __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboole
                }
 
                wfd_sink_debug("cur state is %s, pending state is %s",
-                                       gst_element_state_get_name(cur_state),
-                                       gst_element_state_get_name(pending_state));
+                                               gst_element_state_get_name(cur_state),
+                                               gst_element_state_get_name(pending_state));
        }
 
 
@@ -1092,9 +1474,9 @@ _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_if_fail(wfd_sink &&
-                                       wfd_sink->pipeline &&
-                                       wfd_sink->pipeline->mainbin &&
-                                       wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
+                                                       wfd_sink->pipeline &&
+                                                       wfd_sink->pipeline->mainbin &&
+                                                       wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
        wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
 
 
@@ -1147,17 +1529,225 @@ _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
 }
 
 int
-__mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
+__mm_wfd_sink_unprepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
 {
-       GstElement *bin = NULL;
+       GstElement *pipeline  = NULL;
+       GstElement *v_decodebin  = NULL;
+       GstElement *v_sinkbin  = NULL;
+       GstPad *sinkpad = NULL;
+       GstPad *srcpad = NULL;
+       int ret = MM_ERROR_NONE;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE) {
+               wfd_sink_debug("Skip unprepare video pipeline for none audio codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
+
+       PRINT_WFD_REF_COUNT(wfd_sink);
+       wfd_sink_error("No-error:unprepare video sink bin");
+       if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
+               v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
+
+               if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin)))) {
+                       sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
+                       if (!sinkpad) {
+                               wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_sinkbin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(sinkpad)) {
+                               srcpad = gst_pad_get_peer(sinkpad);
+                               if (!srcpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(srcpad);
+                               srcpad = NULL;
+                       } else {
+                               wfd_sink_debug("video sinkbin's sinkpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(sinkpad);
+                       sinkpad = NULL;
+
+                       wfd_sink_error("try to remove %s from %s",
+                                       GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
+
+                       gst_object_ref(v_sinkbin);
+                       if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
+                               wfd_sink_error("failed to remove %s from %s",
+                                                               GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
+               }
+
+               ret = __mm_wfd_sink_destroy_video_sinkbin(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to destroy video sinkbin");
+                       goto ERROR;
+               }
+       }
+       PRINT_WFD_REF_COUNT(wfd_sink);
+
+       wfd_sink_error("No-error:unprepare video decode bin");
+       if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
+               v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
+
+               if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin)))) {
+                       sinkpad = gst_element_get_static_pad(v_decodebin, "sink");
+                       if (!sinkpad) {
+                               wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(sinkpad)) {
+                               srcpad = gst_pad_get_peer(sinkpad);
+                               if (!srcpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(srcpad);
+                               srcpad = NULL;
+                       } else {
+                               wfd_sink_debug("video decodebin's sinkpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(sinkpad);
+                       sinkpad = NULL;
+
+                       srcpad = gst_element_get_static_pad(v_decodebin, "src");
+                       if (!srcpad) {
+                               wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(v_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(srcpad)) {
+                               sinkpad = gst_pad_get_peer(srcpad);
+                               if (!sinkpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(sinkpad);
+                               sinkpad = NULL;
+                       } else {
+                               wfd_sink_debug("video decodebin's srcpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(srcpad);
+                       srcpad = NULL;
+
+                       wfd_sink_error("try to remove %s from %s",
+                                                       GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_ref(v_decodebin);
+                       if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
+                               wfd_sink_error("failed to remove %s from %s",
+                                                               GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
+               }
+
+               ret = __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to destroy video decodebin");
+                       goto ERROR;
+               }
+       }
+       PRINT_WFD_REF_COUNT(wfd_sink);
+
+       wfd_sink_debug_fleave();
+
+       return ret;
+
+       /* ERRORS */
+ERROR:
+       if (pipeline) {
+               gst_object_unref(pipeline);
+               pipeline = NULL;
+       }
+
+       if (sinkpad) {
+               gst_object_unref(sinkpad);
+               sinkpad = NULL;
+       }
+
+       if (srcpad) {
+               gst_object_unref(srcpad);
+               srcpad = NULL;
+       }
+
+       /* need to notify to app */
+       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+
+       return MM_ERROR_WFD_INTERNAL;
+}
+
+int
+__mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
+{
+       GstElement *pipeline  = NULL;
+       GstElement *v_decodebin  = NULL;
+       GstElement *v_sinkbin  = NULL;
+       GstPad *srcpad = NULL;
+       GstPad *sinkpad = NULL;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE) {
+               wfd_sink_debug("Skip prepare video pipeline for none audio codec");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
 
        /* check video decodebin is linked */
        if (!wfd_sink->video_decodebin_is_linked) {
@@ -1182,56 +1772,375 @@ __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
                        goto ERROR;
                }
        }
-
-       /* set video decodebin state as READY */
+       /* add video decodebin to pipeline */
        if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
-               bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
-               if (GST_STATE(bin) <= GST_STATE_NULL) {
-                       if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
-                               wfd_sink_error("failed to set state(READY) to video decodebin");
+               v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
+
+               pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin));
+               if (!pipeline) {
+                       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
+
+                       if (GST_STATE(v_decodebin) <= GST_STATE_NULL) {
+                               wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_decodebin));
+                               if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_decodebin, GST_STATE_READY)) {
+                                       wfd_sink_error("failed to set state(READY) to video decodebin");
+                                       goto ERROR;
+                               }
+                       }
+
+                       wfd_sink_debug("try to add %s to %s",
+                                                       GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
+                       if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
+                               wfd_sink_error("failed to add %s to %s",
+                                                               GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_decodebin));
+                       if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_decodebin))) {
+                               wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_decodebin));
                                goto ERROR;
                        }
+               } else {
+                       wfd_sink_debug("%s is already added to %s",
+                                                       GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
                }
        } else {
                wfd_sink_warning("going on without video decodebin....");
        }
 
-       /* set video sinkbin state as READY */
+       /* add video sinkbin to pipeline */
        if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
-               bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
-               if (GST_STATE(bin) <= GST_STATE_NULL) {
-                       if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
-                               wfd_sink_error("failed to set state(READY) to video sinkbin");
+               v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
+
+               pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin));
+               if (!pipeline) {
+                       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
+
+                       /* prepare video sinkbin before adding */
+                       if (GST_STATE(v_sinkbin) <= GST_STATE_NULL) {
+                               wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_sinkbin));
+                               if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_sinkbin, GST_STATE_READY)) {
+                                       wfd_sink_error("failed to set state(READY) to video sinkbin");
+                                       goto ERROR;
+                               }
+                       }
+                       /* add video sinkbin to pipeline */
+                       wfd_sink_debug("try to  add %s to %s",
+                                                       GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
+                       if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
+                               wfd_sink_error("failed to add %s to %s",
+                                                               GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       /* sync state with parent */
+                       wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_sinkbin));
+                       if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_sinkbin))) {
+                               wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_sinkbin));
                                goto ERROR;
                        }
+               } else {
+                       wfd_sink_debug("%s is already added to %s",
+                                                       GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
                }
        } else {
                wfd_sink_warning("going on without video sinkbin....");
        }
 
+
+       /* link video decodebin and sinkbin */
+       if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
+               v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
+
+               if (pad)
+                       *pad = gst_element_get_static_pad(v_decodebin, "sink");
+
+               if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
+
+                       v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
+
+                       srcpad = gst_element_get_static_pad(v_decodebin, "src");
+                       if (!srcpad) {
+                               wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(v_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (!gst_pad_is_linked(srcpad)) {
+                               sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
+                               if (!sinkpad) {
+                                       wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(v_sinkbin));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_debug("try to link %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+                                       wfd_sink_error("failed to link %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(sinkpad);
+                               sinkpad = NULL;
+                       }
+                       gst_object_unref(srcpad);
+                       srcpad = NULL;
+               }
+       } else if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
+               v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
+               if (pad)
+                       *pad = gst_element_get_static_pad(v_sinkbin, "sink");
+       }
+
        wfd_sink_debug_fleave();
 
        return MM_ERROR_NONE;
 
        /* ERRORS */
 ERROR:
+       if (sinkpad != NULL) {
+               gst_object_unref(sinkpad);
+               sinkpad = NULL;
+       }
+
+       if (srcpad != NULL) {
+               gst_object_unref(srcpad);
+               srcpad = NULL;
+       }
+
+       /* need to notify to app */
+       MMWFDSINK_POST_MESSAGE(wfd_sink,
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
+
+       return MM_ERROR_WFD_INTERNAL;
+}
+
+int
+__mm_wfd_sink_unprepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
+{
+       GstElement *pipeline  = NULL;
+       GstElement *a_decodebin  = NULL;
+       GstElement *a_sinkbin  = NULL;
+       GstPad *sinkpad = NULL;
+       GstPad *srcpad = NULL;
+       int ret = MM_ERROR_NONE;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_val_if_fail(wfd_sink &&
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
+               wfd_sink_debug("Skip unprepare audio pipeline for none audio codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
+
+       wfd_sink_error("No-error:unprepare audio sink bin");
+       PRINT_WFD_REF_COUNT(wfd_sink);
+
+       if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
+               a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
+
+               if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin)))) {
+                       sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
+                       if (!sinkpad) {
+                               wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_sinkbin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(sinkpad)) {
+                               srcpad = gst_pad_get_peer(sinkpad);
+                               if (!srcpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(srcpad);
+                               srcpad = NULL;
+                       } else {
+                               wfd_sink_debug("audio sinkbin's sinkpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(sinkpad);
+                       sinkpad = NULL;
+
+                       wfd_sink_error("try to remove %s from %s", GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
+
+                       gst_object_ref(a_sinkbin);
+                       if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
+                               wfd_sink_error("failed to remove %s from %s",
+                                                               GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
+               }
+
+               ret = __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to destroy audio sinkbin");
+                       goto ERROR;
+               }
+       }
+       PRINT_WFD_REF_COUNT(wfd_sink);
+
+       wfd_sink_error("No-error:unprepare audio decode bin");
+       if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
+               a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
+
+               if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin)))) {
+                       sinkpad = gst_element_get_static_pad(a_decodebin, "sink");
+                       if (!sinkpad) {
+                               wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(sinkpad)) {
+                               srcpad = gst_pad_get_peer(sinkpad);
+                               if (!srcpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       goto ERROR;
+                               }
+                               gst_object_unref(srcpad);
+                               srcpad = NULL;
+                       } else {
+                               wfd_sink_debug("audio decodebin's sinkpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(sinkpad);
+                       sinkpad = NULL;
+
+                       srcpad = gst_element_get_static_pad(a_decodebin, "src");
+                       if (!srcpad) {
+                               wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(a_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (gst_pad_is_linked(srcpad)) {
+                               sinkpad = gst_pad_get_peer(srcpad);
+                               if (!sinkpad) {
+                                       wfd_sink_error("failed to get peer pad of %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
+                                       return MM_ERROR_WFD_INTERNAL;
+                               }
+
+                               wfd_sink_error("try to unlink %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (!gst_pad_unlink(srcpad, sinkpad)) {
+                                       wfd_sink_error("failed to unlink %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                                       return MM_ERROR_WFD_INTERNAL;
+                               }
+                               gst_object_unref(sinkpad);
+                               sinkpad = NULL;
+                       } else {
+                               wfd_sink_debug("audio decodebin's srcpad is not linked, no need to unlink it");
+                       }
+                       gst_object_unref(srcpad);
+                       srcpad = NULL;
+
+                       wfd_sink_error("try to remove %s from %s",
+                                                       GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_ref(a_decodebin);
+                       if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
+                               wfd_sink_error("failed to remove %s from %s",
+                                                               GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
+               }
+
+               ret = __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("failed to destroy audio decodebin");
+                       goto ERROR;
+               }
+       }
+       PRINT_WFD_REF_COUNT(wfd_sink);
+
+       wfd_sink_debug_fleave();
+
+       return ret;
+
+       /* ERRORS */
+ERROR:
+       if (pipeline) {
+               gst_object_unref(pipeline);
+               pipeline = NULL;
+       }
+       if (sinkpad) {
+               gst_object_unref(sinkpad);
+               sinkpad = NULL;
+       }
+
+       if (srcpad) {
+               gst_object_unref(srcpad);
+               srcpad = NULL;
+       }
+
        /* need to notify to app */
        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                               MM_ERROR_WFD_INTERNAL,
-                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
 
        return MM_ERROR_WFD_INTERNAL;
 }
 
-int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
+int
+__mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
 {
-       GstElement *bin  = NULL;
+       GstElement *pipeline  = NULL;
+       GstElement *a_decodebin  = NULL;
+       GstElement *a_sinkbin  = NULL;
+       GstPad *srcpad = NULL;
+       GstPad *sinkpad = NULL;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
+               wfd_sink_debug("Skip prepare audio pipeline for none audio codec");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
 
        /* check audio decodebin is linked */
        if (!wfd_sink->audio_decodebin_is_linked) {
@@ -1257,42 +2166,159 @@ int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
                }
        }
 
-       /* set audio decodebin state as READY */
+       /* add audio decodebin to pipeline */
        if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
-               bin  = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
-               if (GST_STATE(bin) <= GST_STATE_NULL) {
-                       if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
-                               wfd_sink_error("failed to set state(READY) to audio decodebin");
+               a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
+
+               pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin));
+               if (!pipeline) {
+                       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
+
+                       if (GST_STATE(a_decodebin) <= GST_STATE_NULL) {
+                               wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_decodebin));
+                               if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_decodebin, GST_STATE_READY)) {
+                                       wfd_sink_error("failed to set state(READY) to audio decodebin");
+                                       goto ERROR;
+                               }
+                       }
+
+                       wfd_sink_debug("try to add %s to %s",
+                                                       GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
+                       if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
+                               wfd_sink_error("failed to add %s to %s",
+                                                               GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
                                goto ERROR;
                        }
+
+                       wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_decodebin));
+                       if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_decodebin))) {
+                               wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_decodebin));
+                               goto ERROR;
+                       }
+               } else {
+                       wfd_sink_debug("%s is already added to %s",
+                                                       GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
                }
        } else {
                wfd_sink_warning("going on without audio decodebin....");
        }
 
-       /* set audio sinkbin state as READY */
+       /* add audio sinkbin to pipeline */
        if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
-               bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
-               if (GST_STATE(bin) <= GST_STATE_NULL) {
-                       if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) {
-                               wfd_sink_error("failed to set state(READY) to audio sinkbin");
+               a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
+
+               pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin));
+               if (!pipeline) {
+                       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
+
+                       /* prepare audio sinkbin before adding */
+                       if (GST_STATE(a_sinkbin) <= GST_STATE_NULL) {
+                               wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_sinkbin));
+                               if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_sinkbin, GST_STATE_READY)) {
+                                       wfd_sink_error("failed to set state(READY) to audio sinkbin");
+                                       goto ERROR;
+                               }
+                       }
+
+                       /* add audio sinkbin to pipeline */
+                       wfd_sink_debug("try to  add %s to %s",
+                                                       GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
+                       if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
+                               wfd_sink_error("failed to add %s to %s",
+                                                               GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
+                               goto ERROR;
+                       }
+
+                       /* sync state with parent */
+                       wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_sinkbin));
+                       if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_sinkbin))) {
+                               wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_sinkbin));
                                goto ERROR;
                        }
+               } else {
+                       wfd_sink_debug("%s is already added to %s",
+                                                       GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
+                       gst_object_unref(pipeline);
+                       pipeline = NULL;
                }
        } else {
                wfd_sink_warning("going on without audio sinkbin....");
        }
 
+
+       /* link audio decodebin and sinkbin */
+       if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
+               a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
+
+               if (pad)
+                       *pad = gst_element_get_static_pad(a_decodebin, "sink");
+
+               if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
+
+                       a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
+
+                       srcpad = gst_element_get_static_pad(a_decodebin, "src");
+                       if (!srcpad) {
+                               wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(a_decodebin));
+                               goto ERROR;
+                       }
+
+                       if (!gst_pad_is_linked(srcpad)) {
+                               sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
+                               if (!sinkpad) {
+                                       wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(a_sinkbin));
+                                       goto ERROR;
+                               }
+
+                               wfd_sink_debug("try to link %s:%s and %s:%s",
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+                               if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+                                       wfd_sink_error("failed to link %s:%s and %s:%s",
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+
+                                       goto ERROR;
+                               }
+                               gst_object_unref(sinkpad);
+                               sinkpad = NULL;
+                       }
+                       gst_object_unref(srcpad);
+                       srcpad = NULL;
+               }
+       } else if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
+               a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
+               if (pad)
+                       *pad = gst_element_get_static_pad(a_sinkbin, "sink");
+       }
+
        wfd_sink_debug_fleave();
 
        return MM_ERROR_NONE;
 
        /* ERRORS */
 ERROR:
+       if (pipeline) {
+               gst_object_unref(pipeline);
+               pipeline = NULL;
+       }
+
+       if (sinkpad) {
+               gst_object_unref(sinkpad);
+               sinkpad = NULL;
+       }
+
+       if (srcpad) {
+               gst_object_unref(srcpad);
+               srcpad = NULL;
+       }
+
        /* need to notify to app */
        MMWFDSINK_POST_MESSAGE(wfd_sink,
-                                               MM_ERROR_WFD_INTERNAL,
-                                               MMWFDSINK_CURRENT_STATE(wfd_sink));
+                                                       MM_ERROR_WFD_INTERNAL,
+                                                       MMWFDSINK_CURRENT_STATE(wfd_sink));
 
        return MM_ERROR_WFD_INTERNAL;
 }
@@ -1315,10 +2341,10 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
 
        wfd_sink_return_val_if_fail(info, FALSE);
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
-                                               GST_PAD_PROBE_DROP);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->mainbin &&
+                                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
+                                                               GST_PAD_PROBE_DROP);
 
        if (!wfd_sink->clock) {
                wfd_sink_warning("pipeline did not select clock, yet");
@@ -1341,8 +2367,8 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                running_time = current_time - (start_time + base_time);
        } else {
                wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
-                                       "  base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
-                                       GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
+                                               "  base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
+                                               GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
                return GST_PAD_PROBE_OK;
        }
 
@@ -1370,11 +2396,11 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                if (diff < 0) {
                        /* this buffer could be NOT rendered */
                        wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
-                                               GST_STR_NULL((GST_OBJECT_NAME(pad))),
-                                               GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
+                                                       GST_STR_NULL((GST_OBJECT_NAME(pad))),
+                                                       GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
                } else {
                        /* this buffer could be rendered */
-                       /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */
+                       /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "", */
                        /*      GST_STR_NULL((GST_OBJECT_NAME(pad))), */
                        /*      GST_TIME_ARGS(diff)); */
                }
@@ -1422,14 +2448,14 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                                                video_minus_compensation = FALSE;
                                        }
                                } else {
-                                       wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
+                                       wfd_sink_debug("first update video average gap(%"G_GINT64_FORMAT"d) ", video_avgrage_gap);
                                        wfd_sink->video_average_gap = video_avgrage_gap;
                                }
                        } else {
                                wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
-                                                       " ~ %" GST_TIME_FORMAT"",
-                                                       GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
-                                                       GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
+                                                               " ~ %" GST_TIME_FORMAT"",
+                                                               GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
+                                                               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
                        }
 
                        /* check audio */
@@ -1445,14 +2471,14 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                                                audio_minus_compensation = FALSE;
                                        }
                                } else {
-                                       wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
+                                       wfd_sink_debug("first update audio average gap(%"G_GINT64_FORMAT"d) ", audio_avgrage_gap);
                                        wfd_sink->audio_average_gap = audio_avgrage_gap;
                                }
                        } else {
                                wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
-                                                       " ~ %" GST_TIME_FORMAT"",
-                                                       GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
-                                                       GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
+                                                               " ~ %" GST_TIME_FORMAT"",
+                                                               GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
+                                                               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
                        }
 
                        /* selecet average_gap_diff between video and audio */
@@ -1485,9 +2511,9 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                                avgrage_gap_diff = audio_avgrage_gap_diff;
                        }
 
-                       wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
-                                               audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
-                                               video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
+                       wfd_sink_debug("average diff gap difference beween audio:%s%"G_GINT64_FORMAT"d and video:%s%"G_GINT64_FORMAT"d ",
+                                                       audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
+                                                       video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
 
 
                        /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
@@ -1497,18 +2523,18 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                                else
                                        ts_offset += avgrage_gap_diff;
 
-                               wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
-                                               GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
-                                               minus_compensation ? "-" : "", avgrage_gap_diff,
-                                               GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
+                               wfd_sink_debug("do timestamp compensation : %s%"G_GINT64_FORMAT"d (ts-offset : %"
+                                                               GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
+                                                               minus_compensation ? "-" : "", avgrage_gap_diff,
+                                                               GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
 
                                if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
                                        g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
                                if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
                                        g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
                        } else {
-                               wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
-                                               minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
+                               wfd_sink_debug("don't need to do timestamp compensation : %s%"G_GINT64_FORMAT"d (ts-offset : %"GST_TIME_FORMAT ")",
+                                                               minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
                        }
 
                        /* reset values*/
@@ -1520,7 +2546,7 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
                }
        } else {
                wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
-                                       GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
+                                               GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
                wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
        }
 
@@ -1529,92 +2555,84 @@ _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_d
 
 
 static void
-__mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data)
+__mm_wfd_sink_demux_pad_added(GstElement *demux, GstPad *pad, gpointer data)
 {
        mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
-       gchar *name = gst_pad_get_name(pad);
+       gchar *name = NULL;
        GstElement *pipeline = NULL;
-       GstElement *decodebin = NULL;
-       GstElement *sinkbin = NULL;
+       GstElement *valve = NULL;
        GstPad *sinkpad = NULL;
        GstPad *srcpad = NULL;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_if_fail(wfd_sink &&
-                                       wfd_sink->pipeline &&
-                                       wfd_sink->pipeline->mainbin &&
-                                       wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
-
-       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
-
-       /* take decodebin/sinkbin */
-       if (name[0] == 'v') {
-               wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
+                                                       wfd_sink->pipeline &&
+                                                       wfd_sink->pipeline->mainbin &&
+                                                       wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
 
-               MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
-
-               gst_pad_add_probe(pad,
-                                       GST_PAD_PROBE_TYPE_BUFFER,
-                                       _mm_wfd_sink_check_running_time,
-                                       (gpointer)wfd_sink,
-                                       NULL);
+       name = gst_pad_get_name(pad);
+       if (name == NULL) {
+               wfd_sink_error("fail to get pad");
+               goto ERROR;
+       }
 
-               if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) {
-                       wfd_sink_error("failed to prepare video pipeline....");
-                       goto ERROR;
-               }
+       wfd_sink_debug("Mux pad added, video_codec=%d, audio_codec=%d, name[0] = %c",
+                               wfd_sink->stream_info.video_stream_info.codec,
+                               wfd_sink->stream_info.audio_stream_info.codec,
+                               name[0]);
 
-               if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst)
-                       decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
-               if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst)
-                       sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
-       } else if (name[0] == 'a') {
-               wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
+       //In case of none vieo codec, we don't add video pad
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE && name[0] == 'v') {
+               wfd_sink_error("Skip video pad add for none video codec");
+               // Do nothing
+               goto done;
+       }
 
-               MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
+       //In case of none audio codec, we don't add audio pad
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE && name[0] == 'a') {
+               wfd_sink_error("Skip audio pad add for none audio codec");
+               // Do nothing
+               goto done;
+       }
 
-               gst_pad_add_probe(pad,
-                                       GST_PAD_PROBE_TYPE_BUFFER,
-                                       _mm_wfd_sink_check_running_time,
-                                       (gpointer)wfd_sink,
-                                       NULL);
+       pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
 
-               if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) {
-                       wfd_sink_error("failed to prepare audio pipeline....");
-                       goto ERROR;
-               }
+       /* take srcpad from demuxer added pad */
+       srcpad = gst_object_ref(pad);
 
-               if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst)
-                       decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
-               if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst)
-                       sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
-       } else {
-               wfd_sink_error("unexceptable pad is added!!!");
-               return;
+       if (name[0] == 'v') {
+               if (wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst)
+                       valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
+       } else if (name[0] == 'a') {
+               if (wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst)
+                       valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
        }
 
-       srcpad = gst_object_ref(pad);
+       /* add, link and run the valve */
+       if (valve) {
+               wfd_sink_debug("try to add %s to pipeline", GST_ELEMENT_NAME(valve));
 
-       /* add decodebin and link */
-       if (decodebin) {
-               if (!gst_bin_add(GST_BIN(pipeline), decodebin)) {
+               if (!gst_bin_add(GST_BIN(pipeline), valve)) {
                        wfd_sink_error("failed to add %s to pipeline",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
+                                                       GST_ELEMENT_NAME(valve));
                        goto ERROR;
                }
 
-               sinkpad = gst_element_get_static_pad(decodebin, "sink");
+               sinkpad = gst_element_get_static_pad(valve, "sink");
                if (!sinkpad) {
-                       wfd_sink_error("failed to get sink pad from %s",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
+                               wfd_sink_error("failed to get sink pad from %s",
+                                                               GST_ELEMENT_NAME(valve));
                        goto ERROR;
                }
 
-               if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
-                       wfd_sink_error("failed to link %s and %s",
-                                       GST_STR_NULL(GST_PAD_NAME(srcpad)),
-                                       GST_STR_NULL(GST_PAD_NAME(sinkpad)));
+               wfd_sink_debug("try to link %s:%s and %s:%s",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+               if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+                       wfd_sink_error("failed to link %s:%s and %s:%s",
+                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
                        goto ERROR;
                }
                gst_object_unref(GST_OBJECT(srcpad));
@@ -1622,94 +2640,96 @@ __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data)
                gst_object_unref(GST_OBJECT(sinkpad));
                sinkpad = NULL;
 
-               srcpad = gst_element_get_static_pad(decodebin, "src");
+               wfd_sink_debug("try to sync %s's state with parent", GST_ELEMENT_NAME(valve));
+               if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(valve))) {
+                       wfd_sink_error("failed to sync %s state with parent",
+                                                       GST_PAD_NAME(valve));
+                       goto ERROR;
+               }
+
+               srcpad = gst_element_get_static_pad(valve, "src");
                if (!srcpad) {
                        wfd_sink_error("failed to get src pad from %s",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
+                                                       GST_ELEMENT_NAME(valve));
                        goto ERROR;
                }
-       } else {
-               wfd_sink_warning("going on without decodebin...");
        }
 
-       /* add sinkbin and link */
-       if (sinkbin) {
-               if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
-                       wfd_sink_error("failed to add %s to pipeline",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
-                       goto ERROR;
-               }
+       /* take decodebin/sinkbin */
+       if (name[0] == 'v') {
+               wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
 
-               sinkpad = gst_element_get_static_pad(sinkbin, "sink");
-               if (!sinkpad) {
-                       wfd_sink_error("failed to get sink pad from %s",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
-                       goto ERROR;
-               }
+               MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
+
+               gst_pad_add_probe(pad,
+                                               GST_PAD_PROBE_TYPE_BUFFER,
+                                               _mm_wfd_sink_check_running_time,
+                                               (gpointer)wfd_sink,
+                                               NULL);
 
-               if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
-                       wfd_sink_error("failed to link %s and %s",
-                                       GST_STR_NULL(GST_PAD_NAME(srcpad)),
-                                       GST_STR_NULL(GST_PAD_NAME(sinkpad)));
+               if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad)) {
+                       wfd_sink_error("failed to prepare video pipeline....");
                        goto ERROR;
                }
-               gst_object_unref(GST_OBJECT(srcpad));
-               srcpad = NULL;
-               gst_object_unref(GST_OBJECT(sinkpad));
-               sinkpad = NULL;
-       } else {
-               wfd_sink_error("there is no sinkbin...");
-               goto ERROR;
-       }
+       } else if (name[0] == 'a') {
+               wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
 
+               MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
 
-       /* run */
-       if (decodebin) {
-               if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) {
-                       wfd_sink_error("failed to sync %s state with parent",
-                               GST_STR_NULL(GST_PAD_NAME(decodebin)));
+               gst_pad_add_probe(pad,
+                                               GST_PAD_PROBE_TYPE_BUFFER,
+                                               _mm_wfd_sink_check_running_time,
+                                               (gpointer)wfd_sink,
+                                               NULL);
+
+               if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad)) {
+                       wfd_sink_error("failed to prepare audio pipeline....");
                        goto ERROR;
                }
+       } else {
+               wfd_sink_error("unexceptable pad is added!!!");
+               goto ERROR;
        }
 
-       if (sinkbin) {
-               if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) {
-                       wfd_sink_error("failed to sync %s state with parent",
-                               GST_STR_NULL(GST_PAD_NAME(sinkbin)));
-                       goto ERROR;
-               }
+       /* link */
+       wfd_sink_debug("try to link %s:%s and %s:%s",
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                       GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+       if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
+               wfd_sink_error("failed to link %s:%s and %s:%s",
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
+                                               GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
+               goto ERROR;
        }
 
-       if (name[0] == 'v') {
+       if (name[0] == 'v')
                MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
-       } else if (name[0] == 'a') {
+       else if (name[0] == 'a')
                MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
-       }
 
+done:
        MMWFDSINK_FREEIF(name);
 
+       if (srcpad) {
+               gst_object_unref(GST_OBJECT(srcpad));
+               srcpad = NULL;
+       }
+       if (sinkpad) {
+               gst_object_unref(GST_OBJECT(sinkpad));
+               sinkpad = NULL;
+       }
        wfd_sink_debug_fleave();
 
        return;
 
        /* ERRORS */
 ERROR:
-       MMWFDSINK_FREEIF(name);
-
-       if (srcpad)
-               gst_object_unref(GST_OBJECT(srcpad));
-       srcpad = NULL;
-
-       if (sinkpad)
-               gst_object_unref(GST_OBJECT(sinkpad));
-       sinkpad = NULL;
-
        /* need to notify to app */
        MMWFDSINK_POST_MESSAGE(wfd_sink,
                                                        MM_ERROR_WFD_INTERNAL,
                                                        MMWFDSINK_CURRENT_STATE(wfd_sink));
 
-       return;
+       goto done;
 }
 
 static void
@@ -1742,21 +2762,15 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer
        MMWFDSinkStreamInfo *stream_info = NULL;
        gint is_valid_audio_format = FALSE;
        gint is_valid_video_format = FALSE;
-       gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
-       gint video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
        gchar *audio_format;
        gchar *video_format;
 
        wfd_sink_debug_fenter();
-
        wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
        wfd_sink_return_if_fail(wfd_sink);
 
        stream_info = &wfd_sink->stream_info;
 
-       audio_codec = wfd_sink->stream_info.audio_stream_info.codec;
-       video_codec = wfd_sink->stream_info.video_stream_info.codec;
-
        if (gst_structure_has_field(str, "audio_format")) {
                is_valid_audio_format = TRUE;
                audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
@@ -1770,7 +2784,6 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer
                        wfd_sink_error("invalid audio format(%s)...", audio_format);
                        is_valid_audio_format = FALSE;
                }
-
                if (is_valid_audio_format == TRUE) {
                        if (gst_structure_has_field(str, "audio_rate"))
                                gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
@@ -1779,33 +2792,30 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer
                        if (gst_structure_has_field(str, "audio_bitwidth"))
                                gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
 
-                       if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
-                               if (audio_codec != stream_info->audio_stream_info.codec) {
-                                       wfd_sink_debug("audio codec is changed...need to change audio decodebin");
-                               }
-                       } else {
-                               WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
-                       }
+                       WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
 
-                       wfd_sink_debug("audio_format : %s \n \t rate :  %d \n \t channels :  %d \n \t bitwidth :  %d \n \t",
-                                               audio_format,
-                                               stream_info->audio_stream_info.sample_rate,
-                                               stream_info->audio_stream_info.channels,
-                                               stream_info->audio_stream_info.bitwidth);
+                       wfd_sink_debug("audio_format : %s \n \t rate :  %d \n \t channels :  %d \n \t bitwidth :  %d \n \t      \n",
+                                                       audio_format,
+                                                       stream_info->audio_stream_info.sample_rate,
+                                                       stream_info->audio_stream_info.channels,
+                                                       stream_info->audio_stream_info.bitwidth);
                }
-       }
 
+               g_free(audio_format);
+       }
        if (gst_structure_has_field(str, "video_format")) {
                is_valid_video_format = TRUE;
                video_format = g_strdup(gst_structure_get_string(str, "video_format"));
-               if (!g_strrstr(video_format, "H264")) {
+               if (g_strrstr(video_format, "H264")) {
+                       stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
+               } else if (g_strrstr(video_format, "H265")) {
+                       stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H265;
+               } else {
                        wfd_sink_error("invalid video format(%s)...", video_format);
                        is_valid_video_format = FALSE;
                }
 
                if (is_valid_video_format == TRUE) {
-                       stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
-
                        if (gst_structure_has_field(str, "video_width"))
                                gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
                        if (gst_structure_has_field(str, "video_height"))
@@ -1813,20 +2823,16 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer
                        if (gst_structure_has_field(str, "video_framerate"))
                                gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
 
-                       if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
-                               if (video_codec != stream_info->video_stream_info.codec) {
-                                       wfd_sink_debug("video codec is changed...need to change video decodebin");
-                               }
-                       } else {
-                               WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
-                       }
+                       WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
 
                        wfd_sink_debug("video_format : %s \n \t width :  %d \n \t height :  %d \n \t frame_rate :  %d \n \t",
-                                               video_format,
-                                               stream_info->video_stream_info.width,
-                                               stream_info->video_stream_info.height,
-                                               stream_info->video_stream_info.frame_rate);
+                                                       video_format,
+                                                       stream_info->video_stream_info.width,
+                                                       stream_info->video_stream_info.height,
+                                                       stream_info->video_stream_info.frame_rate);
                }
+
+               g_free(video_format);
        }
 
        WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
@@ -1834,16 +2840,50 @@ __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer
        wfd_sink_debug_fleave();
 }
 
+static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint64 *CEA_resolution,
+                                                                                                       guint64 *VESA_resolution, guint64 *HH_resolution)
+{
+       if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
+
+       *CEA_resolution = 0;
+       *VESA_resolution = 0;
+       *HH_resolution = 0;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
+               *CEA_resolution |= WFD_CEA_1920x1080P30;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
+               *CEA_resolution |= WFD_CEA_1280x720P30;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
+               *HH_resolution |= WFD_HH_960x540P30;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
+               *HH_resolution |= WFD_HH_864x480P30;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
+               *CEA_resolution |= WFD_CEA_720x480P60;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
+               *CEA_resolution |= WFD_CEA_640x480P60;
+
+       if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
+               *HH_resolution |= WFD_HH_640x360P30;
+}
+
 static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc)
 {
-       GstStructure *audio_param = NULL;
-       GstStructure *video_param = NULL;
-       GstStructure *hdcp_param = NULL;
+       GstStructure *wfd_audio_codecs = NULL;
+       GstStructure *wfd_video_formats = NULL;
+       GstStructure *wfd_content_protection = NULL;
+       GstStructure *wfd2_video_formats = NULL;
+       GstStructure *wfd2_audio_codecs = NULL;
+       GstStructure *wfd_coupled_sink= NULL;
        gint hdcp_version = 0;
        gint hdcp_port = 0;
-       guint CEA_resolution = 0;
-       guint VESA_resolution = 0;
-       guint HH_resolution = 0;
+       guint64 CEA_resolution = 0;
+       guint64 VESA_resolution = 0;
+       guint64 HH_resolution = 0;
        GObjectClass *klass;
 
        wfd_sink_debug_fenter();
@@ -1854,62 +2894,179 @@ static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfd
 
        klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc));
 
-       g_object_set(G_OBJECT(wfdsrc), "debug", wfd_sink->ini.set_debug_property, NULL);
-       g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdsrc_pad_probe, NULL);
-       if (g_object_class_find_property(klass, "udp-buffer-size"))
-               g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
+       if (g_object_class_find_property(klass, "enable-pad-probe")) /* for common wfdsrc */
+               g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.trace_buffers_of_wfdsrc, NULL);
+       g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
+       g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
+       g_object_set(G_OBJECT(wfdsrc), "user-agent", wfd_sink->ini.user_agent, NULL);
+       g_object_set(G_OBJECT(wfdsrc), "dump-rtsp-message", wfd_sink->ini.dump_rtsp_message, NULL);
+       if (g_object_class_find_property(klass, "dump-rtp-data"))
+               g_object_set(G_OBJECT(wfdsrc), "dump-rtp-data", wfd_sink->ini.dump_rtp_data, NULL);
+       if (g_object_class_find_property(klass, "trace-first-buffer"))
+               g_object_set(G_OBJECT(wfdsrc), "trace-first-buffer", wfd_sink->ini.trace_first_buffer, NULL);
+       if (g_object_class_find_property(klass, "trace-buffers"))
+               g_object_set(G_OBJECT(wfdsrc), "trace-buffers", wfd_sink->ini.trace_buffers, NULL);
        if (g_object_class_find_property(klass, "do-request"))
                g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
-       if (g_object_class_find_property(klass, "latency"))
-               g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
-
-       audio_param = gst_structure_new("audio_param",
-                                                               "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec,
-                                                               "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency,
-                                                               "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel,
-                                                               "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency,
-                                                               NULL);
 
-       CEA_resolution = wfd_sink->ini.video_cea_support;
-       VESA_resolution = wfd_sink->ini.video_vesa_support;
-       HH_resolution =  wfd_sink->ini.video_hh_support;
-
-       __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution, &CEA_resolution, &VESA_resolution, &HH_resolution);
+       /* set audio parameter for Wi-Fi Display session negotiation */
+       wfd_audio_codecs = gst_structure_new("wfd_audio_codecs",
+                                                                               "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_codec,
+                                                                               "audio_latency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_latency,
+                                                                               "audio_channels", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_channel,
+                                                                               "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_sampling_frequency,
+                                                                               NULL);
+
+       if (wfd_audio_codecs) {
+               g_object_set(G_OBJECT(wfdsrc), "wfd-audio-codecs", wfd_audio_codecs, NULL);
+               gst_structure_free(wfd_audio_codecs);
+               wfd_audio_codecs = NULL;
+       }
+
+       /* set video parameter for Wi-Fi Display session negotiation */
+       CEA_resolution = wfd_sink->ini.wfd_video_formats.video_cea_support;
+       VESA_resolution = wfd_sink->ini.wfd_video_formats.video_vesa_support;
+       HH_resolution =  wfd_sink->ini.wfd_video_formats.video_hh_support;
+
+       __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
+                                                                                       &CEA_resolution, &VESA_resolution, &HH_resolution);
+       wfd_video_formats = gst_structure_new("wfd_video_formats",
+                                                                               "video_codec", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_codec,
+                                                                               "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_native_resolution,
+                                                                               "video_cea_support", G_TYPE_UINT64, CEA_resolution,
+                                                                               "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
+                                                                               "video_hh_support", G_TYPE_UINT64, HH_resolution,
+                                                                               "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_profile,
+                                                                               "video_level", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_level,
+                                                                               "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_latency,
+                                                                               "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_vertical_resolution,
+                                                                               "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_horizontal_resolution,
+                                                                               "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_minimum_slicing,
+                                                                               "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_slice_enc_param,
+                                                                               "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_framerate_control_support,
+                                                                               NULL);
+
+       if (wfd_video_formats) {
+               g_object_set(G_OBJECT(wfdsrc), "wfd-video-formats", wfd_video_formats, NULL);
+               gst_structure_free(wfd_video_formats);
+               wfd_video_formats = NULL;
+       }
+       /* set coupled sink information for Wi-Fi Display session negotiation */
+       wfd_coupled_sink = gst_structure_new("wfd_coupled_sink",
+                                                                                       "coupled_sink_status", G_TYPE_INT, wfd_sink->coupled_sink_status,
+                                                                                       "coupled_sink_address", G_TYPE_STRING, wfd_sink->coupled_sink_address,
+                                                                                       "is_coupled_sink_supported", G_TYPE_BOOLEAN, wfd_sink->is_coupled_sink_supported,
+                                                                                       NULL);
+
+       if (wfd_coupled_sink) {
+               g_object_set(G_OBJECT(wfdsrc), "wfd-coupled-sink", wfd_coupled_sink, NULL);
+               gst_structure_free(wfd_coupled_sink);
+               wfd_coupled_sink = NULL;
+       }
+
+       /* set hdcp parameter for Wi-Fi Display session negotiation */
+       if (wfd_sink->ini.wfd_content_protection.enable_hdcp) {
+               mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
+               mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
+               wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
+
+               wfd_content_protection = gst_structure_new("wfd_content_protection",
+                                                                                                       "hdcp_version", G_TYPE_INT, hdcp_version,
+                                                                                                       "hdcp_port_no", G_TYPE_INT, hdcp_port,
+                                                                                                       NULL);
+
+               if (wfd_content_protection) {
+                       g_object_set(G_OBJECT(wfdsrc), "wfd-content-protection", wfd_content_protection, NULL);
+                       gst_structure_free(wfd_content_protection);
+                       wfd_content_protection = NULL;
+               }
+       }
 
-       wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution);
+       if (g_object_class_find_property(klass, "wfd2-audio-codecs")) {
+               /* set audio parameter for Wi-Fi Display R2 session negotiation */
+               wfd2_audio_codecs = gst_structure_new("wfd2-audio-codecs",
+                                                                                       "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_codec,
+                                                                                       "audio_lpcm_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_lpcm_mode,
+                                                                                       "audio_aac_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_aac_mode,
+                                                                                       "audio_ac3_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_ac3_mode,
+                                                                                       NULL);
 
-       video_param = gst_structure_new("video_param",
-                                                       "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec,
-                                                       "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution,
-                                                       "video_cea_support", G_TYPE_UINT, CEA_resolution,
-                                                       "video_vesa_support", G_TYPE_UINT, VESA_resolution,
-                                                       "video_hh_support", G_TYPE_UINT, HH_resolution,
-                                                       "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile,
-                                                       "video_level", G_TYPE_UINT, wfd_sink->ini.video_level,
-                                                       "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency,
-                                                       "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution,
-                                                       "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution,
-                                                       "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing,
-                                                       "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param,
-                                                       "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support,
-                                                       NULL);
+               if (wfd2_audio_codecs) {
+                       g_object_set(G_OBJECT(wfdsrc), "wfd2-audio-codecs", wfd2_audio_codecs, NULL);
+                       gst_structure_free(wfd2_audio_codecs);
+                       wfd2_audio_codecs = NULL;
+               }
+       }
 
-       mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
-       mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
-       wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
+       if (g_object_class_find_property(klass, "wfd2-video-format-h264")) {
+               /* set video parameter for Wi-Fi Display R2 session negotiation */
+               CEA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_cea_support;
+               VESA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_vesa_support;
+               HH_resolution =  wfd_sink->ini.wfd2_video_h264_info.video_hh_support;
+
+               if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H264) {
+                       wfd2_video_formats = gst_structure_new("wfd2-video-format-h264",
+                                                                                               "video_codec", G_TYPE_UINT, WFD_VIDEO_H264,
+                                                                                               "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
+                                                                                               "video_cea_support", G_TYPE_UINT64, CEA_resolution,
+                                                                                               "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
+                                                                                               "video_hh_support", G_TYPE_UINT64, HH_resolution,
+                                                                                               "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_profile,
+                                                                                               "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_level,
+                                                                                               "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_latency,
+                                                                                               "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_vertical_resolution,
+                                                                                               "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_horizontal_resolution,
+                                                                                               "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_minimum_slicing,
+                                                                                               "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_slice_enc_param,
+                                                                                               "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_framerate_control_support,
+                                                                                               "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
+                                                                                               NULL);
+
+                       if (wfd2_video_formats) {
+                               g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h264", wfd2_video_formats, NULL);
+                               gst_structure_free(wfd2_video_formats);
+                               wfd2_video_formats = NULL;
+                       }
+               }
+       }
 
-       hdcp_param = gst_structure_new("hdcp_param",
-                                                       "hdcp_version", G_TYPE_INT, hdcp_version,
-                                                       "hdcp_port_no", G_TYPE_INT, hdcp_port,
-                                                       NULL);
+       if (g_object_class_find_property(klass, "wfd2-video-format-h265")) {
+               /* set video parameter for Wi-Fi Display R2 session negotiation */
+               CEA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_cea_support;
+               VESA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_vesa_support;
+               HH_resolution =  wfd_sink->ini.wfd2_video_h265_info.video_hh_support;
+
+               if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H265) {
+                       wfd2_video_formats = gst_structure_new("wfd2-video-format-h265",
+                                                                                               "video_codec", G_TYPE_UINT, WFD_VIDEO_H265,
+                                                                                               "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
+                                                                                               "video_cea_support", G_TYPE_UINT64, CEA_resolution,
+                                                                                               "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
+                                                                                               "video_hh_support", G_TYPE_UINT64, HH_resolution,
+                                                                                               "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_profile,
+                                                                                               "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_level,
+                                                                                               "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_latency,
+                                                                                               "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_vertical_resolution,
+                                                                                               "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_horizontal_resolution,
+                                                                                               "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_minimum_slicing,
+                                                                                               "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_slice_enc_param,
+                                                                                               "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_framerate_control_support,
+                                                                                               "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
+                                                               NULL);
 
-       g_object_set(G_OBJECT(wfdsrc), "audio-param", audio_param, NULL);
-       g_object_set(G_OBJECT(wfdsrc), "video-param", video_param, NULL);
-       g_object_set(G_OBJECT(wfdsrc), "hdcp-param", hdcp_param, NULL);
+                       if (wfd2_video_formats) {
+                               g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h265", wfd2_video_formats, NULL);
+                               gst_structure_free(wfd2_video_formats);
+                               wfd2_video_formats = NULL;
+                       }
+               }
+       }
 
-       g_signal_connect(wfdsrc, "update-media-info", G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
+       wfd_sink->update_stream_info_sig_id = g_signal_connect(wfdsrc, "update-media-info",
+                                                                                                               G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
 
-       g_signal_connect(wfdsrc, "change-av-format", G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
+       wfd_sink->change_av_format_sig_id = g_signal_connect(wfdsrc, "change-av-format",
+                                                                                                               G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
 
        wfd_sink_debug_fleave();
 
@@ -1923,21 +3080,26 @@ static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demu
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
        wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
 
-       g_signal_connect(demux, "pad-added", G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink);
+       g_signal_connect(demux, "pad-added",
+                                       G_CALLBACK(__mm_wfd_sink_demux_pad_added),      wfd_sink);
 
        wfd_sink_debug_fleave();
 
        return MM_ERROR_NONE;
 }
 
-static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data)
+static void __mm_wfd_sink_queue_overrun(GstElement *queue, gpointer u_data)
 {
+       guint64 time = 0;
+
        wfd_sink_debug_fenter();
 
-       return_if_fail(element);
+       return_if_fail(queue);
+
+       g_object_get(G_OBJECT(queue), "current-level-time", &time, NULL);
 
-       wfd_sink_warning("%s is overrun",
-                                       GST_STR_NULL(GST_ELEMENT_NAME(element)));
+       wfd_sink_warning("%s is overrun(%" GST_TIME_FORMAT")",
+                                               GST_ELEMENT_NAME(queue), GST_TIME_ARGS(time));
 
        wfd_sink_debug_fleave();
 
@@ -1955,7 +3117,8 @@ static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *que
        g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
        g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
        g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
-       g_signal_connect(queue, "overrun", G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
+       g_signal_connect(queue, "overrun",
+                                       G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
 
        wfd_sink_debug_fleave();
 
@@ -1963,7 +3126,7 @@ static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *que
 }
 
 
-static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
 {
        MMWFDSinkGstElement *mainbin = NULL;
        GList *element_bucket = NULL;
@@ -2014,6 +3177,17 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
 
        MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
 
+       /* create queue for ts */
+       MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_QUEUE, "queue", "ts_queue", TRUE);
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "src");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "sink");
+       g_object_set(G_OBJECT(mainbin[WFD_SINK_M_QUEUE].gst), "max-size-buffers", 200000, NULL);
+
+       /* create valve for demux */
+       MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_D_VALVE, "valve", "demux_valve", TRUE);
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "src");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "sink");
+
        /* create tsdemuxer*/
        MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
@@ -2024,6 +3198,16 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
                }
        }
 
+       /* create valve for audio */
+       MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_A_VALVE, "valve", "audio_valve", FALSE);
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "src");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "sink");
+
+       /* create valve for video */
+       MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_V_VALVE, "valve", "video_valve", FALSE);
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "src");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "sink");
+
        /* adding created elements to pipeline */
        if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
                wfd_sink_error("failed to add elements");
@@ -2044,13 +3228,15 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
        }
 
        /* add bus message callback*/
-       gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
+       wfd_sink->msg_callback_id = gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
 
        /* set sync handler to get tag synchronously */
        gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
 
        g_list_free(element_bucket);
+       element_bucket = NULL;
        gst_object_unref(GST_OBJECT(bus));
+       bus = NULL;
 
        /* now we have completed mainbin. take it */
        wfd_sink->pipeline->mainbin = mainbin;
@@ -2063,14 +3249,10 @@ static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
 CREATE_ERROR:
        wfd_sink_error("ERROR : releasing pipeline");
 
-       if (element_bucket)
+       if (element_bucket) {
                g_list_free(element_bucket);
-       element_bucket = NULL;
-
-       /* finished */
-       if (bus)
-               gst_object_unref(GST_OBJECT(bus));
-       bus = NULL;
+               element_bucket = NULL;
+       }
 
        /* release element which are not added to bin */
        for (i = 1; i < WFD_SINK_M_NUM; i++) {  /* NOTE : skip pipeline */
@@ -2083,13 +3265,16 @@ CREATE_ERROR:
                                mainbin[i].gst = NULL;
                        } else {
                                gst_object_unref(GST_OBJECT(parent));
+                               parent = NULL;
                        }
                }
        }
 
        /* release mainbin with it's childs */
-       if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst)
+       if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) {
                gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
+               mainbin[WFD_SINK_M_PIPE].gst = NULL;
+       }
 
        MMWFDSINK_FREEIF(mainbin);
 
@@ -2107,22 +3292,27 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        GstPad *sinkpad = NULL;
        GstPad *srcpad = NULL;
        GstPad *ghostpad = NULL;
-       GList *first_list = NULL;
-       GList *last_list = NULL;
+       GList *list_temp = NULL;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->a_decodebin &&
-                                               wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->a_decodebin &&
+                                                               wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        if (wfd_sink->audio_decodebin_is_linked) {
                wfd_sink_debug("audio decodebin is already linked... nothing to do");
                return MM_ERROR_NONE;
        }
 
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
+               wfd_sink_debug("Skip link audio decodebin for none audio codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
+
        /* take audio decodebin */
        a_decodebin = wfd_sink->pipeline->a_decodebin;
 
@@ -2136,40 +3326,41 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
 
        /* check audio codec */
        switch (wfd_sink->stream_info.audio_stream_info.codec) {
-               case MM_WFD_SINK_AUDIO_CODEC_LPCM:
-                       if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
-                       if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
-                               GstCaps *caps = NULL;
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
-                               caps = gst_caps_new_simple("audio/x-raw",
-                                                                       "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
-                                                                       "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
-                                                                       "format", G_TYPE_STRING, "S16BE", NULL);
-
-                               g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
-                               gst_object_unref(GST_OBJECT(caps));
-                       }
-                       break;
-
-               case MM_WFD_SINK_AUDIO_CODEC_AAC:
-                       if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
-                       if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
-                       break;
-
-               case MM_WFD_SINK_AUDIO_CODEC_AC3:
-                       if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
-                       if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
-                               element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
-                       break;
-
-               default:
-                       wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
-                       return MM_ERROR_WFD_INTERNAL;
-                       break;
+       case MM_WFD_SINK_AUDIO_CODEC_LPCM:
+               if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
+               if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
+                       GstCaps *caps = NULL;
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
+                       caps = gst_caps_new_simple("audio/x-raw",
+                                               "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
+                                               "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
+                                               "format", G_TYPE_STRING, "S16BE", NULL);
+
+                       g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
+                       gst_object_unref(GST_OBJECT(caps));
+                       caps = NULL;
+               }
+               break;
+
+       case MM_WFD_SINK_AUDIO_CODEC_AAC:
+               if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
+               if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
+               break;
+
+       case MM_WFD_SINK_AUDIO_CODEC_AC3:
+               if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
+               if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
+                       element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
+               break;
+
+       default:
+               wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
+               goto fail_to_link;
+               break;
        }
 
        if (element_bucket == NULL) {
@@ -2194,13 +3385,13 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        }
 
        /* get first element's sinkpad for creating ghostpad */
-       first_list = g_list_first(element_bucket);
-       if (first_list == NULL) {
+       list_temp = g_list_first(element_bucket);
+       if (list_temp == NULL) {
                wfd_sink_error("failed to get first list of the element_bucket");
                goto fail_to_link;
        }
 
-       first_element = (MMWFDSinkGstElement *)first_list->data;
+       first_element = (MMWFDSinkGstElement *)list_temp->data;
        if (!first_element) {
                wfd_sink_error("failed to get first element of the audio decodebin");
                goto fail_to_link;
@@ -2209,7 +3400,7 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
        if (!sinkpad) {
                wfd_sink_error("failed to get sink pad from element(%s)",
-                       GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
                goto fail_to_link;
        }
 
@@ -2228,13 +3419,13 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
 
 
        /* get last element's src for creating ghostpad */
-       last_list = g_list_last(element_bucket);
-       if (last_list == NULL) {
+       list_temp = g_list_last(element_bucket);
+       if (list_temp == NULL) {
                wfd_sink_error("failed to get last list of the element_bucket");
                goto fail_to_link;
        }
 
-       last_element = (MMWFDSinkGstElement *)last_list->data;
+       last_element = (MMWFDSinkGstElement *)list_temp->data;
        if (!last_element) {
                wfd_sink_error("failed to get last element of the audio decodebin");
                goto fail_to_link;
@@ -2243,7 +3434,7 @@ int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
        if (!srcpad) {
                wfd_sink_error("failed to get src pad from element(%s)",
-                       GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
                goto fail_to_link;
        }
 
@@ -2271,13 +3462,15 @@ done:
 
        /* ERRORS*/
 fail_to_link:
-       if (srcpad)
+       if (srcpad) {
                gst_object_unref(GST_OBJECT(srcpad));
-       srcpad = NULL;
+               srcpad = NULL;
+       }
 
-       if (sinkpad)
+       if (sinkpad) {
                gst_object_unref(GST_OBJECT(sinkpad));
-       sinkpad = NULL;
+               sinkpad = NULL;
+       }
 
        g_list_free(element_bucket);
 
@@ -2303,14 +3496,14 @@ static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *
        return MM_ERROR_NONE;
 }
 
-static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
+int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
 {
        GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
        MMWFDSinkGstElement *a_decodebin = NULL;
        GstObject *parent = NULL;
        int i;
 
-       wfd_sink_debug_fenter();
+       wfd_sink_error_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
 
@@ -2328,7 +3521,7 @@ static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
                wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
 
                if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
-                       wfd_sink_debug("try to change state of audio decodebin to NULL");
+                       wfd_sink_error("try to change state of audio decodebin to NULL");
                        ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
                        if (ret != GST_STATE_CHANGE_SUCCESS) {
                                wfd_sink_error("failed to change state of audio decodebin to NULL");
@@ -2342,40 +3535,44 @@ static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
                                parent = gst_element_get_parent(a_decodebin[i].gst);
                                if (!parent) {
                                        wfd_sink_debug("unref %s(current ref %d)",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
-                                                       ((GObject *) a_decodebin[i].gst)->ref_count);
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
+                                                                       ((GObject *) a_decodebin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
                                        a_decodebin[i].gst = NULL;
                                } else {
-                                       wfd_sink_debug("unref %s(current ref %d)",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
-                                                       ((GObject *) a_decodebin[i].gst)->ref_count);
+                                       wfd_sink_debug("%s has parent.(current ref %d)",
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
+                                                                       ((GObject *) a_decodebin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(parent));
+                                       parent = NULL;
                                }
                        }
                }
 
                /* release audio decodebin with it's childs */
-               if (a_decodebin[WFD_SINK_A_D_BIN].gst)
+               if (a_decodebin[WFD_SINK_A_D_BIN].gst) {
                        gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
+                       a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
+               }
 
        } else {
                wfd_sink_debug("audio decodebin has parent(%s), unref it ",
-                                       GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
+                                               GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
 
                gst_object_unref(GST_OBJECT(parent));
+               parent = NULL;
        }
 
        wfd_sink->audio_decodebin_is_linked = FALSE;
 
        MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
 
-       wfd_sink_debug_fleave();
+       wfd_sink_error_fleave();
 
        return MM_ERROR_NONE;
 }
 
-static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
 {
        MMWFDSinkGstElement *a_decodebin = NULL;
        gint audio_codec = WFD_AUDIO_UNKNOWN;
@@ -2386,29 +3583,40 @@ static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->pipeline->a_decodebin != NULL) {
+               wfd_sink_error("The audio decode bin is already created.");
+               return MM_ERROR_NONE;
+       }
+
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
+               wfd_sink_debug("Skip create audio decodebin for none audio codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
 
        /* check audio decodebin could be linked now */
-       switch (wfd_sink->stream_info.audio_stream_info.codec) {
-               case MM_WFD_SINK_AUDIO_CODEC_AAC:
-                       audio_codec = WFD_AUDIO_AAC;
-                       link = TRUE;
-                       break;
-               case MM_WFD_SINK_AUDIO_CODEC_AC3:
-                       audio_codec = WFD_AUDIO_AC3;
-                       link = TRUE;
-                       break;
-               case MM_WFD_SINK_AUDIO_CODEC_LPCM:
-                       audio_codec = WFD_AUDIO_LPCM;
-                       link = TRUE;
-                       break;
-               case MM_WFD_SINK_AUDIO_CODEC_NONE:
-               default:
-                       wfd_sink_debug("audio decodebin could NOT be linked now, just create");
-                       audio_codec = wfd_sink->ini.audio_codec;
-                       link = FALSE;
-                       break;
+       switch (wfd_sink->stream_info.audio_stream_info.codec) {
+       case MM_WFD_SINK_AUDIO_CODEC_AAC:
+               audio_codec = WFD_AUDIO_AAC;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_AUDIO_CODEC_AC3:
+               audio_codec = WFD_AUDIO_AC3;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_AUDIO_CODEC_LPCM:
+               audio_codec = WFD_AUDIO_LPCM;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_AUDIO_CODEC_NONE:
+       default:
+               wfd_sink_debug("audio decodebin could NOT be linked now, just create");
+               audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
+               link = FALSE;
+               break;
        }
 
        /* alloc handles */
@@ -2431,15 +3639,17 @@ static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
        /* create queue */
        MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "sink");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "src");
        if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
                __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
 
        /* create hdcp */
        MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "sink");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "src");
 
        /* create codec */
-       audio_codec = wfd_sink->ini.audio_codec;
+       audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
        if (audio_codec & WFD_AUDIO_LPCM) {
                /* create LPCM converter */
                MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
@@ -2510,27 +3720,30 @@ CREATE_ERROR:
                                a_decodebin[i].gst = NULL;
                        } else {
                                gst_object_unref(GST_OBJECT(parent));
+                               parent = NULL;
                        }
                }
        }
 
-       /* release audioo decodebin with it's childs */
-       if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst)
+       /* release audio decodebin with it's childs */
+       if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) {
                gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
+               a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
+       }
 
        MMWFDSINK_FREEIF(a_decodebin);
 
        return MM_ERROR_WFD_INTERNAL;
 }
 
-static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
+int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
 {
        GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
        MMWFDSinkGstElement *a_sinkbin = NULL;
        GstObject *parent = NULL;
        int i;
 
-       wfd_sink_debug_fenter();
+       wfd_sink_error_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
 
@@ -2545,13 +3758,13 @@ static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
 
        parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
        if (!parent) {
-               wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
+               wfd_sink_error("audio sinkbin has no parent.. need to relase by itself");
 
                if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
-                       wfd_sink_debug("try to change state of audio decodebin to NULL");
+                       wfd_sink_error("try to change state of audio sinkbin to NULL");
                        ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
                        if (ret != GST_STATE_CHANGE_SUCCESS) {
-                               wfd_sink_error("failed to change state of audio decodebin to NULL");
+                               wfd_sink_error("failed to change state of audio sinkbin to NULL");
                                return MM_ERROR_WFD_INTERNAL;
                        }
                }
@@ -2562,38 +3775,41 @@ static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
                                parent = gst_element_get_parent(a_sinkbin[i].gst);
                                if (!parent) {
                                        wfd_sink_debug("unref %s(current ref %d)",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
-                                                       ((GObject *) a_sinkbin[i].gst)->ref_count);
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
+                                                                       ((GObject *) a_sinkbin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
                                        a_sinkbin[i].gst = NULL;
                                } else {
-                                       wfd_sink_debug("unref %s(current ref %d)",
-                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
-                                                       ((GObject *) a_sinkbin[i].gst)->ref_count);
+                                       wfd_sink_debug("%s has parent.(current ref %d)",
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
+                                                                       ((GObject *) a_sinkbin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(parent));
+                                       parent = NULL;
                                }
                        }
                }
 
-               /* release audio decodebin with it's childs */
-               if (a_sinkbin[WFD_SINK_A_S_BIN].gst)
+               /* release audio sinkbin with it's childs */
+               if (a_sinkbin[WFD_SINK_A_S_BIN].gst) {
                        gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
-
+                       a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
+               }
        } else {
                wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
-                                       GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
+                                               GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
 
                gst_object_unref(GST_OBJECT(parent));
+               parent = NULL;
        }
 
        MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
 
-       wfd_sink_debug_fleave();
+       wfd_sink_error_fleave();
 
        return MM_ERROR_NONE;
 }
 
-static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
 {
        MMWFDSinkGstElement *a_sinkbin = NULL;
        MMWFDSinkGstElement *first_element = NULL;
@@ -2601,13 +3817,24 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
        GstPad *ghostpad = NULL;
        GstPad *pad = NULL;
        gint i = 0;
-       GList *first_list = NULL;
+       GList *list_temp = NULL;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->pipeline->a_sinkbin != NULL) {
+               wfd_sink_error("The audio sink bin is already created.");
+               return MM_ERROR_NONE;
+       }
+
+       if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
+               wfd_sink_error("Skip create audio sink bin for non audio codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
 
        /* alloc handles */
        a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
@@ -2627,17 +3854,25 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
        }
 
        /* create resampler */
-       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
+       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER,
+                                                       wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "sink");
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "src");
 
        /* create volume */
-       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
+       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME,
+                                                       wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "sink");
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "src");
 
+       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_QUEUE,
+                                                       wfd_sink->ini.name_of_audio_sinkbin_queue, "audio_sinkbin_queue", TRUE);
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "sink");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "src");
+
        /* create sink */
-       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
+       MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK,
+                                                       wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst,  "sink");
        if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
                if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
@@ -2659,13 +3894,13 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
        }
 
        /* get first element's of the audio sinkbin */
-       first_list = g_list_first(element_bucket);
-       if (first_list == NULL) {
+       list_temp = g_list_first(element_bucket);
+       if (list_temp == NULL) {
                wfd_sink_error("failed to get first list of the element_bucket");
                goto CREATE_ERROR;
        }
 
-       first_element = (MMWFDSinkGstElement *)first_list->data;
+       first_element = (MMWFDSinkGstElement *)list_temp->data;
        if (!first_element) {
                wfd_sink_error("failed to get first element of the audio sinkbin");
                goto CREATE_ERROR;
@@ -2675,7 +3910,7 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
        pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
        if (!pad) {
                wfd_sink_error("failed to get sink pad from element(%s)",
-                       GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
                goto CREATE_ERROR;
        }
 
@@ -2690,8 +3925,10 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
                goto CREATE_ERROR;
        }
        gst_object_unref(GST_OBJECT(pad));
+       pad = NULL;
 
        g_list_free(element_bucket);
+       element_bucket = NULL;
 
        /* take it */
        wfd_sink->pipeline->a_sinkbin = a_sinkbin;
@@ -2703,17 +3940,18 @@ static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
 CREATE_ERROR:
        wfd_sink_error("failed to create audio sinkbin, releasing all");
 
-       if (pad)
+       if (pad) {
                gst_object_unref(GST_OBJECT(pad));
-       pad = NULL;
-
-       if (ghostpad)
+               pad = NULL;
+       }
+       if (ghostpad) {
                gst_object_unref(GST_OBJECT(ghostpad));
-       ghostpad = NULL;
-
-       if (element_bucket)
+               ghostpad = NULL;
+       }
+       if (element_bucket) {
                g_list_free(element_bucket);
-       element_bucket = NULL;
+               element_bucket = NULL;
+       }
 
        /* release element which are not added to bin */
        for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
@@ -2726,14 +3964,16 @@ CREATE_ERROR:
                                a_sinkbin[i].gst = NULL;
                        } else {
                                gst_object_unref(GST_OBJECT(parent));
+                               parent = NULL;
                        }
                }
        }
 
        /* release audio sinkbin with it's childs */
-       if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst)
+       if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) {
                gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
-
+               a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
+       }
        MMWFDSINK_FREEIF(a_sinkbin);
 
        return MM_ERROR_WFD_INTERNAL;
@@ -2745,25 +3985,30 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
        MMWFDSinkGstElement *first_element = NULL;
        MMWFDSinkGstElement *last_element = NULL;
        GList *element_bucket = NULL;
+       GList *list_temp = NULL;
        GstPad *sinkpad = NULL;
        GstPad *srcpad = NULL;
        GstPad *ghostpad = NULL;
-       GList *first_list = NULL;
-       GList *last_list = NULL;
 
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->v_decodebin &&
-                                               wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline &&
+                                                               wfd_sink->pipeline->v_decodebin &&
+                                                               wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        if (wfd_sink->video_decodebin_is_linked) {
                wfd_sink_debug("video decodebin is already linked... nothing to do");
                return MM_ERROR_NONE;
        }
 
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE) {
+               wfd_sink_debug("Skip link video decodebin for none video codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
+
        /* take video decodebin */
        v_decodebin = wfd_sink->pipeline->v_decodebin;
 
@@ -2777,28 +4022,30 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
 
        /* check video codec */
        switch (wfd_sink->stream_info.video_stream_info.codec) {
-               case MM_WFD_SINK_VIDEO_CODEC_H264:
-                       if (v_decodebin[WFD_SINK_V_D_PARSE].gst)
-                               element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]);
-                       if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) {
-                               GstCaps *caps = NULL;
-
-                               element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]);
-                               caps = gst_caps_new_simple("video/x-h264",
-                                                                       "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width,
-                                                                       "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height,
-                                                                       "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL);
-                               g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL);
-                               gst_object_unref(GST_OBJECT(caps));
-                       }
-                       if (v_decodebin[WFD_SINK_V_D_DEC].gst)
-                               element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]);
-                       break;
-
-               default:
-                       wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
-                       return MM_ERROR_WFD_INTERNAL;
-                       break;
+       case MM_WFD_SINK_VIDEO_CODEC_H264:
+               if (v_decodebin[WFD_SINK_V_D_H264_PARSE].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_PARSE]);
+               if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_DEC]);
+               break;
+
+       case MM_WFD_SINK_VIDEO_CODEC_H265:
+               if (v_decodebin[WFD_SINK_V_D_H265_PARSE].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_PARSE]);
+               if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_DEC]);
+               break;
+       case MM_WFD_SINK_VIDEO_CODEC_VP9:
+               if (v_decodebin[WFD_SINK_V_D_VP9_PARSE].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_VP9_PARSE]);
+               if (v_decodebin[WFD_SINK_V_D_VP9_DEC].gst)
+                       element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_VP9_DEC]);
+               break;
+
+       default:
+               wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
+               goto fail_to_link;
+               break;
        }
 
        if (element_bucket == NULL) {
@@ -2823,13 +4070,13 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
        }
 
        /* get first element's sinkpad for creating ghostpad */
-       first_list = g_list_first(element_bucket);
-       if (first_list == NULL) {
+       list_temp = g_list_first(element_bucket);
+       if (list_temp == NULL) {
                wfd_sink_error("failed to get first list of the element_bucket");
                goto fail_to_link;
        }
 
-       first_element = (MMWFDSinkGstElement *)first_list->data;
+       first_element = (MMWFDSinkGstElement *)list_temp->data;
        if (!first_element) {
                wfd_sink_error("failed to get first element of the video decodebin");
                goto fail_to_link;
@@ -2838,7 +4085,7 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
        sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
        if (!sinkpad) {
                wfd_sink_error("failed to get sink pad from element(%s)",
-                       GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
                goto fail_to_link;
        }
 
@@ -2857,13 +4104,13 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
 
 
        /* get last element's src for creating ghostpad */
-       last_list = g_list_last(element_bucket);
-       if (last_list == NULL) {
+       list_temp = g_list_last(element_bucket);
+       if (list_temp == NULL) {
                wfd_sink_error("failed to get last list of the element_bucket");
                goto fail_to_link;
        }
 
-       last_element = (MMWFDSinkGstElement *)last_list->data;
+       last_element = (MMWFDSinkGstElement *)list_temp->data;
        if (!last_element) {
                wfd_sink_error("failed to get last element of the video decodebin");
                goto fail_to_link;
@@ -2872,7 +4119,7 @@ int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
        srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
        if (!srcpad) {
                wfd_sink_error("failed to get src pad from element(%s)",
-                       GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
                goto fail_to_link;
        }
 
@@ -2900,16 +4147,20 @@ done:
 
        /* ERRORS*/
 fail_to_link:
-       if (srcpad != NULL)
+       if (srcpad != NULL) {
                gst_object_unref(GST_OBJECT(srcpad));
-       srcpad = NULL;
+               srcpad = NULL;
+       }
 
-       if (sinkpad != NULL)
+       if (sinkpad != NULL) {
                gst_object_unref(GST_OBJECT(sinkpad));
-       sinkpad = NULL;
-
-       g_list_free(element_bucket);
+               sinkpad = NULL;
+       }
 
+       if (element_bucket != NULL) {
+               g_list_free(element_bucket);
+               element_bucket = NULL;
+       }
        return MM_ERROR_WFD_INTERNAL;
 }
 
@@ -2939,104 +4190,50 @@ static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *
 
        /* update display surface */
        mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
-       wfd_sink_debug("check display surface type attribute: %d", surface_type);
+       wfd_sink_info("check display surface type attribute: %d", surface_type);
        mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
-       wfd_sink_debug("check display visible attribute: %d", visible);
+       wfd_sink_info("check display visible attribute: %d", visible);
+
+       if (FALSE == visible) {
+               wfd_sink_info("skipped to prepare video sink. display_visible is FALSE.");
+               g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
+               return MM_ERROR_NONE;
+       }
 
        /* configuring display */
        switch (surface_type) {
-               case MM_DISPLAY_SURFACE_EVAS: {
-                               void *object = NULL;
-                               gint scaling = 0;
-
-                               /* common case if using evas surface */
-                               mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
-                               mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
-                               if (object) {
-                                       wfd_sink_debug("set video param : evas-object %x", object);
-                                       g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
-                               } else {
-                                       wfd_sink_error("no evas object");
-                                       return MM_ERROR_WFD_INTERNAL;
-                               }
-                       }
-                       break;
-
-               case MM_DISPLAY_SURFACE_OVERLAY: {
-                               int wl_window_x = 0;
-                               int wl_window_y = 0;
-                               int wl_window_width = 0;
-                               int wl_window_height = 0;
-                               unsigned int wl_surface_id = 0;
-                               struct wl_surface *wl_surface = NULL;
-                               struct wl_display *wl_display = NULL;
-                               Ecore_Wl_Window *wl_window = NULL;
-                               wl_client *wlclient = NULL;
-                               Evas_Object *obj = NULL;
-                               void *object = NULL;
-                               const char *object_type = NULL;
-                               int ret = 0;
-
-                               mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
-
-                               if (object != NULL) {
-                                       obj = (Evas_Object *)object;
-                                       object_type = evas_object_type_get(obj);
-                                       wfd_sink_debug("window object type : %s", object_type);
-
-                                       /* wayland overlay surface */
-                                       LOGI("Wayland overlay surface type");
-                                       evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height);
-
-                                       wfd_sink_debug ("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y,
-                                               wl_window_width, wl_window_height);
-
-                                       wl_window = elm_win_wl_window_get(obj);
-                                       wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window);
-
-                                       /* get wl_display */
-                                       wl_display = (struct wl_display *) ecore_wl_display_get();
-
-                                       ret = mm_wfd_sink_wlclient_create(&wlclient);
-                                       if ( ret != MM_ERROR_NONE) {
-                                               wfd_sink_error("Wayland client create failure");
-                                               return ret;
-                               }
-
-                                       if (wl_surface && wl_display){
-                                               wfd_sink_debug ("surface = %p, wl_display = %p", wl_surface, wl_display);
-                                               wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wlclient, wl_surface, wl_display);
-                                               wfd_sink_debug ("wl_surface_id = %d", wl_surface_id);
-                                       }
-                                       if (wlclient) {
-                                               g_free(wlclient);
-                                               wlclient = NULL;
-                                       }
-
-                                       wfd_sink_debug("set video param : surface_id %d", wl_surface_id);
-                                       gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink),
-                                               wl_surface_id);
-                                       /* After setting window handle, set render rectangle */
-                                       gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink),
-                                               wl_window_x, wl_window_y, wl_window_width, wl_window_height);
-                               } else {
-                                       wfd_sink_debug ("display object is NULL!");
-                                       return MM_ERROR_WFD_INTERNAL;
-                               }
-                       }
-                       break;
-
-               case MM_DISPLAY_SURFACE_NULL: {
-                               /* do nothing */
-                               wfd_sink_error("Not Supported Surface.");
-                               return MM_ERROR_WFD_INTERNAL;
-                       }
-                       break;
-               default: {
-                               wfd_sink_error("Not Supported Surface.(default case)");
+       case MM_DISPLAY_SURFACE_EVAS: {
+                       void *object = NULL;
+                       gint scaling = 0;
+
+                       /* common case if using evas surface */
+                       mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
+                       mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
+                       if (object) {
+                               wfd_sink_debug("set video param : evas-object %p", object);
+                               g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
+                       } else {
+                               wfd_sink_error("no evas object");
                                return MM_ERROR_WFD_INTERNAL;
                        }
-                       break;
+               }
+               break;
+       case MM_DISPLAY_SURFACE_OVERLAY:
+               if (USE_EXTERNAL_WL_DISPLAY_HANDLE) {
+                       gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink),
+                                                                                       wfd_sink->display_surface_id);
+               } else {
+                       gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(video_sink),
+                                                                                                       wfd_sink->display_surface_id);
+               }
+               break;
+       case MM_DISPLAY_SURFACE_NULL:
+               /* do nothing */
+               wfd_sink_error("Not Supported Surface.");
+               return MM_ERROR_WFD_INTERNAL;
+       default:
+               wfd_sink_error("Not Supported Surface.(default case)");
+               return MM_ERROR_WFD_INTERNAL;
        }
 
        g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
@@ -3050,14 +4247,14 @@ static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *
        return MM_ERROR_NONE;
 }
 
-static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
 {
        GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
        MMWFDSinkGstElement *v_decodebin = NULL;
        GstObject *parent = NULL;
        int i;
 
-       wfd_sink_debug_fenter();
+       wfd_sink_error_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
 
@@ -3076,7 +4273,7 @@ static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
                wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
 
                if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
-                       wfd_sink_debug("try to change state of video decodebin to NULL");
+                       wfd_sink_error("try to change state of video decodebin to NULL");
                        ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
                        if (ret != GST_STATE_CHANGE_SUCCESS) {
                                wfd_sink_error("failed to change state of video decodebin to NULL");
@@ -3089,42 +4286,46 @@ static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
                                parent = gst_element_get_parent(v_decodebin[i].gst);
                                if (!parent) {
                                        wfd_sink_debug("unref %s(current ref %d)",
-                                                               GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
-                                                               ((GObject *) v_decodebin[i].gst)->ref_count);
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
+                                                                       ((GObject *) v_decodebin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
                                        v_decodebin[i].gst = NULL;
                                } else {
-                                       wfd_sink_debug("unref %s(current ref %d)",
-                                                               GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
-                                                               ((GObject *) v_decodebin[i].gst)->ref_count);
+                                       wfd_sink_debug("%s has parent.(current ref %d)",
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
+                                                                       ((GObject *) v_decodebin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(parent));
+                                       parent = NULL;
                                }
                        }
                }
                /* release video decodebin with it's childs */
                if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
-                       gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
                        wfd_sink_debug("unref %s(current ref %d)",
-                                               GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
-                                               ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
+                                                       GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
+                                                       ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
+
+                       gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
+                       v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
                }
        } else {
                wfd_sink_debug("video decodebin has parent(%s), unref it",
-                                       GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
+                                               GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
 
                gst_object_unref(GST_OBJECT(parent));
+               parent = NULL;
        }
 
        wfd_sink->video_decodebin_is_linked = FALSE;
 
        MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
 
-       wfd_sink_debug_fleave();
+       wfd_sink_error_fleave();
 
        return MM_ERROR_NONE;
 }
 
-static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
 {
        MMWFDSinkGstElement *v_decodebin = NULL;
        guint video_codec = WFD_VIDEO_UNKNOWN;
@@ -3135,26 +4336,40 @@ static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
 
        if (wfd_sink->pipeline->v_decodebin) {
                wfd_sink_debug("video decodebin is already created... nothing to do");
                return MM_ERROR_NONE;
        }
 
-       /* check audio decodebin could be linked now */
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE) {
+               wfd_sink_debug("Skip create video decodebin for none video codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
+
+       /* check video decodebin could be linked now */
        switch (wfd_sink->stream_info.video_stream_info.codec) {
-               case MM_WFD_SINK_VIDEO_CODEC_H264:
-                       video_codec = WFD_VIDEO_H264;
-                       link = TRUE;
-                       break;
-               case MM_WFD_SINK_VIDEO_CODEC_NONE:
-               default:
-                       wfd_sink_debug("video decodebin could NOT be linked now, just create");
-                       video_codec = wfd_sink->ini.video_codec;
-                       link = FALSE;
-                       break;
+       case MM_WFD_SINK_VIDEO_CODEC_H264:
+               video_codec = WFD_VIDEO_H264;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_VIDEO_CODEC_H265:
+               video_codec = WFD_VIDEO_H265;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_VIDEO_CODEC_VP9:
+               video_codec = WFD_VIDEO_VP9;
+               link = TRUE;
+               break;
+       case MM_WFD_SINK_VIDEO_CODEC_NONE:
+       default:
+               wfd_sink_debug("video decodebin could NOT be linked now, just create");
+               video_codec = wfd_sink->ini.wfd_video_formats.video_codec | wfd_sink->ini.wfd2_video_formats.video_codec;
+               link = FALSE;
+               break;
        }
 
        /* alloc handles */
@@ -3177,6 +4392,7 @@ static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
        /* create queue */
        MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "sink");
+       MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "src");
        if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
                __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
 
@@ -3187,21 +4403,61 @@ static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
 
        if (video_codec & WFD_VIDEO_H264) {
                /* create parser */
-               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE);
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst,  "sink");
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst,  "src");
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h264_parser", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "src");
+
+               if (!g_strcmp0(wfd_sink->ini.name_of_video_h264_decoder, "sprddec_h264") ||
+                       !g_strcmp0(wfd_sink->ini.name_of_video_h264_decoder, "omxdec_h264")) {
+                       /* acquire HW resource */
+                       wfd_sink_error("wfd_sink->ini.name_of_video_h264_decoder1 :: %s", wfd_sink->ini.name_of_video_h264_decoder);
+                       if (__mm_wfd_sink_acquire_hw_resource(wfd_sink, MM_WFD_SINK_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
+                               wfd_sink_error("failed to acquire video decoder resource");
+                               goto CREATE_ERROR;
+                       }
+               }
+
+               /* create dec */
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_DEC, wfd_sink->ini.name_of_video_h264_decoder, "video_h264_dec", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "src");
+               if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst) {
+                       if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H264_DEC].gst)) {
+                               wfd_sink_error("failed to set video decoder property...");
+                               goto CREATE_ERROR;
+                       }
+               }
+       }
+
+       if (video_codec & WFD_VIDEO_H265) {
+               /* create parser */
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_PARSE, wfd_sink->ini.name_of_video_h265_parser, "video_h265_parser", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "src");
 
-               /* create capssetter */
-               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE);
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst,  "sink");
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst,  "src");
+               /* create dec */
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_DEC, wfd_sink->ini.name_of_video_h265_decoder, "video_h265_dec", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "src");
+               if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst) {
+                       if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H265_DEC].gst)) {
+                               wfd_sink_error("failed to set video decoder property...");
+                               goto CREATE_ERROR;
+                       }
+               }
+       }
+       if (video_codec & WFD_VIDEO_VP9) {
+               /* create parser */
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_VP9_PARSE, wfd_sink->ini.name_of_video_vp9_parser, "video_vp9_parser", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_VP9_PARSE].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_VP9_PARSE].gst,  "src");
 
                /* create dec */
-               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE);
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst,  "sink");
-               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst,  "src");
-               if (v_decodebin[WFD_SINK_V_D_DEC].gst) {
-                       if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) {
+               MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_VP9_DEC, wfd_sink->ini.name_of_video_vp9_decoder, "video_vp9_dec", FALSE);
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_VP9_DEC].gst,  "sink");
+               MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_VP9_DEC].gst,  "src");
+               if (v_decodebin[WFD_SINK_V_D_VP9_DEC].gst) {
+                       if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_VP9_DEC].gst)) {
                                wfd_sink_error("failed to set video decoder property...");
                                goto CREATE_ERROR;
                        }
@@ -3243,27 +4499,30 @@ CREATE_ERROR:
                                v_decodebin[i].gst = NULL;
                        } else {
                                gst_object_unref(GST_OBJECT(parent));
+                               parent = NULL;
                        }
                }
        }
 
        /* release video decodebin with it's childs */
-       if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst)
+       if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) {
                gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
+               v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
+       }
 
        MMWFDSINK_FREEIF(v_decodebin);
 
        return MM_ERROR_WFD_INTERNAL;
 }
 
-static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
 {
        GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
        MMWFDSinkGstElement *v_sinkbin = NULL;
        GstObject *parent = NULL;
        int i;
 
-       wfd_sink_debug_fenter();
+       wfd_sink_error_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
 
@@ -3282,7 +4541,7 @@ static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
                wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
 
                if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
-                       wfd_sink_debug("try to change state of video sinkbin to NULL");
+                       wfd_sink_error("try to change state of video sinkbin to NULL");
                        ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
                        if (ret != GST_STATE_CHANGE_SUCCESS) {
                                wfd_sink_error("failed to change state of video sinkbin to NULL");
@@ -3295,37 +4554,40 @@ static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
                                parent = gst_element_get_parent(v_sinkbin[i].gst);
                                if (!parent) {
                                        wfd_sink_debug("unref %s(current ref %d)",
-                                                               GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
-                                                               ((GObject *) v_sinkbin[i].gst)->ref_count);
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
+                                                                       ((GObject *) v_sinkbin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
                                        v_sinkbin[i].gst = NULL;
                                } else {
-                                       wfd_sink_debug("unref %s(current ref %d)",
-                                                               GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
-                                                               ((GObject *) v_sinkbin[i].gst)->ref_count);
+                                       wfd_sink_debug("%s has parent.(current ref %d)",
+                                                                       GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
+                                                                       ((GObject *) v_sinkbin[i].gst)->ref_count);
                                        gst_object_unref(GST_OBJECT(parent));
+                                       parent = NULL;
                                }
                        }
                }
                /* release video sinkbin with it's childs */
                if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
                        gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
+                       v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
                }
        } else {
                wfd_sink_debug("video sinkbin has parent(%s), unref it ",
-                                       GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
+                                               GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
 
                gst_object_unref(GST_OBJECT(parent));
+               parent = NULL;
        }
 
        MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
 
-       wfd_sink_debug_fleave();
+       wfd_sink_error_fleave();
 
        return MM_ERROR_NONE;
 }
 
-static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
 {
        MMWFDSinkGstElement *first_element = NULL;
        MMWFDSinkGstElement *v_sinkbin = NULL;
@@ -3338,8 +4600,19 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_val_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline,
-                                               MM_ERROR_WFD_NOT_INITIALIZED);
+                                                               wfd_sink->pipeline,
+                                                               MM_ERROR_WFD_NOT_INITIALIZED);
+
+       if (wfd_sink->pipeline->v_sinkbin != NULL) {
+               wfd_sink_error("The video sink bin is already created.");
+               return MM_ERROR_NONE;
+       }
+
+       if (wfd_sink->stream_info.video_stream_info.codec == MM_WFD_SINK_VIDEO_CODEC_NONE) {
+               wfd_sink_error("Skip create video sink bin for non video codec.");
+               wfd_sink_debug_fleave();
+               return MM_ERROR_NONE;
+       }
 
        /* alloc handles */
        v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
@@ -3372,12 +4645,13 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
                caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL);
                g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
                gst_object_unref(GST_OBJECT(caps));
+               caps = NULL;
        }
 
        /* create sink */
        mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
-
-       if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
+       if (surface_type == MM_DISPLAY_SURFACE_OVERLAY &&
+               (__mm_wfd_sink_acquire_hw_resource(wfd_sink, MM_WFD_SINK_RESOURCE_TYPE_VIDEO_OVERLAY) == MM_ERROR_NONE)) {
                MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
        } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) {
                MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE);
@@ -3386,6 +4660,8 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
                goto CREATE_ERROR;
        }
 
+       wfd_sink->interrupted_by_resource = FALSE;
+
        MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst,  "sink");
        if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
                if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
@@ -3416,7 +4692,7 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
        pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
        if (!pad) {
                wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
-                       GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
+                                               GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
                goto CREATE_ERROR;
        }
 
@@ -3432,9 +4708,10 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
        }
 
        gst_object_unref(GST_OBJECT(pad));
+       pad = NULL;
 
        g_list_free(element_bucket);
-
+       element_bucket = NULL;
 
        /* take it */
        wfd_sink->pipeline->v_sinkbin = v_sinkbin;
@@ -3447,15 +4724,20 @@ static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
 CREATE_ERROR:
        wfd_sink_error("failed to create video sinkbin, releasing all");
 
-       if (pad)
+       if (pad) {
                gst_object_unref(GST_OBJECT(pad));
-       pad = NULL;
+               pad = NULL;
+       }
 
-       if (ghostpad)
+       if (ghostpad) {
                gst_object_unref(GST_OBJECT(ghostpad));
-       ghostpad = NULL;
+               ghostpad = NULL;
+       }
 
-       g_list_free(element_bucket);
+       if (element_bucket) {
+               g_list_free(element_bucket);
+               element_bucket = NULL;
+       }
 
        /* release element which are not added to bin */
        for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
@@ -3468,22 +4750,25 @@ CREATE_ERROR:
                                v_sinkbin[i].gst = NULL;
                        } else {
                                gst_object_unref(GST_OBJECT(parent));
+                               parent = NULL;
                        }
                }
        }
 
        /* release video sinkbin with it's childs */
-       if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst)
+       if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) {
                gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
-
+               v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
+       }
        MMWFDSINK_FREEIF(v_sinkbin);
 
        return MM_ERROR_WFD_INTERNAL;
 }
 
-static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
+int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
 {
        GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+       GstBus *bus = NULL;
 
        wfd_sink_debug_fenter();
 
@@ -3494,12 +4779,31 @@ static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
                MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
 
                if (mainbin) {
+
+                       PRINT_WFD_REF_COUNT(wfd_sink);
+
                        ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
                        if (ret != GST_STATE_CHANGE_SUCCESS) {
-                               wfd_sink_error("failed to change state of mainbin to NULL");
+                               wfd_sink_error("failed to change state of pipeline to NULL. ret[%d]", ret);
                                return MM_ERROR_WFD_INTERNAL;
+                       } else {
+                               wfd_sink_debug("Successed to change state of pipeline to NULL");
+                       }
+
+                       bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
+                       if (bus) {
+                               GstMessage *gst_msg = NULL;
+                               while ((gst_msg = gst_bus_pop(bus)) != NULL) {
+                                       _mm_wfd_sink_msg_callback(bus, gst_msg, (gpointer)wfd_sink);
+                                       gst_message_unref(gst_msg);
+                                       gst_msg = NULL;
+                               }
+                               gst_object_unref(bus);
+                               bus = NULL;
                        }
 
+                       PRINT_WFD_REF_COUNT(wfd_sink);
+
                        if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
                                wfd_sink_error("failed to destroy video decodebin");
                                return MM_ERROR_WFD_INTERNAL;
@@ -3521,6 +4825,7 @@ static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
                        }
 
                        gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
+                       mainbin[WFD_SINK_M_PIPE].gst = NULL;
 
                        MMWFDSINK_FREEIF(mainbin);
                }
@@ -3528,9 +4833,15 @@ static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
                MMWFDSINK_FREEIF(wfd_sink->pipeline);
        }
 
+       if (wfd_sink->msg_callback_id > 0) {
+               g_source_remove(wfd_sink->msg_callback_id);
+               wfd_sink->msg_callback_id = 0;
+       }
+
        wfd_sink->audio_decodebin_is_linked = FALSE;
        wfd_sink->video_decodebin_is_linked = FALSE;
        wfd_sink->need_to_reset_basetime = FALSE;
+       wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
 
        wfd_sink_debug_fleave();
 
@@ -3553,41 +4864,42 @@ __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
        wfd_sink_debug_fenter();
 
        wfd_sink_return_if_fail(wfd_sink &&
-                                               wfd_sink->pipeline &&
-                                               wfd_sink->pipeline->mainbin &&
-                                               wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
+                                                       wfd_sink->pipeline &&
+                                                       wfd_sink->pipeline->mainbin &&
+                                                       wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
 
        iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
 
        if (iter != NULL) {
                while (!done) {
                        switch (gst_iterator_next(iter, (gpointer)&item)) {
-                               case GST_ITERATOR_OK:
-                                       gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
-
-                                       factory = gst_element_get_factory(item) ;
-                                       if (factory) {
-                                               wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
-                                                                       GST_STR_NULL(GST_OBJECT_NAME(factory)),
-                                                                       GST_STR_NULL(GST_ELEMENT_NAME(item)),
-                                                                       gst_element_state_get_name(state),
-                                                                       gst_element_state_get_name(pending),
-                                                                       GST_OBJECT_REFCOUNT_VALUE(item));
-                                       }
-                                       gst_object_unref(item);
-                                       break;
-                               case GST_ITERATOR_RESYNC:
-                                       gst_iterator_resync(iter);
-                                       break;
-                               case GST_ITERATOR_ERROR:
-                                       done = TRUE;
-                                       break;
-                               case GST_ITERATOR_DONE:
-                                       done = TRUE;
-                                       break;
-                               default:
-                                       done = TRUE;
-                                       break;
+                       case GST_ITERATOR_OK:
+                               gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
+
+                               factory = gst_element_get_factory(item) ;
+                               if (factory) {
+                                       wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
+                                               GST_STR_NULL(GST_OBJECT_NAME(factory)),
+                                               GST_STR_NULL(GST_ELEMENT_NAME(item)),
+                                               gst_element_state_get_name(state),
+                                               gst_element_state_get_name(pending),
+                                               GST_OBJECT_REFCOUNT_VALUE(item));
+                               }
+                               gst_object_unref(item);
+                               item = NULL;
+                               break;
+                       case GST_ITERATOR_RESYNC:
+                               gst_iterator_resync(iter);
+                               break;
+                       case GST_ITERATOR_ERROR:
+                               done = TRUE;
+                               break;
+                       case GST_ITERATOR_DONE:
+                               done = TRUE;
+                               break;
+                       default:
+                               done = TRUE;
+                               break;
                        }
                }
        }
@@ -3599,11 +4911,11 @@ __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
        factory = gst_element_get_factory(item) ;
        if (factory) {
                wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
-                                       GST_OBJECT_NAME(factory),
-                                       GST_ELEMENT_NAME(item),
-                                       gst_element_state_get_name(state),
-                                       gst_element_state_get_name(pending),
-                                       GST_OBJECT_REFCOUNT_VALUE(item));
+                                               GST_OBJECT_NAME(factory),
+                                               GST_ELEMENT_NAME(item),
+                                               gst_element_state_get_name(state),
+                                               gst_element_state_get_name(pending),
+                                               GST_OBJECT_REFCOUNT_VALUE(item));
        }
 
        if (iter)
@@ -3614,58 +4926,29 @@ __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
        return;
 }
 
-const gchar * _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
+const gchar *
+_mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
 {
        switch (state) {
-               case MM_WFD_SINK_STATE_NONE:
-                       return "NONE";
-               case MM_WFD_SINK_STATE_NULL:
-                       return "NULL";
-               case MM_WFD_SINK_STATE_PREPARED:
-                       return "PREPARED";
-               case MM_WFD_SINK_STATE_CONNECTED:
-                       return "CONNECTED";
-               case MM_WFD_SINK_STATE_PLAYING:
-                       return "PLAYING";
-               case MM_WFD_SINK_STATE_PAUSED:
-                       return "PAUSED";
-               case MM_WFD_SINK_STATE_DISCONNECTED:
-                       return "DISCONNECTED";
-               default:
-                       return "INVAID";
+       case MM_WFD_SINK_STATE_NONE:
+               return "NONE";
+       case MM_WFD_SINK_STATE_NULL:
+               return "NULL";
+       case MM_WFD_SINK_STATE_PREPARED:
+               return "PREPARED";
+       case MM_WFD_SINK_STATE_CONNECTED:
+               return "CONNECTED";
+       case MM_WFD_SINK_STATE_PLAYING:
+               return "PLAYING";
+       case MM_WFD_SINK_STATE_PAUSED:
+               return "PAUSED";
+       case MM_WFD_SINK_STATE_DISCONNECTED:
+               return "DISCONNECTED";
+       default:
+               return "INVAID";
        }
 }
 
-static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution)
-{
-       if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
-
-       *CEA_resolution = 0;
-       *VESA_resolution = 0;
-       *HH_resolution = 0;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
-               *CEA_resolution |= WFD_CEA_1920x1080P30;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
-               *CEA_resolution |= WFD_CEA_1280x720P30;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
-               *HH_resolution |= WFD_HH_960x540P30;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
-               *HH_resolution |= WFD_HH_864x480P30;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
-               *CEA_resolution |= WFD_CEA_720x480P60;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
-               *CEA_resolution |= WFD_CEA_640x480P60;
-
-       if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
-               *HH_resolution |= WFD_HH_640x360P30;
-}
-
 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
 {
        MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
@@ -3687,3 +4970,178 @@ int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution res
 
        return MM_ERROR_NONE;
 }
+
+int _mm_wfd_sink_set_display_overlay(mm_wfd_sink_t *wfd_sink, void *display_object)
+{
+       int wl_surface_id = 0;
+       static void *display_overlay = NULL;
+       int wl_window_x = 0;
+       int wl_window_y = 0;
+       int wl_window_width = 0;
+       int wl_window_height = 0;
+       struct wl_surface *wl_surface = NULL;
+       struct wl_display *wl_display = NULL;
+       Ecore_Wl2_Window *wl2_window = NULL;
+       Ecore_Wl2_Display *wl2_display = NULL;
+       wl_client *wlclient = NULL;
+       Evas_Object *obj = NULL;
+       void *object = display_object;
+       const char *object_type = NULL;
+       int ret = 0;
+       pid_t pid = getpid();
+       pid_t tid = syscall(SYS_gettid);
+
+       if (pid != tid) {
+               wfd_sink_error("API isn't called in main thread");
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       if (object == NULL) {
+               wfd_sink_debug("display object is NULL!");
+               return MM_ERROR_WFD_INTERNAL;
+       }
+       obj = (Evas_Object *)object;
+       object_type = evas_object_type_get(obj);
+       wfd_sink_debug("window object type : %s", object_type);
+
+       if (strcmp(object_type, "elm_win")) {
+               wfd_sink_error("Window type is not elm_win");
+               return MM_ERROR_WFD_INTERNAL;
+       }
+
+       /* wayland overlay surface */
+       wfd_sink_info("Wayland overlay surface type");
+       evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height);
+
+       wfd_sink_debug("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y,
+                                       wl_window_width, wl_window_height);
+
+       wl2_window = ecore_evas_wayland2_window_get(ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
+       ecore_wl2_window_video_has(wl2_window, EINA_TRUE);
+       wl_surface = ecore_wl2_window_surface_get(wl2_window);
+
+       /* get wl_display */
+       wl2_display = ecore_wl2_connected_display_get(NULL);
+       wl_display = ecore_wl2_display_get(wl2_display);
+
+       wfd_sink_debug("previous display object : %p current object : %p", display_overlay, object);
+       if (wl_surface && wl_display && (wl_surface_id == 0 || display_overlay != object)) {
+               wfd_sink_debug("surface = %p, wl_display = %p", wl_surface, wl_display);
+               display_overlay = object;
+
+               ret = mm_wfd_sink_wlclient_create(&wlclient);
+               if (ret != MM_ERROR_NONE) {
+                       wfd_sink_error("Wayland client create failure");
+                       return MM_ERROR_WFD_INTERNAL;
+               }
+               wfd_sink_debug("Try to get surface id");
+
+               wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id(wlclient, wl_surface, wl_display);
+
+               wfd_sink_debug("wl_surface_id = %d", wl_surface_id);
+               if (wl_surface_id == 0) {
+                       wfd_sink_error("wl_surface_id cannot be zero.");
+                       return MM_ERROR_WFD_INTERNAL;
+               }
+               wfd_sink->display_surface_id = wl_surface_id;
+
+               if (wlclient) {
+                       g_free(wlclient);
+                       wlclient = NULL;
+               }
+       }
+       return MM_ERROR_NONE;
+}
+
+void __mm_wfd_sink_print_ref_count(mm_wfd_sink_t *wfd_sink)
+{
+       int i = 0;
+       MMWFDSinkGstElement *mainbin = NULL;
+       MMWFDSinkGstElement *v_decodebin = NULL;
+       MMWFDSinkGstElement *a_decodebin = NULL;
+       MMWFDSinkGstElement *v_sinkbin = NULL;
+       MMWFDSinkGstElement *a_sinkbin = NULL;
+
+       wfd_sink_debug_fenter();
+
+       wfd_sink_return_if_fail(wfd_sink);
+       wfd_sink_return_if_fail(wfd_sink->pipeline);
+
+       wfd_sink_debug("************* wfd pipeline ref count start *************");
+       wfd_sink_debug("try to check mainbin");
+
+       if (wfd_sink->pipeline->mainbin &&
+           wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) {
+               mainbin = wfd_sink->pipeline->mainbin;
+
+               for (i = 0; i < WFD_SINK_M_NUM; i++) {
+                       if (mainbin[i].gst) {
+                               wfd_sink_debug("%s(current ref %d)",
+                                                               GST_ELEMENT_NAME(mainbin[i].gst),
+                                                               GST_OBJECT_REFCOUNT(mainbin[i].gst));
+                       }
+               }
+       }
+
+       wfd_sink_debug("try to check a_decodebin");
+
+       if (wfd_sink->pipeline->a_decodebin &&
+           wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
+               a_decodebin = wfd_sink->pipeline->a_decodebin;
+
+               for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
+                       if (a_decodebin[i].gst) {
+                               wfd_sink_debug("%s(current ref %d)",
+                                                               GST_ELEMENT_NAME(a_decodebin[i].gst),
+                                                               GST_OBJECT_REFCOUNT(a_decodebin[i].gst));
+                       }
+               }
+       }
+
+       wfd_sink_debug("try to check a_sinkbin");
+
+       if (wfd_sink->pipeline->a_sinkbin &&
+           wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
+               a_sinkbin = wfd_sink->pipeline->a_sinkbin;
+
+               for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
+                       if (a_sinkbin[i].gst) {
+                               wfd_sink_debug("%s(current ref %d)",
+                                                               GST_ELEMENT_NAME(a_sinkbin[i].gst),
+                                                               GST_OBJECT_REFCOUNT(a_sinkbin[i].gst));
+                       }
+               }
+       }
+
+       wfd_sink_debug("try to check v_decodebin");
+
+       if (wfd_sink->pipeline->v_decodebin &&
+           wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
+               v_decodebin = wfd_sink->pipeline->v_decodebin;
+
+               for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
+                       if (v_decodebin[i].gst) {
+                               wfd_sink_debug("%s(current ref %d)",
+                                                               GST_ELEMENT_NAME(v_decodebin[i].gst),
+                                                               GST_OBJECT_REFCOUNT(v_decodebin[i].gst));
+                       }
+               }
+       }
+
+       wfd_sink_debug("try to check v_sinkbin");
+
+       if (wfd_sink->pipeline->v_sinkbin &&
+           wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
+               v_sinkbin = wfd_sink->pipeline->v_sinkbin;
+
+               for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
+                       if (v_sinkbin[i].gst) {
+                               wfd_sink_debug("%s(current ref %d)",
+                                                               GST_ELEMENT_NAME(v_sinkbin[i].gst),
+                                                               GST_OBJECT_REFCOUNT(v_sinkbin[i].gst));
+                       }
+               }
+       }
+       wfd_sink_debug("************* wfd pipeline ref count end *************");
+       wfd_sink_debug_fleave();
+}