Fix memory leak
[platform/core/multimedia/libmm-wfd.git] / src / mm_wfd_sink_priv.c
1 /*
2  * libmm-wfd
3  *
4  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, ByungWook Jang <bw.jang@samsung.com>,
7  * Maksym Ukhanov <m.ukhanov@samsung.com>, Hyunjun Ko <zzoon.ko@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include <gst/gst.h>
24 #include <gst/video/videooverlay.h>
25 #include <Elementary.h>
26 #include <Ecore_Wayland.h>
27
28 #include "mm_wfd_sink_util.h"
29 #include "mm_wfd_sink_priv.h"
30 #include "mm_wfd_sink_manager.h"
31 #include "mm_wfd_sink_dlog.h"
32 #include "mm_wfd_sink_enum.h"
33 #include "mm_wfd_sink_wayland.h"
34 #include "mm_wfd_sink_config.h"
35
36 #define PRINT_WFD_REF_COUNT(wfd_sink)\
37         do {\
38                 wfd_sink_debug("PRINT WFD REF COUNT");\
39                 __mm_wfd_sink_print_ref_count(wfd_sink);\
40         } while (0);
41
42 /* gstreamer */
43 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
44 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
45 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
46 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
47 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
48 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink);
49 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
50 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
51 static gboolean _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data);
52
53 /* state */
54 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
55
56 /* util */
57 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
58
59 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink, const char *ini_path)
60 {
61         int result = MM_ERROR_NONE;
62
63         wfd_sink_debug_fenter();
64
65         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
66         if (ini_path == NULL) {
67                 ini_path = MM_WFD_SINK_INI_DEFAULT_PATH;
68                 wfd_sink_debug("The wfd ini file path is set as defalut[%s]", ini_path);
69         }
70
71         mm_wfd_sink_t *new_wfd_sink = NULL;
72
73         /* create handle */
74         new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
75         if (!new_wfd_sink) {
76                 wfd_sink_error("failed to allocate memory for wi-fi display sink");
77                 return MM_ERROR_WFD_NO_FREE_SPACE;
78         }
79
80         /* Initialize gstreamer related */
81         new_wfd_sink->attrs = 0;
82
83         new_wfd_sink->pipeline = NULL;
84         new_wfd_sink->audio_decodebin_is_linked = FALSE;
85         new_wfd_sink->video_decodebin_is_linked = FALSE;
86
87         /* Initialize timestamp compensation related */
88         new_wfd_sink->need_to_reset_basetime = FALSE;
89         new_wfd_sink->clock = NULL;
90         new_wfd_sink->video_buffer_count = 0LL;
91         new_wfd_sink->video_average_gap = 0LL;
92         new_wfd_sink->video_accumulated_gap = 0LL;
93         new_wfd_sink->audio_buffer_count = 0LL;
94         new_wfd_sink->audio_average_gap = 0LL;
95         new_wfd_sink->audio_accumulated_gap = 0LL;
96         new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
97
98         /* Initialize all states */
99         MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
100         MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
101         MMWFDSINK_PENDING_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
102
103         /* initialize audio/video information */
104         new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
105         new_wfd_sink->stream_info.audio_stream_info.channels = 0;
106         new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
107         new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
108         new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
109         new_wfd_sink->stream_info.video_stream_info.width = 0;
110         new_wfd_sink->stream_info.video_stream_info.height = 0;
111         new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
112
113         /* Initialize command */
114         new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
115         new_wfd_sink->waiting_cmd = FALSE;
116
117         /* Initialize manager related */
118         new_wfd_sink->manager_thread = NULL;
119         new_wfd_sink->manager_thread_cmd = NULL;
120         new_wfd_sink->manager_thread_exit = FALSE;
121
122         /* Initialize video resolution */
123         new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
124
125         /* construct attributes */
126         new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
127         if (!new_wfd_sink->attrs) {
128                 MMWFDSINK_FREEIF(new_wfd_sink);
129                 wfd_sink_error("failed to set attribute");
130                 return MM_ERROR_WFD_INTERNAL;
131         }
132
133         /* load ini for initialize */
134         result = mm_wfd_sink_ini_load(&new_wfd_sink->ini, ini_path);
135         if (result != MM_ERROR_NONE) {
136                 wfd_sink_error("failed to load ini file[%s]", ini_path);
137                 goto fail_to_load_ini;
138         }
139         new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
140
141         /* initialize manager */
142         result = _mm_wfd_sink_init_manager(new_wfd_sink);
143         if (result < MM_ERROR_NONE) {
144                 wfd_sink_error("failed to init manager : %d", result);
145                 goto fail_to_init;
146         }
147
148         /* initialize gstreamer */
149         result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
150         if (result < MM_ERROR_NONE) {
151                 wfd_sink_error("failed to init gstreamer : %d", result);
152                 goto fail_to_init;
153         }
154
155         /* set state */
156         __mm_wfd_sink_set_state(new_wfd_sink,  MM_WFD_SINK_STATE_NULL);
157
158         /* now take handle */
159         *wfd_sink = new_wfd_sink;
160
161         wfd_sink_debug_fleave();
162
163         return result;
164
165         /* ERRORS */
166 fail_to_init:
167         mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
168 fail_to_load_ini:
169         _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
170         MMWFDSINK_FREEIF(new_wfd_sink);
171
172         *wfd_sink = NULL;
173
174         return result;
175 }
176
177 int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink)
178 {
179         int result = MM_ERROR_NONE;
180
181         wfd_sink_debug_fenter();
182
183         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
184
185         /* check current wi-fi display sink state */
186         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
187
188         /* construct pipeline */
189         /* create main pipeline */
190         result = __mm_wfd_sink_create_pipeline(wfd_sink);
191         if (result < MM_ERROR_NONE) {
192                 wfd_sink_error("failed to create pipeline : %d", result);
193                 goto fail_to_create;
194         }
195
196         wfd_sink_info("Current session mode : %d", wfd_sink->ini.sink_session_mode);
197         if (wfd_sink->ini.sink_session_mode & (WFD_SESSION_MODE_MIXED | WFD_SESSION_MODE_VIDEO_ONLY)) {
198                 /* create video decodebin */
199                 result = __mm_wfd_sink_create_video_decodebin(wfd_sink);
200                 if (result < MM_ERROR_NONE) {
201                         wfd_sink_error("failed to create video decodebin %d", result);
202                         goto fail_to_create;
203                 }
204
205                 /* create video sinkbin */
206                 result = __mm_wfd_sink_create_video_sinkbin(wfd_sink);
207                 if (result < MM_ERROR_NONE) {
208                         wfd_sink_error("failed to create video sinkbin %d", result);
209                         goto fail_to_create;
210                 }
211         }
212
213         /* create audio decodebin */
214         result = __mm_wfd_sink_create_audio_decodebin(wfd_sink);
215         if (result < MM_ERROR_NONE) {
216                 wfd_sink_error("fail to create audio decodebin : %d", result);
217                 goto fail_to_create;
218         }
219
220         /* create audio sinkbin */
221         result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink);
222         if (result < MM_ERROR_NONE) {
223                 wfd_sink_error("fail to create audio sinkbin : %d", result);
224                 goto fail_to_create;
225         }
226
227         /* set pipeline READY state */
228         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
229         if (result < MM_ERROR_NONE) {
230                 wfd_sink_error("failed to set state : %d", result);
231                 goto fail_to_create;
232         }
233
234         /* set state */
235         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PREPARED);
236
237         wfd_sink_debug_fleave();
238
239         return result;
240
241         /* ERRORS */
242 fail_to_create:
243         /* need to destroy pipeline already created */
244         __mm_wfd_sink_destroy_pipeline(wfd_sink);
245         return result;
246 }
247
248 int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
249 {
250         int result = MM_ERROR_NONE;
251
252         wfd_sink_debug_fenter();
253
254         wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
255                                                                 MM_ERROR_WFD_INVALID_ARGUMENT);
256         wfd_sink_return_val_if_fail(wfd_sink &&
257                                                                 wfd_sink->pipeline &&
258                                                                 wfd_sink->pipeline->mainbin &&
259                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
260                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
261                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
262                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
263                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
264
265         /* check current wi-fi display sink state */
266         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
267
268         wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
269
270         /* set uri to wfdsrc */
271         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
272
273         /* set pipeline PAUSED state */
274         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
275         if (result < MM_ERROR_NONE) {
276                 wfd_sink_error("failed to set state : %d", result);
277                 return result;
278         }
279
280         wfd_sink_debug_fleave();
281
282         return result;
283 }
284
285 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
286 {
287         int result = MM_ERROR_NONE;
288
289         wfd_sink_debug_fenter();
290
291         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
292
293         /* check current wi-fi display sink state */
294         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
295
296         WFD_SINK_MANAGER_LOCK(wfd_sink) ;
297         wfd_sink_debug("check pipeline is ready to start");
298         WFD_SINK_MANAGER_UNLOCK(wfd_sink);
299
300         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
301         if (result < MM_ERROR_NONE) {
302                 wfd_sink_error("failed to set state : %d", result);
303                 return result;
304         }
305
306         wfd_sink_debug_fleave();
307
308         return result;
309 }
310
311 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
312 {
313         int result = MM_ERROR_NONE;
314
315         wfd_sink_debug_fenter();
316
317         wfd_sink_return_val_if_fail(wfd_sink &&
318                                                                 wfd_sink->pipeline &&
319                                                                 wfd_sink->pipeline->mainbin &&
320                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
321                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
322                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
323
324         /* check current wi-fi display sink state */
325         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
326
327         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-pause", NULL);
328
329         wfd_sink_debug_fleave();
330
331         return result;
332 }
333
334 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
335 {
336         int result = MM_ERROR_NONE;
337
338         wfd_sink_debug_fenter();
339
340         wfd_sink_return_val_if_fail(wfd_sink &&
341                                                                 wfd_sink->pipeline &&
342                                                                 wfd_sink->pipeline->mainbin &&
343                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
344                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
345                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
346
347         /* check current wi-fi display sink state */
348         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
349
350         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-resume", NULL);
351
352         wfd_sink_debug_fleave();
353
354         return result;
355 }
356
357 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
358 {
359         int result = MM_ERROR_NONE;
360
361         wfd_sink_debug_fenter();
362
363         wfd_sink_return_val_if_fail(wfd_sink &&
364                                                                 wfd_sink->pipeline &&
365                                                                 wfd_sink->pipeline->mainbin &&
366                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
367                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
368                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
369
370         /* check current wi-fi display sink state */
371         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
372
373         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
374         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
375
376         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-close", NULL);
377
378         wfd_sink_debug_fleave();
379
380         return result;
381 }
382
383 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
384 {
385         int result = MM_ERROR_NONE;
386
387         wfd_sink_debug_fenter();
388
389         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
390
391         /* check current wi-fi display sink state */
392         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
393
394         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
395         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
396
397         /* release pipeline */
398         result =  __mm_wfd_sink_destroy_pipeline(wfd_sink);
399         if (result != MM_ERROR_NONE) {
400                 wfd_sink_error("failed to destory pipeline");
401                 return MM_ERROR_WFD_INTERNAL;
402         } else {
403                 wfd_sink_debug("success to destory pipeline");
404         }
405
406         /* set state */
407         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NULL);
408
409         wfd_sink_debug_fleave();
410
411         return result;
412 }
413
414 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
415 {
416         int result = MM_ERROR_NONE;
417
418         wfd_sink_debug_fenter();
419
420         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
421
422         /* check current wi-fi display sink state */
423         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
424
425         /* unload ini */
426         mm_wfd_sink_ini_unload(&wfd_sink->ini);
427
428         /* release attributes */
429         _mmwfd_deconstruct_attribute(wfd_sink->attrs);
430
431         /* release manager thread  */
432         if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
433                 wfd_sink_error("failed to release manager");
434                 return MM_ERROR_WFD_INTERNAL;
435         }
436
437         /* set state */
438         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NONE);
439
440         wfd_sink_debug_fleave();
441
442         return result;
443 }
444
445 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
446 {
447         int result = MM_ERROR_NONE;
448
449         wfd_sink_debug_fenter();
450
451         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
452
453         wfd_sink->msg_cb = callback;
454         wfd_sink->msg_user_data = user_data;
455
456         wfd_sink_debug_fleave();
457
458         return result;
459 }
460
461 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
462 {
463         int result = MM_ERROR_NONE;
464         gint *argc = NULL;
465         gchar **argv = NULL;
466         static const int max_argc = 50;
467         GError *err = NULL;
468         gint i = 0;
469
470         wfd_sink_debug_fenter();
471
472         /* alloc */
473         argc = calloc(1, sizeof(gint));
474         argv = calloc(max_argc, sizeof(gchar *));
475         if (!argc || !argv) {
476                 wfd_sink_error("failed to allocate memory for wfdsink");
477
478                 MMWFDSINK_FREEIF(argv);
479                 MMWFDSINK_FREEIF(argc);
480
481                 return MM_ERROR_WFD_NO_FREE_SPACE;
482         }
483
484         /* we would not do fork for scanning plugins */
485         argv[*argc] = g_strdup("--gst-disable-registry-fork");
486         (*argc)++;
487
488         /* check disable registry scan */
489         argv[*argc] = g_strdup("--gst-disable-registry-update");
490         (*argc)++;
491
492         /* check disable segtrap */
493         argv[*argc] = g_strdup("--gst-disable-segtrap");
494         (*argc)++;
495
496         /* check ini */
497         for (i = 0; i < 5; i++) {
498                 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
499                         wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
500                         argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
501                         (*argc)++;
502                 }
503         }
504
505         wfd_sink_debug("initializing gstreamer with following parameter");
506         wfd_sink_debug("argc : %d", *argc);
507
508         for (i = 0; i < *argc; i++)
509                 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
510
511         /* initializing gstreamer */
512         if (!gst_init_check(argc, &argv, &err)) {
513                 wfd_sink_error("failed to initialize gstreamer: %s",
514                                                 err ? err->message : "unknown error occurred");
515                 if (err)
516                         g_error_free(err);
517
518                 result = MM_ERROR_WFD_INTERNAL;
519         }
520
521         /* release */
522         for (i = 0; i < *argc; i++)
523                 MMWFDSINK_FREEIF(argv[i]);
524
525         MMWFDSINK_FREEIF(argv);
526         MMWFDSINK_FREEIF(argc);
527
528         wfd_sink_debug_fleave();
529
530         return result;
531 }
532
533 static GstBusSyncReply
534 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
535 {
536         GstBusSyncReply ret = GST_BUS_PASS;
537
538         wfd_sink_return_val_if_fail(message &&
539                                                                 GST_IS_MESSAGE(message) &&
540                                                                 GST_MESSAGE_SRC(message),
541                                                                 GST_BUS_DROP);
542
543         wfd_sink_debug("get message %p, %s from %p, %s", message,
544                                         GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC(message), GST_MESSAGE_SRC_NAME(message));
545
546         switch (GST_MESSAGE_TYPE(message)) {
547         case GST_MESSAGE_TAG:
548                 break;
549         case GST_MESSAGE_DURATION:
550                 break;
551         case GST_MESSAGE_STATE_CHANGED:
552                 /* we only handle state change messages from pipeline */
553                 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
554                         _mm_wfd_sink_msg_callback(bus, message, data);
555
556                 ret = GST_BUS_DROP;
557                 break;
558         case GST_MESSAGE_ASYNC_DONE:
559                 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
560                         _mm_wfd_sink_msg_callback(bus, message, data);
561
562                 ret = GST_BUS_DROP;
563                 break;
564         default:
565                 break;
566         }
567
568         if (ret == GST_BUS_DROP) {
569                 gst_message_unref(message);
570                 message = NULL;
571         }
572
573         return ret;
574 }
575
576 int __mm_wfd_sink_activate_audio_stream(mm_wfd_sink_t *wfd_sink)
577 {
578         GstElement *valve = NULL;
579         GstPad *sinkpad = NULL;
580         GstPad *srcpad = NULL;
581         int result = MM_ERROR_NONE;
582
583         wfd_sink_debug_fenter();
584
585         wfd_sink_return_val_if_fail(wfd_sink &&
586                                                                 wfd_sink->pipeline &&
587                                                                 wfd_sink->pipeline->mainbin &&
588                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
589                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
590                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
591
592         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
593         srcpad = gst_element_get_static_pad(valve, "src");
594         if (!srcpad) {
595                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
596                 goto error;
597         }
598
599         if (gst_pad_is_linked(srcpad)) {
600                 wfd_sink_debug("%s:%s is already linked to %s:%s",
601                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
602                 goto done;
603         }
604
605         result = __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad);
606         if (MM_ERROR_NONE != result) {
607                 wfd_sink_error("failed to prepare audio pipeline....");
608                 goto error;
609         }
610
611         wfd_sink_debug("try to link %s:%s and %s:%s",
612                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
613                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
614         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
615                 wfd_sink_error("failed to link %s:%s and %s:%s",
616                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
617                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
618                 goto error;
619         }
620
621         if (sinkpad != NULL) {
622                 gst_object_unref(GST_OBJECT(sinkpad));
623                 sinkpad = NULL;
624         }
625
626 done:
627         if (srcpad != NULL) {
628                 gst_object_unref(GST_OBJECT(srcpad));
629                 srcpad = NULL;
630         }
631         /* drop all the audio buffers using valve */
632         g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
633
634         wfd_sink_debug_fleave();
635
636         return MM_ERROR_NONE;
637
638 error:
639         if (srcpad != NULL) {
640                 gst_object_unref(GST_OBJECT(srcpad));
641                 srcpad = NULL;
642         }
643
644         if (sinkpad != NULL) {
645                 gst_object_unref(GST_OBJECT(sinkpad));
646                 sinkpad = NULL;
647         }
648
649         wfd_sink_debug_fleave();
650         return MM_ERROR_WFD_INTERNAL;
651 }
652
653 int __mm_wfd_sink_activate_video_stream(mm_wfd_sink_t *wfd_sink)
654 {
655         GstElement *valve = NULL;
656         GstPad *sinkpad = NULL;
657         GstPad *srcpad = NULL;
658         int result = MM_ERROR_NONE;
659
660         wfd_sink_debug_fenter();
661
662         wfd_sink_return_val_if_fail(wfd_sink &&
663                                                                 wfd_sink->pipeline &&
664                                                                 wfd_sink->pipeline->mainbin &&
665                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
666                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
667                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
668
669         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
670         srcpad = gst_element_get_static_pad(valve, "src");
671         if (!srcpad) {
672                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
673                 goto error;
674         }
675
676         if (gst_pad_is_linked(srcpad)) {
677                 wfd_sink_debug("%s is already linked",
678                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
679                 goto done;
680         }
681
682         result = __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad);
683         if (MM_ERROR_NONE != result) {
684                 wfd_sink_error("failed to prepare video pipeline....");
685                 goto error;
686         }
687
688         wfd_sink_debug("try to link %s:%s and %s:%s",
689                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
690                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
691         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
692                 wfd_sink_error("failed to link %s:%s and %s:%s",
693                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
694                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
695                 goto error;
696         }
697         if (sinkpad != NULL) {
698                 gst_object_unref(GST_OBJECT(sinkpad));
699                 sinkpad = NULL;
700         }
701
702 done:
703         if (srcpad != NULL) {
704                 gst_object_unref(GST_OBJECT(srcpad));
705                 srcpad = NULL;
706         }
707         /* drop all the video buffers using valve */
708         g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
709
710         wfd_sink_debug_fleave();
711
712         return MM_ERROR_NONE;
713
714 error:
715         if (srcpad != NULL) {
716                 gst_object_unref(GST_OBJECT(srcpad));
717                 srcpad = NULL;
718         }
719
720         if (sinkpad != NULL) {
721                 gst_object_unref(GST_OBJECT(sinkpad));
722                 sinkpad = NULL;
723         }
724
725         wfd_sink_debug_fleave();
726         return MM_ERROR_WFD_INTERNAL;
727 }
728
729 int __mm_wfd_sink_deactivate_audio_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
730 {
731         int ret = MM_ERROR_NONE;
732
733         wfd_sink_debug_fenter();
734
735         wfd_sink_return_val_if_fail(wfd_sink &&
736                                                                 wfd_sink->pipeline &&
737                                                                 wfd_sink->pipeline->mainbin &&
738                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
739                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
740                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
741
742         /* drop all the audio buffers using valve */
743         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst), "drop", TRUE, NULL);
744
745         if (unprepare) {
746                 /* unprepare audio pipeline */
747                 ret = __mm_wfd_sink_unprepare_audio_pipeline(wfd_sink);
748                 if (ret != MM_ERROR_NONE) {
749                         wfd_sink_error("failed to unprepare audio pipeline...");
750                         return MM_ERROR_WFD_INTERNAL;
751                 }
752         }
753
754         wfd_sink_debug_fleave();
755
756         return MM_ERROR_NONE;
757 }
758
759 int __mm_wfd_sink_deactivate_video_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
760 {
761         int ret = MM_ERROR_NONE;
762
763         wfd_sink_debug_fenter();
764
765         wfd_sink_return_val_if_fail(wfd_sink &&
766                                                                 wfd_sink->pipeline &&
767                                                                 wfd_sink->pipeline->mainbin &&
768                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
769                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
770                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
771
772         /* drop all the video buffers using valve */
773         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst), "drop", TRUE, NULL);
774
775         if (unprepare) {
776                 /* unprepare video pipeline */
777                 ret = __mm_wfd_sink_unprepare_video_pipeline(wfd_sink);
778                 if (ret != MM_ERROR_NONE) {
779                         wfd_sink_error("failed to unprepare video pipeline...");
780                         return MM_ERROR_WFD_INTERNAL;
781                 }
782         }
783
784         wfd_sink_debug_fleave();
785
786         return MM_ERROR_NONE;
787
788 }
789
790 static gboolean
791 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
792 {
793         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
794         const GstStructure *message_structure = gst_message_get_structure(msg);
795         gboolean ret = TRUE;
796         gchar *getname = NULL;
797
798         wfd_sink_return_val_if_fail(wfd_sink, FALSE);
799         wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
800
801         wfd_sink_debug("got %s(%d) from %s",
802                                         GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
803                                         GST_MESSAGE_TYPE(msg),
804                                         GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
805
806         switch (GST_MESSAGE_TYPE(msg)) {
807         case GST_MESSAGE_ERROR: {
808                         GError *error = NULL;
809                         gchar *debug = NULL;
810
811                         /* get error code */
812                         gst_message_parse_error(msg, &error, &debug);
813
814                         wfd_sink_error("error : %s", error->message);
815                         wfd_sink_error("debug : %s", debug);
816
817                         MMWFDSINK_FREEIF(debug);
818                         g_error_free(error);
819                 }
820                 break;
821
822         case GST_MESSAGE_WARNING: {
823                         char *debug = NULL;
824                         GError *error = NULL;
825
826                         gst_message_parse_warning(msg, &error, &debug);
827
828                         wfd_sink_error("warning : %s", error->message);
829                         wfd_sink_error("debug : %s", debug);
830
831                         MMWFDSINK_FREEIF(debug);
832                         g_error_free(error);
833                 }
834                 break;
835
836         case GST_MESSAGE_STATE_CHANGED: {
837                         const GValue *voldstate, *vnewstate, *vpending;
838                         GstState oldstate, newstate, pending;
839                         const GstStructure *structure;
840
841                         /* get state info from msg */
842                         structure = gst_message_get_structure(msg);
843                         if (structure == NULL)
844                                 break;
845
846                         voldstate = gst_structure_get_value(structure, "old-state");
847                         vnewstate = gst_structure_get_value(structure, "new-state");
848                         vpending = gst_structure_get_value(structure, "pending-state");
849                         if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
850                                 break;
851
852                         oldstate = (GstState)voldstate->data[0].v_int;
853                         newstate = (GstState)vnewstate->data[0].v_int;
854                         pending = (GstState)vpending->data[0].v_int;
855
856                         wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
857                                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
858                                                 gst_element_state_get_name((GstState)oldstate),
859                                                 gst_element_state_get_name((GstState)newstate),
860                                                 gst_element_state_get_name((GstState)pending));
861
862                         /* we only handle messages from pipeline */
863                         if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
864                                 break;
865
866                         if (oldstate == newstate) {
867                                 wfd_sink_debug("pipeline reports state transition to old state");
868                                 break;
869                         }
870
871                         switch (newstate) {
872                         case GST_STATE_VOID_PENDING:
873                         case GST_STATE_NULL:
874                         case GST_STATE_READY:
875                         case GST_STATE_PAUSED:
876                         case GST_STATE_PLAYING:
877                         default:
878                                 break;
879                         }
880                 }
881                 break;
882
883         case GST_MESSAGE_CLOCK_LOST: {
884                         GstClock *clock = NULL;
885                         gst_message_parse_clock_lost(msg, &clock);
886                         wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
887                                         (clock ? GST_OBJECT_NAME(clock) : "NULL"));
888                 }
889                 break;
890
891         case GST_MESSAGE_NEW_CLOCK: {
892                         GstClock *clock = NULL;
893                         gst_message_parse_new_clock(msg, &clock);
894                         if (!clock)
895                                 break;
896
897                         if (wfd_sink->clock) {
898                                 if (wfd_sink->clock != clock)
899                                         wfd_sink_debug("clock is changed! [%s] -->[%s]",
900                                                                         GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
901                                                                         GST_STR_NULL(GST_OBJECT_NAME(clock)));
902                                 else
903                                         wfd_sink_debug("same clock is selected again! [%s]",
904                                                                         GST_STR_NULL(GST_OBJECT_NAME(clock)));
905                         } else {
906                                 wfd_sink_debug("new clock [%s] was selected in the pipeline",
907                                                                 (GST_STR_NULL(GST_OBJECT_NAME(clock))));
908                         }
909
910                         wfd_sink->clock = clock;
911                 }
912                 break;
913
914         case GST_MESSAGE_APPLICATION: {
915                         const gchar *message_structure_name;
916
917                         message_structure_name = gst_structure_get_name(message_structure);
918                         if (!message_structure_name)
919                                 break;
920
921                         wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
922                 }
923                 break;
924
925         case GST_MESSAGE_ELEMENT: {
926                         const gchar *structure_name = NULL;
927
928                         structure_name = gst_structure_get_name(message_structure);
929                         if (structure_name) {
930                                 wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
931                                 if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
932                                         wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
933                                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
934                                                                         MM_ERROR_WFD_INTERNAL,
935                                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
936                                 } else if (g_strrstr(structure_name, "GstWFDSessionTimeout")) {
937                                         wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
938                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
939                                                                         MM_ERROR_WFD_INTERNAL,
940                                                                         MM_WFD_SINK_STATE_DISCONNECTED);
941                                 }
942                         }
943                 }
944                 break;
945
946         case GST_MESSAGE_PROGRESS: {
947                         GstProgressType type = GST_PROGRESS_TYPE_ERROR;
948                         gchar *category = NULL, *text = NULL;
949
950                         gst_message_parse_progress(msg, &type, &category, &text);
951                         wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
952
953                         switch (type) {
954                         case GST_PROGRESS_TYPE_START:
955                                 break;
956                         case GST_PROGRESS_TYPE_COMPLETE:
957                                 if (category && !strcmp(category, "open")) {
958                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_CONNECTED);
959                                 } else if (category && !strcmp(category, "play")) {
960                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PLAYING);
961                                         /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
962                                 } else if (category && !strcmp(category, "pause")) {
963                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PAUSED);
964                                 } else if (category && !strcmp(category, "close")) {
965                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
966                                 }
967                                 break;
968                         case GST_PROGRESS_TYPE_CANCELED:
969                                 break;
970                         case GST_PROGRESS_TYPE_ERROR:
971                                 if (category && !strcmp(category, "open")) {
972                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
973                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
974                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
975                                                         MM_ERROR_WFD_INTERNAL,
976                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
977                                 } else if (category && !strcmp(category, "play")) {
978                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
979                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
980                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
981                                                                 MM_ERROR_WFD_INTERNAL,
982                                                                 MMWFDSINK_CURRENT_STATE(wfd_sink));
983                                 } else if (category && !strcmp(category, "pause")) {
984                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
985                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
986                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
987                                                         MM_ERROR_WFD_INTERNAL,
988                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
989                                 } else if (category && !strcmp(category, "close")) {
990                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
991                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
992                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
993                                                         MM_ERROR_WFD_INTERNAL,
994                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
995                                 } else {
996                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
997                                 }
998                                 break;
999                         default:
1000                                 wfd_sink_error("progress message has no type");
1001                                 return ret;
1002                         }
1003
1004                         MMWFDSINK_FREEIF(category);
1005                         MMWFDSINK_FREEIF(text);
1006                 }
1007                 break;
1008
1009         case GST_MESSAGE_ASYNC_START:
1010                 getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
1011                 wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", getname);
1012                 MMWFDSINK_FREEIF(getname);
1013                 break;
1014         case GST_MESSAGE_ASYNC_DONE:
1015                 getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
1016                 wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", getname);
1017                 MMWFDSINK_FREEIF(getname);
1018                 break;
1019         case GST_MESSAGE_UNKNOWN:
1020         case GST_MESSAGE_INFO:
1021         case GST_MESSAGE_TAG:
1022         case GST_MESSAGE_BUFFERING:
1023         case GST_MESSAGE_EOS:
1024         case GST_MESSAGE_STATE_DIRTY:
1025         case GST_MESSAGE_STEP_DONE:
1026         case GST_MESSAGE_CLOCK_PROVIDE:
1027         case GST_MESSAGE_STRUCTURE_CHANGE:
1028         case GST_MESSAGE_STREAM_STATUS:
1029         case GST_MESSAGE_SEGMENT_START:
1030         case GST_MESSAGE_SEGMENT_DONE:
1031         case GST_MESSAGE_DURATION:
1032         case GST_MESSAGE_LATENCY:
1033         case GST_MESSAGE_REQUEST_STATE:
1034         case GST_MESSAGE_STEP_START:
1035         case GST_MESSAGE_QOS:
1036         case GST_MESSAGE_ANY:
1037                 break;
1038         default:
1039                 wfd_sink_debug("unhandled message");
1040                 break;
1041         }
1042
1043         return ret;
1044 }
1045
1046 int
1047 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
1048 {
1049         GList *bucket = element_bucket;
1050         MMWFDSinkGstElement *element = NULL;
1051         int successful_add_count = 0;
1052
1053         wfd_sink_debug_fenter();
1054
1055         wfd_sink_return_val_if_fail(element_bucket, 0);
1056         wfd_sink_return_val_if_fail(bin, 0);
1057
1058         for (; bucket; bucket = bucket->next) {
1059                 element = (MMWFDSinkGstElement *)bucket->data;
1060
1061                 if (element && element->gst) {
1062                         if (need_prepare)
1063                                 gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY);
1064
1065                         if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
1066                                 wfd_sink_error("failed to add element [%s] to bin [%s]",
1067                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1068                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1069                                 return 0;
1070                         }
1071
1072                         wfd_sink_debug("add element [%s] to bin [%s]",
1073                                                         GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1074                                                         GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1075
1076                         successful_add_count++;
1077                 }
1078         }
1079
1080         wfd_sink_debug_fleave();
1081
1082         return successful_add_count;
1083 }
1084
1085 int
1086 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
1087 {
1088         GList *bucket = element_bucket;
1089         MMWFDSinkGstElement *element = NULL;
1090         MMWFDSinkGstElement *prv_element = NULL;
1091         gint successful_link_count = 0;
1092
1093         wfd_sink_debug_fenter();
1094
1095         wfd_sink_return_val_if_fail(element_bucket, -1);
1096
1097         prv_element = (MMWFDSinkGstElement *)bucket->data;
1098         bucket = bucket->next;
1099
1100         for (; bucket; bucket = bucket->next) {
1101                 element = (MMWFDSinkGstElement *)bucket->data;
1102
1103                 if (element && element->gst) {
1104                         if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
1105                                 wfd_sink_debug("linking [%s] to [%s] success",
1106                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1107                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1108                                 successful_link_count++;
1109                         } else {
1110                                 wfd_sink_error("linking [%s] to [%s] failed",
1111                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1112                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1113                                 return -1;
1114                         }
1115                 }
1116
1117                 prv_element = element;
1118         }
1119
1120         wfd_sink_debug_fleave();
1121
1122         return successful_link_count;
1123 }
1124
1125 int
1126 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
1127 {
1128         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
1129
1130         wfd_sink_debug_fenter();
1131
1132         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1133
1134         MMWFDSINK_PRINT_STATE(wfd_sink);
1135
1136         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
1137
1138         switch (cmd) {
1139         case MM_WFD_SINK_COMMAND_CREATE:
1140                 if (cur_state != MM_WFD_SINK_STATE_NONE)
1141                         goto invalid_state;
1142
1143                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1144                 break;
1145
1146         case MM_WFD_SINK_COMMAND_PREPARE:
1147                 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
1148                         goto no_operation;
1149                 else if (cur_state != MM_WFD_SINK_STATE_NULL)
1150                         goto invalid_state;
1151
1152                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
1153                 break;
1154
1155         case MM_WFD_SINK_COMMAND_CONNECT:
1156                 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
1157                         goto no_operation;
1158                 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
1159                         goto invalid_state;
1160
1161                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
1162                 break;
1163
1164         case MM_WFD_SINK_COMMAND_START:
1165                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1166                         goto no_operation;
1167                 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
1168                         goto invalid_state;
1169
1170                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1171                 break;
1172
1173         case MM_WFD_SINK_COMMAND_PAUSE:
1174                 if (cur_state == MM_WFD_SINK_STATE_PAUSED)
1175                         goto no_operation;
1176                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
1177                         goto invalid_state;
1178
1179                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
1180                 break;
1181
1182         case MM_WFD_SINK_COMMAND_RESUME:
1183                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1184                         goto no_operation;
1185                 else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
1186                         goto invalid_state;
1187
1188                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1189                 break;
1190
1191         case MM_WFD_SINK_COMMAND_DISCONNECT:
1192                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1193                     cur_state == MM_WFD_SINK_STATE_NULL ||
1194                     cur_state == MM_WFD_SINK_STATE_PREPARED ||
1195                     cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
1196                         goto no_operation;
1197                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
1198                         cur_state != MM_WFD_SINK_STATE_CONNECTED &&
1199                         cur_state != MM_WFD_SINK_STATE_PAUSED)
1200                         goto invalid_state;
1201
1202                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
1203                 break;
1204
1205         case MM_WFD_SINK_COMMAND_UNPREPARE:
1206                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1207                     cur_state == MM_WFD_SINK_STATE_NULL)
1208                         goto no_operation;
1209
1210                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1211                 break;
1212
1213         case MM_WFD_SINK_COMMAND_DESTROY:
1214                 if (cur_state == MM_WFD_SINK_STATE_NONE)
1215                         goto no_operation;
1216
1217                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1218                 break;
1219
1220         default:
1221                 break;
1222         }
1223
1224         wfd_sink->cmd = cmd;
1225
1226         wfd_sink_debug_fleave();
1227
1228         return MM_ERROR_NONE;
1229
1230 no_operation:
1231         wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state));
1232         return MM_ERROR_WFD_NO_OP;
1233
1234         /* ERRORS */
1235 invalid_state:
1236         wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
1237         return MM_ERROR_WFD_INVALID_STATE;
1238 }
1239
1240 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
1241 {
1242         wfd_sink_debug_fenter();
1243
1244         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1245
1246         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) {
1247                 wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state));
1248                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1249                 return MM_ERROR_NONE;
1250         }
1251
1252         /* update wi-fi display state */
1253         MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1254         MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1255
1256         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
1257                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1258
1259         /* post state message to application */
1260         MMWFDSINK_POST_MESSAGE(wfd_sink,
1261                                                         MM_ERROR_NONE,
1262                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1263
1264         /* print state */
1265         MMWFDSINK_PRINT_STATE(wfd_sink);
1266
1267         wfd_sink_debug_fleave();
1268
1269         return MM_ERROR_NONE;
1270 }
1271
1272 static int
1273 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
1274 {
1275         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1276         GstState cur_state = GST_STATE_VOID_PENDING;
1277         GstState pending_state = GST_STATE_VOID_PENDING;
1278
1279         wfd_sink_debug_fenter();
1280
1281         wfd_sink_return_val_if_fail(wfd_sink &&
1282                                                                 wfd_sink->pipeline &&
1283                                                                 wfd_sink->pipeline->mainbin &&
1284                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1285                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1286
1287         wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING,
1288                                                                 MM_ERROR_WFD_INVALID_ARGUMENT);
1289
1290         wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1291
1292         result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1293         if (result == GST_STATE_CHANGE_FAILURE) {
1294                 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1295                 return MM_ERROR_WFD_INTERNAL;
1296         }
1297
1298         if (!async) {
1299                 wfd_sink_debug("wait for changing state is completed ");
1300
1301                 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1302                                                                                 &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1303                 if (result == GST_STATE_CHANGE_FAILURE) {
1304                         wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1305
1306                         __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1307
1308                         return MM_ERROR_WFD_INTERNAL;
1309                 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1310                         wfd_sink_debug("successfully changed state but is not able to provide data yet");
1311                 }
1312
1313                 wfd_sink_debug("cur state is %s, pending state is %s",
1314                                                 gst_element_state_get_name(cur_state),
1315                                                 gst_element_state_get_name(pending_state));
1316         }
1317
1318
1319         wfd_sink_debug_fleave();
1320
1321         return MM_ERROR_NONE;
1322 }
1323
1324 static void
1325 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1326 {
1327         GstClockTime base_time = GST_CLOCK_TIME_NONE;
1328         int i;
1329
1330         wfd_sink_debug_fenter();
1331
1332         wfd_sink_return_if_fail(wfd_sink &&
1333                                                         wfd_sink->pipeline &&
1334                                                         wfd_sink->pipeline->mainbin &&
1335                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1336         wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1337
1338
1339         if (wfd_sink->clock)
1340                 base_time = gst_clock_get_time(wfd_sink->clock);
1341
1342         if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1343
1344                 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1345
1346                 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1347                         if (wfd_sink->pipeline->mainbin[i].gst)
1348                                 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1349                 }
1350
1351                 if (wfd_sink->pipeline->v_decodebin) {
1352                         for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1353                                 if (wfd_sink->pipeline->v_decodebin[i].gst)
1354                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1355                         }
1356                 }
1357
1358                 if (wfd_sink->pipeline->v_sinkbin) {
1359                         for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1360                                 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1361                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1362                         }
1363                 }
1364
1365                 if (wfd_sink->pipeline->a_decodebin) {
1366                         for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1367                                 if (wfd_sink->pipeline->a_decodebin[i].gst)
1368                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1369                         }
1370                 }
1371
1372                 if (wfd_sink->pipeline->a_sinkbin) {
1373                         for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1374                                 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1375                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1376                         }
1377                 }
1378
1379                 wfd_sink->need_to_reset_basetime = FALSE;
1380         }
1381
1382         wfd_sink_debug_fleave();
1383
1384         return;
1385 }
1386
1387 int
1388 __mm_wfd_sink_unprepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1389 {
1390         GstElement *pipeline  = NULL;
1391         GstElement *v_decodebin  = NULL;
1392         GstElement *v_sinkbin  = NULL;
1393         GstPad *sinkpad = NULL;
1394         GstPad *srcpad = NULL;
1395         int ret = MM_ERROR_NONE;
1396
1397         wfd_sink_debug_fenter();
1398
1399         wfd_sink_return_val_if_fail(wfd_sink &&
1400                                                                 wfd_sink->pipeline,
1401                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1402
1403         PRINT_WFD_REF_COUNT(wfd_sink);
1404         wfd_sink_error("No-error:unprepare video sink bin");
1405         if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1406                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1407
1408                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin)))) {
1409                         sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1410                         if (!sinkpad) {
1411                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_sinkbin));
1412                                 goto ERROR;
1413                         }
1414
1415                         if (gst_pad_is_linked(sinkpad)) {
1416                                 srcpad = gst_pad_get_peer(sinkpad);
1417                                 if (!srcpad) {
1418                                         wfd_sink_error("failed to get peer pad of %s:%s",
1419                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1420                                         goto ERROR;
1421                                 }
1422
1423                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1424                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1425                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1426                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1427                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1428                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1429                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1430                                         goto ERROR;
1431                                 }
1432                                 gst_object_unref(srcpad);
1433                                 srcpad = NULL;
1434                         } else {
1435                                 wfd_sink_debug("video sinkbin's sinkpad is not linked, no need to unlink it");
1436                         }
1437                         gst_object_unref(sinkpad);
1438                         sinkpad = NULL;
1439
1440                         gst_object_ref(v_sinkbin);
1441                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1442                                 wfd_sink_error("failed to remove %s from %s",
1443                                                                 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1444                                 goto ERROR;
1445                         }
1446
1447                         gst_object_unref(pipeline);
1448                         pipeline = NULL;
1449                 }
1450
1451                 ret = __mm_wfd_sink_destroy_video_sinkbin(wfd_sink);
1452                 if (ret != MM_ERROR_NONE) {
1453                         wfd_sink_error("failed to destroy video sinkbin");
1454                         goto ERROR;
1455                 }
1456         }
1457         PRINT_WFD_REF_COUNT(wfd_sink);
1458
1459         wfd_sink_error("No-error:unprepare video decode bin");
1460         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1461                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1462
1463                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin)))) {
1464                         sinkpad = gst_element_get_static_pad(v_decodebin, "sink");
1465                         if (!sinkpad) {
1466                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_decodebin));
1467                                 goto ERROR;
1468                         }
1469
1470                         if (gst_pad_is_linked(sinkpad)) {
1471                                 srcpad = gst_pad_get_peer(sinkpad);
1472                                 if (!srcpad) {
1473                                         wfd_sink_error("failed to get peer pad of %s:%s",
1474                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1475                                         goto ERROR;
1476                                 }
1477
1478                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1479                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1480                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1481                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1482                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1483                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1484                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1485                                         goto ERROR;
1486                                 }
1487                                 gst_object_unref(srcpad);
1488                                 srcpad = NULL;
1489                         } else {
1490                                 wfd_sink_debug("video decodebin's sinkpad is not linked, no need to unlink it");
1491                         }
1492                         gst_object_unref(sinkpad);
1493                         sinkpad = NULL;
1494
1495                         srcpad = gst_element_get_static_pad(v_decodebin, "src");
1496                         if (!srcpad) {
1497                                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(v_decodebin));
1498                                 goto ERROR;
1499                         }
1500
1501                         if (gst_pad_is_linked(srcpad)) {
1502                                 sinkpad = gst_pad_get_peer(srcpad);
1503                                 if (!sinkpad) {
1504                                         wfd_sink_error("failed to get peer pad of %s:%s",
1505                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1506                                         goto ERROR;
1507                                 }
1508
1509                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1510                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1511                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1512                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1513                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1514                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1515                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1516                                         goto ERROR;
1517                                 }
1518                                 gst_object_unref(sinkpad);
1519                                 sinkpad = NULL;
1520                         } else {
1521                                 wfd_sink_debug("video decodebin's srcpad is not linked, no need to unlink it");
1522                         }
1523                         gst_object_unref(srcpad);
1524                         srcpad = NULL;
1525
1526                         wfd_sink_error("try to remove %s from %s",
1527                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1528                         gst_object_ref(v_decodebin);
1529                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1530                                 wfd_sink_error("failed to remove %s from %s",
1531                                                                 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1532                                 goto ERROR;
1533                         }
1534
1535                         gst_object_unref(pipeline);
1536                         pipeline = NULL;
1537                 }
1538
1539                 ret = __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
1540                 if (ret != MM_ERROR_NONE) {
1541                         wfd_sink_error("failed to destroy video decodebin");
1542                         goto ERROR;
1543                 }
1544         }
1545         PRINT_WFD_REF_COUNT(wfd_sink);
1546
1547         wfd_sink_debug_fleave();
1548
1549         return ret;
1550
1551         /* ERRORS */
1552 ERROR:
1553         if (pipeline) {
1554                 gst_object_unref(pipeline);
1555                 pipeline = NULL;
1556         }
1557
1558         if (sinkpad) {
1559                 gst_object_unref(sinkpad);
1560                 sinkpad = NULL;
1561         }
1562
1563         if (srcpad) {
1564                 gst_object_unref(srcpad);
1565                 srcpad = NULL;
1566         }
1567
1568         /* need to notify to app */
1569         MMWFDSINK_POST_MESSAGE(wfd_sink,
1570                                                         MM_ERROR_WFD_INTERNAL,
1571                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1572
1573         return MM_ERROR_WFD_INTERNAL;
1574 }
1575
1576 int
1577 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1578 {
1579         GstElement *pipeline  = NULL;
1580         GstElement *v_decodebin  = NULL;
1581         GstElement *v_sinkbin  = NULL;
1582         GstPad *srcpad = NULL;
1583         GstPad *sinkpad = NULL;
1584
1585         wfd_sink_debug_fenter();
1586
1587         wfd_sink_return_val_if_fail(wfd_sink &&
1588                                                                 wfd_sink->pipeline &&
1589                                                                 wfd_sink->pipeline->mainbin &&
1590                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1591                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1592
1593         /* check video decodebin is linked */
1594         if (!wfd_sink->video_decodebin_is_linked) {
1595                 /* check video decodebin is created */
1596                 if (wfd_sink->pipeline->v_decodebin == NULL) {
1597                         if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1598                                 wfd_sink_error("failed to create video decodebin....");
1599                                 goto ERROR;
1600                         }
1601                 }
1602
1603                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1604                         wfd_sink_error("failed to link video decodebin.....");
1605                         goto ERROR;
1606                 }
1607         }
1608
1609         /* check video sinkbin is created */
1610         if (wfd_sink->pipeline->v_sinkbin == NULL) {
1611                 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1612                         wfd_sink_error("failed to create video sinkbin....");
1613                         goto ERROR;
1614                 }
1615         }
1616         /* add video decodebin to pipeline */
1617         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1618                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1619
1620                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin));
1621                 if (!pipeline) {
1622                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1623
1624                         if (GST_STATE(v_decodebin) <= GST_STATE_NULL) {
1625                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_decodebin));
1626                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_decodebin, GST_STATE_READY)) {
1627                                         wfd_sink_error("failed to set state(READY) to video decodebin");
1628                                         goto ERROR;
1629                                 }
1630                         }
1631
1632                         wfd_sink_debug("try to add %s to %s",
1633                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1634                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1635                                 wfd_sink_error("failed to add %s to %s",
1636                                                                 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1637                                 goto ERROR;
1638                         }
1639
1640                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_decodebin));
1641                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_decodebin))) {
1642                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_decodebin));
1643                                 goto ERROR;
1644                         }
1645                 } else {
1646                         wfd_sink_debug("%s is already added to %s",
1647                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1648                         gst_object_unref(pipeline);
1649                         pipeline = NULL;
1650                 }
1651         } else {
1652                 wfd_sink_warning("going on without video decodebin....");
1653         }
1654
1655         /* add video sinkbin to pipeline */
1656         if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1657                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1658
1659                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin));
1660                 if (!pipeline) {
1661                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1662
1663                         /* prepare video sinkbin before adding */
1664                         if (GST_STATE(v_sinkbin) <= GST_STATE_NULL) {
1665                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_sinkbin));
1666                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_sinkbin, GST_STATE_READY)) {
1667                                         wfd_sink_error("failed to set state(READY) to video sinkbin");
1668                                         goto ERROR;
1669                                 }
1670                         }
1671                         /* add video sinkbin to pipeline */
1672                         wfd_sink_debug("try to  add %s to %s",
1673                                                         GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1674                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1675                                 wfd_sink_error("failed to add %s to %s",
1676                                                                 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1677                                 goto ERROR;
1678                         }
1679
1680                         /* sync state with parent */
1681                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_sinkbin));
1682                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_sinkbin))) {
1683                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_sinkbin));
1684                                 goto ERROR;
1685                         }
1686                 } else {
1687                         wfd_sink_debug("%s is already added to %s",
1688                                                         GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1689                         gst_object_unref(pipeline);
1690                         pipeline = NULL;
1691                 }
1692         } else {
1693                 wfd_sink_warning("going on without video sinkbin....");
1694         }
1695
1696
1697         /* link video decodebin and sinkbin */
1698         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1699                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1700
1701                 if (pad)
1702                         *pad = gst_element_get_static_pad(v_decodebin, "sink");
1703
1704                 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1705
1706                         v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1707
1708                         srcpad = gst_element_get_static_pad(v_decodebin, "src");
1709                         if (!srcpad) {
1710                                 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(v_decodebin));
1711                                 goto ERROR;
1712                         }
1713
1714                         if (!gst_pad_is_linked(srcpad)) {
1715                                 sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1716                                 if (!sinkpad) {
1717                                         wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(v_sinkbin));
1718                                         goto ERROR;
1719                                 }
1720
1721                                 wfd_sink_debug("try to link %s:%s and %s:%s",
1722                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1723                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1724                                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
1725                                         wfd_sink_error("failed to link %s:%s and %s:%s",
1726                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1727                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1728                                         goto ERROR;
1729                                 }
1730                                 gst_object_unref(sinkpad);
1731                                 sinkpad = NULL;
1732                         }
1733                         gst_object_unref(srcpad);
1734                         srcpad = NULL;
1735                 }
1736         } else if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1737                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1738                 if (pad)
1739                         *pad = gst_element_get_static_pad(v_sinkbin, "sink");
1740         }
1741
1742         wfd_sink_debug_fleave();
1743
1744         return MM_ERROR_NONE;
1745
1746         /* ERRORS */
1747 ERROR:
1748         if (sinkpad != NULL) {
1749                 gst_object_unref(sinkpad);
1750                 sinkpad = NULL;
1751         }
1752
1753         if (srcpad != NULL) {
1754                 gst_object_unref(srcpad);
1755                 srcpad = NULL;
1756         }
1757
1758         /* need to notify to app */
1759         MMWFDSINK_POST_MESSAGE(wfd_sink,
1760                                                         MM_ERROR_WFD_INTERNAL,
1761                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1762
1763         return MM_ERROR_WFD_INTERNAL;
1764 }
1765
1766 int
1767 __mm_wfd_sink_unprepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1768 {
1769         GstElement *pipeline  = NULL;
1770         GstElement *a_decodebin  = NULL;
1771         GstElement *a_sinkbin  = NULL;
1772         GstPad *sinkpad = NULL;
1773         GstPad *srcpad = NULL;
1774         int ret = MM_ERROR_NONE;
1775
1776         wfd_sink_debug_fenter();
1777
1778         wfd_sink_return_val_if_fail(wfd_sink &&
1779                                                                 wfd_sink->pipeline,
1780                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1781
1782         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
1783                 wfd_sink_debug("Skip unprepare audio pipeline for none audio codec.");
1784                 wfd_sink_debug_fleave();
1785                 return MM_ERROR_NONE;
1786         }
1787
1788         wfd_sink_error("No-error:unprepare audio sink bin");
1789         PRINT_WFD_REF_COUNT(wfd_sink);
1790
1791         if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1792                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1793
1794                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin)))) {
1795                         sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
1796                         if (!sinkpad) {
1797                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_sinkbin));
1798                                 goto ERROR;
1799                         }
1800
1801                         if (gst_pad_is_linked(sinkpad)) {
1802                                 srcpad = gst_pad_get_peer(sinkpad);
1803                                 if (!srcpad) {
1804                                         wfd_sink_error("failed to get peer pad of %s:%s",
1805                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1806                                         goto ERROR;
1807                                 }
1808
1809                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1810                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1811                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1812                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1813                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1814                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1815                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1816                                         goto ERROR;
1817                                 }
1818                                 gst_object_unref(srcpad);
1819                                 srcpad = NULL;
1820                         } else {
1821                                 wfd_sink_debug("audio sinkbin's sinkpad is not linked, no need to unlink it");
1822                         }
1823                         gst_object_unref(sinkpad);
1824                         sinkpad = NULL;
1825
1826                         gst_object_ref(a_sinkbin);
1827                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
1828                                 wfd_sink_error("failed to remove %s from %s",
1829                                                                 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
1830                                 goto ERROR;
1831                         }
1832
1833                         gst_object_unref(pipeline);
1834                         pipeline = NULL;
1835                 }
1836
1837                 ret = __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink);
1838                 if (ret != MM_ERROR_NONE) {
1839                         wfd_sink_error("failed to destroy audio sinkbin");
1840                         goto ERROR;
1841                 }
1842         }
1843         PRINT_WFD_REF_COUNT(wfd_sink);
1844
1845         wfd_sink_error("No-error:unprepare audio decode bin");
1846         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1847                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1848
1849                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin)))) {
1850                         sinkpad = gst_element_get_static_pad(a_decodebin, "sink");
1851                         if (!sinkpad) {
1852                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_decodebin));
1853                                 goto ERROR;
1854                         }
1855
1856                         if (gst_pad_is_linked(sinkpad)) {
1857                                 srcpad = gst_pad_get_peer(sinkpad);
1858                                 if (!srcpad) {
1859                                         wfd_sink_error("failed to get peer pad of %s:%s",
1860                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1861                                         goto ERROR;
1862                                 }
1863
1864                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1865                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1866                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1867                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1868                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1869                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1870                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1871                                         goto ERROR;
1872                                 }
1873                                 gst_object_unref(srcpad);
1874                                 srcpad = NULL;
1875                         } else {
1876                                 wfd_sink_debug("audio decodebin's sinkpad is not linked, no need to unlink it");
1877                         }
1878                         gst_object_unref(sinkpad);
1879                         sinkpad = NULL;
1880
1881                         srcpad = gst_element_get_static_pad(a_decodebin, "src");
1882                         if (!srcpad) {
1883                                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(a_decodebin));
1884                                 goto ERROR;
1885                         }
1886
1887                         if (gst_pad_is_linked(srcpad)) {
1888                                 sinkpad = gst_pad_get_peer(srcpad);
1889                                 if (!sinkpad) {
1890                                         wfd_sink_error("failed to get peer pad of %s:%s",
1891                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1892                                         return MM_ERROR_WFD_INTERNAL;
1893                                 }
1894
1895                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1896                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1897                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1898                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1899                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1900                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1901                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1902                                         return MM_ERROR_WFD_INTERNAL;
1903                                 }
1904                                 gst_object_unref(sinkpad);
1905                                 sinkpad = NULL;
1906                         } else {
1907                                 wfd_sink_debug("audio decodebin's srcpad is not linked, no need to unlink it");
1908                         }
1909                         gst_object_unref(srcpad);
1910                         srcpad = NULL;
1911
1912                         wfd_sink_error("try to remove %s from %s",
1913                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1914                         gst_object_ref(a_decodebin);
1915                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
1916                                 wfd_sink_error("failed to remove %s from %s",
1917                                                                 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1918                                 goto ERROR;
1919                         }
1920
1921                         gst_object_unref(pipeline);
1922                         pipeline = NULL;
1923                 }
1924
1925                 ret = __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
1926                 if (ret != MM_ERROR_NONE) {
1927                         wfd_sink_error("failed to destroy audio decodebin");
1928                         goto ERROR;
1929                 }
1930         }
1931         PRINT_WFD_REF_COUNT(wfd_sink);
1932
1933         wfd_sink_debug_fleave();
1934
1935         return ret;
1936
1937         /* ERRORS */
1938 ERROR:
1939         if (pipeline) {
1940                 gst_object_unref(pipeline);
1941                 pipeline = NULL;
1942         }
1943         if (sinkpad) {
1944                 gst_object_unref(sinkpad);
1945                 sinkpad = NULL;
1946         }
1947
1948         if (srcpad) {
1949                 gst_object_unref(srcpad);
1950                 srcpad = NULL;
1951         }
1952
1953         /* need to notify to app */
1954         MMWFDSINK_POST_MESSAGE(wfd_sink,
1955                                                         MM_ERROR_WFD_INTERNAL,
1956                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1957
1958         return MM_ERROR_WFD_INTERNAL;
1959 }
1960
1961 int
1962 __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1963 {
1964         GstElement *pipeline  = NULL;
1965         GstElement *a_decodebin  = NULL;
1966         GstElement *a_sinkbin  = NULL;
1967         GstPad *srcpad = NULL;
1968         GstPad *sinkpad = NULL;
1969
1970         wfd_sink_debug_fenter();
1971
1972         wfd_sink_return_val_if_fail(wfd_sink &&
1973                                                                 wfd_sink->pipeline &&
1974                                                                 wfd_sink->pipeline->mainbin &&
1975                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1976                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1977
1978         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
1979                 wfd_sink_debug("Skip prepare audio pipeline for none audio codec");
1980                 wfd_sink_debug_fleave();
1981                 return MM_ERROR_NONE;
1982         }
1983
1984         /* check audio decodebin is linked */
1985         if (!wfd_sink->audio_decodebin_is_linked) {
1986                 /* check audio decodebin is created */
1987                 if (wfd_sink->pipeline->a_decodebin == NULL) {
1988                         if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1989                                 wfd_sink_error("failed to create audio decodebin....");
1990                                 goto ERROR;
1991                         }
1992                 }
1993
1994                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1995                         wfd_sink_error("failed to link audio decodebin.....");
1996                         goto ERROR;
1997                 }
1998         }
1999
2000         /* check audio sinkbin is created */
2001         if (wfd_sink->pipeline->a_sinkbin == NULL) {
2002                 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
2003                         wfd_sink_error("failed to create audio sinkbin....");
2004                         goto ERROR;
2005                 }
2006         }
2007
2008         /* add audio decodebin to pipeline */
2009         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2010                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
2011
2012                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin));
2013                 if (!pipeline) {
2014                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2015
2016                         if (GST_STATE(a_decodebin) <= GST_STATE_NULL) {
2017                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_decodebin));
2018                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_decodebin, GST_STATE_READY)) {
2019                                         wfd_sink_error("failed to set state(READY) to audio decodebin");
2020                                         goto ERROR;
2021                                 }
2022                         }
2023
2024                         wfd_sink_debug("try to add %s to %s",
2025                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2026                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
2027                                 wfd_sink_error("failed to add %s to %s",
2028                                                                 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2029                                 goto ERROR;
2030                         }
2031
2032                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_decodebin));
2033                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_decodebin))) {
2034                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_decodebin));
2035                                 goto ERROR;
2036                         }
2037                 } else {
2038                         wfd_sink_debug("%s is already added to %s",
2039                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2040                         gst_object_unref(pipeline);
2041                         pipeline = NULL;
2042                 }
2043         } else {
2044                 wfd_sink_warning("going on without audio decodebin....");
2045         }
2046
2047         /* add audio sinkbin to pipeline */
2048         if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2049                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2050
2051                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin));
2052                 if (!pipeline) {
2053                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2054
2055                         /* prepare audio sinkbin before adding */
2056                         if (GST_STATE(a_sinkbin) <= GST_STATE_NULL) {
2057                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_sinkbin));
2058                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_sinkbin, GST_STATE_READY)) {
2059                                         wfd_sink_error("failed to set state(READY) to audio sinkbin");
2060                                         goto ERROR;
2061                                 }
2062                         }
2063
2064                         /* add audio sinkbin to pipeline */
2065                         wfd_sink_debug("try to  add %s to %s",
2066                                                         GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2067                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
2068                                 wfd_sink_error("failed to add %s to %s",
2069                                                                 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2070                                 goto ERROR;
2071                         }
2072
2073                         /* sync state with parent */
2074                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_sinkbin));
2075                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_sinkbin))) {
2076                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_sinkbin));
2077                                 goto ERROR;
2078                         }
2079                 } else {
2080                         wfd_sink_debug("%s is already added to %s",
2081                                                         GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2082                         gst_object_unref(pipeline);
2083                         pipeline = NULL;
2084                 }
2085         } else {
2086                 wfd_sink_warning("going on without audio sinkbin....");
2087         }
2088
2089
2090         /* link audio decodebin and sinkbin */
2091         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2092                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
2093
2094                 if (pad)
2095                         *pad = gst_element_get_static_pad(a_decodebin, "sink");
2096
2097                 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2098
2099                         a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2100
2101                         srcpad = gst_element_get_static_pad(a_decodebin, "src");
2102                         if (!srcpad) {
2103                                 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(a_decodebin));
2104                                 goto ERROR;
2105                         }
2106
2107                         if (!gst_pad_is_linked(srcpad)) {
2108                                 sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
2109                                 if (!sinkpad) {
2110                                         wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(a_sinkbin));
2111                                         goto ERROR;
2112                                 }
2113
2114                                 wfd_sink_debug("try to link %s:%s and %s:%s",
2115                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2116                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2117                                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2118                                         wfd_sink_error("failed to link %s:%s and %s:%s",
2119                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2120                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2121
2122                                         goto ERROR;
2123                                 }
2124                                 gst_object_unref(sinkpad);
2125                                 sinkpad = NULL;
2126                         }
2127                         gst_object_unref(srcpad);
2128                         srcpad = NULL;
2129                 }
2130         } else if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2131                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2132                 if (pad)
2133                         *pad = gst_element_get_static_pad(a_sinkbin, "sink");
2134         }
2135
2136         wfd_sink_debug_fleave();
2137
2138         return MM_ERROR_NONE;
2139
2140         /* ERRORS */
2141 ERROR:
2142         if (pipeline) {
2143                 gst_object_unref(pipeline);
2144                 pipeline = NULL;
2145         }
2146
2147         if (sinkpad) {
2148                 gst_object_unref(sinkpad);
2149                 sinkpad = NULL;
2150         }
2151
2152         if (srcpad) {
2153                 gst_object_unref(srcpad);
2154                 srcpad = NULL;
2155         }
2156
2157         /* need to notify to app */
2158         MMWFDSINK_POST_MESSAGE(wfd_sink,
2159                                                         MM_ERROR_WFD_INTERNAL,
2160                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
2161
2162         return MM_ERROR_WFD_INTERNAL;
2163 }
2164
2165 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
2166 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND)  /* 30 sec */
2167
2168 static GstPadProbeReturn
2169 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
2170 {
2171         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
2172         GstClockTime current_time = GST_CLOCK_TIME_NONE;
2173         GstClockTime start_time = GST_CLOCK_TIME_NONE;
2174         GstClockTime running_time = GST_CLOCK_TIME_NONE;
2175         GstClockTime base_time = GST_CLOCK_TIME_NONE;
2176         GstClockTime render_time = GST_CLOCK_TIME_NONE;
2177         GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
2178         GstBuffer *buffer = NULL;
2179         gint64 ts_offset = 0LL;
2180
2181         wfd_sink_return_val_if_fail(info, FALSE);
2182         wfd_sink_return_val_if_fail(wfd_sink &&
2183                                                                 wfd_sink->pipeline &&
2184                                                                 wfd_sink->pipeline->mainbin &&
2185                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
2186                                                                 GST_PAD_PROBE_DROP);
2187
2188         if (!wfd_sink->clock) {
2189                 wfd_sink_warning("pipeline did not select clock, yet");
2190                 return GST_PAD_PROBE_OK;
2191         }
2192
2193         if (wfd_sink->need_to_reset_basetime)
2194                 _mm_wfd_sink_reset_basetime(wfd_sink);
2195
2196         /* calculate current runninig time */
2197         current_time = gst_clock_get_time(wfd_sink->clock);
2198         if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
2199                 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
2200         else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
2201                 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
2202         start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2203         if (GST_CLOCK_TIME_IS_VALID(current_time) &&
2204             GST_CLOCK_TIME_IS_VALID(start_time) &&
2205             GST_CLOCK_TIME_IS_VALID(base_time)) {
2206                 running_time = current_time - (start_time + base_time);
2207         } else {
2208                 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
2209                                                 "  base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
2210                                                 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
2211                 return GST_PAD_PROBE_OK;
2212         }
2213
2214         /* calculate this buffer rendering time */
2215         buffer = gst_pad_probe_info_get_buffer(info);
2216         if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
2217                 wfd_sink_warning("buffer timestamp is invalid.");
2218                 return GST_PAD_PROBE_OK;
2219         }
2220
2221         if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2222                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2223                         g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2224         } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2225                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2226                         g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2227         }
2228
2229         render_time = GST_BUFFER_TIMESTAMP(buffer);
2230         render_time += ts_offset;
2231
2232         /* chekc this buffer could be rendered or not */
2233         if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
2234                 diff = GST_CLOCK_DIFF(running_time, render_time);
2235                 if (diff < 0) {
2236                         /* this buffer could be NOT rendered */
2237                         wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
2238                                                         GST_STR_NULL((GST_OBJECT_NAME(pad))),
2239                                                         GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
2240                 } else {
2241                         /* this buffer could be rendered */
2242                         /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "", */
2243                         /*      GST_STR_NULL((GST_OBJECT_NAME(pad))), */
2244                         /*      GST_TIME_ARGS(diff)); */
2245                 }
2246         }
2247
2248         /* update buffer count and gap */
2249         if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2250                 wfd_sink->video_buffer_count++;
2251                 wfd_sink->video_accumulated_gap += diff;
2252         } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2253                 wfd_sink->audio_buffer_count++;
2254                 wfd_sink->audio_accumulated_gap += diff;
2255         } else {
2256                 wfd_sink_warning("invalid buffer type.. ");
2257                 return GST_PAD_PROBE_DROP;
2258         }
2259
2260         if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
2261                 /* fisrt 60sec, just calculate the gap between source device and sink device */
2262                 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
2263                         return GST_PAD_PROBE_OK;
2264
2265                 /* every 10sec, calculate the gap between source device and sink device */
2266                 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
2267                     > COMPENSATION_CHECK_PERIOD) {
2268                         gint64 audio_avgrage_gap = 0LL;
2269                         gint64 video_avgrage_gap = 0LL;
2270                         gint64 audio_avgrage_gap_diff = 0LL;
2271                         gint64 video_avgrage_gap_diff = 0LL;
2272                         gboolean video_minus_compensation = FALSE;
2273                         gboolean audio_minus_compensation = FALSE;
2274                         gint64 avgrage_gap_diff = 0LL;
2275                         gboolean minus_compensation = FALSE;
2276
2277                         /* check video */
2278                         if (wfd_sink->video_buffer_count > 0) {
2279                                 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
2280
2281                                 if (wfd_sink->video_average_gap != 0) {
2282                                         if (video_avgrage_gap > wfd_sink->video_average_gap) {
2283                                                 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
2284                                                 video_minus_compensation = TRUE;
2285                                         } else {
2286                                                 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
2287                                                 video_minus_compensation = FALSE;
2288                                         }
2289                                 } else {
2290                                         wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
2291                                         wfd_sink->video_average_gap = video_avgrage_gap;
2292                                 }
2293                         } else {
2294                                 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
2295                                                                 " ~ %" GST_TIME_FORMAT"",
2296                                                                 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2297                                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2298                         }
2299
2300                         /* check audio */
2301                         if (wfd_sink->audio_buffer_count > 0) {
2302                                 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
2303
2304                                 if (wfd_sink->audio_average_gap != 0) {
2305                                         if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
2306                                                 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
2307                                                 audio_minus_compensation = TRUE;
2308                                         } else {
2309                                                 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
2310                                                 audio_minus_compensation = FALSE;
2311                                         }
2312                                 } else {
2313                                         wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
2314                                         wfd_sink->audio_average_gap = audio_avgrage_gap;
2315                                 }
2316                         } else {
2317                                 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
2318                                                                 " ~ %" GST_TIME_FORMAT"",
2319                                                                 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2320                                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2321                         }
2322
2323                         /* selecet average_gap_diff between video and audio */
2324                         /*  which makes no buffer drop in the sink elements */
2325                         if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
2326                                 if (!video_minus_compensation && !audio_minus_compensation) {
2327                                         minus_compensation = FALSE;
2328                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2329                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2330                                         else
2331                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2332                                 } else if (video_minus_compensation && audio_minus_compensation) {
2333                                         minus_compensation = TRUE;
2334                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2335                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2336                                         else
2337                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2338                                 } else {
2339                                         minus_compensation = FALSE;
2340                                         if (!video_minus_compensation)
2341                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2342                                         else
2343                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2344                                 }
2345                         } else if (video_avgrage_gap_diff) {
2346                                 minus_compensation = video_minus_compensation;
2347                                 avgrage_gap_diff = video_avgrage_gap_diff;
2348                         } else if (audio_avgrage_gap_diff) {
2349                                 minus_compensation = audio_minus_compensation;
2350                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2351                         }
2352
2353                         wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
2354                                                         audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
2355                                                         video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
2356
2357
2358                         /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
2359                         if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
2360                                 if (minus_compensation)
2361                                         ts_offset -= avgrage_gap_diff;
2362                                 else
2363                                         ts_offset += avgrage_gap_diff;
2364
2365                                 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
2366                                                                 GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
2367                                                                 minus_compensation ? "-" : "", avgrage_gap_diff,
2368                                                                 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
2369
2370                                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2371                                         g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2372                                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2373                                         g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2374                         } else {
2375                                 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
2376                                                                 minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
2377                         }
2378
2379                         /* reset values*/
2380                         wfd_sink->video_buffer_count = 0;
2381                         wfd_sink->video_accumulated_gap = 0LL;
2382                         wfd_sink->audio_buffer_count = 0;
2383                         wfd_sink->audio_accumulated_gap = 0LL;
2384                         wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2385                 }
2386         } else {
2387                 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
2388                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2389                 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2390         }
2391
2392         return GST_PAD_PROBE_OK;
2393 }
2394
2395
2396 static void
2397 __mm_wfd_sink_demux_pad_added(GstElement *demux, GstPad *pad, gpointer data)
2398 {
2399         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2400         gchar *name = NULL;
2401         GstElement *pipeline = NULL;
2402         GstElement *valve = NULL;
2403         GstPad *sinkpad = NULL;
2404         GstPad *srcpad = NULL;
2405
2406         wfd_sink_debug_fenter();
2407
2408         wfd_sink_return_if_fail(wfd_sink &&
2409                                                         wfd_sink->pipeline &&
2410                                                         wfd_sink->pipeline->mainbin &&
2411                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2412
2413         name = gst_pad_get_name(pad);
2414         if (name == NULL) {
2415                 wfd_sink_error("fail to get pad");
2416                 goto ERROR;
2417         }
2418
2419         wfd_sink_debug("Mux pad added, session mode = %d, name[0] = %c", wfd_sink->ini.sink_session_mode, name[0]);
2420
2421         //In case of 'audio-only-mirroring', we don't add video pad
2422         if ((wfd_sink->ini.sink_session_mode & WFD_SESSION_MODE_AUDIO_ONLY) && name[0] == 'v') {
2423                 wfd_sink_error("Skip video pad add in audio only mode");
2424                 // Do nothing
2425                 goto done;
2426         }
2427
2428         //In case of none audio codec, we don't add audio pad
2429         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE && name[0] == 'a') {
2430                 wfd_sink_error("Skip audio pad add for none audio codec");
2431                 // Do nothing
2432                 goto done;
2433         }
2434
2435         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2436
2437         /* take srcpad from demuxer added pad */
2438         srcpad = gst_object_ref(pad);
2439
2440         if (name[0] == 'v') {
2441                 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst)
2442                         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
2443         } else if (name[0] == 'a') {
2444                 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst)
2445                         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
2446         }
2447
2448         /* add, link and run the valve */
2449         if (valve) {
2450                 wfd_sink_debug("try to add %s to pipeline", GST_ELEMENT_NAME(valve));
2451
2452                 if (!gst_bin_add(GST_BIN(pipeline), valve)) {
2453                         wfd_sink_error("failed to add %s to pipeline",
2454                                                         GST_ELEMENT_NAME(valve));
2455                         goto ERROR;
2456                 }
2457
2458                 sinkpad = gst_element_get_static_pad(valve, "sink");
2459                 if (!sinkpad) {
2460                                 wfd_sink_error("failed to get sink pad from %s",
2461                                                                 GST_ELEMENT_NAME(valve));
2462                         goto ERROR;
2463                 }
2464
2465                 wfd_sink_debug("try to link %s:%s and %s:%s",
2466                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2467                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2468                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2469                         wfd_sink_error("failed to link %s:%s and %s:%s",
2470                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2471                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2472                         goto ERROR;
2473                 }
2474                 gst_object_unref(GST_OBJECT(srcpad));
2475                 srcpad = NULL;
2476                 gst_object_unref(GST_OBJECT(sinkpad));
2477                 sinkpad = NULL;
2478
2479                 wfd_sink_debug("try to sync %s's state with parent", GST_ELEMENT_NAME(valve));
2480                 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(valve))) {
2481                         wfd_sink_error("failed to sync %s state with parent",
2482                                                         GST_PAD_NAME(valve));
2483                         goto ERROR;
2484                 }
2485
2486                 srcpad = gst_element_get_static_pad(valve, "src");
2487                 if (!srcpad) {
2488                         wfd_sink_error("failed to get src pad from %s",
2489                                                         GST_ELEMENT_NAME(valve));
2490                         goto ERROR;
2491                 }
2492         }
2493
2494         /* take decodebin/sinkbin */
2495         if (name[0] == 'v') {
2496                 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
2497
2498                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
2499
2500                 gst_pad_add_probe(pad,
2501                                                 GST_PAD_PROBE_TYPE_BUFFER,
2502                                                 _mm_wfd_sink_check_running_time,
2503                                                 (gpointer)wfd_sink,
2504                                                 NULL);
2505
2506                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad)) {
2507                         wfd_sink_error("failed to prepare video pipeline....");
2508                         goto ERROR;
2509                 }
2510         } else if (name[0] == 'a') {
2511                 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
2512
2513                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
2514
2515                 gst_pad_add_probe(pad,
2516                                                 GST_PAD_PROBE_TYPE_BUFFER,
2517                                                 _mm_wfd_sink_check_running_time,
2518                                                 (gpointer)wfd_sink,
2519                                                 NULL);
2520
2521                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad)) {
2522                         wfd_sink_error("failed to prepare audio pipeline....");
2523                         goto ERROR;
2524                 }
2525         } else {
2526                 wfd_sink_error("unexceptable pad is added!!!");
2527                 goto ERROR;
2528         }
2529
2530         /* link */
2531         wfd_sink_debug("try to link %s:%s and %s:%s",
2532                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2533                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2534         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2535                 wfd_sink_error("failed to link %s:%s and %s:%s",
2536                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2537                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2538                 goto ERROR;
2539         }
2540
2541         if (name[0] == 'v') {
2542                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
2543         } else if (name[0] == 'a') {
2544                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
2545         }
2546
2547 done:
2548         MMWFDSINK_FREEIF(name);
2549
2550         if (srcpad) {
2551                 gst_object_unref(GST_OBJECT(srcpad));
2552                 srcpad = NULL;
2553         }
2554         if (sinkpad) {
2555                 gst_object_unref(GST_OBJECT(sinkpad));
2556                 sinkpad = NULL;
2557         }
2558         wfd_sink_debug_fleave();
2559
2560         return;
2561
2562         /* ERRORS */
2563 ERROR:
2564         /* need to notify to app */
2565         MMWFDSINK_POST_MESSAGE(wfd_sink,
2566                                                         MM_ERROR_WFD_INTERNAL,
2567                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
2568
2569         goto done;
2570 }
2571
2572 static void
2573 __mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data)
2574 {
2575         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2576
2577         wfd_sink_debug_fenter();
2578
2579         wfd_sink_return_if_fail(wfd_sink);
2580         wfd_sink_return_if_fail(need_to_flush);
2581
2582         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
2583                 wfd_sink_debug("need to flush pipeline");
2584                 *need_to_flush = (gpointer) TRUE;
2585         } else {
2586                 wfd_sink_debug("don't need to flush pipeline");
2587                 *need_to_flush = (gpointer) FALSE;
2588         }
2589
2590
2591         wfd_sink_debug_fleave();
2592 }
2593
2594
2595 static void
2596 __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data)
2597 {
2598         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2599         MMWFDSinkStreamInfo *stream_info = NULL;
2600         gint is_valid_audio_format = FALSE;
2601         gint is_valid_video_format = FALSE;
2602         gchar *audio_format;
2603         gchar *video_format;
2604
2605         wfd_sink_debug_fenter();
2606         wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
2607         wfd_sink_return_if_fail(wfd_sink);
2608
2609         stream_info = &wfd_sink->stream_info;
2610
2611         if (gst_structure_has_field(str, "audio_format")) {
2612                 is_valid_audio_format = TRUE;
2613                 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
2614                 if (g_strrstr(audio_format, "AAC"))
2615                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
2616                 else if (g_strrstr(audio_format, "AC3"))
2617                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
2618                 else if (g_strrstr(audio_format, "LPCM"))
2619                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
2620                 else {
2621                         wfd_sink_error("invalid audio format(%s)...", audio_format);
2622                         is_valid_audio_format = FALSE;
2623                 }
2624                 if (is_valid_audio_format == TRUE) {
2625                         if (gst_structure_has_field(str, "audio_rate"))
2626                                 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
2627                         if (gst_structure_has_field(str, "audio_channels"))
2628                                 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
2629                         if (gst_structure_has_field(str, "audio_bitwidth"))
2630                                 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
2631
2632                         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
2633
2634                         wfd_sink_debug("audio_format : %s \n \t rate :  %d \n \t channels :  %d \n \t bitwidth :  %d \n \t      \n",
2635                                                         audio_format,
2636                                                         stream_info->audio_stream_info.sample_rate,
2637                                                         stream_info->audio_stream_info.channels,
2638                                                         stream_info->audio_stream_info.bitwidth);
2639                 }
2640
2641                 g_free (audio_format);
2642         }
2643         if (gst_structure_has_field(str, "video_format")) {
2644                 is_valid_video_format = TRUE;
2645                 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
2646                 if (g_strrstr(video_format, "H264")) {
2647                         stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
2648                 } else if (g_strrstr(video_format, "H265")) {
2649                         stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H265;
2650                 } else {
2651                         wfd_sink_error("invalid video format(%s)...", video_format);
2652                         is_valid_video_format = FALSE;
2653                 }
2654
2655                 if (is_valid_video_format == TRUE) {
2656                         if (gst_structure_has_field(str, "video_width"))
2657                                 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
2658                         if (gst_structure_has_field(str, "video_height"))
2659                                 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
2660                         if (gst_structure_has_field(str, "video_framerate"))
2661                                 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
2662
2663                         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
2664
2665                         wfd_sink_debug("video_format : %s \n \t width :  %d \n \t height :  %d \n \t frame_rate :  %d \n \t",
2666                                                         video_format,
2667                                                         stream_info->video_stream_info.width,
2668                                                         stream_info->video_stream_info.height,
2669                                                         stream_info->video_stream_info.frame_rate);
2670                 }
2671
2672                 g_free (video_format);
2673         }
2674
2675         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
2676
2677         wfd_sink_debug_fleave();
2678 }
2679
2680 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint64 *CEA_resolution,
2681                                                                                                         guint64 *VESA_resolution, guint64 *HH_resolution)
2682 {
2683         if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
2684
2685         *CEA_resolution = 0;
2686         *VESA_resolution = 0;
2687         *HH_resolution = 0;
2688
2689         if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
2690                 *CEA_resolution |= WFD_CEA_1920x1080P30;
2691
2692         if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
2693                 *CEA_resolution |= WFD_CEA_1280x720P30;
2694
2695         if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
2696                 *HH_resolution |= WFD_HH_960x540P30;
2697
2698         if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
2699                 *HH_resolution |= WFD_HH_864x480P30;
2700
2701         if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
2702                 *CEA_resolution |= WFD_CEA_720x480P60;
2703
2704         if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
2705                 *CEA_resolution |= WFD_CEA_640x480P60;
2706
2707         if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
2708                 *HH_resolution |= WFD_HH_640x360P30;
2709 }
2710
2711 static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc)
2712 {
2713         GstStructure *wfd_audio_codecs = NULL;
2714         GstStructure *wfd_video_formats = NULL;
2715         GstStructure *wfd_content_protection = NULL;
2716         GstStructure *wfd2_video_formats = NULL;
2717         GstStructure *wfd2_audio_codecs = NULL;
2718         gint hdcp_version = 0;
2719         gint hdcp_port = 0;
2720         guint64 CEA_resolution = 0;
2721         guint64 VESA_resolution = 0;
2722         guint64 HH_resolution = 0;
2723         GObjectClass *klass;
2724
2725         wfd_sink_debug_fenter();
2726
2727         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2728         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2729         wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED);
2730
2731         klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc));
2732
2733         if (g_object_class_find_property(klass, "enable-pad-probe")) /* for common wfdsrc */
2734                 g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.trace_buffers_of_wfdsrc, NULL);
2735         g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
2736         g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
2737         g_object_set(G_OBJECT(wfdsrc), "user-agent", wfd_sink->ini.user_agent, NULL);
2738         g_object_set(G_OBJECT(wfdsrc), "dump-rtsp-message", wfd_sink->ini.dump_rtsp_message, NULL);
2739         if (g_object_class_find_property(klass, "dump-rtp-data"))
2740                 g_object_set(G_OBJECT(wfdsrc), "dump-rtp-data", wfd_sink->ini.dump_rtp_data, NULL);
2741         if (g_object_class_find_property(klass, "trace-first-buffer"))
2742                 g_object_set(G_OBJECT(wfdsrc), "trace-first-buffer", wfd_sink->ini.trace_first_buffer, NULL);
2743         if (g_object_class_find_property(klass, "trace-buffers"))
2744                 g_object_set(G_OBJECT(wfdsrc), "trace-buffers", wfd_sink->ini.trace_buffers, NULL);
2745         if (g_object_class_find_property(klass, "do-request"))
2746                 g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
2747
2748         /* set audio parameter for Wi-Fi Display session negotiation */
2749         wfd_audio_codecs = gst_structure_new("wfd_audio_codecs",
2750                                                                                 "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_codec,
2751                                                                                 "audio_latency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_latency,
2752                                                                                 "audio_channels", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_channel,
2753                                                                                 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_sampling_frequency,
2754                                                                                 NULL);
2755
2756         if (wfd_audio_codecs) {
2757                 g_object_set(G_OBJECT(wfdsrc), "wfd-audio-codecs", wfd_audio_codecs, NULL);
2758                 gst_structure_free(wfd_audio_codecs);
2759                 wfd_audio_codecs = NULL;
2760         }
2761
2762         /* set video parameter for Wi-Fi Display session negotiation */
2763         CEA_resolution = wfd_sink->ini.wfd_video_formats.video_cea_support;
2764         VESA_resolution = wfd_sink->ini.wfd_video_formats.video_vesa_support;
2765         HH_resolution =  wfd_sink->ini.wfd_video_formats.video_hh_support;
2766
2767         __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
2768                                                                                         &CEA_resolution, &VESA_resolution, &HH_resolution);
2769         wfd_video_formats = gst_structure_new("wfd_video_formats",
2770                                                                                 "video_codec", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_codec,
2771                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_native_resolution,
2772                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2773                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2774                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2775                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_profile,
2776                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_level,
2777                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_latency,
2778                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_vertical_resolution,
2779                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_horizontal_resolution,
2780                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_minimum_slicing,
2781                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_slice_enc_param,
2782                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_framerate_control_support,
2783                                                                                 NULL);
2784
2785         if (wfd_video_formats) {
2786                 g_object_set(G_OBJECT(wfdsrc), "wfd-video-formats", wfd_video_formats, NULL);
2787                 gst_structure_free(wfd_video_formats);
2788                 wfd_video_formats = NULL;
2789         }
2790
2791
2792         /* set hdcp parameter for Wi-Fi Display session negotiation */
2793         if (wfd_sink->ini.wfd_content_protection.enable_hdcp) {
2794                 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
2795                 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
2796                 wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
2797
2798                 wfd_content_protection = gst_structure_new("wfd_content_protection",
2799                                                                                                         "hdcp_version", G_TYPE_INT, hdcp_version,
2800                                                                                                         "hdcp_port_no", G_TYPE_INT, hdcp_port,
2801                                                                                                         NULL);
2802
2803                 if (wfd_content_protection) {
2804                         g_object_set(G_OBJECT(wfdsrc), "wfd-content-protection", wfd_content_protection, NULL);
2805                         gst_structure_free(wfd_content_protection);
2806                         wfd_content_protection = NULL;
2807                 }
2808         }
2809
2810         if (g_object_class_find_property(klass, "wfd2-audio-codecs")) {
2811                 /* set audio parameter for Wi-Fi Display R2 session negotiation */
2812                 wfd2_audio_codecs = gst_structure_new("wfd2-audio-codecs",
2813                                                                                         "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_codec,
2814                                                                                         "audio_lpcm_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_lpcm_mode,
2815                                                                                         "audio_aac_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_aac_mode,
2816                                                                                         "audio_ac3_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_ac3_mode,
2817                                                                                         NULL);
2818
2819                 if (wfd2_audio_codecs) {
2820                         g_object_set(G_OBJECT(wfdsrc), "wfd2-audio-codecs", wfd2_audio_codecs, NULL);
2821                         gst_structure_free(wfd2_audio_codecs);
2822                         wfd2_audio_codecs = NULL;
2823                 }
2824         }
2825
2826         if (g_object_class_find_property(klass, "wfd2-video-format-h264")) {
2827                 /* set video parameter for Wi-Fi Display R2 session negotiation */
2828                 CEA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_cea_support;
2829                 VESA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_vesa_support;
2830                 HH_resolution =  wfd_sink->ini.wfd2_video_h264_info.video_hh_support;
2831
2832                 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H264) {
2833                         wfd2_video_formats = gst_structure_new("wfd2-video-format-h264",
2834                                                                                                 "video_codec", G_TYPE_UINT, WFD_VIDEO_H264,
2835                                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2836                                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2837                                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2838                                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2839                                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_profile,
2840                                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_level,
2841                                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_latency,
2842                                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_vertical_resolution,
2843                                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_horizontal_resolution,
2844                                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_minimum_slicing,
2845                                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_slice_enc_param,
2846                                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_framerate_control_support,
2847                                                                                                 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2848                                                                                                 NULL);
2849
2850                         if (wfd2_video_formats) {
2851                                 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h264", wfd2_video_formats, NULL);
2852                                 gst_structure_free(wfd2_video_formats);
2853                                 wfd2_video_formats = NULL;
2854                         }
2855                 }
2856         }
2857
2858         if (g_object_class_find_property(klass, "wfd2-video-format-h265")) {
2859                 /* set video parameter for Wi-Fi Display R2 session negotiation */
2860                 CEA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_cea_support;
2861                 VESA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_vesa_support;
2862                 HH_resolution =  wfd_sink->ini.wfd2_video_h265_info.video_hh_support;
2863
2864                 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H265) {
2865                         wfd2_video_formats = gst_structure_new("wfd2-video-format-h265",
2866                                                                                                 "video_codec", G_TYPE_UINT, WFD_VIDEO_H265,
2867                                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2868                                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2869                                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2870                                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2871                                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_profile,
2872                                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_level,
2873                                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_latency,
2874                                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_vertical_resolution,
2875                                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_horizontal_resolution,
2876                                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_minimum_slicing,
2877                                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_slice_enc_param,
2878                                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_framerate_control_support,
2879                                                                                                 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2880                                                                 NULL);
2881
2882                         if (wfd2_video_formats) {
2883                                 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h265", wfd2_video_formats, NULL);
2884                                 gst_structure_free(wfd2_video_formats);
2885                                 wfd2_video_formats = NULL;
2886                         }
2887                 }
2888         }
2889
2890         wfd_sink->update_stream_info_sig_id = g_signal_connect(wfdsrc, "update-media-info",
2891                                                                                                                 G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
2892
2893         wfd_sink->change_av_format_sig_id = g_signal_connect(wfdsrc, "change-av-format",
2894                                                                                                                 G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
2895
2896         wfd_sink_debug_fleave();
2897
2898         return MM_ERROR_NONE;
2899 }
2900
2901 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
2902 {
2903         wfd_sink_debug_fenter();
2904
2905         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2906         wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
2907
2908         g_signal_connect(demux, "pad-added",
2909                                         G_CALLBACK(__mm_wfd_sink_demux_pad_added),      wfd_sink);
2910
2911         wfd_sink_debug_fleave();
2912
2913         return MM_ERROR_NONE;
2914 }
2915
2916 static void __mm_wfd_sink_queue_overrun(GstElement *queue, gpointer u_data)
2917 {
2918         guint64 time = 0;
2919
2920         wfd_sink_debug_fenter();
2921
2922         return_if_fail(queue);
2923
2924         g_object_get(G_OBJECT(queue), "current-level-time", &time, NULL);
2925
2926         wfd_sink_warning("%s is overrun(%" GST_TIME_FORMAT")",
2927                                                 GST_ELEMENT_NAME(queue), GST_TIME_ARGS(time));
2928
2929         wfd_sink_debug_fleave();
2930
2931         return;
2932 }
2933
2934 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
2935 {
2936         wfd_sink_debug_fenter();
2937
2938         wfd_sink_return_if_fail(wfd_sink);
2939         wfd_sink_return_if_fail(queue);
2940
2941         /* set maximum buffer size of queue as 3sec */
2942         g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
2943         g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
2944         g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
2945         g_signal_connect(queue, "overrun",
2946                                         G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
2947
2948         wfd_sink_debug_fleave();
2949
2950         return;
2951 }
2952
2953
2954 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
2955 {
2956         MMWFDSinkGstElement *mainbin = NULL;
2957         GList *element_bucket = NULL;
2958         GstBus  *bus = NULL;
2959         int i;
2960
2961         wfd_sink_debug_fenter();
2962
2963         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2964         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2965
2966         /* Create pipeline */
2967         wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
2968         if (wfd_sink->pipeline == NULL)
2969                 goto CREATE_ERROR;
2970
2971         memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
2972
2973         /* create mainbin */
2974         mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2975         if (mainbin == NULL)
2976                 goto CREATE_ERROR;
2977
2978         memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2979
2980         /* create pipeline */
2981         mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
2982         mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
2983         if (!mainbin[WFD_SINK_M_PIPE].gst) {
2984                 wfd_sink_error("failed to create pipeline");
2985                 goto CREATE_ERROR;
2986         }
2987
2988         /* create wfdsrc */
2989         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE);
2990         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst,  "src");
2991         if (mainbin[WFD_SINK_M_SRC].gst) {
2992                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2993                         wfd_sink_error("failed to prepare wfdsrc...");
2994                         goto CREATE_ERROR;
2995                 }
2996         }
2997
2998         /* create rtpmp2tdepay */
2999         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
3000         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
3001         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
3002
3003         MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
3004
3005         /* create queue for ts */
3006         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_QUEUE, "queue", "ts_queue", TRUE);
3007         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "src");
3008         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "sink");
3009         g_object_set(G_OBJECT(mainbin[WFD_SINK_M_QUEUE].gst), "max-size-buffers", 200000, NULL);
3010
3011         /* create valve for demux */
3012         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_D_VALVE, "valve", "demux_valve", TRUE);
3013         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "src");
3014         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "sink");
3015
3016         /* create tsdemuxer*/
3017         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
3018         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
3019         if (mainbin[WFD_SINK_M_DEMUX].gst) {
3020                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
3021                         wfd_sink_error("failed to prepare demux...");
3022                         goto CREATE_ERROR;
3023                 }
3024         }
3025
3026         /* create valve for audio */
3027         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_A_VALVE, "valve", "audio_valve", FALSE);
3028         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "src");
3029         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "sink");
3030
3031         if (wfd_sink->ini.sink_session_mode & (WFD_SESSION_MODE_MIXED | WFD_SESSION_MODE_VIDEO_ONLY)) {
3032                 /* create valve for video */
3033                 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_V_VALVE, "valve", "video_valve", FALSE);
3034                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "src");
3035                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "sink");
3036         }
3037
3038         /* adding created elements to pipeline */
3039         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
3040                 wfd_sink_error("failed to add elements");
3041                 goto CREATE_ERROR;
3042         }
3043
3044         /* linking elements in the bucket by added order. */
3045         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3046                 wfd_sink_error("failed to link elements");
3047                 goto CREATE_ERROR;
3048         }
3049
3050         /* connect bus callback */
3051         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
3052         if (!bus) {
3053                 wfd_sink_error("cannot get bus from pipeline.");
3054                 goto CREATE_ERROR;
3055         }
3056
3057         /* add bus message callback*/
3058         wfd_sink->msg_callback_id = gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
3059
3060         /* set sync handler to get tag synchronously */
3061         gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
3062
3063         g_list_free(element_bucket);
3064         element_bucket = NULL;
3065         gst_object_unref(GST_OBJECT(bus));
3066         bus = NULL;
3067
3068         /* now we have completed mainbin. take it */
3069         wfd_sink->pipeline->mainbin = mainbin;
3070
3071         wfd_sink_debug_fleave();
3072
3073         return MM_ERROR_NONE;
3074
3075         /* ERRORS */
3076 CREATE_ERROR:
3077         wfd_sink_error("ERROR : releasing pipeline");
3078
3079         if (element_bucket) {
3080                 g_list_free(element_bucket);
3081                 element_bucket = NULL;
3082         }
3083
3084         /* release element which are not added to bin */
3085         for (i = 1; i < WFD_SINK_M_NUM; i++) {  /* NOTE : skip pipeline */
3086                 if (mainbin != NULL && mainbin[i].gst) {
3087                         GstObject *parent = NULL;
3088                         parent = gst_element_get_parent(mainbin[i].gst);
3089
3090                         if (!parent) {
3091                                 gst_object_unref(GST_OBJECT(mainbin[i].gst));
3092                                 mainbin[i].gst = NULL;
3093                         } else {
3094                                 gst_object_unref(GST_OBJECT(parent));
3095                                 parent = NULL;
3096                         }
3097                 }
3098         }
3099
3100         /* release mainbin with it's childs */
3101         if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) {
3102                 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3103                 mainbin[WFD_SINK_M_PIPE].gst = NULL;
3104         }
3105
3106         MMWFDSINK_FREEIF(mainbin);
3107
3108         MMWFDSINK_FREEIF(wfd_sink->pipeline);
3109
3110         return MM_ERROR_WFD_INTERNAL;
3111 }
3112
3113 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3114 {
3115         MMWFDSinkGstElement *a_decodebin = NULL;
3116         MMWFDSinkGstElement *first_element = NULL;
3117         MMWFDSinkGstElement *last_element = NULL;
3118         GList *element_bucket = NULL;
3119         GstPad *sinkpad = NULL;
3120         GstPad *srcpad = NULL;
3121         GstPad *ghostpad = NULL;
3122         GList *list_temp = NULL;
3123
3124         wfd_sink_debug_fenter();
3125
3126         wfd_sink_return_val_if_fail(wfd_sink &&
3127                                                                 wfd_sink->pipeline &&
3128                                                                 wfd_sink->pipeline->a_decodebin &&
3129                                                                 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
3130                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3131
3132         if (wfd_sink->audio_decodebin_is_linked) {
3133                 wfd_sink_debug("audio decodebin is already linked... nothing to do");
3134                 return MM_ERROR_NONE;
3135         }
3136
3137         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3138                 wfd_sink_debug("Skip link audio decodebin for none audio codec.");
3139                 wfd_sink_debug_fleave();
3140                 return MM_ERROR_NONE;
3141         }
3142
3143         /* take audio decodebin */
3144         a_decodebin = wfd_sink->pipeline->a_decodebin;
3145
3146         /* check audio queue */
3147         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3148                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]);
3149
3150         /* check audio hdcp */
3151         if (a_decodebin[WFD_SINK_A_D_HDCP].gst)
3152                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]);
3153
3154         /* check audio codec */
3155         switch (wfd_sink->stream_info.audio_stream_info.codec) {
3156         case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3157                 if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
3158                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
3159                 if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
3160                         GstCaps *caps = NULL;
3161                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
3162                         caps = gst_caps_new_simple("audio/x-raw",
3163                                                 "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
3164                                                 "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
3165                                                 "format", G_TYPE_STRING, "S16BE", NULL);
3166
3167                         g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
3168                         gst_object_unref(GST_OBJECT(caps));
3169                         caps = NULL;
3170                 }
3171                 break;
3172
3173         case MM_WFD_SINK_AUDIO_CODEC_AAC:
3174                 if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
3175                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
3176                 if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
3177                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
3178                 break;
3179
3180         case MM_WFD_SINK_AUDIO_CODEC_AC3:
3181                 if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
3182                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
3183                 if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
3184                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
3185                 break;
3186
3187         default:
3188                 wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
3189                 return MM_ERROR_WFD_INTERNAL;
3190                 break;
3191         }
3192
3193         if (element_bucket == NULL) {
3194                 wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it");
3195                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3196                         wfd_sink_error("failed to destroy audio decodebin");
3197                         goto fail_to_link;
3198                 }
3199                 goto done;
3200         }
3201
3202         /* adding elements to audio decodebin */
3203         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) {
3204                 wfd_sink_error("failed to add elements to audio decodebin");
3205                 goto fail_to_link;
3206         }
3207
3208         /* linking elements in the bucket by added order. */
3209         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3210                 wfd_sink_error("failed to link elements of the audio decodebin");
3211                 goto fail_to_link;
3212         }
3213
3214         /* get first element's sinkpad for creating ghostpad */
3215         list_temp = g_list_first(element_bucket);
3216         if (list_temp == NULL) {
3217                 wfd_sink_error("failed to get first list of the element_bucket");
3218                 goto fail_to_link;
3219         }
3220
3221         first_element = (MMWFDSinkGstElement *)list_temp->data;
3222         if (!first_element) {
3223                 wfd_sink_error("failed to get first element of the audio decodebin");
3224                 goto fail_to_link;
3225         }
3226
3227         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3228         if (!sinkpad) {
3229                 wfd_sink_error("failed to get sink pad from element(%s)",
3230                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3231                 goto fail_to_link;
3232         }
3233
3234         ghostpad = gst_ghost_pad_new("sink", sinkpad);
3235         if (!ghostpad) {
3236                 wfd_sink_error("failed to create ghostpad of audio decodebin");
3237                 goto fail_to_link;
3238         }
3239
3240         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3241                 wfd_sink_error("failed to add ghostpad to audio decodebin");
3242                 goto fail_to_link;
3243         }
3244         gst_object_unref(GST_OBJECT(sinkpad));
3245         sinkpad = NULL;
3246
3247
3248         /* get last element's src for creating ghostpad */
3249         list_temp = g_list_last(element_bucket);
3250         if (list_temp == NULL) {
3251                 wfd_sink_error("failed to get last list of the element_bucket");
3252                 goto fail_to_link;
3253         }
3254
3255         last_element = (MMWFDSinkGstElement *)list_temp->data;
3256         if (!last_element) {
3257                 wfd_sink_error("failed to get last element of the audio decodebin");
3258                 goto fail_to_link;
3259         }
3260
3261         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3262         if (!srcpad) {
3263                 wfd_sink_error("failed to get src pad from element(%s)",
3264                                                 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3265                 goto fail_to_link;
3266         }
3267
3268         ghostpad = gst_ghost_pad_new("src", srcpad);
3269         if (!ghostpad) {
3270                 wfd_sink_error("failed to create ghostpad of audio decodebin");
3271                 goto fail_to_link;
3272         }
3273
3274         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3275                 wfd_sink_error("failed to add ghostpad to audio decodebin");
3276                 goto fail_to_link;
3277         }
3278         gst_object_unref(GST_OBJECT(srcpad));
3279         srcpad = NULL;
3280
3281         g_list_free(element_bucket);
3282
3283 done:
3284         wfd_sink->audio_decodebin_is_linked = TRUE;
3285
3286         wfd_sink_debug_fleave();
3287
3288         return MM_ERROR_NONE;
3289
3290         /* ERRORS*/
3291 fail_to_link:
3292         if (srcpad) {
3293                 gst_object_unref(GST_OBJECT(srcpad));
3294                 srcpad = NULL;
3295         }
3296
3297         if (sinkpad) {
3298                 gst_object_unref(GST_OBJECT(sinkpad));
3299                 sinkpad = NULL;
3300         }
3301
3302         g_list_free(element_bucket);
3303
3304         return MM_ERROR_WFD_INTERNAL;
3305 }
3306
3307 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
3308 {
3309         wfd_sink_debug_fenter();
3310
3311         /* check audiosink is created */
3312         wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
3313         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3314
3315         g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE,  NULL);
3316         g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
3317         g_object_set(G_OBJECT(audio_sink), "slave-method", 2,  NULL);
3318         g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async,  NULL);
3319         g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
3320
3321         wfd_sink_debug_fleave();
3322
3323         return MM_ERROR_NONE;
3324 }
3325
3326 static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3327 {
3328         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3329         MMWFDSinkGstElement *a_decodebin = NULL;
3330         GstObject *parent = NULL;
3331         int i;
3332
3333         wfd_sink_debug_fenter();
3334
3335         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3336
3337         if (wfd_sink->pipeline &&
3338             wfd_sink->pipeline->a_decodebin &&
3339             wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
3340                 a_decodebin = wfd_sink->pipeline->a_decodebin;
3341         } else {
3342                 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
3343                 return MM_ERROR_NONE;
3344         }
3345
3346         parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
3347         if (!parent) {
3348                 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
3349
3350                 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
3351                         wfd_sink_debug("try to change state of audio decodebin to NULL");
3352                         ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
3353                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3354                                 wfd_sink_error("failed to change state of audio decodebin to NULL");
3355                                 return MM_ERROR_WFD_INTERNAL;
3356                         }
3357                 }
3358
3359                 /* release element which are not added to bin */
3360                 for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
3361                         if (a_decodebin[i].gst) {
3362                                 parent = gst_element_get_parent(a_decodebin[i].gst);
3363                                 if (!parent) {
3364                                         wfd_sink_debug("unref %s(current ref %d)",
3365                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3366                                                                         ((GObject *) a_decodebin[i].gst)->ref_count);
3367                                         gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3368                                         a_decodebin[i].gst = NULL;
3369                                 } else {
3370                                         wfd_sink_debug("%s has parent.(current ref %d)",
3371                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3372                                                                         ((GObject *) a_decodebin[i].gst)->ref_count);
3373                                         gst_object_unref(GST_OBJECT(parent));
3374                                         parent = NULL;
3375                                 }
3376                         }
3377                 }
3378
3379                 /* release audio decodebin with it's childs */
3380                 if (a_decodebin[WFD_SINK_A_D_BIN].gst) {
3381                         gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3382                         a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3383                 }
3384
3385         } else {
3386                 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
3387                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3388
3389                 gst_object_unref(GST_OBJECT(parent));
3390                 parent = NULL;
3391         }
3392
3393         wfd_sink->audio_decodebin_is_linked = FALSE;
3394
3395         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
3396
3397         wfd_sink_debug_fleave();
3398
3399         return MM_ERROR_NONE;
3400 }
3401
3402 int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3403 {
3404         MMWFDSinkGstElement *a_decodebin = NULL;
3405         gint audio_codec = WFD_AUDIO_UNKNOWN;
3406         GList *element_bucket = NULL;
3407         gboolean link = TRUE;
3408         gint i = 0;
3409
3410         wfd_sink_debug_fenter();
3411
3412         wfd_sink_return_val_if_fail(wfd_sink &&
3413                                                                 wfd_sink->pipeline,
3414                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3415
3416         if (wfd_sink->pipeline->a_decodebin != NULL) {
3417                 wfd_sink_error("The audio decode bin is already created.");
3418                 return MM_ERROR_NONE;
3419         }
3420
3421         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3422                 wfd_sink_debug("Skip create audio decodebin for none audio codec.");
3423                 wfd_sink_debug_fleave();
3424                 return MM_ERROR_NONE;
3425         }
3426
3427         /* check audio decodebin could be linked now */
3428         switch (wfd_sink->stream_info.audio_stream_info.codec) {
3429         case MM_WFD_SINK_AUDIO_CODEC_AAC:
3430                 audio_codec = WFD_AUDIO_AAC;
3431                 link = TRUE;
3432                 break;
3433         case MM_WFD_SINK_AUDIO_CODEC_AC3:
3434                 audio_codec = WFD_AUDIO_AC3;
3435                 link = TRUE;
3436                 break;
3437         case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3438                 audio_codec = WFD_AUDIO_LPCM;
3439                 link = TRUE;
3440                 break;
3441         case MM_WFD_SINK_AUDIO_CODEC_NONE:
3442         default:
3443                 wfd_sink_debug("audio decodebin could NOT be linked now, just create");
3444                 audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3445                 link = FALSE;
3446                 break;
3447         }
3448
3449         /* alloc handles */
3450         a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3451         if (!a_decodebin) {
3452                 wfd_sink_error("failed to allocate memory for audio decodebin");
3453                 return MM_ERROR_WFD_NO_FREE_SPACE;
3454         }
3455
3456         memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3457
3458         /* create audio decodebin */
3459         a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
3460         a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
3461         if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
3462                 wfd_sink_error("failed to create audio decodebin");
3463                 goto CREATE_ERROR;
3464         }
3465
3466         /* create queue */
3467         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
3468         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "sink");
3469         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "src");
3470         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3471                 __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
3472
3473         /* create hdcp */
3474         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
3475         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "sink");
3476         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "src");
3477
3478         /* create codec */
3479         audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3480         if (audio_codec & WFD_AUDIO_LPCM) {
3481                 /* create LPCM converter */
3482                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
3483                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "sink");
3484                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "src");
3485
3486                 /* create LPCM filter */
3487                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
3488                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "sink");
3489                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "src");
3490         }
3491
3492         if (audio_codec & WFD_AUDIO_AAC) {
3493                 /* create AAC parse  */
3494                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
3495                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "sink");
3496                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "src");
3497
3498                 /* create AAC decoder  */
3499                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
3500                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "sink");
3501                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "src");
3502         }
3503
3504         if (audio_codec & WFD_AUDIO_AC3) {
3505                 /* create AC3 parser  */
3506                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
3507                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "sink");
3508                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "src");
3509
3510                 /* create AC3 decoder  */
3511                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
3512                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "sink");
3513                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "src");
3514         }
3515
3516         g_list_free(element_bucket);
3517
3518         /* take it */
3519         wfd_sink->pipeline->a_decodebin = a_decodebin;
3520
3521         /* link audio decodebin if audio codec is fixed */
3522         if (link) {
3523                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
3524                         wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
3525                         __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
3526                         return MM_ERROR_WFD_INTERNAL;
3527                 }
3528         }
3529
3530         wfd_sink_debug_fleave();
3531
3532         return MM_ERROR_NONE;
3533
3534 CREATE_ERROR:
3535         wfd_sink_error("failed to create audio decodebin, release all");
3536
3537         g_list_free(element_bucket);
3538
3539         /* release element which are not added to bin */
3540         for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
3541                 if (a_decodebin != NULL && a_decodebin[i].gst) {
3542                         GstObject *parent = NULL;
3543                         parent = gst_element_get_parent(a_decodebin[i].gst);
3544
3545                         if (!parent) {
3546                                 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3547                                 a_decodebin[i].gst = NULL;
3548                         } else {
3549                                 gst_object_unref(GST_OBJECT(parent));
3550                                 parent = NULL;
3551                         }
3552                 }
3553         }
3554
3555         /* release audio decodebin with it's childs */
3556         if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) {
3557                 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3558                 a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3559         }
3560
3561         MMWFDSINK_FREEIF(a_decodebin);
3562
3563         return MM_ERROR_WFD_INTERNAL;
3564 }
3565
3566 static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3567 {
3568         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3569         MMWFDSinkGstElement *a_sinkbin = NULL;
3570         GstObject *parent = NULL;
3571         int i;
3572
3573         wfd_sink_debug_fenter();
3574
3575         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3576
3577         if (wfd_sink->pipeline &&
3578             wfd_sink->pipeline->a_sinkbin &&
3579             wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3580                 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
3581         } else {
3582                 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
3583                 return MM_ERROR_NONE;
3584         }
3585
3586         parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
3587         if (!parent) {
3588                 wfd_sink_debug("audio sinkbin has no parent.. need to relase by itself");
3589
3590                 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
3591                         wfd_sink_debug("try to change state of audio sinkbin to NULL");
3592                         ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
3593                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3594                                 wfd_sink_error("failed to change state of audio sinkbin to NULL");
3595                                 return MM_ERROR_WFD_INTERNAL;
3596                         }
3597                 }
3598
3599                 /* release element which are not added to bin */
3600                 for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
3601                         if (a_sinkbin[i].gst) {
3602                                 parent = gst_element_get_parent(a_sinkbin[i].gst);
3603                                 if (!parent) {
3604                                         wfd_sink_debug("unref %s(current ref %d)",
3605                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3606                                                                         ((GObject *) a_sinkbin[i].gst)->ref_count);
3607                                         gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3608                                         a_sinkbin[i].gst = NULL;
3609                                 } else {
3610                                         wfd_sink_debug("%s has parent.(current ref %d)",
3611                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3612                                                                         ((GObject *) a_sinkbin[i].gst)->ref_count);
3613                                         gst_object_unref(GST_OBJECT(parent));
3614                                         parent = NULL;
3615                                 }
3616                         }
3617                 }
3618
3619                 /* release audio sinkbin with it's childs */
3620                 if (a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3621                         gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3622                         a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3623                 }
3624         } else {
3625                 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
3626                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3627
3628                 gst_object_unref(GST_OBJECT(parent));
3629                 parent = NULL;
3630         }
3631
3632         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
3633
3634         wfd_sink_debug_fleave();
3635
3636         return MM_ERROR_NONE;
3637 }
3638
3639 int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3640 {
3641         MMWFDSinkGstElement *a_sinkbin = NULL;
3642         MMWFDSinkGstElement *first_element = NULL;
3643         GList *element_bucket = NULL;
3644         GstPad *ghostpad = NULL;
3645         GstPad *pad = NULL;
3646         gint i = 0;
3647         GList *list_temp = NULL;
3648
3649         wfd_sink_debug_fenter();
3650
3651         wfd_sink_return_val_if_fail(wfd_sink &&
3652                                                                 wfd_sink->pipeline,
3653                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3654
3655         if (wfd_sink->pipeline->a_sinkbin != NULL) {
3656                 wfd_sink_error("The audio sink bin is already created.");
3657                 return MM_ERROR_NONE;
3658         }
3659
3660         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3661                 wfd_sink_error("Skip create audio sink bin for non audio codec. %d", wfd_sink->stream_info.audio_stream_info.codec);
3662                 wfd_sink_debug_fleave();
3663                 return MM_ERROR_NONE;
3664         }
3665
3666         /* alloc handles */
3667         a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3668         if (!a_sinkbin) {
3669                 wfd_sink_error("failed to allocate memory for audio sinkbin");
3670                 return MM_ERROR_WFD_NO_FREE_SPACE;
3671         }
3672
3673         memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3674
3675         /* create audio sinkbin */
3676         a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
3677         a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
3678         if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3679                 wfd_sink_error("failed to create audio sinkbin");
3680                 goto CREATE_ERROR;
3681         }
3682
3683         /* create resampler */
3684         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER,
3685                                                         wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
3686         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "sink");
3687         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "src");
3688
3689         /* create volume */
3690         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME,
3691                                                         wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
3692         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "sink");
3693         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "src");
3694
3695         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_QUEUE,
3696                                                         wfd_sink->ini.name_of_audio_sinkbin_queue, "audio_sinkbin_queue", TRUE);
3697         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "sink");
3698         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "src");
3699
3700         /* create sink */
3701         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK,
3702                                                         wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
3703         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst,  "sink");
3704         if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
3705                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
3706                         wfd_sink_error("failed to set audio sink property....");
3707                         goto CREATE_ERROR;
3708                 }
3709         }
3710
3711         /* adding created elements to audio sinkbin */
3712         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
3713                 wfd_sink_error("failed to add elements to audio sinkbin");
3714                 goto CREATE_ERROR;
3715         }
3716
3717         /* linking elements in the bucket by added order. */
3718         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3719                 wfd_sink_error("failed to link elements fo the audio sinkbin");
3720                 goto CREATE_ERROR;
3721         }
3722
3723         /* get first element's of the audio sinkbin */
3724         list_temp = g_list_first(element_bucket);
3725         if (list_temp == NULL) {
3726                 wfd_sink_error("failed to get first list of the element_bucket");
3727                 goto CREATE_ERROR;
3728         }
3729
3730         first_element = (MMWFDSinkGstElement *)list_temp->data;
3731         if (!first_element) {
3732                 wfd_sink_error("failed to get first element of the audio sinkbin");
3733                 goto CREATE_ERROR;
3734         }
3735
3736         /* get first element's sinkpad for creating ghostpad */
3737         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3738         if (!pad) {
3739                 wfd_sink_error("failed to get sink pad from element(%s)",
3740                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3741                 goto CREATE_ERROR;
3742         }
3743
3744         ghostpad = gst_ghost_pad_new("sink", pad);
3745         if (!ghostpad) {
3746                 wfd_sink_error("failed to create ghostpad of audio sinkbin");
3747                 goto CREATE_ERROR;
3748         }
3749
3750         if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
3751                 wfd_sink_error("failed to add ghostpad to audio sinkbin");
3752                 goto CREATE_ERROR;
3753         }
3754         gst_object_unref(GST_OBJECT(pad));
3755         pad = NULL;
3756
3757         g_list_free(element_bucket);
3758         element_bucket = NULL;
3759
3760         /* take it */
3761         wfd_sink->pipeline->a_sinkbin = a_sinkbin;
3762
3763         wfd_sink_debug_fleave();
3764
3765         return MM_ERROR_NONE;
3766
3767 CREATE_ERROR:
3768         wfd_sink_error("failed to create audio sinkbin, releasing all");
3769
3770         if (pad) {
3771                 gst_object_unref(GST_OBJECT(pad));
3772                 pad = NULL;
3773         }
3774         if (ghostpad) {
3775                 gst_object_unref(GST_OBJECT(ghostpad));
3776                 ghostpad = NULL;
3777         }
3778         if (element_bucket) {
3779                 g_list_free(element_bucket);
3780                 element_bucket = NULL;
3781         }
3782
3783         /* release element which are not added to bin */
3784         for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
3785                 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
3786                         GstObject *parent = NULL;
3787                         parent = gst_element_get_parent(a_sinkbin[i].gst);
3788
3789                         if (!parent) {
3790                                 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3791                                 a_sinkbin[i].gst = NULL;
3792                         } else {
3793                                 gst_object_unref(GST_OBJECT(parent));
3794                                 parent = NULL;
3795                         }
3796                 }
3797         }
3798
3799         /* release audio sinkbin with it's childs */
3800         if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3801                 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3802                 a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3803         }
3804         MMWFDSINK_FREEIF(a_sinkbin);
3805
3806         return MM_ERROR_WFD_INTERNAL;
3807 }
3808
3809 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
3810 {
3811         MMWFDSinkGstElement *v_decodebin = NULL;
3812         MMWFDSinkGstElement *first_element = NULL;
3813         MMWFDSinkGstElement *last_element = NULL;
3814         GList *element_bucket = NULL;
3815         GList *list_temp = NULL;
3816         GstPad *sinkpad = NULL;
3817         GstPad *srcpad = NULL;
3818         GstPad *ghostpad = NULL;
3819
3820         wfd_sink_debug_fenter();
3821
3822         wfd_sink_return_val_if_fail(wfd_sink &&
3823                                                                 wfd_sink->pipeline &&
3824                                                                 wfd_sink->pipeline->v_decodebin &&
3825                                                                 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
3826                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3827
3828         if (wfd_sink->video_decodebin_is_linked) {
3829                 wfd_sink_debug("video decodebin is already linked... nothing to do");
3830                 return MM_ERROR_NONE;
3831         }
3832
3833         /* take video decodebin */
3834         v_decodebin = wfd_sink->pipeline->v_decodebin;
3835
3836         /* check video queue */
3837         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3838                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
3839
3840         /* check video hdcp */
3841         if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
3842                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
3843
3844         /* check video codec */
3845         switch (wfd_sink->stream_info.video_stream_info.codec) {
3846         case MM_WFD_SINK_VIDEO_CODEC_H264:
3847                 if (v_decodebin[WFD_SINK_V_D_H264_PARSE].gst)
3848                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_PARSE]);
3849                 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst)
3850                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_DEC]);
3851                 break;
3852
3853         case MM_WFD_SINK_VIDEO_CODEC_H265:
3854                 if (v_decodebin[WFD_SINK_V_D_H265_PARSE].gst)
3855                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_PARSE]);
3856                 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst)
3857                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_DEC]);
3858                 break;
3859
3860         default:
3861                 wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
3862                 return MM_ERROR_WFD_INTERNAL;
3863                 break;
3864         }
3865
3866         if (element_bucket == NULL) {
3867                 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
3868                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3869                         wfd_sink_error("failed to destroy video decodebin");
3870                         goto fail_to_link;
3871                 }
3872                 goto done;
3873         }
3874
3875         /* adding elements to video decodebin */
3876         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
3877                 wfd_sink_error("failed to add elements to video decodebin");
3878                 goto fail_to_link;
3879         }
3880
3881         /* linking elements in the bucket by added order. */
3882         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3883                 wfd_sink_error("failed to link elements of the video decodebin");
3884                 goto fail_to_link;
3885         }
3886
3887         /* get first element's sinkpad for creating ghostpad */
3888         list_temp = g_list_first(element_bucket);
3889         if (list_temp == NULL) {
3890                 wfd_sink_error("failed to get first list of the element_bucket");
3891                 goto fail_to_link;
3892         }
3893
3894         first_element = (MMWFDSinkGstElement *)list_temp->data;
3895         if (!first_element) {
3896                 wfd_sink_error("failed to get first element of the video decodebin");
3897                 goto fail_to_link;
3898         }
3899
3900         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3901         if (!sinkpad) {
3902                 wfd_sink_error("failed to get sink pad from element(%s)",
3903                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3904                 goto fail_to_link;
3905         }
3906
3907         ghostpad = gst_ghost_pad_new("sink", sinkpad);
3908         if (!ghostpad) {
3909                 wfd_sink_error("failed to create ghostpad of video decodebin");
3910                 goto fail_to_link;
3911         }
3912
3913         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3914                 wfd_sink_error("failed to add ghostpad to video decodebin");
3915                 goto fail_to_link;
3916         }
3917         gst_object_unref(GST_OBJECT(sinkpad));
3918         sinkpad = NULL;
3919
3920
3921         /* get last element's src for creating ghostpad */
3922         list_temp = g_list_last(element_bucket);
3923         if (list_temp == NULL) {
3924                 wfd_sink_error("failed to get last list of the element_bucket");
3925                 goto fail_to_link;
3926         }
3927
3928         last_element = (MMWFDSinkGstElement *)list_temp->data;
3929         if (!last_element) {
3930                 wfd_sink_error("failed to get last element of the video decodebin");
3931                 goto fail_to_link;
3932         }
3933
3934         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3935         if (!srcpad) {
3936                 wfd_sink_error("failed to get src pad from element(%s)",
3937                                                 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3938                 goto fail_to_link;
3939         }
3940
3941         ghostpad = gst_ghost_pad_new("src", srcpad);
3942         if (!ghostpad) {
3943                 wfd_sink_error("failed to create ghostpad of video decodebin");
3944                 goto fail_to_link;
3945         }
3946
3947         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3948                 wfd_sink_error("failed to add ghostpad to video decodebin");
3949                 goto fail_to_link;
3950         }
3951         gst_object_unref(GST_OBJECT(srcpad));
3952         srcpad = NULL;
3953
3954         g_list_free(element_bucket);
3955
3956 done:
3957         wfd_sink->video_decodebin_is_linked = TRUE;
3958
3959         wfd_sink_debug_fleave();
3960
3961         return MM_ERROR_NONE;
3962
3963         /* ERRORS*/
3964 fail_to_link:
3965         if (srcpad != NULL) {
3966                 gst_object_unref(GST_OBJECT(srcpad));
3967                 srcpad = NULL;
3968         }
3969
3970         if (sinkpad != NULL) {
3971                 gst_object_unref(GST_OBJECT(sinkpad));
3972                 sinkpad = NULL;
3973         }
3974
3975         if (element_bucket != NULL) {
3976                 g_list_free(element_bucket);
3977                 element_bucket = NULL;
3978         }
3979         return MM_ERROR_WFD_INTERNAL;
3980 }
3981
3982 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
3983 {
3984         wfd_sink_debug_fenter();
3985
3986         /* check video decoder is created */
3987         wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
3988         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
3989
3990         wfd_sink_debug_fleave();
3991
3992         return MM_ERROR_NONE;
3993 }
3994
3995 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
3996 {
3997         gboolean visible = TRUE;
3998         gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
3999
4000         wfd_sink_debug_fenter();
4001
4002         /* check videosink is created */
4003         wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
4004         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
4005
4006         /* update display surface */
4007         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
4008         wfd_sink_info("check display surface type attribute: %d", surface_type);
4009         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
4010         wfd_sink_info("check display visible attribute: %d", visible);
4011
4012         if (FALSE == visible) {
4013                 wfd_sink_info("skipped to prepare video sink. display_visible is FALSE.");
4014                 g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
4015                 return MM_ERROR_NONE;
4016         }
4017
4018         /* configuring display */
4019         switch (surface_type) {
4020                 case MM_DISPLAY_SURFACE_EVAS: {
4021                                 void *object = NULL;
4022                                 gint scaling = 0;
4023
4024                                 /* common case if using evas surface */
4025                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
4026                                 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
4027                                 if (object) {
4028                                         wfd_sink_debug("set video param : evas-object %x", object);
4029                                         g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
4030                                 } else {
4031                                         wfd_sink_error("no evas object");
4032                                         return MM_ERROR_WFD_INTERNAL;
4033                                 }
4034                         }
4035                         break;
4036
4037                 case MM_DISPLAY_SURFACE_OVERLAY: {
4038                                 static unsigned int wl_surface_id = 0;
4039                                 static void *display_overlay = NULL;
4040                                 int wl_window_x = 0;
4041                                 int wl_window_y = 0;
4042                                 int wl_window_width = 0;
4043                                 int wl_window_height = 0;
4044                                 struct wl_surface *wl_surface = NULL;
4045                                 struct wl_display *wl_display = NULL;
4046                                 Ecore_Wl_Window *wl_window = NULL;
4047                                 wl_client *wlclient = NULL;
4048                                 Evas_Object *obj = NULL;
4049                                 void *object = NULL;
4050                                 const char *object_type = NULL;
4051                                 int ret = 0;
4052
4053                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
4054
4055                                 if (object != NULL) {
4056                                         obj = (Evas_Object *)object;
4057                                         object_type = evas_object_type_get(obj);
4058                                         wfd_sink_debug("window object type : %s", object_type);
4059
4060                                         /* wayland overlay surface */
4061                                         LOGI("Wayland overlay surface type");
4062                                         evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height);
4063
4064                                         wfd_sink_debug("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y,
4065                                                                         wl_window_width, wl_window_height);
4066
4067                                         wl_window = elm_win_wl_window_get(obj);
4068                                         wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window);
4069
4070                                         /* get wl_display */
4071                                         wl_display = (struct wl_display *) ecore_wl_display_get();
4072
4073                                         wfd_sink_debug("previous display object : %p current object : %p", display_overlay, object);
4074                                         if (wl_surface && wl_display && (wl_surface_id == 0 || display_overlay != object)) {
4075                                                 wfd_sink_debug("surface = %p, wl_display = %p", wl_surface, wl_display);
4076                                                 display_overlay = object;
4077
4078                                                 ret = mm_wfd_sink_wlclient_create(&wlclient);
4079                                                 if (ret != MM_ERROR_NONE) {
4080                                                         wfd_sink_error("Wayland client create failure");
4081                                                         return ret;
4082                                                 }
4083                                                 wfd_sink_debug("Try to get surface id");
4084
4085                                                 wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id(wlclient, wl_surface, wl_display);
4086
4087                                                 wfd_sink_debug("wl_surface_id = %d", wl_surface_id);
4088
4089                                                 if (wlclient) {
4090                                                         g_free(wlclient);
4091                                                         wlclient = NULL;
4092                                                 }
4093                                         }
4094                                         wfd_sink_debug("set video param : surface_id %d", wl_surface_id);
4095
4096                                         if (USE_EXTERNAL_WL_DISPLAY_HANDLE) {
4097                                                 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink),
4098                                                                                                                 wl_surface_id);
4099                                         } else {
4100                                                 gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(video_sink),
4101                                                                                                                                 wl_surface_id);
4102                                         }
4103
4104                                         /* After setting window handle, set render rectangle */
4105                                         gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink),
4106                                                                                                                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
4107                                 } else {
4108                                         wfd_sink_debug("display object is NULL!");
4109                                         return MM_ERROR_WFD_INTERNAL;
4110                                 }
4111                         }
4112                         break;
4113
4114                 case MM_DISPLAY_SURFACE_NULL: {
4115                                 /* do nothing */
4116                                 wfd_sink_error("Not Supported Surface.");
4117                                 return MM_ERROR_WFD_INTERNAL;
4118                         }
4119                         break;
4120                 default: {
4121                                 wfd_sink_error("Not Supported Surface.(default case)");
4122                                 return MM_ERROR_WFD_INTERNAL;
4123                         }
4124                         break;
4125         }
4126
4127         g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
4128         g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
4129         g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
4130         g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
4131         g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
4132
4133         wfd_sink_debug_fleave();
4134
4135         return MM_ERROR_NONE;
4136 }
4137
4138 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
4139 {
4140         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4141         MMWFDSinkGstElement *v_decodebin = NULL;
4142         GstObject *parent = NULL;
4143         int i;
4144
4145         wfd_sink_debug_fenter();
4146
4147         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4148
4149         if (wfd_sink->pipeline &&
4150             wfd_sink->pipeline->v_decodebin &&
4151             wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4152                 v_decodebin = wfd_sink->pipeline->v_decodebin;
4153         } else {
4154                 wfd_sink_debug("video decodebin is not created, nothing to destroy");
4155                 return MM_ERROR_NONE;
4156         }
4157
4158
4159         parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
4160         if (!parent) {
4161                 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
4162
4163                 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
4164                         wfd_sink_debug("try to change state of video decodebin to NULL");
4165                         ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
4166                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4167                                 wfd_sink_error("failed to change state of video decodebin to NULL");
4168                                 return MM_ERROR_WFD_INTERNAL;
4169                         }
4170                 }
4171                 /* release element which are not added to bin */
4172                 for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
4173                         if (v_decodebin[i].gst) {
4174                                 parent = gst_element_get_parent(v_decodebin[i].gst);
4175                                 if (!parent) {
4176                                         wfd_sink_debug("unref %s(current ref %d)",
4177                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4178                                                                         ((GObject *) v_decodebin[i].gst)->ref_count);
4179                                         gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4180                                         v_decodebin[i].gst = NULL;
4181                                 } else {
4182                                         wfd_sink_debug("%s has parent.(current ref %d)",
4183                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4184                                                                         ((GObject *) v_decodebin[i].gst)->ref_count);
4185                                         gst_object_unref(GST_OBJECT(parent));
4186                                         parent = NULL;
4187                                 }
4188                         }
4189                 }
4190                 /* release video decodebin with it's childs */
4191                 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
4192                         wfd_sink_debug("unref %s(current ref %d)",
4193                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
4194                                                         ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
4195
4196                         gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4197                         v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4198                 }
4199         } else {
4200                 wfd_sink_debug("video decodebin has parent(%s), unref it",
4201                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4202
4203                 gst_object_unref(GST_OBJECT(parent));
4204                 parent = NULL;
4205         }
4206
4207         wfd_sink->video_decodebin_is_linked = FALSE;
4208
4209         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
4210
4211         wfd_sink_debug_fleave();
4212
4213         return MM_ERROR_NONE;
4214 }
4215
4216 int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
4217 {
4218         MMWFDSinkGstElement *v_decodebin = NULL;
4219         guint video_codec = WFD_VIDEO_UNKNOWN;
4220         GList *element_bucket = NULL;
4221         gboolean link = TRUE;
4222         gint i = 0;
4223
4224         wfd_sink_debug_fenter();
4225
4226         wfd_sink_return_val_if_fail(wfd_sink &&
4227                                                                 wfd_sink->pipeline,
4228                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
4229
4230         if (wfd_sink->pipeline->v_decodebin) {
4231                 wfd_sink_debug("video decodebin is already created... nothing to do");
4232                 return MM_ERROR_NONE;
4233         }
4234
4235         /* check video decodebin could be linked now */
4236         switch (wfd_sink->stream_info.video_stream_info.codec) {
4237         case MM_WFD_SINK_VIDEO_CODEC_H264:
4238                 video_codec = WFD_VIDEO_H264;
4239                 link = TRUE;
4240                 break;
4241         case MM_WFD_SINK_VIDEO_CODEC_H265:
4242                 video_codec = WFD_VIDEO_H265;
4243                 link = TRUE;
4244                 break;
4245         case MM_WFD_SINK_VIDEO_CODEC_NONE:
4246         default:
4247                 wfd_sink_debug("video decodebin could NOT be linked now, just create");
4248                 video_codec = wfd_sink->ini.wfd_video_formats.video_codec | wfd_sink->ini.wfd2_video_formats.video_codec;
4249                 link = FALSE;
4250                 break;
4251         }
4252
4253         /* alloc handles */
4254         v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4255         if (!v_decodebin) {
4256                 wfd_sink_error("failed to allocate memory for video decodebin");
4257                 return MM_ERROR_WFD_NO_FREE_SPACE;
4258         }
4259
4260         memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4261
4262         /* create video decodebin */
4263         v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
4264         v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
4265         if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
4266                 wfd_sink_error("failed to create video decodebin");
4267                 goto CREATE_ERROR;
4268         }
4269
4270         /* create queue */
4271         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
4272         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "sink");
4273         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "src");
4274         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
4275                 __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
4276
4277         /* create hdcp */
4278         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
4279         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "sink");
4280         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "src");
4281
4282         if (video_codec & WFD_VIDEO_H264) {
4283                 /* create parser */
4284                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h264_parser", FALSE);
4285                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "sink");
4286                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "src");
4287
4288                 /* create dec */
4289                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_DEC, wfd_sink->ini.name_of_video_h264_decoder, "video_h264_dec", FALSE);
4290                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "sink");
4291                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "src");
4292                 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst) {
4293                         if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H264_DEC].gst)) {
4294                                 wfd_sink_error("failed to set video decoder property...");
4295                                 goto CREATE_ERROR;
4296                         }
4297                 }
4298         }
4299
4300         if (video_codec & WFD_VIDEO_H265) {
4301                 /* create parser */
4302                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h265_parser", FALSE);
4303                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "sink");
4304                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "src");
4305
4306                 /* create dec */
4307                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_DEC, wfd_sink->ini.name_of_video_h265_decoder, "video_h265_dec", FALSE);
4308                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "sink");
4309                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "src");
4310                 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst) {
4311                         if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H265_DEC].gst)) {
4312                                 wfd_sink_error("failed to set video decoder property...");
4313                                 goto CREATE_ERROR;
4314                         }
4315                 }
4316         }
4317
4318         g_list_free(element_bucket);
4319
4320         /* take it */
4321         wfd_sink->pipeline->v_decodebin = v_decodebin;
4322
4323         /* link video decodebin if video codec is fixed */
4324         if (link) {
4325                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
4326                         wfd_sink_error("failed to link video decodebin, destroy video decodebin");
4327                         __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
4328                         return MM_ERROR_WFD_INTERNAL;
4329                 }
4330         }
4331
4332         wfd_sink_debug_fleave();
4333
4334         return MM_ERROR_NONE;
4335
4336         /* ERRORS */
4337 CREATE_ERROR:
4338         wfd_sink_error("failed to create video decodebin, releasing all");
4339
4340         g_list_free(element_bucket);
4341
4342         /* release element which are not added to bin */
4343         for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
4344                 if (v_decodebin != NULL && v_decodebin[i].gst) {
4345                         GstObject *parent = NULL;
4346                         parent = gst_element_get_parent(v_decodebin[i].gst);
4347
4348                         if (!parent) {
4349                                 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4350                                 v_decodebin[i].gst = NULL;
4351                         } else {
4352                                 gst_object_unref(GST_OBJECT(parent));
4353                                 parent = NULL;
4354                         }
4355                 }
4356         }
4357
4358         /* release video decodebin with it's childs */
4359         if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) {
4360                 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4361                 v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4362         }
4363
4364         MMWFDSINK_FREEIF(v_decodebin);
4365
4366         return MM_ERROR_WFD_INTERNAL;
4367 }
4368
4369 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4370 {
4371         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4372         MMWFDSinkGstElement *v_sinkbin = NULL;
4373         GstObject *parent = NULL;
4374         int i;
4375
4376         wfd_sink_debug_fenter();
4377
4378         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4379
4380         if (wfd_sink->pipeline &&
4381             wfd_sink->pipeline->v_sinkbin &&
4382             wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4383                 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4384         } else {
4385                 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
4386                 return MM_ERROR_NONE;
4387         }
4388
4389
4390         parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
4391         if (!parent) {
4392                 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
4393
4394                 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
4395                         wfd_sink_debug("try to change state of video sinkbin to NULL");
4396                         ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
4397                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4398                                 wfd_sink_error("failed to change state of video sinkbin to NULL");
4399                                 return MM_ERROR_WFD_INTERNAL;
4400                         }
4401                 }
4402                 /* release element which are not added to bin */
4403                 for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
4404                         if (v_sinkbin[i].gst) {
4405                                 parent = gst_element_get_parent(v_sinkbin[i].gst);
4406                                 if (!parent) {
4407                                         wfd_sink_debug("unref %s(current ref %d)",
4408                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4409                                                                         ((GObject *) v_sinkbin[i].gst)->ref_count);
4410                                         gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4411                                         v_sinkbin[i].gst = NULL;
4412                                 } else {
4413                                         wfd_sink_debug("%s has parent.(current ref %d)",
4414                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4415                                                                         ((GObject *) v_sinkbin[i].gst)->ref_count);
4416                                         gst_object_unref(GST_OBJECT(parent));
4417                                         parent = NULL;
4418                                 }
4419                         }
4420                 }
4421                 /* release video sinkbin with it's childs */
4422                 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4423                         gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4424                         v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4425                 }
4426         } else {
4427                 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
4428                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4429
4430                 gst_object_unref(GST_OBJECT(parent));
4431                 parent = NULL;
4432         }
4433
4434         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
4435
4436         wfd_sink_debug_fleave();
4437
4438         return MM_ERROR_NONE;
4439 }
4440
4441 int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4442 {
4443         MMWFDSinkGstElement *first_element = NULL;
4444         MMWFDSinkGstElement *v_sinkbin = NULL;
4445         GList *element_bucket = NULL;
4446         GstPad *pad = NULL;
4447         GstPad *ghostpad = NULL;
4448         gint i = 0;
4449         gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
4450
4451         wfd_sink_debug_fenter();
4452
4453         wfd_sink_return_val_if_fail(wfd_sink &&
4454                                                                 wfd_sink->pipeline,
4455                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
4456
4457         if (wfd_sink->pipeline->v_sinkbin != NULL) {
4458                 wfd_sink_error("The video sink bin is already created.");
4459                 return MM_ERROR_NONE;
4460         }
4461
4462         /* alloc handles */
4463         v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4464         if (!v_sinkbin) {
4465                 wfd_sink_error("failed to allocate memory for video sinkbin");
4466                 return MM_ERROR_WFD_NO_FREE_SPACE;
4467         }
4468
4469         memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4470
4471         /* create video sinkbin */
4472         v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
4473         v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
4474         if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4475                 wfd_sink_error("failed to create video sinkbin");
4476                 goto CREATE_ERROR;
4477         }
4478
4479         /* create convert */
4480         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
4481         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "sink");
4482         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "src");
4483
4484         /* create filter */
4485         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
4486         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "sink");
4487         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "src");
4488         if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
4489                 GstCaps *caps = NULL;
4490                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL);
4491                 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
4492                 gst_object_unref(GST_OBJECT(caps));
4493                 caps = NULL;
4494         }
4495
4496         /* create sink */
4497         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
4498
4499         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
4500                 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
4501         } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) {
4502                 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE);
4503         } else {
4504                 wfd_sink_error("failed to set video sink....");
4505                 goto CREATE_ERROR;
4506         }
4507
4508         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst,  "sink");
4509         if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
4510                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
4511                         wfd_sink_error("failed to set video sink property....");
4512                         goto CREATE_ERROR;
4513                 }
4514         }
4515
4516         /* adding created elements to video sinkbin */
4517         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
4518                 wfd_sink_error("failed to add elements to video sinkbin");
4519                 goto CREATE_ERROR;
4520         }
4521
4522         /* linking elements in the bucket by added order. */
4523         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
4524                 wfd_sink_error("failed to link elements of the video sinkbin");
4525                 goto CREATE_ERROR;
4526         }
4527
4528         /* get first element's sinkpad for creating ghostpad */
4529         first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
4530         if (!first_element) {
4531                 wfd_sink_error("failed to get first element of the video sinkbin");
4532                 goto CREATE_ERROR;
4533         }
4534
4535         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4536         if (!pad) {
4537                 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
4538                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
4539                 goto CREATE_ERROR;
4540         }
4541
4542         ghostpad = gst_ghost_pad_new("sink", pad);
4543         if (!ghostpad) {
4544                 wfd_sink_error("failed to create ghostpad of the video sinkbin");
4545                 goto CREATE_ERROR;
4546         }
4547
4548         if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
4549                 wfd_sink_error("failed to add ghostpad to video sinkbin");
4550                 goto CREATE_ERROR;
4551         }
4552
4553         gst_object_unref(GST_OBJECT(pad));
4554         pad = NULL;
4555
4556         g_list_free(element_bucket);
4557         element_bucket = NULL;
4558
4559         /* take it */
4560         wfd_sink->pipeline->v_sinkbin = v_sinkbin;
4561
4562         wfd_sink_debug_fleave();
4563
4564         return MM_ERROR_NONE;
4565
4566         /* ERRORS */
4567 CREATE_ERROR:
4568         wfd_sink_error("failed to create video sinkbin, releasing all");
4569
4570         if (pad) {
4571                 gst_object_unref(GST_OBJECT(pad));
4572                 pad = NULL;
4573         }
4574
4575         if (ghostpad) {
4576                 gst_object_unref(GST_OBJECT(ghostpad));
4577                 ghostpad = NULL;
4578         }
4579
4580         if (element_bucket) {
4581                 g_list_free(element_bucket);
4582                 element_bucket = NULL;
4583         }
4584
4585         /* release element which are not added to bin */
4586         for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
4587                 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
4588                         GstObject *parent = NULL;
4589                         parent = gst_element_get_parent(v_sinkbin[i].gst);
4590
4591                         if (!parent) {
4592                                 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4593                                 v_sinkbin[i].gst = NULL;
4594                         } else {
4595                                 gst_object_unref(GST_OBJECT(parent));
4596                                 parent = NULL;
4597                         }
4598                 }
4599         }
4600
4601         /* release video sinkbin with it's childs */
4602         if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4603                 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4604                 v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4605         }
4606         MMWFDSINK_FREEIF(v_sinkbin);
4607
4608         return MM_ERROR_WFD_INTERNAL;
4609 }
4610
4611 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
4612 {
4613         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4614         GstBus *bus = NULL;
4615
4616         wfd_sink_debug_fenter();
4617
4618         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4619
4620         /* cleanup gst stuffs */
4621         if (wfd_sink->pipeline) {
4622                 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
4623
4624                 if (mainbin) {
4625
4626                         PRINT_WFD_REF_COUNT(wfd_sink);
4627
4628                         ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
4629                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4630                                 wfd_sink_error("failed to change state of pipeline to NULL");
4631                                 return MM_ERROR_WFD_INTERNAL;
4632                         } else {
4633                                 wfd_sink_debug("Successed to change state of pipeline to NULL");
4634                         }
4635
4636                         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
4637                         if (bus) {
4638                                 GstMessage *gst_msg = NULL;
4639                                 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
4640                                         _mm_wfd_sink_msg_callback(bus, gst_msg, (gpointer)wfd_sink);
4641                                         gst_message_unref(gst_msg);
4642                                         gst_msg = NULL;
4643                                 }
4644                                 gst_object_unref(bus);
4645                                 bus = NULL;
4646                         }
4647
4648                         PRINT_WFD_REF_COUNT(wfd_sink);
4649
4650                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
4651                                 wfd_sink_error("failed to destroy video decodebin");
4652                                 return MM_ERROR_WFD_INTERNAL;
4653                         }
4654
4655                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
4656                                 wfd_sink_error("failed to destroy audio decodebin");
4657                                 return MM_ERROR_WFD_INTERNAL;
4658                         }
4659
4660                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
4661                                 wfd_sink_error("failed to destroy video sinkbin");
4662                                 return MM_ERROR_WFD_INTERNAL;
4663                         }
4664
4665                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
4666                                 wfd_sink_error("failed to destroy audio sinkbin");
4667                                 return MM_ERROR_WFD_INTERNAL;
4668                         }
4669
4670                         gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
4671                         mainbin[WFD_SINK_M_PIPE].gst = NULL;
4672
4673                         MMWFDSINK_FREEIF(mainbin);
4674                 }
4675
4676                 MMWFDSINK_FREEIF(wfd_sink->pipeline);
4677         }
4678
4679         if (wfd_sink->msg_callback_id > 0) {
4680                 g_source_remove(wfd_sink->msg_callback_id);
4681                 wfd_sink->msg_callback_id = 0;
4682         }
4683
4684         wfd_sink->audio_decodebin_is_linked = FALSE;
4685         wfd_sink->video_decodebin_is_linked = FALSE;
4686         wfd_sink->need_to_reset_basetime = FALSE;
4687
4688         wfd_sink_debug_fleave();
4689
4690         return MM_ERROR_NONE;
4691 }
4692
4693 static void
4694 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
4695 {
4696         GstIterator *iter = NULL;
4697         gboolean done = FALSE;
4698
4699         GstElement *item = NULL;
4700         GstElementFactory *factory = NULL;
4701
4702         GstState state = GST_STATE_VOID_PENDING;
4703         GstState pending = GST_STATE_VOID_PENDING;
4704         GstClockTime time = 200 * GST_MSECOND;
4705
4706         wfd_sink_debug_fenter();
4707
4708         wfd_sink_return_if_fail(wfd_sink &&
4709                                                         wfd_sink->pipeline &&
4710                                                         wfd_sink->pipeline->mainbin &&
4711                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4712
4713         iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
4714
4715         if (iter != NULL) {
4716                 while (!done) {
4717                         switch (gst_iterator_next(iter, (gpointer)&item)) {
4718                         case GST_ITERATOR_OK:
4719                                 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4720
4721                                 factory = gst_element_get_factory(item) ;
4722                                 if (factory) {
4723                                         wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4724                                                 GST_STR_NULL(GST_OBJECT_NAME(factory)),
4725                                                 GST_STR_NULL(GST_ELEMENT_NAME(item)),
4726                                                 gst_element_state_get_name(state),
4727                                                 gst_element_state_get_name(pending),
4728                                                 GST_OBJECT_REFCOUNT_VALUE(item));
4729                                 }
4730                                 gst_object_unref(item);
4731                                 item = NULL;
4732                                 break;
4733                         case GST_ITERATOR_RESYNC:
4734                                 gst_iterator_resync(iter);
4735                                 break;
4736                         case GST_ITERATOR_ERROR:
4737                                 done = TRUE;
4738                                 break;
4739                         case GST_ITERATOR_DONE:
4740                                 done = TRUE;
4741                                 break;
4742                         default:
4743                                 done = TRUE;
4744                                 break;
4745                         }
4746                 }
4747         }
4748
4749         item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4750
4751         gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4752
4753         factory = gst_element_get_factory(item) ;
4754         if (factory) {
4755                 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4756                                                 GST_OBJECT_NAME(factory),
4757                                                 GST_ELEMENT_NAME(item),
4758                                                 gst_element_state_get_name(state),
4759                                                 gst_element_state_get_name(pending),
4760                                                 GST_OBJECT_REFCOUNT_VALUE(item));
4761         }
4762
4763         if (iter)
4764                 gst_iterator_free(iter);
4765
4766         wfd_sink_debug_fleave();
4767
4768         return;
4769 }
4770
4771 const gchar *
4772 _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
4773 {
4774         switch (state) {
4775         case MM_WFD_SINK_STATE_NONE:
4776                 return "NONE";
4777         case MM_WFD_SINK_STATE_NULL:
4778                 return "NULL";
4779         case MM_WFD_SINK_STATE_PREPARED:
4780                 return "PREPARED";
4781         case MM_WFD_SINK_STATE_CONNECTED:
4782                 return "CONNECTED";
4783         case MM_WFD_SINK_STATE_PLAYING:
4784                 return "PLAYING";
4785         case MM_WFD_SINK_STATE_PAUSED:
4786                 return "PAUSED";
4787         case MM_WFD_SINK_STATE_DISCONNECTED:
4788                 return "DISCONNECTED";
4789         default:
4790                 return "INVAID";
4791         }
4792 }
4793
4794 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
4795 {
4796         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
4797
4798         wfd_sink_debug_fenter();
4799
4800         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4801
4802         MMWFDSINK_PRINT_STATE(wfd_sink);
4803         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
4804         if (cur_state != MM_WFD_SINK_STATE_NULL) {
4805                 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
4806                 return MM_ERROR_WFD_INVALID_STATE;
4807         }
4808
4809         wfd_sink->supportive_resolution = resolution;
4810
4811         wfd_sink_debug_fleave();
4812
4813         return MM_ERROR_NONE;
4814 }
4815
4816 void __mm_wfd_sink_print_ref_count(mm_wfd_sink_t *wfd_sink)
4817 {
4818         int i = 0;
4819         MMWFDSinkGstElement *mainbin = NULL;
4820         MMWFDSinkGstElement *v_decodebin = NULL;
4821         MMWFDSinkGstElement *a_decodebin = NULL;
4822         MMWFDSinkGstElement *v_sinkbin = NULL;
4823         MMWFDSinkGstElement *a_sinkbin = NULL;
4824
4825         wfd_sink_debug_fenter();
4826
4827         wfd_sink_return_if_fail(wfd_sink);
4828         wfd_sink_return_if_fail(wfd_sink->pipeline);
4829
4830         wfd_sink_debug("************* wfd pipeline ref count start *************");
4831         wfd_sink_debug("try to check mainbin");
4832
4833         if (wfd_sink->pipeline->mainbin &&
4834             wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) {
4835                 mainbin = wfd_sink->pipeline->mainbin;
4836
4837                 for (i = 0; i < WFD_SINK_M_NUM; i++) {
4838                         if (mainbin[i].gst) {
4839                                 wfd_sink_debug("%s(current ref %d)",
4840                                                                 GST_ELEMENT_NAME(mainbin[i].gst),
4841                                                                 GST_OBJECT_REFCOUNT(mainbin[i].gst));
4842                         }
4843                 }
4844         }
4845
4846         wfd_sink_debug("try to check a_decodebin");
4847
4848         if (wfd_sink->pipeline->a_decodebin &&
4849             wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
4850                 a_decodebin = wfd_sink->pipeline->a_decodebin;
4851
4852                 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
4853                         if (a_decodebin[i].gst) {
4854                                 wfd_sink_debug("%s(current ref %d)",
4855                                                                 GST_ELEMENT_NAME(a_decodebin[i].gst),
4856                                                                 GST_OBJECT_REFCOUNT(a_decodebin[i].gst));
4857                         }
4858                 }
4859         }
4860
4861         wfd_sink_debug("try to check a_sinkbin");
4862
4863         if (wfd_sink->pipeline->a_sinkbin &&
4864             wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
4865                 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
4866
4867                 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
4868                         if (a_sinkbin[i].gst) {
4869                                 wfd_sink_debug("%s(current ref %d)",
4870                                                                 GST_ELEMENT_NAME(a_sinkbin[i].gst),
4871                                                                 GST_OBJECT_REFCOUNT(a_sinkbin[i].gst));
4872                         }
4873                 }
4874         }
4875
4876         wfd_sink_debug("try to check v_decodebin");
4877
4878         if (wfd_sink->pipeline->v_decodebin &&
4879             wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4880                 v_decodebin = wfd_sink->pipeline->v_decodebin;
4881
4882                 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
4883                         if (v_decodebin[i].gst) {
4884                                 wfd_sink_debug("%s(current ref %d)",
4885                                                                 GST_ELEMENT_NAME(v_decodebin[i].gst),
4886                                                                 GST_OBJECT_REFCOUNT(v_decodebin[i].gst));
4887                         }
4888                 }
4889         }
4890
4891         wfd_sink_debug("try to check v_sinkbin");
4892
4893         if (wfd_sink->pipeline->v_sinkbin &&
4894             wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4895                 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4896
4897                 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
4898                         if (v_sinkbin[i].gst) {
4899                                 wfd_sink_debug("%s(current ref %d)",
4900                                                                 GST_ELEMENT_NAME(v_sinkbin[i].gst),
4901                                                                 GST_OBJECT_REFCOUNT(v_sinkbin[i].gst));
4902                         }
4903                 }
4904         }
4905         wfd_sink_debug("************* wfd pipeline ref count end *************");
4906         wfd_sink_debug_fleave();
4907 }