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