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