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