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