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