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