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