Remove unused variables
[platform/core/multimedia/libmm-wfd.git] / sink / 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
26 #include "mm_wfd_sink_util.h"
27 #include "mm_wfd_sink_priv.h"
28 #include "mm_wfd_sink_manager.h"
29 #include "mm_wfd_sink_dlog.h"
30 #include <wfdconfigmessage.h>
31
32
33 /* gstreamer */
34 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
35 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
36 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink);
37 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink);
38 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
39 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
40 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink);
41 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
42 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
43 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
44
45 /* state */
46 static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd);
47 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
48
49 /* util */
50 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
51 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution,
52                                                    guint *VESA_resolution, guint *HH_resolution);
53
54 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
55 {
56         int result = MM_ERROR_NONE;
57
58         wfd_sink_debug_fenter();
59
60         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
61
62         mm_wfd_sink_t *new_wfd_sink = NULL;
63
64         /* create handle */
65         new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
66         if (!new_wfd_sink) {
67                 wfd_sink_error("failed to allocate memory for wi-fi display sink");
68                 return MM_ERROR_WFD_NO_FREE_SPACE;
69         }
70
71         /* Initialize gstreamer related */
72         new_wfd_sink->attrs = 0;
73
74         new_wfd_sink->pipeline = NULL;
75         new_wfd_sink->audio_decodebin_is_linked = FALSE;
76         new_wfd_sink->video_decodebin_is_linked = FALSE;
77
78         /* Initialize timestamp compensation related */
79         new_wfd_sink->need_to_reset_basetime = FALSE;
80         new_wfd_sink->clock = NULL;
81         new_wfd_sink->video_buffer_count = 0LL;
82         new_wfd_sink->video_average_gap = 0LL;
83         new_wfd_sink->video_accumulated_gap = 0LL;
84         new_wfd_sink->audio_buffer_count = 0LL;
85         new_wfd_sink->audio_average_gap = 0LL;
86         new_wfd_sink->audio_accumulated_gap = 0LL;
87         new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
88
89         /* Initialize all states */
90         MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
91         MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
92         MMWFDSINK_PENDING_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
93
94         /* initialize audio/video information */
95         new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
96         new_wfd_sink->stream_info.audio_stream_info.channels = 0;
97         new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
98         new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
99         new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
100         new_wfd_sink->stream_info.video_stream_info.width = 0;
101         new_wfd_sink->stream_info.video_stream_info.height = 0;
102         new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
103
104         /* Initialize command */
105         new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
106         new_wfd_sink->waiting_cmd = FALSE;
107
108         /* Initialize manager related */
109         new_wfd_sink->manager_thread = NULL;
110         new_wfd_sink->manager_thread_cmd = NULL;
111         new_wfd_sink->manager_thread_exit = FALSE;
112
113         /* Initialize video resolution */
114         new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
115
116         /* construct attributes */
117         new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
118         if (!new_wfd_sink->attrs) {
119                 MMWFDSINK_FREEIF(new_wfd_sink);
120                 wfd_sink_error("failed to set attribute");
121                 return MM_ERROR_WFD_INTERNAL;
122         }
123
124         /* load ini for initialize */
125         result = mm_wfd_sink_ini_load(&new_wfd_sink->ini);
126         if (result != MM_ERROR_NONE) {
127                 wfd_sink_error("failed to load ini file");
128                 goto fail_to_load_ini;
129         }
130         new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
131
132         /* initialize manager */
133         result = _mm_wfd_sink_init_manager(new_wfd_sink);
134         if (result < MM_ERROR_NONE) {
135                 wfd_sink_error("failed to init manager : %d", result);
136                 goto fail_to_init;
137         }
138
139         /* initialize gstreamer */
140         result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
141         if (result < MM_ERROR_NONE) {
142                 wfd_sink_error("failed to init gstreamer : %d", result);
143                 goto fail_to_init;
144         }
145
146         /* set state */
147         __mm_wfd_sink_set_state(new_wfd_sink,  MM_WFD_SINK_STATE_NULL);
148
149         /* now take handle */
150         *wfd_sink = new_wfd_sink;
151
152         wfd_sink_debug_fleave();
153
154         return result;
155
156         /* ERRORS */
157 fail_to_init:
158         mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
159 fail_to_load_ini:
160         _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
161         MMWFDSINK_FREEIF(new_wfd_sink);
162
163         *wfd_sink = NULL;
164
165         return result;
166 }
167
168 int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink)
169 {
170         int result = MM_ERROR_NONE;
171
172         wfd_sink_debug_fenter();
173
174         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
175
176         /* check current wi-fi display sink state */
177         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
178
179         /* construct pipeline */
180         /* create main pipeline */
181         result = __mm_wfd_sink_create_pipeline(wfd_sink);
182         if (result < MM_ERROR_NONE) {
183                 wfd_sink_error("failed to create pipeline : %d", result);
184                 goto fail_to_create;
185         }
186
187         /* create video decodebin */
188         result = __mm_wfd_sink_create_video_decodebin(wfd_sink);
189         if (result < MM_ERROR_NONE) {
190                 wfd_sink_error("failed to create video decodebin %d", result);
191                 goto fail_to_create;
192         }
193
194         /* create video sinkbin */
195         result = __mm_wfd_sink_create_video_sinkbin(wfd_sink);
196         if (result < MM_ERROR_NONE) {
197                 wfd_sink_error("failed to create video sinkbin %d", result);
198                 goto fail_to_create;
199         }
200
201         /* create audio decodebin */
202         result = __mm_wfd_sink_create_audio_decodebin(wfd_sink);
203         if (result < MM_ERROR_NONE) {
204                 wfd_sink_error("fail to create audio decodebin : %d", result);
205                 goto fail_to_create;
206         }
207
208         /* create audio sinkbin */
209         result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink);
210         if (result < MM_ERROR_NONE) {
211                 wfd_sink_error("fail to create audio sinkbin : %d", result);
212                 goto fail_to_create;
213         }
214
215         /* set pipeline READY state */
216         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
217         if (result < MM_ERROR_NONE) {
218                 wfd_sink_error("failed to set state : %d", result);
219                 goto fail_to_create;
220         }
221
222         /* set state */
223         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PREPARED);
224
225         wfd_sink_debug_fleave();
226
227         return result;
228
229         /* ERRORS */
230 fail_to_create:
231         /* need to destroy pipeline already created */
232         __mm_wfd_sink_destroy_pipeline(wfd_sink);
233         return result;
234 }
235
236 int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
237 {
238         int result = MM_ERROR_NONE;
239
240         wfd_sink_debug_fenter();
241
242         wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
243                                     MM_ERROR_WFD_INVALID_ARGUMENT);
244         wfd_sink_return_val_if_fail(wfd_sink &&
245                                     wfd_sink->pipeline &&
246                                     wfd_sink->pipeline->mainbin &&
247                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
248                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
249                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
250                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
251                                     MM_ERROR_WFD_NOT_INITIALIZED);
252
253         /* check current wi-fi display sink state */
254         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
255
256         wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
257
258         /* set uri to wfdrtspsrc */
259         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
260
261         /* set pipeline PAUSED state */
262         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
263         if (result < MM_ERROR_NONE) {
264                 wfd_sink_error("failed to set state : %d", result);
265                 return result;
266         }
267
268         wfd_sink_debug_fleave();
269
270         return result;
271 }
272
273 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
274 {
275         int result = MM_ERROR_NONE;
276
277         wfd_sink_debug_fenter();
278
279         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
280
281         /* check current wi-fi display sink state */
282         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
283
284         WFD_SINK_MANAGER_LOCK(wfd_sink) ;
285         wfd_sink_debug("check pipeline is ready to start");
286         WFD_SINK_MANAGER_UNLOCK(wfd_sink);
287
288         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
289         if (result < MM_ERROR_NONE) {
290                 wfd_sink_error("failed to set state : %d", result);
291                 return result;
292         }
293
294         wfd_sink_debug_fleave();
295
296         return result;
297 }
298
299 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
300 {
301         int result = MM_ERROR_NONE;
302
303         wfd_sink_debug_fenter();
304
305         wfd_sink_return_val_if_fail(wfd_sink &&
306                                     wfd_sink->pipeline &&
307                                     wfd_sink->pipeline->mainbin &&
308                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
309                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
310                                     MM_ERROR_WFD_NOT_INITIALIZED);
311
312         /* check current wi-fi display sink state */
313         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
314
315         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL);
316
317         wfd_sink_debug_fleave();
318
319         return result;
320 }
321
322 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
323 {
324         int result = MM_ERROR_NONE;
325
326         wfd_sink_debug_fenter();
327
328         wfd_sink_return_val_if_fail(wfd_sink &&
329                                     wfd_sink->pipeline &&
330                                     wfd_sink->pipeline->mainbin &&
331                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
332                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
333                                     MM_ERROR_WFD_NOT_INITIALIZED);
334
335         /* check current wi-fi display sink state */
336         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
337
338         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL);
339
340         wfd_sink_debug_fleave();
341
342         return result;
343 }
344
345 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
346 {
347         int result = MM_ERROR_NONE;
348
349         wfd_sink_debug_fenter();
350
351         wfd_sink_return_val_if_fail(wfd_sink &&
352                                     wfd_sink->pipeline &&
353                                     wfd_sink->pipeline->mainbin &&
354                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
355                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
356                                     MM_ERROR_WFD_NOT_INITIALIZED);
357
358         /* check current wi-fi display sink state */
359         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
360
361         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
362         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
363
364         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL);
365
366         wfd_sink_debug_fleave();
367
368         return result;
369 }
370
371 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
372 {
373         int result = MM_ERROR_NONE;
374
375         wfd_sink_debug_fenter();
376
377         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
378
379         /* check current wi-fi display sink state */
380         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
381
382         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
383         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
384
385         /* release pipeline */
386         result =  __mm_wfd_sink_destroy_pipeline(wfd_sink);
387         if (result != MM_ERROR_NONE) {
388                 wfd_sink_error("failed to destory pipeline");
389                 return MM_ERROR_WFD_INTERNAL;
390         } else {
391                 wfd_sink_debug("success to destory pipeline");
392         }
393
394         /* set state */
395         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NULL);
396
397         wfd_sink_debug_fleave();
398
399         return result;
400 }
401
402 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
403 {
404         int result = MM_ERROR_NONE;
405
406         wfd_sink_debug_fenter();
407
408         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
409
410         /* check current wi-fi display sink state */
411         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
412
413         /* unload ini */
414         mm_wfd_sink_ini_unload(&wfd_sink->ini);
415
416         /* release attributes */
417         _mmwfd_deconstruct_attribute(wfd_sink->attrs);
418
419         if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
420                 wfd_sink_error("failed to release manager");
421                 return MM_ERROR_WFD_INTERNAL;
422         }
423
424
425         /* set state */
426         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NONE);
427
428         wfd_sink_debug_fleave();
429
430         return result;
431 }
432
433 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
434 {
435         int result = MM_ERROR_NONE;
436
437         wfd_sink_debug_fenter();
438
439         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
440
441         wfd_sink->msg_cb = callback;
442         wfd_sink->msg_user_data = user_data;
443
444         wfd_sink_debug_fleave();
445
446         return result;
447 }
448
449 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
450 {
451         int result = MM_ERROR_NONE;
452         gint *argc = NULL;
453         gchar **argv = NULL;
454         static const int max_argc = 50;
455         GError *err = NULL;
456         gint i = 0;
457
458         wfd_sink_debug_fenter();
459
460         /* alloc */
461         argc = calloc(1, sizeof(gint));
462         argv = calloc(max_argc, sizeof(gchar *));
463         if (!argc || !argv) {
464                 wfd_sink_error("failed to allocate memory for wfdsink");
465
466                 MMWFDSINK_FREEIF(argv);
467                 MMWFDSINK_FREEIF(argc);
468
469                 return MM_ERROR_WFD_NO_FREE_SPACE;
470         }
471
472         /* we would not do fork for scanning plugins */
473         argv[*argc] = g_strdup("--gst-disable-registry-fork");
474         (*argc)++;
475
476         /* check disable registry scan */
477         argv[*argc] = g_strdup("--gst-disable-registry-update");
478         (*argc)++;
479
480         /* check disable segtrap */
481         argv[*argc] = g_strdup("--gst-disable-segtrap");
482         (*argc)++;
483
484         /* check ini */
485         for (i = 0; i < 5; i++) {
486                 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
487                         wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
488                         argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
489                         (*argc)++;
490                 }
491         }
492
493         wfd_sink_debug("initializing gstreamer with following parameter");
494         wfd_sink_debug("argc : %d", *argc);
495
496         for (i = 0; i < *argc; i++) {
497                 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
498         }
499
500         /* initializing gstreamer */
501         if (!gst_init_check(argc, &argv, &err)) {
502                 wfd_sink_error("failed to initialize gstreamer: %s",
503                                err ? err->message : "unknown error occurred");
504                 if (err)
505                         g_error_free(err);
506
507                 result = MM_ERROR_WFD_INTERNAL;
508         }
509
510         /* release */
511         for (i = 0; i < *argc; i++) {
512                 MMWFDSINK_FREEIF(argv[i]);
513         }
514         MMWFDSINK_FREEIF(argv);
515         MMWFDSINK_FREEIF(argc);
516
517         wfd_sink_debug_fleave();
518
519         return result;
520 }
521
522 static GstBusSyncReply
523 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
524 {
525         GstBusSyncReply ret = GST_BUS_PASS;
526
527         wfd_sink_return_val_if_fail(message &&
528                                     GST_IS_MESSAGE(message) &&
529                                     GST_MESSAGE_SRC(message),
530                                     GST_BUS_DROP);
531
532         switch (GST_MESSAGE_TYPE(message)) {
533                 case GST_MESSAGE_TAG:
534                         break;
535                 case GST_MESSAGE_DURATION:
536                         break;
537                 case GST_MESSAGE_STATE_CHANGED: {
538                                 /* we only handle state change messages from pipeline */
539                                 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
540                                         ret = GST_BUS_DROP;
541                         }
542                         break;
543                 case GST_MESSAGE_ASYNC_DONE: {
544                                 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
545                                         ret = GST_BUS_DROP;
546                         }
547                         break;
548                 default:
549                         break;
550         }
551
552         return ret;
553 }
554
555 static gboolean
556 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
557 {
558         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
559         const GstStructure *message_structure = gst_message_get_structure(msg);
560         gboolean ret = TRUE;
561
562         wfd_sink_return_val_if_fail(wfd_sink, FALSE);
563         wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
564
565         wfd_sink_debug("got %s from %s",
566                        GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
567                        GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
568
569         switch (GST_MESSAGE_TYPE(msg)) {
570                 case GST_MESSAGE_ERROR: {
571                                 GError *error = NULL;
572                                 gchar *debug = NULL;
573
574                                 /* get error code */
575                                 gst_message_parse_error(msg, &error, &debug);
576
577                                 wfd_sink_error("error : %s", error->message);
578                                 wfd_sink_error("debug : %s", debug);
579
580                                 MMWFDSINK_FREEIF(debug);
581                                 g_error_free(error);
582                         }
583                         break;
584
585                 case GST_MESSAGE_WARNING: {
586                                 char *debug = NULL;
587                                 GError *error = NULL;
588
589                                 gst_message_parse_warning(msg, &error, &debug);
590
591                                 wfd_sink_warning("warning : %s", error->message);
592                                 wfd_sink_warning("debug : %s", debug);
593
594                                 MMWFDSINK_FREEIF(debug);
595                                 g_error_free(error);
596                         }
597                         break;
598
599                 case GST_MESSAGE_STATE_CHANGED: {
600                                 const GValue *voldstate, *vnewstate, *vpending;
601                                 GstState oldstate, newstate, pending;
602                                 const GstStructure *structure;
603
604                                 /* we only handle messages from pipeline */
605                                 if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
606                                         break;
607
608                                 /* get state info from msg */
609                                 structure = gst_message_get_structure(msg);
610                                 if (structure == NULL)
611                                         break;
612
613                                 voldstate = gst_structure_get_value(structure, "old-state");
614                                 vnewstate = gst_structure_get_value(structure, "new-state");
615                                 vpending = gst_structure_get_value(structure, "pending-state");
616                                 if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
617                                         break;
618
619                                 oldstate = (GstState)voldstate->data[0].v_int;
620                                 newstate = (GstState)vnewstate->data[0].v_int;
621                                 pending = (GstState)vpending->data[0].v_int;
622
623                                 wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
624                                                GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
625                                                gst_element_state_get_name((GstState)oldstate),
626                                                gst_element_state_get_name((GstState)newstate),
627                                                gst_element_state_get_name((GstState)pending));
628
629                                 if (oldstate == newstate) {
630                                         wfd_sink_debug("pipeline reports state transition to old state");
631                                         break;
632                                 }
633
634                                 switch (newstate) {
635                                         case GST_STATE_VOID_PENDING:
636                                         case GST_STATE_NULL:
637                                         case GST_STATE_READY:
638                                         case GST_STATE_PAUSED:
639                                         case GST_STATE_PLAYING:
640                                         default:
641                                                 break;
642                                 }
643                         }
644                         break;
645
646                 case GST_MESSAGE_CLOCK_LOST: {
647                                 GstClock *clock = NULL;
648                                 gst_message_parse_clock_lost(msg, &clock);
649                                 wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
650                                                (clock ? GST_OBJECT_NAME(clock) : "NULL"));
651                         }
652                         break;
653
654                 case GST_MESSAGE_NEW_CLOCK: {
655                                 GstClock *clock = NULL;
656                                 gst_message_parse_new_clock(msg, &clock);
657                                 if (!clock)
658                                         break;
659
660                                 if (wfd_sink->clock) {
661                                         if (wfd_sink->clock != clock)
662                                                 wfd_sink_debug("clock is changed! [%s] -->[%s]",
663                                                                GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
664                                                                GST_STR_NULL(GST_OBJECT_NAME(clock)));
665                                         else
666                                                 wfd_sink_debug("same clock is selected again! [%s]",
667                                                                GST_STR_NULL(GST_OBJECT_NAME(clock)));
668                                 } else {
669                                         wfd_sink_debug("new clock [%s] was selected in the pipeline",
670                                                        (GST_STR_NULL(GST_OBJECT_NAME(clock))));
671                                 }
672
673                                 wfd_sink->clock = clock;
674                         }
675                         break;
676
677                 case GST_MESSAGE_APPLICATION: {
678                                 const gchar *message_structure_name;
679
680                                 message_structure_name = gst_structure_get_name(message_structure);
681                                 if (!message_structure_name)
682                                         break;
683
684                                 wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
685                         }
686                         break;
687
688                 case GST_MESSAGE_ELEMENT: {
689                                 const gchar *structure_name = NULL;
690
691                                 structure_name = gst_structure_get_name(message_structure);
692                                 if (structure_name) {
693                                         wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
694                                         if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
695                                                 wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
696                                                 MMWFDSINK_POST_MESSAGE(wfd_sink,
697                                                                        MM_ERROR_WFD_INTERNAL,
698                                                                        MMWFDSINK_CURRENT_STATE(wfd_sink));
699                                         }
700                                 }
701                         }
702                         break;
703
704                 case GST_MESSAGE_PROGRESS: {
705                                 GstProgressType type = GST_PROGRESS_TYPE_ERROR;
706                                 gchar *category = NULL, *text = NULL;
707
708                                 gst_message_parse_progress(msg, &type, &category, &text);
709                                 wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
710
711                                 switch (type) {
712                                         case GST_PROGRESS_TYPE_START:
713                                                 break;
714                                         case GST_PROGRESS_TYPE_COMPLETE:
715                                                 if (category && !strcmp(category, "open"))
716                                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_CONNECTED);
717                                                 else if (category && !strcmp(category, "play")) {
718                                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PLAYING);
719                                                         /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
720                                                 } else if (category && !strcmp(category, "pause"))
721                                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PAUSED);
722                                                 else if (category && !strcmp(category, "close"))
723                                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
724
725
726                                                 break;
727                                         case GST_PROGRESS_TYPE_CANCELED:
728                                                 break;
729                                         case GST_PROGRESS_TYPE_ERROR:
730                                                 if (category && !strcmp(category, "open")) {
731                                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
732                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
733                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
734                                                                                MM_ERROR_WFD_INTERNAL,
735                                                                                MMWFDSINK_CURRENT_STATE(wfd_sink));
736                                                 } else if (category && !strcmp(category, "play")) {
737                                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
738                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
739                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
740                                                                                MM_ERROR_WFD_INTERNAL,
741                                                                                MMWFDSINK_CURRENT_STATE(wfd_sink));
742                                                 } else if (category && !strcmp(category, "pause")) {
743                                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
744                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
745                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
746                                                                                MM_ERROR_WFD_INTERNAL,
747                                                                                MMWFDSINK_CURRENT_STATE(wfd_sink));
748                                                 } else if (category && !strcmp(category, "close")) {
749                                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
750                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
751                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
752                                                                                MM_ERROR_WFD_INTERNAL,
753                                                                                MMWFDSINK_CURRENT_STATE(wfd_sink));
754                                                 } else {
755                                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
756                                                 }
757                                                 break;
758                                         default:
759                                                 wfd_sink_error("progress message has no type");
760                                                 return ret;
761                                 }
762
763                                 MMWFDSINK_FREEIF(category);
764                                 MMWFDSINK_FREEIF(text);
765                         }
766                         break;
767                 case GST_MESSAGE_ASYNC_START:
768                         wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
769                         break;
770                 case GST_MESSAGE_ASYNC_DONE:
771                         wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
772                         break;
773                 case GST_MESSAGE_UNKNOWN:
774                 case GST_MESSAGE_INFO:
775                 case GST_MESSAGE_TAG:
776                 case GST_MESSAGE_BUFFERING:
777                 case GST_MESSAGE_EOS:
778                 case GST_MESSAGE_STATE_DIRTY:
779                 case GST_MESSAGE_STEP_DONE:
780                 case GST_MESSAGE_CLOCK_PROVIDE:
781                 case GST_MESSAGE_STRUCTURE_CHANGE:
782                 case GST_MESSAGE_STREAM_STATUS:
783                 case GST_MESSAGE_SEGMENT_START:
784                 case GST_MESSAGE_SEGMENT_DONE:
785                 case GST_MESSAGE_DURATION:
786                 case GST_MESSAGE_LATENCY:
787                 case GST_MESSAGE_REQUEST_STATE:
788                 case GST_MESSAGE_STEP_START:
789                 case GST_MESSAGE_QOS:
790                 case GST_MESSAGE_ANY:
791                         break;
792                 default:
793                         wfd_sink_debug("unhandled message");
794                         break;
795         }
796
797         return ret;
798 }
799
800 static int
801 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
802 {
803         GList *bucket = element_bucket;
804         MMWFDSinkGstElement *element = NULL;
805         int successful_add_count = 0;
806
807         wfd_sink_debug_fenter();
808
809         wfd_sink_return_val_if_fail(element_bucket, 0);
810         wfd_sink_return_val_if_fail(bin, 0);
811
812         for (; bucket; bucket = bucket->next) {
813                 element = (MMWFDSinkGstElement *)bucket->data;
814
815                 if (element && element->gst) {
816                         if (need_prepare)
817                                 gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY);
818
819                         if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
820                                 wfd_sink_error("failed to add element [%s] to bin [%s]",
821                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
822                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
823                                 return 0;
824                         }
825
826                         wfd_sink_debug("add element [%s] to bin [%s]",
827                                        GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
828                                        GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
829
830                         successful_add_count++;
831                 }
832         }
833
834         wfd_sink_debug_fleave();
835
836         return successful_add_count;
837 }
838
839 static int
840 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
841 {
842         GList *bucket = element_bucket;
843         MMWFDSinkGstElement *element = NULL;
844         MMWFDSinkGstElement *prv_element = NULL;
845         gint successful_link_count = 0;
846
847         wfd_sink_debug_fenter();
848
849         wfd_sink_return_val_if_fail(element_bucket, -1);
850
851         prv_element = (MMWFDSinkGstElement *)bucket->data;
852         bucket = bucket->next;
853
854         for (; bucket; bucket = bucket->next) {
855                 element = (MMWFDSinkGstElement *)bucket->data;
856
857                 if (element && element->gst) {
858                         if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
859                                 wfd_sink_debug("linking [%s] to [%s] success",
860                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
861                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
862                                 successful_link_count++;
863                         } else {
864                                 wfd_sink_error("linking [%s] to [%s] failed",
865                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
866                                                GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
867                                 return -1;
868                         }
869                 }
870
871                 prv_element = element;
872         }
873
874         wfd_sink_debug_fleave();
875
876         return successful_link_count;
877 }
878
879 static int
880 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
881 {
882         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
883
884         wfd_sink_debug_fenter();
885
886         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
887
888         MMWFDSINK_PRINT_STATE(wfd_sink);
889
890         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
891
892         switch (cmd) {
893                 case MM_WFD_SINK_COMMAND_CREATE: {
894                                 if (cur_state != MM_WFD_SINK_STATE_NONE)
895                                         goto invalid_state;
896
897                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
898                         }
899                         break;
900
901                 case MM_WFD_SINK_COMMAND_PREPARE: {
902                                 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
903                                         goto no_operation;
904                                 else if (cur_state != MM_WFD_SINK_STATE_NULL)
905                                         goto invalid_state;
906
907                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
908                         }
909                         break;
910
911                 case MM_WFD_SINK_COMMAND_CONNECT: {
912                                 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
913                                         goto no_operation;
914                                 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
915                                         goto invalid_state;
916
917                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
918                         }
919                         break;
920
921                 case MM_WFD_SINK_COMMAND_START: {
922                                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
923                                         goto no_operation;
924                                 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
925                                         goto invalid_state;
926
927                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
928                         }
929                         break;
930
931                 case MM_WFD_SINK_COMMAND_PAUSE: {
932                                 if (cur_state == MM_WFD_SINK_STATE_PAUSED)
933                                         goto no_operation;
934                                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
935                                         goto invalid_state;
936
937                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
938                         }
939                         break;
940
941                 case MM_WFD_SINK_COMMAND_RESUME: {
942                                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
943                                         goto no_operation;
944                                 else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
945                                         goto invalid_state;
946
947                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
948                         }
949                         break;
950
951                 case MM_WFD_SINK_COMMAND_DISCONNECT: {
952                                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
953                                     cur_state == MM_WFD_SINK_STATE_NULL ||
954                                     cur_state == MM_WFD_SINK_STATE_PREPARED ||
955                                     cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
956                                         goto no_operation;
957                                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
958                                          cur_state != MM_WFD_SINK_STATE_CONNECTED &&
959                                          cur_state != MM_WFD_SINK_STATE_PAUSED)
960                                         goto invalid_state;
961
962                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
963                         }
964                         break;
965
966                 case MM_WFD_SINK_COMMAND_UNPREPARE: {
967                                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
968                                     cur_state == MM_WFD_SINK_STATE_NULL)
969                                         goto no_operation;
970
971                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
972                         }
973                         break;
974
975                 case MM_WFD_SINK_COMMAND_DESTROY: {
976                                 if (cur_state == MM_WFD_SINK_STATE_NONE)
977                                         goto no_operation;
978
979                                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
980                         }
981                         break;
982
983                 default:
984                         break;
985         }
986
987         wfd_sink->cmd = cmd;
988
989         wfd_sink_debug_fleave();
990
991         return MM_ERROR_NONE;
992
993 no_operation:
994         wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state));
995         return MM_ERROR_WFD_NO_OP;
996
997         /* ERRORS */
998 invalid_state:
999         wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
1000         return MM_ERROR_WFD_INVALID_STATE;
1001 }
1002
1003 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
1004 {
1005         wfd_sink_debug_fenter();
1006
1007         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1008
1009         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) {
1010                 wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state));
1011                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1012                 return MM_ERROR_NONE;
1013         }
1014
1015         /* update wi-fi display state */
1016         MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1017         MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1018
1019         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
1020                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1021
1022         /* poset state message to application */
1023         MMWFDSINK_POST_MESSAGE(wfd_sink,
1024                                MM_ERROR_NONE,
1025                                MMWFDSINK_CURRENT_STATE(wfd_sink));
1026
1027         /* print state */
1028         MMWFDSINK_PRINT_STATE(wfd_sink);
1029
1030         wfd_sink_debug_fleave();
1031
1032         return MM_ERROR_NONE;
1033 }
1034
1035 static int
1036 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
1037 {
1038         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1039         GstState cur_state = GST_STATE_VOID_PENDING;
1040         GstState pending_state = GST_STATE_VOID_PENDING;
1041
1042         wfd_sink_debug_fenter();
1043
1044         wfd_sink_return_val_if_fail(wfd_sink &&
1045                                     wfd_sink->pipeline &&
1046                                     wfd_sink->pipeline->mainbin &&
1047                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1048                                     MM_ERROR_WFD_NOT_INITIALIZED);
1049
1050         wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING,
1051                                     MM_ERROR_WFD_INVALID_ARGUMENT);
1052
1053         wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1054
1055         result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1056         if (result == GST_STATE_CHANGE_FAILURE) {
1057                 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1058                 return MM_ERROR_WFD_INTERNAL;
1059         }
1060
1061         if (!async) {
1062                 wfd_sink_debug("wait for changing state is completed ");
1063
1064                 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1065                                                &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1066                 if (result == GST_STATE_CHANGE_FAILURE) {
1067                         wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1068
1069                         __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1070
1071                         return MM_ERROR_WFD_INTERNAL;
1072                 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1073                         wfd_sink_debug("successfully changed state but is not able to provide data yet");
1074                 }
1075
1076                 wfd_sink_debug("cur state is %s, pending state is %s",
1077                                gst_element_state_get_name(cur_state),
1078                                gst_element_state_get_name(pending_state));
1079         }
1080
1081
1082         wfd_sink_debug_fleave();
1083
1084         return MM_ERROR_NONE;
1085 }
1086
1087 static void
1088 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1089 {
1090         GstClockTime base_time = GST_CLOCK_TIME_NONE;
1091         int i;
1092
1093         wfd_sink_debug_fenter();
1094
1095         wfd_sink_return_if_fail(wfd_sink &&
1096                                 wfd_sink->pipeline &&
1097                                 wfd_sink->pipeline->mainbin &&
1098                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1099         wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1100
1101
1102         if (wfd_sink->clock)
1103                 base_time = gst_clock_get_time(wfd_sink->clock);
1104
1105         if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1106
1107                 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1108
1109                 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1110                         if (wfd_sink->pipeline->mainbin[i].gst)
1111                                 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1112                 }
1113
1114                 if (wfd_sink->pipeline->v_decodebin) {
1115                         for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1116                                 if (wfd_sink->pipeline->v_decodebin[i].gst)
1117                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1118                         }
1119                 }
1120
1121                 if (wfd_sink->pipeline->v_sinkbin) {
1122                         for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1123                                 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1124                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1125                         }
1126                 }
1127
1128                 if (wfd_sink->pipeline->a_decodebin) {
1129                         for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1130                                 if (wfd_sink->pipeline->a_decodebin[i].gst)
1131                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1132                         }
1133                 }
1134
1135                 if (wfd_sink->pipeline->a_sinkbin) {
1136                         for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1137                                 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1138                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1139                         }
1140                 }
1141
1142                 wfd_sink->need_to_reset_basetime = FALSE;
1143         }
1144
1145         wfd_sink_debug_fleave();
1146
1147         return;
1148 }
1149
1150 int
1151 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1152 {
1153         GstElement *bin = NULL;
1154
1155         wfd_sink_debug_fenter();
1156
1157         wfd_sink_return_val_if_fail(wfd_sink &&
1158                                     wfd_sink->pipeline &&
1159                                     wfd_sink->pipeline->mainbin &&
1160                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1161                                     MM_ERROR_WFD_NOT_INITIALIZED);
1162
1163         /* check video decodebin is linked */
1164         if (!wfd_sink->video_decodebin_is_linked) {
1165                 /* check video decodebin is created */
1166                 if (wfd_sink->pipeline->v_decodebin == NULL) {
1167                         if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1168                                 wfd_sink_error("failed to create video decodebin....");
1169                                 goto ERROR;
1170                         }
1171                 }
1172
1173                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1174                         wfd_sink_error("failed to link video decodebin.....");
1175                         goto ERROR;
1176                 }
1177         }
1178
1179         /* check video sinkbin is created */
1180         if (wfd_sink->pipeline->v_sinkbin == NULL) {
1181                 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1182                         wfd_sink_error("failed to create video sinkbin....");
1183                         goto ERROR;
1184                 }
1185         }
1186
1187         /* set video decodebin state as READY */
1188         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1189                 bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1190                 if (GST_STATE(bin) <= GST_STATE_NULL) {
1191                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1192                                 wfd_sink_error("failed to set state(READY) to video decodebin");
1193                                 goto ERROR;
1194                         }
1195                 }
1196         } else {
1197                 wfd_sink_warning("going on without video decodebin....");
1198         }
1199
1200         /* set video sinkbin state as READY */
1201         if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1202                 bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1203                 if (GST_STATE(bin) <= GST_STATE_NULL) {
1204                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1205                                 wfd_sink_error("failed to set state(READY) to video sinkbin");
1206                                 goto ERROR;
1207                         }
1208                 }
1209         } else {
1210                 wfd_sink_warning("going on without video sinkbin....");
1211         }
1212
1213         wfd_sink_debug_fleave();
1214
1215         return MM_ERROR_NONE;
1216
1217         /* ERRORS */
1218 ERROR:
1219         /* need to notify to app */
1220         MMWFDSINK_POST_MESSAGE(wfd_sink,
1221                                MM_ERROR_WFD_INTERNAL,
1222                                MMWFDSINK_CURRENT_STATE(wfd_sink));
1223
1224         return MM_ERROR_WFD_INTERNAL;
1225 }
1226
1227 int
1228 __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1229 {
1230         GstElement *bin  = NULL;
1231
1232         wfd_sink_debug_fenter();
1233
1234         wfd_sink_return_val_if_fail(wfd_sink &&
1235                                     wfd_sink->pipeline,
1236                                     MM_ERROR_WFD_NOT_INITIALIZED);
1237
1238         /* check audio decodebin is linked */
1239         if (!wfd_sink->audio_decodebin_is_linked) {
1240                 /* check audio decodebin is created */
1241                 if (wfd_sink->pipeline->a_decodebin == NULL) {
1242                         if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1243                                 wfd_sink_error("failed to create audio decodebin....");
1244                                 goto ERROR;
1245                         }
1246                 }
1247
1248                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1249                         wfd_sink_error("failed to link audio decodebin.....");
1250                         goto ERROR;
1251                 }
1252         }
1253
1254         /* check audio sinkbin is created */
1255         if (wfd_sink->pipeline->a_sinkbin == NULL) {
1256                 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
1257                         wfd_sink_error("failed to create audio sinkbin....");
1258                         goto ERROR;
1259                 }
1260         }
1261
1262         /* set audio decodebin state as READY */
1263         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1264                 bin  = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1265                 if (GST_STATE(bin) <= GST_STATE_NULL) {
1266                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1267                                 wfd_sink_error("failed to set state(READY) to audio decodebin");
1268                                 goto ERROR;
1269                         }
1270                 }
1271         } else {
1272                 wfd_sink_warning("going on without audio decodebin....");
1273         }
1274
1275         /* set audio sinkbin state as READY */
1276         if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1277                 bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1278                 if (GST_STATE(bin ) <= GST_STATE_NULL) {
1279                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) {
1280                                 wfd_sink_error("failed to set state(READY) to audio sinkbin");
1281                                 goto ERROR;
1282                         }
1283                 }
1284         } else {
1285                 wfd_sink_warning("going on without audio sinkbin....");
1286         }
1287
1288         wfd_sink_debug_fleave();
1289
1290         return MM_ERROR_NONE;
1291
1292         /* ERRORS */
1293 ERROR:
1294         /* need to notify to app */
1295         MMWFDSINK_POST_MESSAGE(wfd_sink,
1296                                MM_ERROR_WFD_INTERNAL,
1297                                MMWFDSINK_CURRENT_STATE(wfd_sink));
1298
1299         return MM_ERROR_WFD_INTERNAL;
1300 }
1301
1302 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
1303 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND)  /* 30 sec */
1304
1305 static GstPadProbeReturn
1306 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1307 {
1308         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
1309         GstClockTime current_time = GST_CLOCK_TIME_NONE;
1310         GstClockTime start_time = GST_CLOCK_TIME_NONE;
1311         GstClockTime running_time = GST_CLOCK_TIME_NONE;
1312         GstClockTime base_time = GST_CLOCK_TIME_NONE;
1313         GstClockTime render_time = GST_CLOCK_TIME_NONE;
1314         GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
1315         GstBuffer *buffer = NULL;
1316         gint64 ts_offset = 0LL;
1317
1318         wfd_sink_return_val_if_fail(info, FALSE);
1319         wfd_sink_return_val_if_fail(wfd_sink &&
1320                                     wfd_sink->pipeline &&
1321                                     wfd_sink->pipeline->mainbin &&
1322                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1323                                     GST_PAD_PROBE_DROP);
1324
1325         if (!wfd_sink->clock) {
1326                 wfd_sink_warning("pipeline did not select clock, yet");
1327                 return GST_PAD_PROBE_OK;
1328         }
1329
1330         if (wfd_sink->need_to_reset_basetime)
1331                 _mm_wfd_sink_reset_basetime(wfd_sink);
1332
1333         /* calculate current runninig time */
1334         current_time = gst_clock_get_time(wfd_sink->clock);
1335         if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1336                 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
1337         else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1338                 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
1339         start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1340         if (GST_CLOCK_TIME_IS_VALID(current_time) &&
1341             GST_CLOCK_TIME_IS_VALID(start_time) &&
1342             GST_CLOCK_TIME_IS_VALID(base_time)) {
1343                 running_time = current_time - (start_time + base_time);
1344         } else {
1345                 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
1346                                "  base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
1347                                GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
1348                 return GST_PAD_PROBE_OK;
1349         }
1350
1351         /* calculate this buffer rendering time */
1352         buffer = gst_pad_probe_info_get_buffer(info);
1353         if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
1354                 wfd_sink_warning("buffer timestamp is invalid.");
1355                 return GST_PAD_PROBE_OK;
1356         }
1357
1358         if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1359                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1360                         g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1361         } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1362                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1363                         g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1364         }
1365
1366         render_time = GST_BUFFER_TIMESTAMP(buffer);
1367         render_time += ts_offset;
1368
1369         /* chekc this buffer could be rendered or not */
1370         if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
1371                 diff = GST_CLOCK_DIFF(running_time, render_time);
1372                 if (diff < 0) {
1373                         /* this buffer could be NOT rendered */
1374                         wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
1375                                        GST_STR_NULL((GST_OBJECT_NAME(pad))),
1376                                        GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
1377                 } else {
1378                         /* this buffer could be rendered */
1379                         /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */
1380                         /*      GST_STR_NULL((GST_OBJECT_NAME(pad))), */
1381                         /*      GST_TIME_ARGS(diff)); */
1382                 }
1383         }
1384
1385         /* update buffer count and gap */
1386         if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1387                 wfd_sink->video_buffer_count++;
1388                 wfd_sink->video_accumulated_gap += diff;
1389         } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1390                 wfd_sink->audio_buffer_count++;
1391                 wfd_sink->audio_accumulated_gap += diff;
1392         } else {
1393                 wfd_sink_warning("invalid buffer type.. ");
1394                 return GST_PAD_PROBE_DROP;
1395         }
1396
1397         if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
1398                 /* fisrt 60sec, just calculate the gap between source device and sink device */
1399                 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
1400                         return GST_PAD_PROBE_OK;
1401
1402                 /* every 10sec, calculate the gap between source device and sink device */
1403                 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
1404                     > COMPENSATION_CHECK_PERIOD) {
1405                         gint64 audio_avgrage_gap = 0LL;
1406                         gint64 video_avgrage_gap = 0LL;
1407                         gint64 audio_avgrage_gap_diff = 0LL;
1408                         gint64 video_avgrage_gap_diff = 0LL;
1409                         gboolean video_minus_compensation = FALSE;
1410                         gboolean audio_minus_compensation = FALSE;
1411                         gint64 avgrage_gap_diff = 0LL;
1412                         gboolean minus_compensation = FALSE;
1413
1414                         /* check video */
1415                         if (wfd_sink->video_buffer_count > 0) {
1416                                 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
1417
1418                                 if (wfd_sink->video_average_gap != 0) {
1419                                         if (video_avgrage_gap > wfd_sink->video_average_gap) {
1420                                                 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
1421                                                 video_minus_compensation = TRUE;
1422                                         } else {
1423                                                 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
1424                                                 video_minus_compensation = FALSE;
1425                                         }
1426                                 } else {
1427                                         wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
1428                                         wfd_sink->video_average_gap = video_avgrage_gap;
1429                                 }
1430                         } else {
1431                                 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
1432                                                " ~ %" GST_TIME_FORMAT"",
1433                                                GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1434                                                GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1435                         }
1436
1437                         /* check audio */
1438                         if (wfd_sink->audio_buffer_count > 0) {
1439                                 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
1440
1441                                 if (wfd_sink->audio_average_gap != 0) {
1442                                         if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
1443                                                 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
1444                                                 audio_minus_compensation = TRUE;
1445                                         } else {
1446                                                 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
1447                                                 audio_minus_compensation = FALSE;
1448                                         }
1449                                 } else {
1450                                         wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
1451                                         wfd_sink->audio_average_gap = audio_avgrage_gap;
1452                                 }
1453                         } else {
1454                                 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
1455                                                " ~ %" GST_TIME_FORMAT"",
1456                                                GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1457                                                GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1458                         }
1459
1460                         /* selecet average_gap_diff between video and audio */
1461                         /*  which makes no buffer drop in the sink elements */
1462                         if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
1463                                 if (!video_minus_compensation && !audio_minus_compensation) {
1464                                         minus_compensation = FALSE;
1465                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1466                                                 avgrage_gap_diff = video_avgrage_gap_diff;
1467                                         else
1468                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
1469                                 } else if (video_minus_compensation && audio_minus_compensation) {
1470                                         minus_compensation = TRUE;
1471                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1472                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
1473                                         else
1474                                                 avgrage_gap_diff = video_avgrage_gap_diff;
1475                                 } else {
1476                                         minus_compensation = FALSE;
1477                                         if (!video_minus_compensation)
1478                                                 avgrage_gap_diff = video_avgrage_gap_diff;
1479                                         else
1480                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
1481                                 }
1482                         } else if (video_avgrage_gap_diff) {
1483                                 minus_compensation = video_minus_compensation;
1484                                 avgrage_gap_diff = video_avgrage_gap_diff;
1485                         } else if (audio_avgrage_gap_diff) {
1486                                 minus_compensation = audio_minus_compensation;
1487                                 avgrage_gap_diff = audio_avgrage_gap_diff;
1488                         }
1489
1490                         wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
1491                                        audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
1492                                        video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
1493
1494
1495                         /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
1496                         if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
1497                                 if (minus_compensation)
1498                                         ts_offset -= avgrage_gap_diff;
1499                                 else
1500                                         ts_offset += avgrage_gap_diff;
1501
1502                                 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
1503                                                GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
1504                                                minus_compensation ? "-" : "", avgrage_gap_diff,
1505                                                GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
1506
1507                                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1508                                         g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1509                                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1510                                         g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1511                         } else {
1512                                 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
1513                                                minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
1514                         }
1515
1516                         /* reset values*/
1517                         wfd_sink->video_buffer_count = 0;
1518                         wfd_sink->video_accumulated_gap = 0LL;
1519                         wfd_sink->audio_buffer_count = 0;
1520                         wfd_sink->audio_accumulated_gap = 0LL;
1521                         wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1522                 }
1523         } else {
1524                 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
1525                                GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1526                 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1527         }
1528
1529         return GST_PAD_PROBE_OK;
1530 }
1531
1532
1533 static void
1534 __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data)
1535 {
1536         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1537         gchar *name = gst_pad_get_name(pad);
1538         GstElement *pipeline = NULL;
1539         GstElement *decodebin = NULL;
1540         GstElement *sinkbin = NULL;
1541         GstPad *sinkpad = NULL;
1542         GstPad *srcpad = NULL;
1543
1544         wfd_sink_debug_fenter();
1545
1546         wfd_sink_return_if_fail(wfd_sink &&
1547                                     wfd_sink->pipeline &&
1548                                     wfd_sink->pipeline->mainbin &&
1549                                     wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1550
1551         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1552
1553         /* take decodebin/sinkbin */
1554         if (name[0] == 'v') {
1555                 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
1556
1557                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
1558
1559                 gst_pad_add_probe(pad,
1560                                   GST_PAD_PROBE_TYPE_BUFFER,
1561                                   _mm_wfd_sink_check_running_time,
1562                                   (gpointer)wfd_sink,
1563                                   NULL);
1564
1565                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) {
1566                         wfd_sink_error("failed to prepare video pipeline....");
1567                         goto ERROR;
1568                 }
1569
1570                 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst)
1571                         decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1572                 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst)
1573                         sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;  
1574         } else if (name[0] == 'a') {
1575                 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
1576
1577                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
1578
1579                 gst_pad_add_probe(pad,
1580                                   GST_PAD_PROBE_TYPE_BUFFER,
1581                                   _mm_wfd_sink_check_running_time,
1582                                   (gpointer)wfd_sink,
1583                                   NULL);
1584
1585                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) {
1586                         wfd_sink_error("failed to prepare audio pipeline....");
1587                         goto ERROR;
1588                 }
1589
1590                 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst)
1591                         decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1592                 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst)
1593                         sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1594         } else {
1595                 wfd_sink_error("unexceptable pad is added!!!");
1596                 return;
1597         }
1598
1599         srcpad = gst_object_ref(pad);
1600
1601         /* add decodebin and link */
1602         if (decodebin) {
1603                 if (!gst_bin_add(GST_BIN(pipeline), decodebin)) {
1604                         wfd_sink_error("failed to add %s to pipeline",
1605                                         GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1606                         goto ERROR;
1607                 }
1608
1609                 sinkpad = gst_element_get_static_pad(decodebin, "sink");
1610                 if (!sinkpad) {
1611                         wfd_sink_error("failed to get sink pad from %s",
1612                                         GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1613                         goto ERROR;
1614                 }
1615
1616                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1617                         wfd_sink_error("failed to link %s and %s",
1618                                         GST_STR_NULL(GST_PAD_NAME(srcpad)),
1619                                         GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1620                         goto ERROR;
1621                 }
1622                 gst_object_unref(GST_OBJECT(srcpad));
1623                 srcpad = NULL;
1624                 gst_object_unref(GST_OBJECT(sinkpad));
1625                 sinkpad = NULL;
1626
1627                 srcpad = gst_element_get_static_pad (decodebin, "src");
1628                 if (!srcpad) {
1629                         wfd_sink_error("failed to get src pad from %s",
1630                                         GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1631                         goto ERROR;
1632                 }
1633         } else {
1634                 wfd_sink_warning("going on without decodebin...");
1635         }
1636
1637         /* add sinkbin and link */
1638         if (sinkbin) {
1639                 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1640                         wfd_sink_error("failed to add %s to pipeline",
1641                                         GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1642                         goto ERROR;
1643                 }
1644
1645                 sinkpad = gst_element_get_static_pad(sinkbin, "sink");
1646                 if (!sinkpad) {
1647                         wfd_sink_error("failed to get sink pad from %s",
1648                                         GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1649                         goto ERROR;
1650                 }
1651
1652                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1653                         wfd_sink_error("failed to link %s and %s",
1654                                         GST_STR_NULL(GST_PAD_NAME(srcpad)),
1655                                         GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1656                         goto ERROR;
1657                 }
1658                 gst_object_unref(GST_OBJECT(srcpad));
1659                 srcpad = NULL;
1660                 gst_object_unref(GST_OBJECT(sinkpad));
1661                 sinkpad = NULL;
1662         } else {
1663                 wfd_sink_error("there is no sinkbin...");
1664                 goto ERROR;
1665         }
1666
1667
1668         /* run */
1669         if (decodebin) {
1670                 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) {
1671                         wfd_sink_error("failed to sync %s state with parent",
1672                                 GST_STR_NULL(GST_PAD_NAME(decodebin)));
1673                         goto ERROR;
1674                 }
1675         }
1676
1677         if (sinkbin) {
1678                 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) {
1679                         wfd_sink_error("failed to sync %s state with parent",
1680                                 GST_STR_NULL(GST_PAD_NAME(sinkbin)));
1681                         goto ERROR;
1682                 }
1683         }
1684
1685         if (name[0] == 'v') {
1686                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
1687         } else if (name[0] == 'a') {
1688                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
1689         }
1690
1691         MMWFDSINK_FREEIF(name);
1692
1693         wfd_sink_debug_fleave();
1694
1695         return;
1696
1697         /* ERRORS */
1698 ERROR:
1699         MMWFDSINK_FREEIF(name);
1700
1701         if (srcpad)
1702                 gst_object_unref(GST_OBJECT(srcpad));
1703         srcpad = NULL;
1704
1705         if (sinkpad)
1706                 gst_object_unref(GST_OBJECT(sinkpad));
1707         sinkpad = NULL;
1708
1709         /* need to notify to app */
1710         MMWFDSINK_POST_MESSAGE(wfd_sink,
1711                                MM_ERROR_WFD_INTERNAL,
1712                                MMWFDSINK_CURRENT_STATE(wfd_sink));
1713
1714         return;
1715 }
1716
1717 static void
1718 __mm_wfd_sink_change_av_format(GstElement *wfdrtspsrc, gpointer *need_to_flush, gpointer data)
1719 {
1720         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1721
1722         wfd_sink_debug_fenter();
1723
1724         wfd_sink_return_if_fail(wfd_sink);
1725         wfd_sink_return_if_fail(need_to_flush);
1726
1727         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
1728                 wfd_sink_debug("need to flush pipeline");
1729                 *need_to_flush = (gpointer) TRUE;
1730         } else {
1731                 wfd_sink_debug("don't need to flush pipeline");
1732                 *need_to_flush = (gpointer) FALSE;
1733         }
1734
1735
1736         wfd_sink_debug_fleave();
1737 }
1738
1739
1740 static void
1741 __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpointer data)
1742 {
1743         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1744         MMWFDSinkStreamInfo *stream_info = NULL;
1745         gint is_valid_audio_format = FALSE;
1746         gint is_valid_video_format = FALSE;
1747         MMWFDSinkAudioCodec audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
1748         MMWFDSinkVideoCodec video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
1749         gchar *audio_format;
1750         gchar *video_format;
1751
1752         wfd_sink_debug_fenter();
1753
1754         wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
1755         wfd_sink_return_if_fail(wfd_sink);
1756
1757         stream_info = &wfd_sink->stream_info;
1758
1759         audio_codec = wfd_sink->stream_info.audio_stream_info.codec;
1760         video_codec = wfd_sink->stream_info.video_stream_info.codec;
1761
1762         if (gst_structure_has_field(str, "audio_format")) {
1763                 is_valid_audio_format = TRUE;
1764                 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
1765                 if (g_strrstr(audio_format, "AAC"))
1766                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
1767                 else if (g_strrstr(audio_format, "AC3"))
1768                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
1769                 else if (g_strrstr(audio_format, "LPCM"))
1770                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
1771                 else {
1772                         wfd_sink_error("invalid audio format(%s)...", audio_format);
1773                         is_valid_audio_format = FALSE;
1774                 }
1775
1776                 if (is_valid_audio_format == TRUE) {
1777                         if (gst_structure_has_field(str, "audio_rate"))
1778                                 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
1779                         if (gst_structure_has_field(str, "audio_channels"))
1780                                 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
1781                         if (gst_structure_has_field(str, "audio_bitwidth"))
1782                                 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
1783
1784                         if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1785                                 if (audio_codec != stream_info->audio_stream_info.codec) {
1786                                         wfd_sink_debug("audio codec is changed...need to change audio decodebin");
1787                                 }
1788                         } else {
1789                                 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
1790                         }
1791
1792                         wfd_sink_debug("audio_format : %s \n \t rate :  %d \n \t channels :  %d \n \t bitwidth :  %d \n \t",
1793                                        audio_format,
1794                                        stream_info->audio_stream_info.sample_rate,
1795                                        stream_info->audio_stream_info.channels,
1796                                        stream_info->audio_stream_info.bitwidth);
1797                 }
1798         }
1799
1800         if (gst_structure_has_field(str, "video_format")) {
1801                 is_valid_video_format = TRUE;
1802                 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
1803                 if (!g_strrstr(video_format, "H264")) {
1804                         wfd_sink_error("invalid video format(%s)...", video_format);
1805                         is_valid_video_format = FALSE;
1806                 }
1807
1808                 if (is_valid_video_format == TRUE) {
1809                         stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
1810
1811                         if (gst_structure_has_field(str, "video_width"))
1812                                 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
1813                         if (gst_structure_has_field(str, "video_height"))
1814                                 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
1815                         if (gst_structure_has_field(str, "video_framerate"))
1816                                 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
1817
1818                         if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1819                                 if (video_codec != stream_info->video_stream_info.codec) {
1820                                         wfd_sink_debug("video codec is changed...need to change video decodebin");
1821                                 }
1822                         } else {
1823                                 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
1824                         }
1825
1826                         wfd_sink_debug("video_format : %s \n \t width :  %d \n \t height :  %d \n \t frame_rate :  %d \n \t",
1827                                        video_format,
1828                                        stream_info->video_stream_info.width,
1829                                        stream_info->video_stream_info.height,
1830                                        stream_info->video_stream_info.frame_rate);
1831                 }
1832         }
1833
1834         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
1835
1836         wfd_sink_debug_fleave();
1837 }
1838
1839 static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement *wfdrtspsrc)
1840 {
1841         GstStructure *audio_param = NULL;
1842         GstStructure *video_param = NULL;
1843         GstStructure *hdcp_param = NULL;
1844         gint hdcp_version = 0;
1845         gint hdcp_port = 0;
1846         guint CEA_resolution = 0;
1847         guint VESA_resolution = 0;
1848         guint HH_resolution = 0;
1849
1850         wfd_sink_debug_fenter();
1851
1852         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1853         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1854         wfd_sink_return_val_if_fail(wfdrtspsrc, MM_ERROR_WFD_NOT_INITIALIZED);
1855
1856         g_object_set(G_OBJECT(wfdrtspsrc), "debug", wfd_sink->ini.set_debug_property, NULL);
1857         g_object_set(G_OBJECT(wfdrtspsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
1858         g_object_set(G_OBJECT(wfdrtspsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
1859         g_object_set(G_OBJECT(wfdrtspsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdrtspsrc_pad_probe, NULL);
1860         g_object_set(G_OBJECT(wfdrtspsrc), "udp-buffer-size", 2097152, NULL);
1861
1862         audio_param = gst_structure_new("audio_param",
1863                                         "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec,
1864                                         "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency,
1865                                         "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel,
1866                                         "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency,
1867                                         NULL);
1868
1869         CEA_resolution = wfd_sink->ini.video_cea_support;
1870         VESA_resolution = wfd_sink->ini.video_vesa_support;
1871         HH_resolution =  wfd_sink->ini.video_hh_support;
1872
1873         __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
1874                                                &CEA_resolution, &VESA_resolution, &HH_resolution);
1875
1876         wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution);
1877
1878         video_param = gst_structure_new("video_param",
1879                                         "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec,
1880                                         "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution,
1881                                         "video_cea_support", G_TYPE_UINT, CEA_resolution,
1882                                         "video_vesa_support", G_TYPE_UINT, VESA_resolution,
1883                                         "video_hh_support", G_TYPE_UINT, HH_resolution,
1884                                         "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile,
1885                                         "video_level", G_TYPE_UINT, wfd_sink->ini.video_level,
1886                                         "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency,
1887                                         "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution,
1888                                         "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution,
1889                                         "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing,
1890                                         "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param,
1891                                         "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support,
1892                                         NULL);
1893
1894         mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
1895         mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
1896         wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
1897
1898         hdcp_param = gst_structure_new("hdcp_param",
1899                                        "hdcp_version", G_TYPE_INT, hdcp_version,
1900                                        "hdcp_port_no", G_TYPE_INT, hdcp_port,
1901                                        NULL);
1902
1903         g_object_set(G_OBJECT(wfdrtspsrc), "audio-param", audio_param, NULL);
1904         g_object_set(G_OBJECT(wfdrtspsrc), "video-param", video_param, NULL);
1905         g_object_set(G_OBJECT(wfdrtspsrc), "hdcp-param", hdcp_param, NULL);
1906
1907         g_signal_connect(wfdrtspsrc, "update-media-info",
1908                          G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
1909
1910         g_signal_connect(wfdrtspsrc, "change-av-format",
1911                          G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
1912
1913         wfd_sink_debug_fleave();
1914
1915         return MM_ERROR_NONE;
1916 }
1917
1918 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
1919 {
1920         wfd_sink_debug_fenter();
1921
1922         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1923         wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
1924
1925         g_signal_connect(demux, "pad-added",
1926                          G_CALLBACK(__mm_wfd_sink_demux_pad_added),     wfd_sink);
1927
1928         wfd_sink_debug_fleave();
1929
1930         return MM_ERROR_NONE;
1931 }
1932
1933 static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data)
1934 {
1935         wfd_sink_debug_fenter();
1936
1937         return_if_fail(element);
1938
1939         wfd_sink_warning("%s is overrun",
1940                          GST_STR_NULL(GST_ELEMENT_NAME(element)));
1941
1942         wfd_sink_debug_fleave();
1943
1944         return;
1945 }
1946
1947 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
1948 {
1949         wfd_sink_debug_fenter();
1950
1951         wfd_sink_return_if_fail(wfd_sink);
1952         wfd_sink_return_if_fail(queue);
1953
1954         /* set maximum buffer size of queue as 3sec */
1955         g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
1956         g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
1957         g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
1958         g_signal_connect(queue, "overrun",
1959                          G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
1960
1961         wfd_sink_debug_fleave();
1962
1963         return;
1964 }
1965
1966
1967 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
1968 {
1969         MMWFDSinkGstElement *mainbin = NULL;
1970         GList *element_bucket = NULL;
1971         GstBus  *bus = NULL;
1972         int i;
1973
1974         wfd_sink_debug_fenter();
1975
1976         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1977         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1978
1979         /* Create pipeline */
1980         wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
1981         if (wfd_sink->pipeline == NULL)
1982                 goto CREATE_ERROR;
1983
1984         memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
1985
1986         /* create mainbin */
1987         mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1988         if (mainbin == NULL)
1989                 goto CREATE_ERROR;
1990
1991         memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1992
1993         /* create pipeline */
1994         mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
1995         mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
1996         if (!mainbin[WFD_SINK_M_PIPE].gst) {
1997                 wfd_sink_error("failed to create pipeline");
1998                 goto CREATE_ERROR;
1999         }
2000
2001         /* create wfdrtspsrc */
2002         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, "wfdrtspsrc", "wfdsink_source", TRUE);
2003         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst,  "src");
2004         if (mainbin[WFD_SINK_M_SRC].gst) {
2005                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_wfdrtspsrc(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2006                         wfd_sink_error("failed to prepare wfdrtspsrc...");
2007                         goto CREATE_ERROR;
2008                 }
2009         }
2010
2011         /* create rtpmp2tdepay */
2012         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
2013         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2014         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
2015
2016         MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2017
2018         /* create tsdemuxer*/
2019         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
2020         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
2021         if (mainbin[WFD_SINK_M_DEMUX].gst) {
2022                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
2023                         wfd_sink_error("failed to prepare demux...");
2024                         goto CREATE_ERROR;
2025                 }
2026         }
2027
2028         /* adding created elements to pipeline */
2029         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
2030                 wfd_sink_error("failed to add elements");
2031                 goto CREATE_ERROR;
2032         }
2033
2034         /* linking elements in the bucket by added order. */
2035         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2036                 wfd_sink_error("failed to link elements");
2037                 goto CREATE_ERROR;
2038         }
2039
2040         /* connect bus callback */
2041         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
2042         if (!bus) {
2043                 wfd_sink_error("cannot get bus from pipeline.");
2044                 goto CREATE_ERROR;
2045         }
2046
2047         /* add bus message callback*/
2048         gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
2049
2050         /* set sync handler to get tag synchronously */
2051         gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
2052
2053         g_list_free(element_bucket);
2054         gst_object_unref(GST_OBJECT(bus));
2055
2056         /* now we have completed mainbin. take it */
2057         wfd_sink->pipeline->mainbin = mainbin;
2058
2059         wfd_sink_debug_fleave();
2060
2061         return MM_ERROR_NONE;
2062
2063         /* ERRORS */
2064 CREATE_ERROR:
2065         wfd_sink_error("ERROR : releasing pipeline");
2066
2067         if (element_bucket)
2068                 g_list_free(element_bucket);
2069         element_bucket = NULL;
2070
2071         /* finished */
2072         if (bus)
2073                 gst_object_unref(GST_OBJECT(bus));
2074         bus = NULL;
2075
2076         /* release element which are not added to bin */
2077         for (i = 1; i < WFD_SINK_M_NUM; i++) {  /* NOTE : skip pipeline */
2078                 if (mainbin != NULL && mainbin[i].gst) {
2079                         GstObject *parent = NULL;
2080                         parent = gst_element_get_parent(mainbin[i].gst);
2081
2082                         if (!parent) {
2083                                 gst_object_unref(GST_OBJECT(mainbin[i].gst));
2084                                 mainbin[i].gst = NULL;
2085                         } else {
2086                                 gst_object_unref(GST_OBJECT(parent));
2087                         }
2088                 }
2089         }
2090
2091         /* release mainbin with it's childs */
2092         if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst)
2093                 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
2094
2095         MMWFDSINK_FREEIF(mainbin);
2096
2097         MMWFDSINK_FREEIF(wfd_sink->pipeline);
2098
2099         return MM_ERROR_WFD_INTERNAL;
2100 }
2101
2102 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2103 {
2104         MMWFDSinkGstElement *a_decodebin = NULL;
2105         MMWFDSinkGstElement *first_element = NULL;
2106         MMWFDSinkGstElement *last_element = NULL;
2107         GList *element_bucket = NULL;
2108         GstPad *sinkpad = NULL;
2109         GstPad *srcpad = NULL;
2110         GstPad *ghostpad = NULL;
2111
2112         wfd_sink_debug_fenter();
2113
2114         wfd_sink_return_val_if_fail(wfd_sink &&
2115                                     wfd_sink->pipeline &&
2116                                     wfd_sink->pipeline->a_decodebin &&
2117                                     wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
2118                                     MM_ERROR_WFD_NOT_INITIALIZED);
2119
2120         if (wfd_sink->audio_decodebin_is_linked) {
2121                 wfd_sink_debug("audio decodebin is already linked... nothing to do");
2122                 return MM_ERROR_NONE;
2123         }
2124
2125         /* take audio decodebin */
2126         a_decodebin = wfd_sink->pipeline->a_decodebin;
2127
2128         /* check audio queue */
2129         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
2130                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]);
2131
2132         /* check audio hdcp */
2133         if (a_decodebin[WFD_SINK_A_D_HDCP].gst)
2134                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]);
2135
2136         /* check audio codec */
2137         switch (wfd_sink->stream_info.audio_stream_info.codec) {
2138                 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
2139                         if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
2140                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
2141                         if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
2142                                 GstCaps *caps = NULL;
2143                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
2144                                 caps = gst_caps_new_simple("audio/x-raw",
2145                                                    "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
2146                                                    "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
2147                                                    "format", G_TYPE_STRING, "S16BE", NULL);
2148
2149                                 g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
2150                                 gst_object_unref(GST_OBJECT(caps));
2151                         }
2152                         break;
2153
2154                 case MM_WFD_SINK_AUDIO_CODEC_AAC:
2155                         if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
2156                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
2157                         if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
2158                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
2159                         break;
2160
2161                 case MM_WFD_SINK_AUDIO_CODEC_AC3:
2162                         if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
2163                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
2164                         if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
2165                                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
2166                         break;
2167
2168                 default:
2169                         wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
2170                         return MM_ERROR_WFD_INTERNAL;
2171                         break;
2172         }
2173
2174         if (element_bucket == NULL) {
2175                 wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it");
2176                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
2177                         wfd_sink_error("failed to destroy audio decodebin");
2178                         goto fail_to_link;
2179                 }
2180                 goto done;
2181         }
2182
2183         /* adding elements to audio decodebin */
2184         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) {
2185                 wfd_sink_error("failed to add elements to audio decodebin");
2186                 goto fail_to_link;
2187         }
2188
2189         /* linking elements in the bucket by added order. */
2190         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2191                 wfd_sink_error("failed to link elements of the audio decodebin");
2192                 goto fail_to_link;
2193         }
2194
2195         /* get first element's sinkpad for creating ghostpad */
2196         first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2197         if (!first_element) {
2198                 wfd_sink_error("failed to get first element of the audio decodebin");
2199                 goto fail_to_link;
2200         }
2201
2202         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2203         if (!sinkpad) {
2204                 wfd_sink_error("failed to get sink pad from element(%s)",
2205                         GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2206                 goto fail_to_link;
2207         }
2208
2209         ghostpad = gst_ghost_pad_new("sink", sinkpad);
2210         if (!ghostpad) {
2211                 wfd_sink_error("failed to create ghostpad of audio decodebin");
2212                 goto fail_to_link;
2213         }
2214
2215         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2216                 wfd_sink_error("failed to add ghostpad to audio decodebin");
2217                 goto fail_to_link;
2218         }
2219         gst_object_unref(GST_OBJECT(sinkpad));
2220         sinkpad = NULL;
2221
2222
2223         /* get last element's src for creating ghostpad */
2224         last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data;
2225         if (!last_element) {
2226                 wfd_sink_error("failed to get last element of the audio decodebin");
2227                 goto fail_to_link;
2228         }
2229
2230         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2231         if (!srcpad) {
2232                 wfd_sink_error("failed to get src pad from element(%s)",
2233                         GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2234                 goto fail_to_link;
2235         }
2236
2237         ghostpad = gst_ghost_pad_new("src", srcpad);
2238         if (!ghostpad) {
2239                 wfd_sink_error("failed to create ghostpad of audio decodebin");
2240                 goto fail_to_link;
2241         }
2242
2243         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2244                 wfd_sink_error("failed to add ghostpad to audio decodebin");
2245                 goto fail_to_link;
2246         }
2247         gst_object_unref(GST_OBJECT(srcpad));
2248         srcpad = NULL;
2249
2250         g_list_free(element_bucket);
2251
2252 done:
2253         wfd_sink->audio_decodebin_is_linked = TRUE;
2254
2255         wfd_sink_debug_fleave();
2256
2257         return MM_ERROR_NONE;
2258
2259         /* ERRORS*/
2260 fail_to_link:
2261         if (srcpad)
2262                 gst_object_unref(GST_OBJECT(srcpad));
2263         srcpad = NULL;
2264
2265         if (sinkpad)
2266                 gst_object_unref(GST_OBJECT(sinkpad));
2267         sinkpad = NULL;
2268
2269         g_list_free(element_bucket);
2270
2271         return MM_ERROR_WFD_INTERNAL;
2272 }
2273
2274 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
2275 {
2276         wfd_sink_debug_fenter();
2277
2278         /* check audiosink is created */
2279         wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2280         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2281
2282         g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE,  NULL);
2283         g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
2284         g_object_set(G_OBJECT(audio_sink), "slave-method", 2,  NULL);
2285         g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async,  NULL);
2286         g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
2287
2288         wfd_sink_debug_fleave();
2289
2290         return MM_ERROR_NONE;
2291 }
2292
2293 static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2294 {
2295         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2296         MMWFDSinkGstElement *a_decodebin = NULL;
2297         GstObject *parent = NULL;
2298         int i;
2299
2300         wfd_sink_debug_fenter();
2301
2302         wfd_sink_return_val_if_fail(wfd_sink,
2303                                     MM_ERROR_WFD_NOT_INITIALIZED);
2304
2305         if (wfd_sink->pipeline &&
2306             wfd_sink->pipeline->a_decodebin&&
2307             wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2308                 a_decodebin = wfd_sink->pipeline->a_decodebin;
2309         } else {
2310                 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
2311                 return MM_ERROR_NONE;
2312         }
2313
2314         parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
2315         if (!parent) {
2316                 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2317
2318                 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
2319                         wfd_sink_debug("try to change state of audio decodebin to NULL");
2320                         ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
2321                         if (ret != GST_STATE_CHANGE_SUCCESS) {
2322                                 wfd_sink_error("failed to change state of audio decodebin to NULL");
2323                                 return MM_ERROR_WFD_INTERNAL;
2324                         }
2325                 }
2326
2327                 /* release element which are not added to bin */
2328                 for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
2329                         if (a_decodebin[i].gst) {
2330                                 parent = gst_element_get_parent(a_decodebin[i].gst);
2331                                 if (!parent) {
2332                                         wfd_sink_debug("unref %s(current ref %d)",
2333                                                        GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2334                                                        ((GObject *) a_decodebin[i].gst)->ref_count);
2335                                         gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2336                                         a_decodebin[i].gst = NULL;
2337                                 } else {
2338                                         wfd_sink_debug("unref %s(current ref %d)",
2339                                                        GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2340                                                        ((GObject *) a_decodebin[i].gst)->ref_count);
2341                                         gst_object_unref(GST_OBJECT(parent));
2342                                 }
2343                         }
2344                 }
2345
2346                 /* release audio decodebin with it's childs */
2347                 if (a_decodebin[WFD_SINK_A_D_BIN].gst)
2348                         gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2349
2350         } else {
2351                 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
2352                                GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2353
2354                 gst_object_unref(GST_OBJECT(parent));
2355         }
2356
2357         wfd_sink->audio_decodebin_is_linked = FALSE;
2358
2359         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
2360
2361         wfd_sink_debug_fleave();
2362
2363         return MM_ERROR_NONE;
2364 }
2365
2366 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2367 {
2368         MMWFDSinkGstElement *a_decodebin = NULL;
2369         gint audio_codec = WFD_AUDIO_UNKNOWN;
2370         GList *element_bucket = NULL;
2371         gboolean link = TRUE;
2372         gint i=0;
2373
2374         wfd_sink_debug_fenter();
2375
2376         wfd_sink_return_val_if_fail(wfd_sink &&
2377                                     wfd_sink->pipeline,
2378                                     MM_ERROR_WFD_NOT_INITIALIZED);
2379
2380         /* check audio decodebin could be linked now */
2381         switch (wfd_sink->stream_info.audio_stream_info.codec) {
2382                 case MM_WFD_SINK_AUDIO_CODEC_AAC:
2383                         audio_codec = WFD_AUDIO_AAC;
2384                         link = TRUE;
2385                         break;
2386                 case MM_WFD_SINK_AUDIO_CODEC_AC3:
2387                         audio_codec = WFD_AUDIO_AC3;
2388                         link = TRUE;
2389                         break;
2390                 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
2391                         audio_codec = WFD_AUDIO_LPCM;
2392                         link = TRUE;
2393                         break;
2394                 case MM_WFD_SINK_AUDIO_CODEC_NONE:
2395                 default:
2396                         wfd_sink_debug("audio decodebin could NOT be linked now, just create");
2397                         audio_codec = wfd_sink->ini.audio_codec;
2398                         link = FALSE;
2399                         break;
2400         }
2401
2402         /* alloc handles */
2403         a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2404         if (!a_decodebin) {
2405                 wfd_sink_error("failed to allocate memory for audio decodebin");
2406                 return MM_ERROR_WFD_NO_FREE_SPACE;
2407         }
2408
2409         memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2410
2411         /* create audio decodebin */
2412         a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
2413         a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
2414         if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
2415                 wfd_sink_error("failed to create audio decodebin");
2416                 goto CREATE_ERROR;
2417         }
2418
2419         /* create queue */
2420         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
2421         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "sink");
2422         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
2423                 __mm_wfd_sink_prepare_queue( wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
2424
2425         /* create hdcp */
2426         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
2427         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "sink");
2428
2429         /* create codec */
2430         audio_codec = wfd_sink->ini.audio_codec;
2431         if (audio_codec & WFD_AUDIO_LPCM) {
2432                 /* create LPCM converter */
2433                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
2434                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "sink");
2435                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "src");
2436
2437                 /* create LPCM filter */
2438                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
2439                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "sink");
2440                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "src");
2441         }
2442
2443         if (audio_codec & WFD_AUDIO_AAC) {
2444                 /* create AAC parse  */
2445                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
2446                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "sink");
2447                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "src");
2448
2449                 /* create AAC decoder  */
2450                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
2451                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "sink");
2452                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "src");
2453         }
2454
2455         if (audio_codec & WFD_AUDIO_AC3) {
2456                 /* create AC3 parser  */
2457                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
2458                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "sink");
2459                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "src");
2460
2461                 /* create AC3 decoder  */
2462                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
2463                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "sink");
2464                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "src");
2465         }
2466
2467         g_list_free(element_bucket);
2468
2469         /* take it */
2470         wfd_sink->pipeline->a_decodebin= a_decodebin;
2471
2472         /* link audio decodebin if audio codec is fixed */
2473         if (link) {
2474                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
2475                         wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
2476                         __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
2477                         return MM_ERROR_WFD_INTERNAL;
2478                 }
2479         }
2480
2481         wfd_sink_debug_fleave();
2482
2483         return MM_ERROR_NONE;
2484
2485 CREATE_ERROR:
2486         wfd_sink_error("failed to create audio decodebin, release all");
2487
2488         g_list_free(element_bucket);
2489
2490         /* release element which are not added to bin */
2491         for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
2492                 if (a_decodebin != NULL && a_decodebin[i].gst) {
2493                         GstObject *parent = NULL;
2494                         parent = gst_element_get_parent(a_decodebin[i].gst);
2495
2496                         if (!parent) {
2497                                 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2498                                 a_decodebin[i].gst = NULL;
2499                         } else {
2500                                 gst_object_unref(GST_OBJECT(parent));
2501                         }
2502                 }
2503         }
2504
2505         /* release audioo decodebin with it's childs */
2506         if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst)
2507                 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2508
2509         MMWFDSINK_FREEIF(a_decodebin);
2510
2511         return MM_ERROR_WFD_INTERNAL;
2512 }
2513
2514 static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2515 {
2516         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2517         MMWFDSinkGstElement *a_sinkbin = NULL;
2518         GstObject *parent = NULL;
2519         int i;
2520
2521         wfd_sink_debug_fenter();
2522
2523         wfd_sink_return_val_if_fail(wfd_sink,
2524                                     MM_ERROR_WFD_NOT_INITIALIZED);
2525
2526         if (wfd_sink->pipeline &&
2527             wfd_sink->pipeline->a_sinkbin&&
2528             wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2529                 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
2530         } else {
2531                 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
2532                 return MM_ERROR_NONE;
2533         }
2534
2535
2536         parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
2537         if (!parent) {
2538                 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2539
2540                 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
2541                         wfd_sink_debug("try to change state of audio decodebin to NULL");
2542                         ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
2543                         if (ret != GST_STATE_CHANGE_SUCCESS) {
2544                                 wfd_sink_error("failed to change state of audio decodebin to NULL");
2545                                 return MM_ERROR_WFD_INTERNAL;
2546                         }
2547                 }
2548
2549                 /* release element which are not added to bin */
2550                 for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
2551                         if (a_sinkbin[i].gst) {
2552                                 parent = gst_element_get_parent(a_sinkbin[i].gst);
2553                                 if (!parent) {
2554                                         wfd_sink_debug("unref %s(current ref %d)",
2555                                                        GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2556                                                        ((GObject *) a_sinkbin[i].gst)->ref_count);
2557                                         gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2558                                         a_sinkbin[i].gst = NULL;
2559                                 } else {
2560                                         wfd_sink_debug("unref %s(current ref %d)",
2561                                                        GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2562                                                        ((GObject *) a_sinkbin[i].gst)->ref_count);
2563                                         gst_object_unref(GST_OBJECT(parent));
2564                                 }
2565                         }
2566                 }
2567
2568                 /* release audio decodebin with it's childs */
2569                 if (a_sinkbin[WFD_SINK_A_S_BIN].gst)
2570                         gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2571
2572         } else {
2573                 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
2574                                GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2575
2576                 gst_object_unref(GST_OBJECT(parent));
2577         }
2578
2579         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
2580
2581         wfd_sink_debug_fleave();
2582
2583         return MM_ERROR_NONE;
2584 }
2585
2586 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2587 {
2588         MMWFDSinkGstElement *a_sinkbin = NULL;
2589         MMWFDSinkGstElement *first_element = NULL;
2590         GList *element_bucket = NULL;
2591         GstPad *ghostpad = NULL;
2592         GstPad *pad = NULL;
2593         gint i=0;
2594
2595         wfd_sink_debug_fenter();
2596
2597         wfd_sink_return_val_if_fail(wfd_sink &&
2598                                     wfd_sink->pipeline,
2599                                     MM_ERROR_WFD_NOT_INITIALIZED);
2600
2601         /* alloc handles */
2602         a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2603         if (!a_sinkbin) {
2604                 wfd_sink_error("failed to allocate memory for audio sinkbin");
2605                 return MM_ERROR_WFD_NO_FREE_SPACE;
2606         }
2607
2608         memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2609
2610         /* create audio sinkbin */
2611         a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
2612         a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
2613         if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2614                 wfd_sink_error("failed to create audio sinkbin");
2615                 goto CREATE_ERROR;
2616         }
2617
2618         /* create resampler */
2619         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
2620         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "sink");
2621         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "src");
2622
2623         /* create volume */
2624         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
2625         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "sink");
2626         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "src");
2627
2628         /* create sink */
2629         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
2630         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst,  "sink");
2631         if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
2632                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
2633                         wfd_sink_error("failed to set audio sink property....");
2634                         goto CREATE_ERROR;
2635                 }
2636         }
2637
2638         /* adding created elements to audio sinkbin */
2639         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
2640                 wfd_sink_error("failed to add elements to audio sinkbin");
2641                 goto CREATE_ERROR;
2642         }
2643
2644         /* linking elements in the bucket by added order. */
2645         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2646                 wfd_sink_error("failed to link elements fo the audio sinkbin");
2647                 goto CREATE_ERROR;
2648         }
2649
2650         /* get first element's of the audio sinkbin */
2651         first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2652         if (!first_element) {
2653                 wfd_sink_error("failed to get first element of the audio sinkbin");
2654                 goto CREATE_ERROR;
2655         }
2656
2657         /* get first element's sinkpad for creating ghostpad */
2658         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2659         if (!pad) {
2660                 wfd_sink_error("failed to get sink pad from element(%s)",
2661                         GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2662                 goto CREATE_ERROR;
2663         }
2664
2665         ghostpad = gst_ghost_pad_new("sink", pad);
2666         if (!ghostpad) {
2667                 wfd_sink_error("failed to create ghostpad of audio sinkbin");
2668                 goto CREATE_ERROR;
2669         }
2670
2671         if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
2672                 wfd_sink_error("failed to add ghostpad to audio sinkbin");
2673                 goto CREATE_ERROR;
2674         }
2675         gst_object_unref(GST_OBJECT(pad));
2676
2677         g_list_free(element_bucket);
2678
2679         /* take it */
2680         wfd_sink->pipeline->a_sinkbin = a_sinkbin;
2681
2682         wfd_sink_debug_fleave();
2683
2684         return MM_ERROR_NONE;
2685
2686 CREATE_ERROR:
2687         wfd_sink_error("failed to create audio sinkbin, releasing all");
2688
2689         if (pad)
2690                 gst_object_unref(GST_OBJECT(pad));
2691         pad = NULL;
2692
2693         if (ghostpad)
2694                 gst_object_unref(GST_OBJECT(ghostpad));
2695         ghostpad = NULL;
2696
2697         if (element_bucket)
2698                 g_list_free(element_bucket);
2699         element_bucket = NULL;
2700
2701         /* release element which are not added to bin */
2702         for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
2703                 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
2704                         GstObject *parent = NULL;
2705                         parent = gst_element_get_parent(a_sinkbin[i].gst);
2706
2707                         if (!parent) {
2708                                 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2709                                 a_sinkbin[i].gst = NULL;
2710                         } else {
2711                                 gst_object_unref(GST_OBJECT(parent));
2712                         }
2713                 }
2714         }
2715
2716         /* release audio sinkbin with it's childs */
2717         if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst)
2718                 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2719
2720         MMWFDSINK_FREEIF(a_sinkbin);
2721
2722         return MM_ERROR_WFD_INTERNAL;
2723 }
2724
2725 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
2726 {
2727         MMWFDSinkGstElement     *v_decodebin = NULL;
2728         MMWFDSinkGstElement *first_element = NULL;
2729         MMWFDSinkGstElement *last_element = NULL;
2730         GList *element_bucket = NULL;
2731         GstPad *sinkpad = NULL;
2732         GstPad *srcpad = NULL;
2733         GstPad *ghostpad = NULL;
2734
2735         wfd_sink_debug_fenter();
2736
2737         wfd_sink_return_val_if_fail(wfd_sink &&
2738                                     wfd_sink->pipeline &&
2739                                     wfd_sink->pipeline->v_decodebin &&
2740                                     wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
2741                                     MM_ERROR_WFD_NOT_INITIALIZED);
2742
2743         if (wfd_sink->video_decodebin_is_linked) {
2744                 wfd_sink_debug("video decodebin is already linked... nothing to do");
2745                 return MM_ERROR_NONE;
2746         }
2747
2748         /* take video decodebin */
2749         v_decodebin = wfd_sink->pipeline->v_decodebin;
2750
2751         /* check video queue */
2752         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
2753                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
2754
2755         /* check video hdcp */
2756         if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
2757                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
2758
2759         /* check video codec */
2760         switch (wfd_sink->stream_info.video_stream_info.codec) {
2761                 case MM_WFD_SINK_VIDEO_CODEC_H264:
2762                         if (v_decodebin[WFD_SINK_V_D_PARSE].gst)
2763                                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]);
2764                         if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) {
2765                                 GstCaps *caps = NULL;
2766
2767                                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]);
2768                                 caps = gst_caps_new_simple("video/x-h264",
2769                                                            "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width,
2770                                                            "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height,
2771                                                            "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL);
2772                                 g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL);
2773                                 gst_object_unref(GST_OBJECT(caps));
2774                         }
2775                         if (v_decodebin[WFD_SINK_V_D_DEC].gst)
2776                                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]);
2777                         break;
2778
2779                 default:
2780                         wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
2781                         return MM_ERROR_WFD_INTERNAL;
2782                         break;
2783         }
2784
2785         if (element_bucket == NULL) {
2786                 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
2787                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
2788                         wfd_sink_error("failed to destroy video decodebin");
2789                         goto fail_to_link;
2790                 }
2791                 goto done;
2792         }
2793
2794         /* adding elements to video decodebin */
2795         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
2796                 wfd_sink_error("failed to add elements to video decodebin");
2797                 goto fail_to_link;
2798         }
2799
2800         /* linking elements in the bucket by added order. */
2801         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2802                 wfd_sink_error("failed to link elements of the video decodebin");
2803                 goto fail_to_link;
2804         }
2805
2806         /* get first element's sinkpad for creating ghostpad */
2807         first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2808         if (!first_element) {
2809                 wfd_sink_error("failed to get first element of the video decodebin");
2810                 goto fail_to_link;
2811         }
2812
2813         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2814         if (!sinkpad) {
2815                 wfd_sink_error("failed to get sink pad from element(%s)",
2816                         GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2817                 goto fail_to_link;
2818         }
2819
2820         ghostpad = gst_ghost_pad_new("sink", sinkpad);
2821         if (!ghostpad) {
2822                 wfd_sink_error("failed to create ghostpad of video decodebin");
2823                 goto fail_to_link;
2824         }
2825
2826         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2827                 wfd_sink_error("failed to add ghostpad to video decodebin");
2828                 goto fail_to_link;
2829         }
2830         gst_object_unref(GST_OBJECT(sinkpad));
2831         sinkpad = NULL;
2832
2833
2834         /* get last element's src for creating ghostpad */
2835         last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data;
2836         if (!last_element) {
2837                 wfd_sink_error("failed to get last element of the video decodebin");
2838                 goto fail_to_link;
2839         }
2840
2841         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2842         if (!srcpad) {
2843                 wfd_sink_error("failed to get src pad from element(%s)",
2844                         GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2845                 goto fail_to_link;
2846         }
2847
2848         ghostpad = gst_ghost_pad_new("src", srcpad);
2849         if (!ghostpad) {
2850                 wfd_sink_error("failed to create ghostpad of video decodebin");
2851                 goto fail_to_link;
2852         }
2853
2854         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2855                 wfd_sink_error("failed to add ghostpad to video decodebin");
2856                 goto fail_to_link;
2857         }
2858         gst_object_unref(GST_OBJECT(srcpad));
2859         srcpad = NULL;
2860
2861         g_list_free(element_bucket);
2862
2863 done:
2864         wfd_sink->video_decodebin_is_linked = TRUE;
2865
2866         wfd_sink_debug_fleave();
2867
2868         return MM_ERROR_NONE;
2869
2870         /* ERRORS*/
2871 fail_to_link:
2872         if (srcpad != NULL)
2873                 gst_object_unref(GST_OBJECT(srcpad));
2874         srcpad = NULL;
2875
2876         if (sinkpad != NULL)
2877                 gst_object_unref(GST_OBJECT(sinkpad));
2878         sinkpad = NULL;
2879
2880         g_list_free(element_bucket);
2881
2882         return MM_ERROR_WFD_INTERNAL;
2883 }
2884
2885 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
2886 {
2887         wfd_sink_debug_fenter();
2888
2889         /* check video decoder is created */
2890         wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
2891         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2892
2893         wfd_sink_debug_fleave();
2894
2895         return MM_ERROR_NONE;
2896 }
2897
2898 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
2899 {
2900         gboolean visible = TRUE;
2901         gint surface_type = MM_DISPLAY_SURFACE_X;
2902         gulong xid = 0;
2903
2904         wfd_sink_debug_fenter();
2905
2906         /* check videosink is created */
2907         wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2908         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2909
2910         /* update display surface */
2911         /*      mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); */
2912         wfd_sink_debug("check display surface type attribute: %d", surface_type);
2913         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
2914         wfd_sink_debug("check display visible attribute: %d", visible);
2915
2916         /* configuring display */
2917         switch (surface_type) {
2918                 case MM_DISPLAY_SURFACE_EVAS: {
2919                                 void *object = NULL;
2920                                 gint scaling = 0;
2921
2922                                 /* common case if using evas surface */
2923                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
2924                                 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
2925                                 if (object) {
2926                                         wfd_sink_debug("set video param : evas-object %x", object);
2927                                         g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
2928                                 } else {
2929                                         wfd_sink_error("no evas object");
2930                                         return MM_ERROR_WFD_INTERNAL;
2931                                 }
2932                         }
2933                         break;
2934
2935                 case MM_DISPLAY_SURFACE_X: {
2936                                 int *object = NULL;
2937
2938                                 /* x surface */
2939                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", (void **)&object);
2940                                 if (object) {
2941                                         xid = *object;
2942                                         wfd_sink_debug("xid = %lu", xid);
2943                                         gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), xid);
2944                                 } else {
2945                                         wfd_sink_warning("Handle is NULL. Set xid as 0.. but, it's not recommended.");
2946                                         gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), 0);
2947                                 }
2948                         }
2949                         break;
2950
2951                 case MM_DISPLAY_SURFACE_NULL: {
2952                                 /* do nothing */
2953                                 wfd_sink_error("Not Supported Surface.");
2954                                 return MM_ERROR_WFD_INTERNAL;
2955                         }
2956                         break;
2957                 default: {
2958                                 wfd_sink_error("Not Supported Surface.(default case)");
2959                                 return MM_ERROR_WFD_INTERNAL;
2960                         }
2961                         break;
2962         }
2963
2964         g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
2965         g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
2966         g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
2967         g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
2968         g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
2969
2970         wfd_sink_debug_fleave();
2971
2972         return MM_ERROR_NONE;
2973 }
2974
2975 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
2976 {
2977         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2978         MMWFDSinkGstElement *v_decodebin = NULL;
2979         GstObject *parent = NULL;
2980         int i;
2981
2982         wfd_sink_debug_fenter();
2983
2984         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2985
2986         if (wfd_sink->pipeline &&
2987             wfd_sink->pipeline->v_decodebin &&
2988             wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
2989                 v_decodebin = wfd_sink->pipeline->v_decodebin;
2990         } else {
2991                 wfd_sink_debug("video decodebin is not created, nothing to destroy");
2992                 return MM_ERROR_NONE;
2993         }
2994
2995
2996         parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
2997         if (!parent) {
2998                 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
2999
3000                 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
3001                         wfd_sink_debug("try to change state of video decodebin to NULL");
3002                         ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
3003                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3004                                 wfd_sink_error("failed to change state of video decodebin to NULL");
3005                                 return MM_ERROR_WFD_INTERNAL;
3006                         }
3007                 }
3008                 /* release element which are not added to bin */
3009                 for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
3010                         if (v_decodebin[i].gst) {
3011                                 parent = gst_element_get_parent(v_decodebin[i].gst);
3012                                 if (!parent) {
3013                                         wfd_sink_debug("unref %s(current ref %d)",
3014                                                        GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3015                                                        ((GObject *) v_decodebin[i].gst)->ref_count);
3016                                         gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3017                                         v_decodebin[i].gst = NULL;
3018                                 } else {
3019                                         wfd_sink_debug("unref %s(current ref %d)",
3020                                                        GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3021                                                        ((GObject *) v_decodebin[i].gst)->ref_count);
3022                                         gst_object_unref(GST_OBJECT(parent));
3023                                 }
3024                         }
3025                 }
3026                 /* release video decodebin with it's childs */
3027                 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
3028                         gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3029                         wfd_sink_debug("unref %s(current ref %d)",
3030                                                GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
3031                                                ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
3032                 }
3033         } else {
3034                 wfd_sink_debug("video decodebin has parent(%s), unref it",
3035                                GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3036
3037                 gst_object_unref(GST_OBJECT(parent));
3038         }
3039
3040         wfd_sink->video_decodebin_is_linked = FALSE;
3041
3042         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
3043
3044         wfd_sink_debug_fleave();
3045
3046         return MM_ERROR_NONE;
3047 }
3048
3049 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
3050 {
3051         MMWFDSinkGstElement *v_decodebin = NULL;
3052         guint video_codec = WFD_VIDEO_UNKNOWN;
3053         GList *element_bucket = NULL;
3054         gboolean link = TRUE;
3055         gint i=0;
3056
3057         wfd_sink_debug_fenter();
3058
3059         wfd_sink_return_val_if_fail(wfd_sink &&
3060                                     wfd_sink->pipeline,
3061                                     MM_ERROR_WFD_NOT_INITIALIZED);
3062
3063         if (wfd_sink->pipeline->v_decodebin) {
3064                 wfd_sink_debug("video decodebin is already created... nothing to do");
3065                 return MM_ERROR_NONE;
3066         }
3067
3068         /* check audio decodebin could be linked now */
3069         switch (wfd_sink->stream_info.video_stream_info.codec) {
3070                 case MM_WFD_SINK_VIDEO_CODEC_H264:
3071                         video_codec = WFD_VIDEO_H264;
3072                         link = TRUE;
3073                         break;
3074                 case MM_WFD_SINK_VIDEO_CODEC_NONE:
3075                 default:
3076                         wfd_sink_debug("video decodebin could NOT be linked now, just create");
3077                         video_codec = wfd_sink->ini.video_codec;
3078                         link = FALSE;
3079                         break;
3080         }
3081
3082         /* alloc handles */
3083         v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3084         if (!v_decodebin) {
3085                 wfd_sink_error("failed to allocate memory for video decodebin");
3086                 return MM_ERROR_WFD_NO_FREE_SPACE;
3087         }
3088
3089         memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3090
3091         /* create video decodebin */
3092         v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
3093         v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
3094         if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
3095                 wfd_sink_error("failed to create video decodebin");
3096                 goto CREATE_ERROR;
3097         }
3098
3099         /* create queue */
3100         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
3101         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "sink");
3102         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3103                 __mm_wfd_sink_prepare_queue( wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
3104
3105         /* create hdcp */
3106         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
3107         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "sink");
3108         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "src");
3109
3110         if (video_codec & WFD_VIDEO_H264) {
3111                 /* create parser */
3112                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE);
3113                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst,  "sink");
3114                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst,  "src");
3115
3116                 /* create capssetter */
3117                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE);
3118                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst,  "sink");
3119                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst,  "src");
3120
3121                 /* create dec */
3122                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE);
3123                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst,  "sink");
3124                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst,  "src");
3125                 if (v_decodebin[WFD_SINK_V_D_DEC].gst) {
3126                         if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) {
3127                                 wfd_sink_error("failed to set video decoder property...");
3128                                 goto CREATE_ERROR;
3129                         }
3130                 }
3131         }
3132
3133         g_list_free(element_bucket);
3134
3135         /* take it */
3136         wfd_sink->pipeline->v_decodebin = v_decodebin;
3137
3138         /* link video decodebin if video codec is fixed */
3139         if (link) {
3140                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
3141                         wfd_sink_error("failed to link video decodebin, destroy video decodebin");
3142                         __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
3143                         return MM_ERROR_WFD_INTERNAL;
3144                 }
3145         }
3146
3147         wfd_sink_debug_fleave();
3148
3149         return MM_ERROR_NONE;
3150
3151         /* ERRORS */
3152 CREATE_ERROR:
3153         wfd_sink_error("failed to create video decodebin, releasing all");
3154
3155         g_list_free(element_bucket);
3156
3157         /* release element which are not added to bin */
3158         for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
3159                 if (v_decodebin != NULL && v_decodebin[i].gst) {
3160                         GstObject *parent = NULL;
3161                         parent = gst_element_get_parent(v_decodebin[i].gst);
3162
3163                         if (!parent) {
3164                                 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3165                                 v_decodebin[i].gst = NULL;
3166                         } else {
3167                                 gst_object_unref(GST_OBJECT(parent));
3168                         }
3169                 }
3170         }
3171
3172         /* release video decodebin with it's childs */
3173         if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst)
3174                 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3175
3176         MMWFDSINK_FREEIF(v_decodebin);
3177
3178         return MM_ERROR_WFD_INTERNAL;
3179 }
3180
3181 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3182 {
3183         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3184         MMWFDSinkGstElement *v_sinkbin = NULL;
3185         GstObject *parent = NULL;
3186         int i;
3187
3188         wfd_sink_debug_fenter();
3189
3190         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3191
3192         if (wfd_sink->pipeline &&
3193             wfd_sink->pipeline->v_sinkbin &&
3194             wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3195                 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
3196         } else {
3197                 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
3198                 return MM_ERROR_NONE;
3199         }
3200
3201
3202         parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
3203         if (!parent) {
3204                 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
3205
3206                 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
3207                         wfd_sink_debug("try to change state of video sinkbin to NULL");
3208                         ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
3209                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3210                                 wfd_sink_error("failed to change state of video sinkbin to NULL");
3211                                 return MM_ERROR_WFD_INTERNAL;
3212                         }
3213                 }
3214                 /* release element which are not added to bin */
3215                 for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
3216                         if (v_sinkbin[i].gst) {
3217                                 parent = gst_element_get_parent(v_sinkbin[i].gst);
3218                                 if (!parent) {
3219                                         wfd_sink_debug("unref %s(current ref %d)",
3220                                                        GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3221                                                        ((GObject *) v_sinkbin[i].gst)->ref_count);
3222                                         gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3223                                         v_sinkbin[i].gst = NULL;
3224                                 } else {
3225                                         wfd_sink_debug("unref %s(current ref %d)",
3226                                                        GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3227                                                        ((GObject *) v_sinkbin[i].gst)->ref_count);
3228                                         gst_object_unref(GST_OBJECT(parent));
3229                                 }
3230                         }
3231                 }
3232                 /* release video sinkbin with it's childs */
3233                 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3234                         gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3235                 }
3236         } else {
3237                 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
3238                                GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3239
3240                 gst_object_unref(GST_OBJECT(parent));
3241         }
3242
3243         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
3244
3245         wfd_sink_debug_fleave();
3246
3247         return MM_ERROR_NONE;
3248 }
3249
3250 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3251 {
3252         MMWFDSinkGstElement *first_element = NULL;
3253         MMWFDSinkGstElement *v_sinkbin = NULL;
3254         GList *element_bucket = NULL;
3255         GstPad *pad = NULL;
3256         GstPad *ghostpad = NULL;
3257         gint i=0;
3258
3259         wfd_sink_debug_fenter();
3260
3261         wfd_sink_return_val_if_fail(wfd_sink &&
3262                                     wfd_sink->pipeline,
3263                                     MM_ERROR_WFD_NOT_INITIALIZED);
3264
3265         /* alloc handles */
3266         v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3267         if (!v_sinkbin) {
3268                 wfd_sink_error("failed to allocate memory for video sinkbin");
3269                 return MM_ERROR_WFD_NO_FREE_SPACE;
3270         }
3271
3272         memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3273
3274         /* create video sinkbin */
3275         v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
3276         v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
3277         if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3278                 wfd_sink_error("failed to create video sinkbin");
3279                 goto CREATE_ERROR;
3280         }
3281
3282         /* create convert */
3283         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
3284         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "sink");
3285         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "src");
3286
3287         /* create filter */
3288         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
3289         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "sink");
3290         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "src");
3291         if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
3292                 GstCaps *caps = NULL;
3293                 caps = gst_caps_new_simple("video/x-raw",
3294                                            "format", G_TYPE_STRING, "SN12", NULL);
3295                 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
3296                 gst_object_unref(GST_OBJECT(caps));
3297         }
3298         
3299         /* create sink */
3300         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
3301         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst,  "sink");
3302         if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
3303                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
3304                         wfd_sink_error("failed to set video sink property....");
3305                         goto CREATE_ERROR;
3306                 }
3307         }
3308
3309         /* adding created elements to video sinkbin */
3310         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
3311                 wfd_sink_error("failed to add elements to video sinkbin");
3312                 goto CREATE_ERROR;
3313         }
3314
3315         /* linking elements in the bucket by added order. */
3316         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3317                 wfd_sink_error("failed to link elements of the video sinkbin");
3318                 goto CREATE_ERROR;
3319         }
3320
3321         /* get first element's sinkpad for creating ghostpad */
3322         first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
3323         if (!first_element) {
3324                 wfd_sink_error("failed to get first element of the video sinkbin");
3325                 goto CREATE_ERROR;
3326         }
3327
3328         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3329         if (!pad) {
3330                 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
3331                         GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3332                 goto CREATE_ERROR;
3333         }
3334
3335         ghostpad = gst_ghost_pad_new("sink", pad);
3336         if (!ghostpad) {
3337                 wfd_sink_error("failed to create ghostpad of the video sinkbin");
3338                 goto CREATE_ERROR;
3339         }
3340
3341         if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
3342                 wfd_sink_error("failed to add ghostpad to video sinkbin");
3343                 goto CREATE_ERROR;
3344         }
3345
3346         gst_object_unref(GST_OBJECT(pad));
3347
3348         g_list_free(element_bucket);
3349
3350
3351         /* take it */
3352         wfd_sink->pipeline->v_sinkbin = v_sinkbin;
3353
3354         wfd_sink_debug_fleave();
3355
3356         return MM_ERROR_NONE;
3357
3358         /* ERRORS */
3359 CREATE_ERROR:
3360         wfd_sink_error("failed to create video sinkbin, releasing all");
3361
3362         if (pad)
3363                 gst_object_unref(GST_OBJECT(pad));
3364         pad = NULL;
3365
3366         if (ghostpad)
3367                 gst_object_unref(GST_OBJECT(ghostpad));
3368         ghostpad = NULL;
3369
3370         g_list_free(element_bucket);
3371
3372         /* release element which are not added to bin */
3373         for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
3374                 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
3375                         GstObject *parent = NULL;
3376                         parent = gst_element_get_parent(v_sinkbin[i].gst);
3377
3378                         if (!parent) {
3379                                 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3380                                 v_sinkbin[i].gst = NULL;
3381                         } else {
3382                                 gst_object_unref(GST_OBJECT(parent));
3383                         }
3384                 }
3385         }
3386
3387         /* release video sinkbin with it's childs */
3388         if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst)
3389                 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3390
3391         MMWFDSINK_FREEIF(v_sinkbin);
3392
3393         return MM_ERROR_WFD_INTERNAL;
3394 }
3395
3396 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
3397 {
3398         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3399
3400         wfd_sink_debug_fenter();
3401
3402         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3403
3404         /* cleanup gst stuffs */
3405         if (wfd_sink->pipeline) {
3406                 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
3407
3408                 if (mainbin) {
3409                         ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
3410                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3411                                 wfd_sink_error("failed to change state of mainbin to NULL");
3412                                 return MM_ERROR_WFD_INTERNAL;
3413                         }
3414
3415                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3416                                 wfd_sink_error("failed to destroy video decodebin");
3417                                 return MM_ERROR_WFD_INTERNAL;
3418                         }
3419
3420                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3421                                 wfd_sink_error("failed to destroy audio decodebin");
3422                                 return MM_ERROR_WFD_INTERNAL;
3423                         }
3424
3425                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
3426                                 wfd_sink_error("failed to destroy video sinkbin");
3427                                 return MM_ERROR_WFD_INTERNAL;
3428                         }
3429
3430                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
3431                                 wfd_sink_error("failed to destroy audio sinkbin");
3432                                 return MM_ERROR_WFD_INTERNAL;
3433                         }
3434
3435                         gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3436
3437                         MMWFDSINK_FREEIF(mainbin);
3438                 }
3439
3440                 MMWFDSINK_FREEIF(wfd_sink->pipeline);
3441         }
3442
3443         wfd_sink->audio_decodebin_is_linked = FALSE;
3444         wfd_sink->video_decodebin_is_linked = FALSE;
3445         wfd_sink->need_to_reset_basetime = FALSE;
3446
3447         wfd_sink_debug_fleave();
3448
3449         return MM_ERROR_NONE;
3450 }
3451
3452 static void
3453 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
3454 {
3455         GstIterator *iter = NULL;
3456         gboolean done = FALSE;
3457
3458         GstElement *item = NULL;
3459         GstElementFactory *factory = NULL;
3460
3461         GstState state = GST_STATE_VOID_PENDING;
3462         GstState pending = GST_STATE_VOID_PENDING;
3463         GstClockTime time = 200 * GST_MSECOND;
3464
3465         wfd_sink_debug_fenter();
3466
3467         wfd_sink_return_if_fail(wfd_sink &&
3468                                 wfd_sink->pipeline &&
3469                                 wfd_sink->pipeline->mainbin &&
3470                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3471
3472         iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
3473
3474         if (iter != NULL) {
3475                 while (!done) {
3476                         switch (gst_iterator_next(iter, (gpointer)&item)) {
3477                                 case GST_ITERATOR_OK:
3478                                         gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3479
3480                                         factory = gst_element_get_factory(item) ;
3481                                         if (factory) {
3482                                                 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3483                                                                GST_STR_NULL(GST_OBJECT_NAME(factory)),
3484                                                                GST_STR_NULL(GST_ELEMENT_NAME(item)),
3485                                                                gst_element_state_get_name(state),
3486                                                                gst_element_state_get_name(pending),
3487                                                                GST_OBJECT_REFCOUNT_VALUE(item));
3488                                         }
3489                                         gst_object_unref(item);
3490                                         break;
3491                                 case GST_ITERATOR_RESYNC:
3492                                         gst_iterator_resync(iter);
3493                                         break;
3494                                 case GST_ITERATOR_ERROR:
3495                                         done = TRUE;
3496                                         break;
3497                                 case GST_ITERATOR_DONE:
3498                                         done = TRUE;
3499                                         break;
3500                                 default:
3501                                         done = TRUE;
3502                                         break;
3503                         }
3504                 }
3505         }
3506
3507         item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3508
3509         gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3510
3511         factory = gst_element_get_factory(item) ;
3512         if (factory) {
3513                 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3514                                GST_OBJECT_NAME(factory),
3515                                GST_ELEMENT_NAME(item),
3516                                gst_element_state_get_name(state),
3517                                gst_element_state_get_name(pending),
3518                                GST_OBJECT_REFCOUNT_VALUE(item));
3519         }
3520
3521         if (iter)
3522                 gst_iterator_free(iter);
3523
3524         wfd_sink_debug_fleave();
3525
3526         return;
3527 }
3528
3529 const gchar *
3530 _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
3531 {
3532         switch (state) {
3533                 case MM_WFD_SINK_STATE_NONE:
3534                         return "NONE";
3535                 case MM_WFD_SINK_STATE_NULL:
3536                         return "NULL";
3537                 case MM_WFD_SINK_STATE_PREPARED:
3538                         return "PREPARED";
3539                 case MM_WFD_SINK_STATE_CONNECTED:
3540                         return "CONNECTED";
3541                 case MM_WFD_SINK_STATE_PLAYING:
3542                         return "PLAYING";
3543                 case MM_WFD_SINK_STATE_PAUSED:
3544                         return "PAUSED";
3545                 case MM_WFD_SINK_STATE_DISCONNECTED:
3546                         return "DISCONNECTED";
3547                 default:
3548                         return "INVAID";
3549         }
3550 }
3551
3552 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution,
3553                                                    guint *VESA_resolution, guint *HH_resolution)
3554 {
3555         if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
3556
3557         *CEA_resolution = 0;
3558         *VESA_resolution = 0;
3559         *HH_resolution = 0;
3560
3561         if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
3562                 *CEA_resolution |= WFD_CEA_1920x1080P30;
3563
3564         if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
3565                 *CEA_resolution |= WFD_CEA_1280x720P30;
3566
3567         if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
3568                 *HH_resolution |= WFD_HH_960x540P30;
3569
3570         if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
3571                 *HH_resolution |= WFD_HH_864x480P30;
3572
3573         if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
3574                 *CEA_resolution |= WFD_CEA_720x480P60;
3575
3576         if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
3577                 *CEA_resolution |= WFD_CEA_640x480P60;
3578
3579         if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
3580                 *HH_resolution |= WFD_HH_640x360P30;
3581 }
3582
3583 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
3584 {
3585         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
3586
3587         wfd_sink_debug_fenter();
3588
3589         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3590
3591         MMWFDSINK_PRINT_STATE(wfd_sink);
3592         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
3593         if (cur_state != MM_WFD_SINK_STATE_NULL) {
3594                 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
3595                 return MM_ERROR_WFD_INVALID_STATE;
3596         }
3597
3598         wfd_sink->supportive_resolution = resolution;
3599
3600         wfd_sink_debug_fleave();
3601
3602         return MM_ERROR_NONE;
3603 }