Change pipeline creation for Video only session
[platform/core/multimedia/libmm-wfd.git] / src / mm_wfd_sink_priv.c
1 /*
2  * libmm-wfd
3  *
4  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, ByungWook Jang <bw.jang@samsung.com>,
7  * Maksym Ukhanov <m.ukhanov@samsung.com>, Hyunjun Ko <zzoon.ko@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include <gst/gst.h>
24 #include <gst/video/videooverlay.h>
25 #include <Elementary.h>
26 #include <Ecore_Wayland.h>
27
28 #include "mm_wfd_sink_util.h"
29 #include "mm_wfd_sink_priv.h"
30 #include "mm_wfd_sink_manager.h"
31 #include "mm_wfd_sink_dlog.h"
32 #include "mm_wfd_sink_enum.h"
33 #include "mm_wfd_sink_wayland.h"
34 #include "mm_wfd_sink_config.h"
35
36 #define PRINT_WFD_REF_COUNT(wfd_sink)\
37         do {\
38                 wfd_sink_debug("PRINT WFD REF COUNT");\
39                 __mm_wfd_sink_print_ref_count(wfd_sink);\
40         } while (0);
41
42 /* gstreamer */
43 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
44 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
45 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
46 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
47 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
48 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink);
49 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
50 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
51 static gboolean _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data);
52
53 /* state */
54 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
55
56 /* util */
57 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
58
59 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink, const char *ini_path)
60 {
61         int result = MM_ERROR_NONE;
62
63         wfd_sink_debug_fenter();
64
65         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
66         if (ini_path == NULL) {
67                 ini_path = MM_WFD_SINK_INI_DEFAULT_PATH;
68                 wfd_sink_debug("The wfd ini file path is set as defalut[%s]", ini_path);
69         }
70
71         mm_wfd_sink_t *new_wfd_sink = NULL;
72
73         /* create handle */
74         new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
75         if (!new_wfd_sink) {
76                 wfd_sink_error("failed to allocate memory for wi-fi display sink");
77                 return MM_ERROR_WFD_NO_FREE_SPACE;
78         }
79
80         /* Initialize gstreamer related */
81         new_wfd_sink->attrs = 0;
82
83         new_wfd_sink->pipeline = NULL;
84         new_wfd_sink->audio_decodebin_is_linked = FALSE;
85         new_wfd_sink->video_decodebin_is_linked = FALSE;
86
87         /* Initialize timestamp compensation related */
88         new_wfd_sink->need_to_reset_basetime = FALSE;
89         new_wfd_sink->clock = NULL;
90         new_wfd_sink->video_buffer_count = 0LL;
91         new_wfd_sink->video_average_gap = 0LL;
92         new_wfd_sink->video_accumulated_gap = 0LL;
93         new_wfd_sink->audio_buffer_count = 0LL;
94         new_wfd_sink->audio_average_gap = 0LL;
95         new_wfd_sink->audio_accumulated_gap = 0LL;
96         new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
97
98         /* Initialize all states */
99         MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
100         MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
101         MMWFDSINK_PENDING_STATE(new_wfd_sink) =  MM_WFD_SINK_STATE_NONE;
102
103         /* initialize audio/video information */
104         new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
105         new_wfd_sink->stream_info.audio_stream_info.channels = 0;
106         new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
107         new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
108         new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
109         new_wfd_sink->stream_info.video_stream_info.width = 0;
110         new_wfd_sink->stream_info.video_stream_info.height = 0;
111         new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
112
113         /* Initialize command */
114         new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
115         new_wfd_sink->waiting_cmd = FALSE;
116
117         /* Initialize manager related */
118         new_wfd_sink->manager_thread = NULL;
119         new_wfd_sink->manager_thread_cmd = NULL;
120         new_wfd_sink->manager_thread_exit = FALSE;
121
122         /* Initialize video resolution */
123         new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
124
125         /* construct attributes */
126         new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
127         if (!new_wfd_sink->attrs) {
128                 MMWFDSINK_FREEIF(new_wfd_sink);
129                 wfd_sink_error("failed to set attribute");
130                 return MM_ERROR_WFD_INTERNAL;
131         }
132
133         /* load ini for initialize */
134         result = mm_wfd_sink_ini_load(&new_wfd_sink->ini, ini_path);
135         if (result != MM_ERROR_NONE) {
136                 wfd_sink_error("failed to load ini file[%s]", ini_path);
137                 goto fail_to_load_ini;
138         }
139         new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
140
141         /* initialize manager */
142         result = _mm_wfd_sink_init_manager(new_wfd_sink);
143         if (result < MM_ERROR_NONE) {
144                 wfd_sink_error("failed to init manager : %d", result);
145                 goto fail_to_init;
146         }
147
148         /* initialize gstreamer */
149         result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
150         if (result < MM_ERROR_NONE) {
151                 wfd_sink_error("failed to init gstreamer : %d", result);
152                 goto fail_to_init;
153         }
154
155         /* set state */
156         __mm_wfd_sink_set_state(new_wfd_sink,  MM_WFD_SINK_STATE_NULL);
157
158         /* now take handle */
159         *wfd_sink = new_wfd_sink;
160
161         wfd_sink_debug_fleave();
162
163         return result;
164
165         /* ERRORS */
166 fail_to_init:
167         mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
168 fail_to_load_ini:
169         _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
170         MMWFDSINK_FREEIF(new_wfd_sink);
171
172         *wfd_sink = NULL;
173
174         return result;
175 }
176
177 int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink)
178 {
179         int result = MM_ERROR_NONE;
180
181         wfd_sink_debug_fenter();
182
183         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
184
185         /* check current wi-fi display sink state */
186         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
187
188         /* construct pipeline */
189         /* create main pipeline */
190         result = __mm_wfd_sink_create_pipeline(wfd_sink);
191         if (result < MM_ERROR_NONE) {
192                 wfd_sink_error("failed to create pipeline : %d", result);
193                 goto fail_to_create;
194         }
195
196         wfd_sink_info("Current session mode : %d", wfd_sink->ini.sink_session_mode);
197         if (wfd_sink->ini.sink_session_mode & (WFD_SESSION_MODE_MIXED | WFD_SESSION_MODE_VIDEO_ONLY)) {
198                 /* create video decodebin */
199                 result = __mm_wfd_sink_create_video_decodebin(wfd_sink);
200                 if (result < MM_ERROR_NONE) {
201                         wfd_sink_error("failed to create video decodebin %d", result);
202                         goto fail_to_create;
203                 }
204
205                 /* create video sinkbin */
206                 result = __mm_wfd_sink_create_video_sinkbin(wfd_sink);
207                 if (result < MM_ERROR_NONE) {
208                         wfd_sink_error("failed to create video sinkbin %d", result);
209                         goto fail_to_create;
210                 }
211         }
212
213         /* create audio decodebin */
214         result = __mm_wfd_sink_create_audio_decodebin(wfd_sink);
215         if (result < MM_ERROR_NONE) {
216                 wfd_sink_error("fail to create audio decodebin : %d", result);
217                 goto fail_to_create;
218         }
219
220         /* create audio sinkbin */
221         result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink);
222         if (result < MM_ERROR_NONE) {
223                 wfd_sink_error("fail to create audio sinkbin : %d", result);
224                 goto fail_to_create;
225         }
226
227         /* set pipeline READY state */
228         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
229         if (result < MM_ERROR_NONE) {
230                 wfd_sink_error("failed to set state : %d", result);
231                 goto fail_to_create;
232         }
233
234         /* set state */
235         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PREPARED);
236
237         wfd_sink_debug_fleave();
238
239         return result;
240
241         /* ERRORS */
242 fail_to_create:
243         /* need to destroy pipeline already created */
244         __mm_wfd_sink_destroy_pipeline(wfd_sink);
245         return result;
246 }
247
248 int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
249 {
250         int result = MM_ERROR_NONE;
251
252         wfd_sink_debug_fenter();
253
254         wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
255                                                                 MM_ERROR_WFD_INVALID_ARGUMENT);
256         wfd_sink_return_val_if_fail(wfd_sink &&
257                                                                 wfd_sink->pipeline &&
258                                                                 wfd_sink->pipeline->mainbin &&
259                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
260                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
261                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
262                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
263                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
264
265         /* check current wi-fi display sink state */
266         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
267
268         wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
269
270         /* set uri to wfdsrc */
271         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
272
273         /* set pipeline PAUSED state */
274         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
275         if (result < MM_ERROR_NONE) {
276                 wfd_sink_error("failed to set state : %d", result);
277                 return result;
278         }
279
280         wfd_sink_debug_fleave();
281
282         return result;
283 }
284
285 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
286 {
287         int result = MM_ERROR_NONE;
288
289         wfd_sink_debug_fenter();
290
291         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
292
293         /* check current wi-fi display sink state */
294         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
295
296         WFD_SINK_MANAGER_LOCK(wfd_sink) ;
297         wfd_sink_debug("check pipeline is ready to start");
298         WFD_SINK_MANAGER_UNLOCK(wfd_sink);
299
300         result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
301         if (result < MM_ERROR_NONE) {
302                 wfd_sink_error("failed to set state : %d", result);
303                 return result;
304         }
305
306         wfd_sink_debug_fleave();
307
308         return result;
309 }
310
311 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
312 {
313         int result = MM_ERROR_NONE;
314
315         wfd_sink_debug_fenter();
316
317         wfd_sink_return_val_if_fail(wfd_sink &&
318                                                                 wfd_sink->pipeline &&
319                                                                 wfd_sink->pipeline->mainbin &&
320                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
321                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
322                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
323
324         /* check current wi-fi display sink state */
325         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
326
327         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-pause", NULL);
328
329         wfd_sink_debug_fleave();
330
331         return result;
332 }
333
334 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
335 {
336         int result = MM_ERROR_NONE;
337
338         wfd_sink_debug_fenter();
339
340         wfd_sink_return_val_if_fail(wfd_sink &&
341                                                                 wfd_sink->pipeline &&
342                                                                 wfd_sink->pipeline->mainbin &&
343                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
344                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
345                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
346
347         /* check current wi-fi display sink state */
348         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
349
350         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-resume", NULL);
351
352         wfd_sink_debug_fleave();
353
354         return result;
355 }
356
357 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
358 {
359         int result = MM_ERROR_NONE;
360
361         wfd_sink_debug_fenter();
362
363         wfd_sink_return_val_if_fail(wfd_sink &&
364                                                                 wfd_sink->pipeline &&
365                                                                 wfd_sink->pipeline->mainbin &&
366                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
367                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
368                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
369
370         /* check current wi-fi display sink state */
371         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
372
373         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
374         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
375
376         g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-close", NULL);
377
378         wfd_sink_debug_fleave();
379
380         return result;
381 }
382
383 int _mm_wfd_sink_unprepare(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_UNPREPARE);
393
394         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
395         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
396
397         /* release pipeline */
398         result =  __mm_wfd_sink_destroy_pipeline(wfd_sink);
399         if (result != MM_ERROR_NONE) {
400                 wfd_sink_error("failed to destory pipeline");
401                 return MM_ERROR_WFD_INTERNAL;
402         } else {
403                 wfd_sink_debug("success to destory pipeline");
404         }
405
406         /* set state */
407         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NULL);
408
409         wfd_sink_debug_fleave();
410
411         return result;
412 }
413
414 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
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         /* check current wi-fi display sink state */
423         MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
424
425         /* unload ini */
426         mm_wfd_sink_ini_unload(&wfd_sink->ini);
427
428         /* release attributes */
429         _mmwfd_deconstruct_attribute(wfd_sink->attrs);
430
431         /* release manager thread  */
432         if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
433                 wfd_sink_error("failed to release manager");
434                 return MM_ERROR_WFD_INTERNAL;
435         }
436
437         /* set state */
438         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_NONE);
439
440         wfd_sink_debug_fleave();
441
442         return result;
443 }
444
445 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
446 {
447         int result = MM_ERROR_NONE;
448
449         wfd_sink_debug_fenter();
450
451         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
452
453         wfd_sink->msg_cb = callback;
454         wfd_sink->msg_user_data = user_data;
455
456         wfd_sink_debug_fleave();
457
458         return result;
459 }
460
461 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
462 {
463         int result = MM_ERROR_NONE;
464         gint *argc = NULL;
465         gchar **argv = NULL;
466         static const int max_argc = 50;
467         GError *err = NULL;
468         gint i = 0;
469
470         wfd_sink_debug_fenter();
471
472         /* alloc */
473         argc = calloc(1, sizeof(gint));
474         argv = calloc(max_argc, sizeof(gchar *));
475         if (!argc || !argv) {
476                 wfd_sink_error("failed to allocate memory for wfdsink");
477
478                 MMWFDSINK_FREEIF(argv);
479                 MMWFDSINK_FREEIF(argc);
480
481                 return MM_ERROR_WFD_NO_FREE_SPACE;
482         }
483
484         /* we would not do fork for scanning plugins */
485         argv[*argc] = g_strdup("--gst-disable-registry-fork");
486         (*argc)++;
487
488         /* check disable registry scan */
489         argv[*argc] = g_strdup("--gst-disable-registry-update");
490         (*argc)++;
491
492         /* check disable segtrap */
493         argv[*argc] = g_strdup("--gst-disable-segtrap");
494         (*argc)++;
495
496         /* check ini */
497         for (i = 0; i < 5; i++) {
498                 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
499                         wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
500                         argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
501                         (*argc)++;
502                 }
503         }
504
505         wfd_sink_debug("initializing gstreamer with following parameter");
506         wfd_sink_debug("argc : %d", *argc);
507
508         for (i = 0; i < *argc; i++)
509                 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
510
511         /* initializing gstreamer */
512         if (!gst_init_check(argc, &argv, &err)) {
513                 wfd_sink_error("failed to initialize gstreamer: %s",
514                                                 err ? err->message : "unknown error occurred");
515                 if (err)
516                         g_error_free(err);
517
518                 result = MM_ERROR_WFD_INTERNAL;
519         }
520
521         /* release */
522         for (i = 0; i < *argc; i++)
523                 MMWFDSINK_FREEIF(argv[i]);
524
525         MMWFDSINK_FREEIF(argv);
526         MMWFDSINK_FREEIF(argc);
527
528         wfd_sink_debug_fleave();
529
530         return result;
531 }
532
533 static GstBusSyncReply
534 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
535 {
536         GstBusSyncReply ret = GST_BUS_PASS;
537
538         wfd_sink_return_val_if_fail(message &&
539                                                                 GST_IS_MESSAGE(message) &&
540                                                                 GST_MESSAGE_SRC(message),
541                                                                 GST_BUS_DROP);
542
543         wfd_sink_debug("get message %p, %s from %p, %s", message,
544                                         GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC(message), GST_MESSAGE_SRC_NAME(message));
545
546         switch (GST_MESSAGE_TYPE(message)) {
547         case GST_MESSAGE_TAG:
548                 break;
549         case GST_MESSAGE_DURATION:
550                 break;
551         case GST_MESSAGE_STATE_CHANGED:
552                 /* we only handle state change messages from pipeline */
553                 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
554                         _mm_wfd_sink_msg_callback(bus, message, data);
555
556                 ret = GST_BUS_DROP;
557                 break;
558         case GST_MESSAGE_ASYNC_DONE:
559                 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
560                         _mm_wfd_sink_msg_callback(bus, message, data);
561
562                 ret = GST_BUS_DROP;
563                 break;
564         default:
565                 break;
566         }
567
568         if (ret == GST_BUS_DROP) {
569                 gst_message_unref(message);
570                 message = NULL;
571         }
572
573         return ret;
574 }
575
576 int __mm_wfd_sink_activate_audio_stream(mm_wfd_sink_t *wfd_sink)
577 {
578         GstElement *valve = NULL;
579         GstPad *sinkpad = NULL;
580         GstPad *srcpad = NULL;
581         int result = MM_ERROR_NONE;
582
583         wfd_sink_debug_fenter();
584
585         wfd_sink_return_val_if_fail(wfd_sink &&
586                                                                 wfd_sink->pipeline &&
587                                                                 wfd_sink->pipeline->mainbin &&
588                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
589                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
590                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
591
592         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
593         srcpad = gst_element_get_static_pad(valve, "src");
594         if (!srcpad) {
595                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
596                 goto error;
597         }
598
599         if (gst_pad_is_linked(srcpad)) {
600                 wfd_sink_debug("%s:%s is already linked to %s:%s",
601                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
602                 goto done;
603         }
604
605         result = __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad);
606         if (MM_ERROR_NONE != result) {
607                 wfd_sink_error("failed to prepare audio pipeline....");
608                 goto error;
609         }
610
611         wfd_sink_debug("try to link %s:%s and %s:%s",
612                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
613                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
614         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
615                 wfd_sink_error("failed to link %s:%s and %s:%s",
616                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
617                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
618                 goto error;
619         }
620
621         if (sinkpad != NULL) {
622                 gst_object_unref(GST_OBJECT(sinkpad));
623                 sinkpad = NULL;
624         }
625
626 done:
627         if (srcpad != NULL) {
628                 gst_object_unref(GST_OBJECT(srcpad));
629                 srcpad = NULL;
630         }
631         /* drop all the audio buffers using valve */
632         g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
633
634         wfd_sink_debug_fleave();
635
636         return MM_ERROR_NONE;
637
638 error:
639         if (srcpad != NULL) {
640                 gst_object_unref(GST_OBJECT(srcpad));
641                 srcpad = NULL;
642         }
643
644         if (sinkpad != NULL) {
645                 gst_object_unref(GST_OBJECT(sinkpad));
646                 sinkpad = NULL;
647         }
648
649         wfd_sink_debug_fleave();
650         return MM_ERROR_WFD_INTERNAL;
651 }
652
653 int __mm_wfd_sink_activate_video_stream(mm_wfd_sink_t *wfd_sink)
654 {
655         GstElement *valve = NULL;
656         GstPad *sinkpad = NULL;
657         GstPad *srcpad = NULL;
658         int result = MM_ERROR_NONE;
659
660         wfd_sink_debug_fenter();
661
662         wfd_sink_return_val_if_fail(wfd_sink &&
663                                                                 wfd_sink->pipeline &&
664                                                                 wfd_sink->pipeline->mainbin &&
665                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
666                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
667                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
668
669         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
670         srcpad = gst_element_get_static_pad(valve, "src");
671         if (!srcpad) {
672                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
673                 goto error;
674         }
675
676         if (gst_pad_is_linked(srcpad)) {
677                 wfd_sink_debug("%s is already linked",
678                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
679                 goto done;
680         }
681
682         result = __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad);
683         if (MM_ERROR_NONE != result) {
684                 wfd_sink_error("failed to prepare video pipeline....");
685                 goto error;
686         }
687
688         wfd_sink_debug("try to link %s:%s and %s:%s",
689                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
690                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
691         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
692                 wfd_sink_error("failed to link %s:%s and %s:%s",
693                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
694                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
695                 goto error;
696         }
697         if (sinkpad != NULL) {
698                 gst_object_unref(GST_OBJECT(sinkpad));
699                 sinkpad = NULL;
700         }
701
702 done:
703         if (srcpad != NULL) {
704                 gst_object_unref(GST_OBJECT(srcpad));
705                 srcpad = NULL;
706         }
707         /* drop all the video buffers using valve */
708         g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
709
710         wfd_sink_debug_fleave();
711
712         return MM_ERROR_NONE;
713
714 error:
715         if (srcpad != NULL) {
716                 gst_object_unref(GST_OBJECT(srcpad));
717                 srcpad = NULL;
718         }
719
720         if (sinkpad != NULL) {
721                 gst_object_unref(GST_OBJECT(sinkpad));
722                 sinkpad = NULL;
723         }
724
725         wfd_sink_debug_fleave();
726         return MM_ERROR_WFD_INTERNAL;
727 }
728
729 int __mm_wfd_sink_deactivate_audio_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
730 {
731         int ret = MM_ERROR_NONE;
732
733         wfd_sink_debug_fenter();
734
735         wfd_sink_return_val_if_fail(wfd_sink &&
736                                                                 wfd_sink->pipeline &&
737                                                                 wfd_sink->pipeline->mainbin &&
738                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
739                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
740                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
741
742         /* drop all the audio buffers using valve */
743         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst), "drop", TRUE, NULL);
744
745         if (unprepare) {
746                 /* unprepare audio pipeline */
747                 ret = __mm_wfd_sink_unprepare_audio_pipeline(wfd_sink);
748                 if (ret != MM_ERROR_NONE) {
749                         wfd_sink_error("failed to unprepare audio pipeline...");
750                         return MM_ERROR_WFD_INTERNAL;
751                 }
752         }
753
754         wfd_sink_debug_fleave();
755
756         return MM_ERROR_NONE;
757 }
758
759 int __mm_wfd_sink_deactivate_video_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
760 {
761         int ret = MM_ERROR_NONE;
762
763         wfd_sink_debug_fenter();
764
765         wfd_sink_return_val_if_fail(wfd_sink &&
766                                                                 wfd_sink->pipeline &&
767                                                                 wfd_sink->pipeline->mainbin &&
768                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
769                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
770                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
771
772         /* drop all the video buffers using valve */
773         g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst), "drop", TRUE, NULL);
774
775         if (unprepare) {
776                 /* unprepare video pipeline */
777                 ret = __mm_wfd_sink_unprepare_video_pipeline(wfd_sink);
778                 if (ret != MM_ERROR_NONE) {
779                         wfd_sink_error("failed to unprepare video pipeline...");
780                         return MM_ERROR_WFD_INTERNAL;
781                 }
782         }
783
784         wfd_sink_debug_fleave();
785
786         return MM_ERROR_NONE;
787
788 }
789
790 static gboolean
791 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
792 {
793         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
794         const GstStructure *message_structure = gst_message_get_structure(msg);
795         gboolean ret = TRUE;
796         gchar *getname = NULL;
797
798         wfd_sink_return_val_if_fail(wfd_sink, FALSE);
799         wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
800
801         wfd_sink_debug("got %s(%d) from %s",
802                                         GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
803                                         GST_MESSAGE_TYPE(msg),
804                                         GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
805
806         switch (GST_MESSAGE_TYPE(msg)) {
807         case GST_MESSAGE_ERROR: {
808                         GError *error = NULL;
809                         gchar *debug = NULL;
810
811                         /* get error code */
812                         gst_message_parse_error(msg, &error, &debug);
813
814                         wfd_sink_error("error : %s", error->message);
815                         wfd_sink_error("debug : %s", debug);
816
817                         MMWFDSINK_FREEIF(debug);
818                         g_error_free(error);
819                 }
820                 break;
821
822         case GST_MESSAGE_WARNING: {
823                         char *debug = NULL;
824                         GError *error = NULL;
825
826                         gst_message_parse_warning(msg, &error, &debug);
827
828                         wfd_sink_error("warning : %s", error->message);
829                         wfd_sink_error("debug : %s", debug);
830
831                         MMWFDSINK_FREEIF(debug);
832                         g_error_free(error);
833                 }
834                 break;
835
836         case GST_MESSAGE_STATE_CHANGED: {
837                         const GValue *voldstate, *vnewstate, *vpending;
838                         GstState oldstate, newstate, pending;
839                         const GstStructure *structure;
840
841                         /* get state info from msg */
842                         structure = gst_message_get_structure(msg);
843                         if (structure == NULL)
844                                 break;
845
846                         voldstate = gst_structure_get_value(structure, "old-state");
847                         vnewstate = gst_structure_get_value(structure, "new-state");
848                         vpending = gst_structure_get_value(structure, "pending-state");
849                         if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
850                                 break;
851
852                         oldstate = (GstState)voldstate->data[0].v_int;
853                         newstate = (GstState)vnewstate->data[0].v_int;
854                         pending = (GstState)vpending->data[0].v_int;
855
856                         wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
857                                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
858                                                 gst_element_state_get_name((GstState)oldstate),
859                                                 gst_element_state_get_name((GstState)newstate),
860                                                 gst_element_state_get_name((GstState)pending));
861
862                         /* we only handle messages from pipeline */
863                         if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
864                                 break;
865
866                         if (oldstate == newstate) {
867                                 wfd_sink_debug("pipeline reports state transition to old state");
868                                 break;
869                         }
870
871                         switch (newstate) {
872                         case GST_STATE_VOID_PENDING:
873                         case GST_STATE_NULL:
874                         case GST_STATE_READY:
875                         case GST_STATE_PAUSED:
876                         case GST_STATE_PLAYING:
877                         default:
878                                 break;
879                         }
880                 }
881                 break;
882
883         case GST_MESSAGE_CLOCK_LOST: {
884                         GstClock *clock = NULL;
885                         gst_message_parse_clock_lost(msg, &clock);
886                         wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
887                                         (clock ? GST_OBJECT_NAME(clock) : "NULL"));
888                 }
889                 break;
890
891         case GST_MESSAGE_NEW_CLOCK: {
892                         GstClock *clock = NULL;
893                         gst_message_parse_new_clock(msg, &clock);
894                         if (!clock)
895                                 break;
896
897                         if (wfd_sink->clock) {
898                                 if (wfd_sink->clock != clock)
899                                         wfd_sink_debug("clock is changed! [%s] -->[%s]",
900                                                                         GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
901                                                                         GST_STR_NULL(GST_OBJECT_NAME(clock)));
902                                 else
903                                         wfd_sink_debug("same clock is selected again! [%s]",
904                                                                         GST_STR_NULL(GST_OBJECT_NAME(clock)));
905                         } else {
906                                 wfd_sink_debug("new clock [%s] was selected in the pipeline",
907                                                                 (GST_STR_NULL(GST_OBJECT_NAME(clock))));
908                         }
909
910                         wfd_sink->clock = clock;
911                 }
912                 break;
913
914         case GST_MESSAGE_APPLICATION: {
915                         const gchar *message_structure_name;
916
917                         message_structure_name = gst_structure_get_name(message_structure);
918                         if (!message_structure_name)
919                                 break;
920
921                         wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
922                 }
923                 break;
924
925         case GST_MESSAGE_ELEMENT: {
926                         const gchar *structure_name = NULL;
927
928                         structure_name = gst_structure_get_name(message_structure);
929                         if (structure_name) {
930                                 wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
931                                 if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
932                                         wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
933                                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
934                                                                         MM_ERROR_WFD_INTERNAL,
935                                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
936                                 } else if (g_strrstr(structure_name, "GstWFDSessionTimeout")) {
937                                         wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
938                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
939                                                                         MM_ERROR_WFD_INTERNAL,
940                                                                         MM_WFD_SINK_STATE_DISCONNECTED);
941                                 }
942                         }
943                 }
944                 break;
945
946         case GST_MESSAGE_PROGRESS: {
947                         GstProgressType type = GST_PROGRESS_TYPE_ERROR;
948                         gchar *category = NULL, *text = NULL;
949
950                         gst_message_parse_progress(msg, &type, &category, &text);
951                         wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
952
953                         switch (type) {
954                         case GST_PROGRESS_TYPE_START:
955                                 break;
956                         case GST_PROGRESS_TYPE_COMPLETE:
957                                 if (category && !strcmp(category, "open")) {
958                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_CONNECTED);
959                                 } else if (category && !strcmp(category, "play")) {
960                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PLAYING);
961                                         /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
962                                 } else if (category && !strcmp(category, "pause")) {
963                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_PAUSED);
964                                 } else if (category && !strcmp(category, "close")) {
965                                         __mm_wfd_sink_set_state(wfd_sink,  MM_WFD_SINK_STATE_DISCONNECTED);
966                                 }
967                                 break;
968                         case GST_PROGRESS_TYPE_CANCELED:
969                                 break;
970                         case GST_PROGRESS_TYPE_ERROR:
971                                 if (category && !strcmp(category, "open")) {
972                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
973                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
974                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
975                                                         MM_ERROR_WFD_INTERNAL,
976                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
977                                 } else if (category && !strcmp(category, "play")) {
978                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
979                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
980                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
981                                                                 MM_ERROR_WFD_INTERNAL,
982                                                                 MMWFDSINK_CURRENT_STATE(wfd_sink));
983                                 } else if (category && !strcmp(category, "pause")) {
984                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
985                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
986                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
987                                                         MM_ERROR_WFD_INTERNAL,
988                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
989                                 } else if (category && !strcmp(category, "close")) {
990                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
991                                                         /*_mm_wfd_sink_disconnect (wfd_sink); */
992                                                         MMWFDSINK_POST_MESSAGE(wfd_sink,
993                                                         MM_ERROR_WFD_INTERNAL,
994                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
995                                 } else {
996                                         wfd_sink_error("got error : %s", GST_STR_NULL(text));
997                                 }
998                                 break;
999                         default:
1000                                 wfd_sink_error("progress message has no type");
1001                                 return ret;
1002                         }
1003
1004                         MMWFDSINK_FREEIF(category);
1005                         MMWFDSINK_FREEIF(text);
1006                 }
1007                 break;
1008
1009         case GST_MESSAGE_ASYNC_START:
1010                 getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
1011                 wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", getname);
1012                 MMWFDSINK_FREEIF(getname);
1013                 break;
1014         case GST_MESSAGE_ASYNC_DONE:
1015                 getname = gst_element_get_name(GST_MESSAGE_SRC(msg));
1016                 wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", getname);
1017                 MMWFDSINK_FREEIF(getname);
1018                 break;
1019         case GST_MESSAGE_UNKNOWN:
1020         case GST_MESSAGE_INFO:
1021         case GST_MESSAGE_TAG:
1022         case GST_MESSAGE_BUFFERING:
1023         case GST_MESSAGE_EOS:
1024         case GST_MESSAGE_STATE_DIRTY:
1025         case GST_MESSAGE_STEP_DONE:
1026         case GST_MESSAGE_CLOCK_PROVIDE:
1027         case GST_MESSAGE_STRUCTURE_CHANGE:
1028         case GST_MESSAGE_STREAM_STATUS:
1029         case GST_MESSAGE_SEGMENT_START:
1030         case GST_MESSAGE_SEGMENT_DONE:
1031         case GST_MESSAGE_DURATION:
1032         case GST_MESSAGE_LATENCY:
1033         case GST_MESSAGE_REQUEST_STATE:
1034         case GST_MESSAGE_STEP_START:
1035         case GST_MESSAGE_QOS:
1036         case GST_MESSAGE_ANY:
1037                 break;
1038         default:
1039                 wfd_sink_debug("unhandled message");
1040                 break;
1041         }
1042
1043         return ret;
1044 }
1045
1046 int
1047 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
1048 {
1049         GList *bucket = element_bucket;
1050         MMWFDSinkGstElement *element = NULL;
1051         int successful_add_count = 0;
1052
1053         wfd_sink_debug_fenter();
1054
1055         wfd_sink_return_val_if_fail(element_bucket, 0);
1056         wfd_sink_return_val_if_fail(bin, 0);
1057
1058         for (; bucket; bucket = bucket->next) {
1059                 element = (MMWFDSinkGstElement *)bucket->data;
1060
1061                 if (element && element->gst) {
1062                         if (need_prepare)
1063                                 gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY);
1064
1065                         if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
1066                                 wfd_sink_error("failed to add element [%s] to bin [%s]",
1067                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1068                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1069                                 return 0;
1070                         }
1071
1072                         wfd_sink_debug("add element [%s] to bin [%s]",
1073                                                         GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1074                                                         GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1075
1076                         successful_add_count++;
1077                 }
1078         }
1079
1080         wfd_sink_debug_fleave();
1081
1082         return successful_add_count;
1083 }
1084
1085 int
1086 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
1087 {
1088         GList *bucket = element_bucket;
1089         MMWFDSinkGstElement *element = NULL;
1090         MMWFDSinkGstElement *prv_element = NULL;
1091         gint successful_link_count = 0;
1092
1093         wfd_sink_debug_fenter();
1094
1095         wfd_sink_return_val_if_fail(element_bucket, -1);
1096
1097         prv_element = (MMWFDSinkGstElement *)bucket->data;
1098         bucket = bucket->next;
1099
1100         for (; bucket; bucket = bucket->next) {
1101                 element = (MMWFDSinkGstElement *)bucket->data;
1102
1103                 if (element && element->gst) {
1104                         if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
1105                                 wfd_sink_debug("linking [%s] to [%s] success",
1106                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1107                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1108                                 successful_link_count++;
1109                         } else {
1110                                 wfd_sink_error("linking [%s] to [%s] failed",
1111                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1112                                                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1113                                 return -1;
1114                         }
1115                 }
1116
1117                 prv_element = element;
1118         }
1119
1120         wfd_sink_debug_fleave();
1121
1122         return successful_link_count;
1123 }
1124
1125 int
1126 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
1127 {
1128         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
1129
1130         wfd_sink_debug_fenter();
1131
1132         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1133
1134         MMWFDSINK_PRINT_STATE(wfd_sink);
1135
1136         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
1137
1138         switch (cmd) {
1139         case MM_WFD_SINK_COMMAND_CREATE:
1140                 if (cur_state != MM_WFD_SINK_STATE_NONE)
1141                         goto invalid_state;
1142
1143                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1144                 break;
1145
1146         case MM_WFD_SINK_COMMAND_PREPARE:
1147                 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
1148                         goto no_operation;
1149                 else if (cur_state != MM_WFD_SINK_STATE_NULL)
1150                         goto invalid_state;
1151
1152                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
1153                 break;
1154
1155         case MM_WFD_SINK_COMMAND_CONNECT:
1156                 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
1157                         goto no_operation;
1158                 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
1159                         goto invalid_state;
1160
1161                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
1162                 break;
1163
1164         case MM_WFD_SINK_COMMAND_START:
1165                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1166                         goto no_operation;
1167                 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
1168                         goto invalid_state;
1169
1170                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1171                 break;
1172
1173         case MM_WFD_SINK_COMMAND_PAUSE:
1174                 if (cur_state == MM_WFD_SINK_STATE_PAUSED)
1175                         goto no_operation;
1176                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
1177                         goto invalid_state;
1178
1179                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
1180                 break;
1181
1182         case MM_WFD_SINK_COMMAND_RESUME:
1183                 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1184                         goto no_operation;
1185                 else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
1186                         goto invalid_state;
1187
1188                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1189                 break;
1190
1191         case MM_WFD_SINK_COMMAND_DISCONNECT:
1192                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1193                     cur_state == MM_WFD_SINK_STATE_NULL ||
1194                     cur_state == MM_WFD_SINK_STATE_PREPARED ||
1195                     cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
1196                         goto no_operation;
1197                 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
1198                         cur_state != MM_WFD_SINK_STATE_CONNECTED &&
1199                         cur_state != MM_WFD_SINK_STATE_PAUSED)
1200                         goto invalid_state;
1201
1202                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
1203                 break;
1204
1205         case MM_WFD_SINK_COMMAND_UNPREPARE:
1206                 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1207                     cur_state == MM_WFD_SINK_STATE_NULL)
1208                         goto no_operation;
1209
1210                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1211                 break;
1212
1213         case MM_WFD_SINK_COMMAND_DESTROY:
1214                 if (cur_state == MM_WFD_SINK_STATE_NONE)
1215                         goto no_operation;
1216
1217                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1218                 break;
1219
1220         default:
1221                 break;
1222         }
1223
1224         wfd_sink->cmd = cmd;
1225
1226         wfd_sink_debug_fleave();
1227
1228         return MM_ERROR_NONE;
1229
1230 no_operation:
1231         wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state));
1232         return MM_ERROR_WFD_NO_OP;
1233
1234         /* ERRORS */
1235 invalid_state:
1236         wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
1237         return MM_ERROR_WFD_INVALID_STATE;
1238 }
1239
1240 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
1241 {
1242         wfd_sink_debug_fenter();
1243
1244         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1245
1246         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) {
1247                 wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state));
1248                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1249                 return MM_ERROR_NONE;
1250         }
1251
1252         /* update wi-fi display state */
1253         MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1254         MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1255
1256         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
1257                 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1258
1259         /* post state message to application */
1260         MMWFDSINK_POST_MESSAGE(wfd_sink,
1261                                                         MM_ERROR_NONE,
1262                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1263
1264         /* print state */
1265         MMWFDSINK_PRINT_STATE(wfd_sink);
1266
1267         wfd_sink_debug_fleave();
1268
1269         return MM_ERROR_NONE;
1270 }
1271
1272 static int
1273 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
1274 {
1275         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1276         GstState cur_state = GST_STATE_VOID_PENDING;
1277         GstState pending_state = GST_STATE_VOID_PENDING;
1278
1279         wfd_sink_debug_fenter();
1280
1281         wfd_sink_return_val_if_fail(wfd_sink &&
1282                                                                 wfd_sink->pipeline &&
1283                                                                 wfd_sink->pipeline->mainbin &&
1284                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1285                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1286
1287         wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING,
1288                                                                 MM_ERROR_WFD_INVALID_ARGUMENT);
1289
1290         wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1291
1292         result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1293         if (result == GST_STATE_CHANGE_FAILURE) {
1294                 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1295                 return MM_ERROR_WFD_INTERNAL;
1296         }
1297
1298         if (!async) {
1299                 wfd_sink_debug("wait for changing state is completed ");
1300
1301                 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1302                                                                                 &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1303                 if (result == GST_STATE_CHANGE_FAILURE) {
1304                         wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1305
1306                         __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1307
1308                         return MM_ERROR_WFD_INTERNAL;
1309                 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1310                         wfd_sink_debug("successfully changed state but is not able to provide data yet");
1311                 }
1312
1313                 wfd_sink_debug("cur state is %s, pending state is %s",
1314                                                 gst_element_state_get_name(cur_state),
1315                                                 gst_element_state_get_name(pending_state));
1316         }
1317
1318
1319         wfd_sink_debug_fleave();
1320
1321         return MM_ERROR_NONE;
1322 }
1323
1324 static void
1325 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1326 {
1327         GstClockTime base_time = GST_CLOCK_TIME_NONE;
1328         int i;
1329
1330         wfd_sink_debug_fenter();
1331
1332         wfd_sink_return_if_fail(wfd_sink &&
1333                                                         wfd_sink->pipeline &&
1334                                                         wfd_sink->pipeline->mainbin &&
1335                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1336         wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1337
1338
1339         if (wfd_sink->clock)
1340                 base_time = gst_clock_get_time(wfd_sink->clock);
1341
1342         if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1343
1344                 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1345
1346                 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1347                         if (wfd_sink->pipeline->mainbin[i].gst)
1348                                 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1349                 }
1350
1351                 if (wfd_sink->pipeline->v_decodebin) {
1352                         for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1353                                 if (wfd_sink->pipeline->v_decodebin[i].gst)
1354                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1355                         }
1356                 }
1357
1358                 if (wfd_sink->pipeline->v_sinkbin) {
1359                         for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1360                                 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1361                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1362                         }
1363                 }
1364
1365                 if (wfd_sink->pipeline->a_decodebin) {
1366                         for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1367                                 if (wfd_sink->pipeline->a_decodebin[i].gst)
1368                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1369                         }
1370                 }
1371
1372                 if (wfd_sink->pipeline->a_sinkbin) {
1373                         for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1374                                 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1375                                         gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1376                         }
1377                 }
1378
1379                 wfd_sink->need_to_reset_basetime = FALSE;
1380         }
1381
1382         wfd_sink_debug_fleave();
1383
1384         return;
1385 }
1386
1387 int
1388 __mm_wfd_sink_unprepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1389 {
1390         GstElement *pipeline  = NULL;
1391         GstElement *v_decodebin  = NULL;
1392         GstElement *v_sinkbin  = NULL;
1393         GstPad *sinkpad = NULL;
1394         GstPad *srcpad = NULL;
1395         int ret = MM_ERROR_NONE;
1396
1397         wfd_sink_debug_fenter();
1398
1399         wfd_sink_return_val_if_fail(wfd_sink &&
1400                                                                 wfd_sink->pipeline,
1401                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1402
1403         PRINT_WFD_REF_COUNT(wfd_sink);
1404         wfd_sink_error("No-error:unprepare video sink bin");
1405         if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1406                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1407
1408                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin)))) {
1409                         sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1410                         if (!sinkpad) {
1411                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_sinkbin));
1412                                 goto ERROR;
1413                         }
1414
1415                         if (gst_pad_is_linked(sinkpad)) {
1416                                 srcpad = gst_pad_get_peer(sinkpad);
1417                                 if (!srcpad) {
1418                                         wfd_sink_error("failed to get peer pad of %s:%s",
1419                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1420                                         goto ERROR;
1421                                 }
1422
1423                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1424                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1425                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1426                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1427                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1428                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1429                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1430                                         goto ERROR;
1431                                 }
1432                                 gst_object_unref(srcpad);
1433                                 srcpad = NULL;
1434                         } else {
1435                                 wfd_sink_debug("video sinkbin's sinkpad is not linked, no need to unlink it");
1436                         }
1437                         gst_object_unref(sinkpad);
1438                         sinkpad = NULL;
1439
1440                         gst_object_ref(v_sinkbin);
1441                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1442                                 wfd_sink_error("failed to remove %s from %s",
1443                                                                 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1444                                 goto ERROR;
1445                         }
1446
1447                         gst_object_unref(pipeline);
1448                         pipeline = NULL;
1449                 }
1450
1451                 ret = __mm_wfd_sink_destroy_video_sinkbin(wfd_sink);
1452                 if (ret != MM_ERROR_NONE) {
1453                         wfd_sink_error("failed to destroy video sinkbin");
1454                         goto ERROR;
1455                 }
1456         }
1457         PRINT_WFD_REF_COUNT(wfd_sink);
1458
1459         wfd_sink_error("No-error:unprepare video decode bin");
1460         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1461                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1462
1463                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin)))) {
1464                         sinkpad = gst_element_get_static_pad(v_decodebin, "sink");
1465                         if (!sinkpad) {
1466                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_decodebin));
1467                                 goto ERROR;
1468                         }
1469
1470                         if (gst_pad_is_linked(sinkpad)) {
1471                                 srcpad = gst_pad_get_peer(sinkpad);
1472                                 if (!srcpad) {
1473                                         wfd_sink_error("failed to get peer pad of %s:%s",
1474                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1475                                         goto ERROR;
1476                                 }
1477
1478                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1479                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1480                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1481                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1482                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1483                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1484                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1485                                         goto ERROR;
1486                                 }
1487                                 gst_object_unref(srcpad);
1488                                 srcpad = NULL;
1489                         } else {
1490                                 wfd_sink_debug("video decodebin's sinkpad is not linked, no need to unlink it");
1491                         }
1492                         gst_object_unref(sinkpad);
1493                         sinkpad = NULL;
1494
1495                         srcpad = gst_element_get_static_pad(v_decodebin, "src");
1496                         if (!srcpad) {
1497                                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(v_decodebin));
1498                                 goto ERROR;
1499                         }
1500
1501                         if (gst_pad_is_linked(srcpad)) {
1502                                 sinkpad = gst_pad_get_peer(srcpad);
1503                                 if (!sinkpad) {
1504                                         wfd_sink_error("failed to get peer pad of %s:%s",
1505                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1506                                         goto ERROR;
1507                                 }
1508
1509                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1510                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1511                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1512                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1513                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1514                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1515                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1516                                         goto ERROR;
1517                                 }
1518                                 gst_object_unref(sinkpad);
1519                                 sinkpad = NULL;
1520                         } else {
1521                                 wfd_sink_debug("video decodebin's srcpad is not linked, no need to unlink it");
1522                         }
1523                         gst_object_unref(srcpad);
1524                         srcpad = NULL;
1525
1526                         wfd_sink_error("try to remove %s from %s",
1527                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1528                         gst_object_ref(v_decodebin);
1529                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1530                                 wfd_sink_error("failed to remove %s from %s",
1531                                                                 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1532                                 goto ERROR;
1533                         }
1534
1535                         gst_object_unref(pipeline);
1536                         pipeline = NULL;
1537                 }
1538
1539                 ret = __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
1540                 if (ret != MM_ERROR_NONE) {
1541                         wfd_sink_error("failed to destroy video decodebin");
1542                         goto ERROR;
1543                 }
1544         }
1545         PRINT_WFD_REF_COUNT(wfd_sink);
1546
1547         wfd_sink_debug_fleave();
1548
1549         return ret;
1550
1551         /* ERRORS */
1552 ERROR:
1553         if (pipeline) {
1554                 gst_object_unref(pipeline);
1555                 pipeline = NULL;
1556         }
1557
1558         if (sinkpad) {
1559                 gst_object_unref(sinkpad);
1560                 sinkpad = NULL;
1561         }
1562
1563         if (srcpad) {
1564                 gst_object_unref(srcpad);
1565                 srcpad = NULL;
1566         }
1567
1568         /* need to notify to app */
1569         MMWFDSINK_POST_MESSAGE(wfd_sink,
1570                                                         MM_ERROR_WFD_INTERNAL,
1571                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1572
1573         return MM_ERROR_WFD_INTERNAL;
1574 }
1575
1576 int
1577 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1578 {
1579         GstElement *pipeline  = NULL;
1580         GstElement *v_decodebin  = NULL;
1581         GstElement *v_sinkbin  = NULL;
1582         GstPad *srcpad = NULL;
1583         GstPad *sinkpad = NULL;
1584
1585         wfd_sink_debug_fenter();
1586
1587         wfd_sink_return_val_if_fail(wfd_sink &&
1588                                                                 wfd_sink->pipeline &&
1589                                                                 wfd_sink->pipeline->mainbin &&
1590                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1591                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1592
1593         /* check video decodebin is linked */
1594         if (!wfd_sink->video_decodebin_is_linked) {
1595                 /* check video decodebin is created */
1596                 if (wfd_sink->pipeline->v_decodebin == NULL) {
1597                         if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1598                                 wfd_sink_error("failed to create video decodebin....");
1599                                 goto ERROR;
1600                         }
1601                 }
1602
1603                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1604                         wfd_sink_error("failed to link video decodebin.....");
1605                         goto ERROR;
1606                 }
1607         }
1608
1609         /* check video sinkbin is created */
1610         if (wfd_sink->pipeline->v_sinkbin == NULL) {
1611                 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1612                         wfd_sink_error("failed to create video sinkbin....");
1613                         goto ERROR;
1614                 }
1615         }
1616         /* add video decodebin to pipeline */
1617         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1618                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1619
1620                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin));
1621                 if (!pipeline) {
1622                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1623
1624                         if (GST_STATE(v_decodebin) <= GST_STATE_NULL) {
1625                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_decodebin));
1626                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_decodebin, GST_STATE_READY)) {
1627                                         wfd_sink_error("failed to set state(READY) to video decodebin");
1628                                         goto ERROR;
1629                                 }
1630                         }
1631
1632                         wfd_sink_debug("try to add %s to %s",
1633                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1634                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1635                                 wfd_sink_error("failed to add %s to %s",
1636                                                                 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1637                                 goto ERROR;
1638                         }
1639
1640                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_decodebin));
1641                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_decodebin))) {
1642                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_decodebin));
1643                                 goto ERROR;
1644                         }
1645                 } else {
1646                         wfd_sink_debug("%s is already added to %s",
1647                                                         GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1648                         gst_object_unref(pipeline);
1649                         pipeline = NULL;
1650                 }
1651         } else {
1652                 wfd_sink_warning("going on without video decodebin....");
1653         }
1654
1655         /* add video sinkbin to pipeline */
1656         if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1657                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1658
1659                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin));
1660                 if (!pipeline) {
1661                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1662
1663                         /* prepare video sinkbin before adding */
1664                         if (GST_STATE(v_sinkbin) <= GST_STATE_NULL) {
1665                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_sinkbin));
1666                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_sinkbin, GST_STATE_READY)) {
1667                                         wfd_sink_error("failed to set state(READY) to video sinkbin");
1668                                         goto ERROR;
1669                                 }
1670                         }
1671                         /* add video sinkbin to pipeline */
1672                         wfd_sink_debug("try to  add %s to %s",
1673                                                         GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1674                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1675                                 wfd_sink_error("failed to add %s to %s",
1676                                                                 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1677                                 goto ERROR;
1678                         }
1679
1680                         /* sync state with parent */
1681                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_sinkbin));
1682                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_sinkbin))) {
1683                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_sinkbin));
1684                                 goto ERROR;
1685                         }
1686                 } else {
1687                         wfd_sink_debug("%s is already added to %s",
1688                                                         GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1689                         gst_object_unref(pipeline);
1690                         pipeline = NULL;
1691                 }
1692         } else {
1693                 wfd_sink_warning("going on without video sinkbin....");
1694         }
1695
1696
1697         /* link video decodebin and sinkbin */
1698         if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1699                 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1700
1701                 if (pad)
1702                         *pad = gst_element_get_static_pad(v_decodebin, "sink");
1703
1704                 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1705
1706                         v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1707
1708                         srcpad = gst_element_get_static_pad(v_decodebin, "src");
1709                         if (!srcpad) {
1710                                 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(v_decodebin));
1711                                 goto ERROR;
1712                         }
1713
1714                         if (!gst_pad_is_linked(srcpad)) {
1715                                 sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1716                                 if (!sinkpad) {
1717                                         wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(v_sinkbin));
1718                                         goto ERROR;
1719                                 }
1720
1721                                 wfd_sink_debug("try to link %s:%s and %s:%s",
1722                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1723                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1724                                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
1725                                         wfd_sink_error("failed to link %s:%s and %s:%s",
1726                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1727                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1728                                         goto ERROR;
1729                                 }
1730                                 gst_object_unref(sinkpad);
1731                                 sinkpad = NULL;
1732                         }
1733                         gst_object_unref(srcpad);
1734                         srcpad = NULL;
1735                 }
1736         } else if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1737                 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1738                 if (pad)
1739                         *pad = gst_element_get_static_pad(v_sinkbin, "sink");
1740         }
1741
1742         wfd_sink_debug_fleave();
1743
1744         return MM_ERROR_NONE;
1745
1746         /* ERRORS */
1747 ERROR:
1748         if (sinkpad != NULL) {
1749                 gst_object_unref(sinkpad);
1750                 sinkpad = NULL;
1751         }
1752
1753         if (srcpad != NULL) {
1754                 gst_object_unref(srcpad);
1755                 srcpad = NULL;
1756         }
1757
1758         /* need to notify to app */
1759         MMWFDSINK_POST_MESSAGE(wfd_sink,
1760                                                         MM_ERROR_WFD_INTERNAL,
1761                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1762
1763         return MM_ERROR_WFD_INTERNAL;
1764 }
1765
1766 int
1767 __mm_wfd_sink_unprepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1768 {
1769         GstElement *pipeline  = NULL;
1770         GstElement *a_decodebin  = NULL;
1771         GstElement *a_sinkbin  = NULL;
1772         GstPad *sinkpad = NULL;
1773         GstPad *srcpad = NULL;
1774         int ret = MM_ERROR_NONE;
1775
1776         wfd_sink_debug_fenter();
1777
1778         wfd_sink_return_val_if_fail(wfd_sink &&
1779                                                                 wfd_sink->pipeline,
1780                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1781
1782         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
1783                 wfd_sink_debug("Skip unprepare audio pipeline for none audio codec.");
1784                 wfd_sink_debug_fleave();
1785                 return MM_ERROR_NONE;
1786         }
1787
1788         wfd_sink_error("No-error:unprepare audio sink bin");
1789         PRINT_WFD_REF_COUNT(wfd_sink);
1790
1791         if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1792                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1793
1794                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin)))) {
1795                         sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
1796                         if (!sinkpad) {
1797                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_sinkbin));
1798                                 goto ERROR;
1799                         }
1800
1801                         if (gst_pad_is_linked(sinkpad)) {
1802                                 srcpad = gst_pad_get_peer(sinkpad);
1803                                 if (!srcpad) {
1804                                         wfd_sink_error("failed to get peer pad of %s:%s",
1805                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1806                                         goto ERROR;
1807                                 }
1808
1809                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1810                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1811                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1812                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1813                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1814                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1815                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1816                                         goto ERROR;
1817                                 }
1818                                 gst_object_unref(srcpad);
1819                                 srcpad = NULL;
1820                         } else {
1821                                 wfd_sink_debug("audio sinkbin's sinkpad is not linked, no need to unlink it");
1822                         }
1823                         gst_object_unref(sinkpad);
1824                         sinkpad = NULL;
1825
1826                         gst_object_ref(a_sinkbin);
1827                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
1828                                 wfd_sink_error("failed to remove %s from %s",
1829                                                                 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
1830                                 goto ERROR;
1831                         }
1832
1833                         gst_object_unref(pipeline);
1834                         pipeline = NULL;
1835                 }
1836
1837                 ret = __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink);
1838                 if (ret != MM_ERROR_NONE) {
1839                         wfd_sink_error("failed to destroy audio sinkbin");
1840                         goto ERROR;
1841                 }
1842         }
1843         PRINT_WFD_REF_COUNT(wfd_sink);
1844
1845         wfd_sink_error("No-error:unprepare audio decode bin");
1846         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1847                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1848
1849                 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin)))) {
1850                         sinkpad = gst_element_get_static_pad(a_decodebin, "sink");
1851                         if (!sinkpad) {
1852                                 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_decodebin));
1853                                 goto ERROR;
1854                         }
1855
1856                         if (gst_pad_is_linked(sinkpad)) {
1857                                 srcpad = gst_pad_get_peer(sinkpad);
1858                                 if (!srcpad) {
1859                                         wfd_sink_error("failed to get peer pad of %s:%s",
1860                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1861                                         goto ERROR;
1862                                 }
1863
1864                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1865                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1866                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1867                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1868                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1869                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1870                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1871                                         goto ERROR;
1872                                 }
1873                                 gst_object_unref(srcpad);
1874                                 srcpad = NULL;
1875                         } else {
1876                                 wfd_sink_debug("audio decodebin's sinkpad is not linked, no need to unlink it");
1877                         }
1878                         gst_object_unref(sinkpad);
1879                         sinkpad = NULL;
1880
1881                         srcpad = gst_element_get_static_pad(a_decodebin, "src");
1882                         if (!srcpad) {
1883                                 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(a_decodebin));
1884                                 goto ERROR;
1885                         }
1886
1887                         if (gst_pad_is_linked(srcpad)) {
1888                                 sinkpad = gst_pad_get_peer(srcpad);
1889                                 if (!sinkpad) {
1890                                         wfd_sink_error("failed to get peer pad of %s:%s",
1891                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1892                                         return MM_ERROR_WFD_INTERNAL;
1893                                 }
1894
1895                                 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1896                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1897                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1898                                 if (!gst_pad_unlink(srcpad, sinkpad)) {
1899                                         wfd_sink_error("failed to unlink %s:%s and %s:%s",
1900                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1901                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1902                                         return MM_ERROR_WFD_INTERNAL;
1903                                 }
1904                                 gst_object_unref(sinkpad);
1905                                 sinkpad = NULL;
1906                         } else {
1907                                 wfd_sink_debug("audio decodebin's srcpad is not linked, no need to unlink it");
1908                         }
1909                         gst_object_unref(srcpad);
1910                         srcpad = NULL;
1911
1912                         wfd_sink_error("try to remove %s from %s",
1913                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1914                         gst_object_ref(a_decodebin);
1915                         if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
1916                                 wfd_sink_error("failed to remove %s from %s",
1917                                                                 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1918                                 goto ERROR;
1919                         }
1920
1921                         gst_object_unref(pipeline);
1922                         pipeline = NULL;
1923                 }
1924
1925                 ret = __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
1926                 if (ret != MM_ERROR_NONE) {
1927                         wfd_sink_error("failed to destroy audio decodebin");
1928                         goto ERROR;
1929                 }
1930         }
1931         PRINT_WFD_REF_COUNT(wfd_sink);
1932
1933         wfd_sink_debug_fleave();
1934
1935         return ret;
1936
1937         /* ERRORS */
1938 ERROR:
1939         if (pipeline) {
1940                 gst_object_unref(pipeline);
1941                 pipeline = NULL;
1942         }
1943         if (sinkpad) {
1944                 gst_object_unref(sinkpad);
1945                 sinkpad = NULL;
1946         }
1947
1948         if (srcpad) {
1949                 gst_object_unref(srcpad);
1950                 srcpad = NULL;
1951         }
1952
1953         /* need to notify to app */
1954         MMWFDSINK_POST_MESSAGE(wfd_sink,
1955                                                         MM_ERROR_WFD_INTERNAL,
1956                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
1957
1958         return MM_ERROR_WFD_INTERNAL;
1959 }
1960
1961 int
1962 __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1963 {
1964         GstElement *pipeline  = NULL;
1965         GstElement *a_decodebin  = NULL;
1966         GstElement *a_sinkbin  = NULL;
1967         GstPad *srcpad = NULL;
1968         GstPad *sinkpad = NULL;
1969
1970         wfd_sink_debug_fenter();
1971
1972         wfd_sink_return_val_if_fail(wfd_sink &&
1973                                                                 wfd_sink->pipeline &&
1974                                                                 wfd_sink->pipeline->mainbin &&
1975                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1976                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
1977
1978         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
1979                 wfd_sink_debug("Skip prepare audio pipeline for none audio codec");
1980                 wfd_sink_debug_fleave();
1981                 return MM_ERROR_NONE;
1982         }
1983
1984         /* check audio decodebin is linked */
1985         if (!wfd_sink->audio_decodebin_is_linked) {
1986                 /* check audio decodebin is created */
1987                 if (wfd_sink->pipeline->a_decodebin == NULL) {
1988                         if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1989                                 wfd_sink_error("failed to create audio decodebin....");
1990                                 goto ERROR;
1991                         }
1992                 }
1993
1994                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1995                         wfd_sink_error("failed to link audio decodebin.....");
1996                         goto ERROR;
1997                 }
1998         }
1999
2000         /* check audio sinkbin is created */
2001         if (wfd_sink->pipeline->a_sinkbin == NULL) {
2002                 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
2003                         wfd_sink_error("failed to create audio sinkbin....");
2004                         goto ERROR;
2005                 }
2006         }
2007
2008         /* add audio decodebin to pipeline */
2009         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2010                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
2011
2012                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin));
2013                 if (!pipeline) {
2014                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2015
2016                         if (GST_STATE(a_decodebin) <= GST_STATE_NULL) {
2017                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_decodebin));
2018                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_decodebin, GST_STATE_READY)) {
2019                                         wfd_sink_error("failed to set state(READY) to audio decodebin");
2020                                         goto ERROR;
2021                                 }
2022                         }
2023
2024                         wfd_sink_debug("try to add %s to %s",
2025                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2026                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
2027                                 wfd_sink_error("failed to add %s to %s",
2028                                                                 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2029                                 goto ERROR;
2030                         }
2031
2032                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_decodebin));
2033                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_decodebin))) {
2034                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_decodebin));
2035                                 goto ERROR;
2036                         }
2037                 } else {
2038                         wfd_sink_debug("%s is already added to %s",
2039                                                         GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2040                         gst_object_unref(pipeline);
2041                         pipeline = NULL;
2042                 }
2043         } else {
2044                 wfd_sink_warning("going on without audio decodebin....");
2045         }
2046
2047         /* add audio sinkbin to pipeline */
2048         if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2049                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2050
2051                 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin));
2052                 if (!pipeline) {
2053                         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2054
2055                         /* prepare audio sinkbin before adding */
2056                         if (GST_STATE(a_sinkbin) <= GST_STATE_NULL) {
2057                                 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_sinkbin));
2058                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_sinkbin, GST_STATE_READY)) {
2059                                         wfd_sink_error("failed to set state(READY) to audio sinkbin");
2060                                         goto ERROR;
2061                                 }
2062                         }
2063
2064                         /* add audio sinkbin to pipeline */
2065                         wfd_sink_debug("try to  add %s to %s",
2066                                                         GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2067                         if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
2068                                 wfd_sink_error("failed to add %s to %s",
2069                                                                 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2070                                 goto ERROR;
2071                         }
2072
2073                         /* sync state with parent */
2074                         wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_sinkbin));
2075                         if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_sinkbin))) {
2076                                 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_sinkbin));
2077                                 goto ERROR;
2078                         }
2079                 } else {
2080                         wfd_sink_debug("%s is already added to %s",
2081                                                         GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2082                         gst_object_unref(pipeline);
2083                         pipeline = NULL;
2084                 }
2085         } else {
2086                 wfd_sink_warning("going on without audio sinkbin....");
2087         }
2088
2089
2090         /* link audio decodebin and sinkbin */
2091         if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2092                 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
2093
2094                 if (pad)
2095                         *pad = gst_element_get_static_pad(a_decodebin, "sink");
2096
2097                 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2098
2099                         a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2100
2101                         srcpad = gst_element_get_static_pad(a_decodebin, "src");
2102                         if (!srcpad) {
2103                                 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(a_decodebin));
2104                                 goto ERROR;
2105                         }
2106
2107                         if (!gst_pad_is_linked(srcpad)) {
2108                                 sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
2109                                 if (!sinkpad) {
2110                                         wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(a_sinkbin));
2111                                         goto ERROR;
2112                                 }
2113
2114                                 wfd_sink_debug("try to link %s:%s and %s:%s",
2115                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2116                                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2117                                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2118                                         wfd_sink_error("failed to link %s:%s and %s:%s",
2119                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2120                                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2121
2122                                         goto ERROR;
2123                                 }
2124                                 gst_object_unref(sinkpad);
2125                                 sinkpad = NULL;
2126                         }
2127                         gst_object_unref(srcpad);
2128                         srcpad = NULL;
2129                 }
2130         } else if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2131                 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2132                 if (pad)
2133                         *pad = gst_element_get_static_pad(a_sinkbin, "sink");
2134         }
2135
2136         wfd_sink_debug_fleave();
2137
2138         return MM_ERROR_NONE;
2139
2140         /* ERRORS */
2141 ERROR:
2142         if (pipeline) {
2143                 gst_object_unref(pipeline);
2144                 pipeline = NULL;
2145         }
2146
2147         if (sinkpad) {
2148                 gst_object_unref(sinkpad);
2149                 sinkpad = NULL;
2150         }
2151
2152         if (srcpad) {
2153                 gst_object_unref(srcpad);
2154                 srcpad = NULL;
2155         }
2156
2157         /* need to notify to app */
2158         MMWFDSINK_POST_MESSAGE(wfd_sink,
2159                                                         MM_ERROR_WFD_INTERNAL,
2160                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
2161
2162         return MM_ERROR_WFD_INTERNAL;
2163 }
2164
2165 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
2166 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND)  /* 30 sec */
2167
2168 static GstPadProbeReturn
2169 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
2170 {
2171         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
2172         GstClockTime current_time = GST_CLOCK_TIME_NONE;
2173         GstClockTime start_time = GST_CLOCK_TIME_NONE;
2174         GstClockTime running_time = GST_CLOCK_TIME_NONE;
2175         GstClockTime base_time = GST_CLOCK_TIME_NONE;
2176         GstClockTime render_time = GST_CLOCK_TIME_NONE;
2177         GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
2178         GstBuffer *buffer = NULL;
2179         gint64 ts_offset = 0LL;
2180
2181         wfd_sink_return_val_if_fail(info, FALSE);
2182         wfd_sink_return_val_if_fail(wfd_sink &&
2183                                                                 wfd_sink->pipeline &&
2184                                                                 wfd_sink->pipeline->mainbin &&
2185                                                                 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
2186                                                                 GST_PAD_PROBE_DROP);
2187
2188         if (!wfd_sink->clock) {
2189                 wfd_sink_warning("pipeline did not select clock, yet");
2190                 return GST_PAD_PROBE_OK;
2191         }
2192
2193         if (wfd_sink->need_to_reset_basetime)
2194                 _mm_wfd_sink_reset_basetime(wfd_sink);
2195
2196         /* calculate current runninig time */
2197         current_time = gst_clock_get_time(wfd_sink->clock);
2198         if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
2199                 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
2200         else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
2201                 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
2202         start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2203         if (GST_CLOCK_TIME_IS_VALID(current_time) &&
2204             GST_CLOCK_TIME_IS_VALID(start_time) &&
2205             GST_CLOCK_TIME_IS_VALID(base_time)) {
2206                 running_time = current_time - (start_time + base_time);
2207         } else {
2208                 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
2209                                                 "  base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
2210                                                 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
2211                 return GST_PAD_PROBE_OK;
2212         }
2213
2214         /* calculate this buffer rendering time */
2215         buffer = gst_pad_probe_info_get_buffer(info);
2216         if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
2217                 wfd_sink_warning("buffer timestamp is invalid.");
2218                 return GST_PAD_PROBE_OK;
2219         }
2220
2221         if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2222                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2223                         g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2224         } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2225                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2226                         g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2227         }
2228
2229         render_time = GST_BUFFER_TIMESTAMP(buffer);
2230         render_time += ts_offset;
2231
2232         /* chekc this buffer could be rendered or not */
2233         if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
2234                 diff = GST_CLOCK_DIFF(running_time, render_time);
2235                 if (diff < 0) {
2236                         /* this buffer could be NOT rendered */
2237                         wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
2238                                                         GST_STR_NULL((GST_OBJECT_NAME(pad))),
2239                                                         GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
2240                 } else {
2241                         /* this buffer could be rendered */
2242                         /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "", */
2243                         /*      GST_STR_NULL((GST_OBJECT_NAME(pad))), */
2244                         /*      GST_TIME_ARGS(diff)); */
2245                 }
2246         }
2247
2248         /* update buffer count and gap */
2249         if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2250                 wfd_sink->video_buffer_count++;
2251                 wfd_sink->video_accumulated_gap += diff;
2252         } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2253                 wfd_sink->audio_buffer_count++;
2254                 wfd_sink->audio_accumulated_gap += diff;
2255         } else {
2256                 wfd_sink_warning("invalid buffer type.. ");
2257                 return GST_PAD_PROBE_DROP;
2258         }
2259
2260         if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
2261                 /* fisrt 60sec, just calculate the gap between source device and sink device */
2262                 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
2263                         return GST_PAD_PROBE_OK;
2264
2265                 /* every 10sec, calculate the gap between source device and sink device */
2266                 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
2267                     > COMPENSATION_CHECK_PERIOD) {
2268                         gint64 audio_avgrage_gap = 0LL;
2269                         gint64 video_avgrage_gap = 0LL;
2270                         gint64 audio_avgrage_gap_diff = 0LL;
2271                         gint64 video_avgrage_gap_diff = 0LL;
2272                         gboolean video_minus_compensation = FALSE;
2273                         gboolean audio_minus_compensation = FALSE;
2274                         gint64 avgrage_gap_diff = 0LL;
2275                         gboolean minus_compensation = FALSE;
2276
2277                         /* check video */
2278                         if (wfd_sink->video_buffer_count > 0) {
2279                                 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
2280
2281                                 if (wfd_sink->video_average_gap != 0) {
2282                                         if (video_avgrage_gap > wfd_sink->video_average_gap) {
2283                                                 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
2284                                                 video_minus_compensation = TRUE;
2285                                         } else {
2286                                                 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
2287                                                 video_minus_compensation = FALSE;
2288                                         }
2289                                 } else {
2290                                         wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
2291                                         wfd_sink->video_average_gap = video_avgrage_gap;
2292                                 }
2293                         } else {
2294                                 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
2295                                                                 " ~ %" GST_TIME_FORMAT"",
2296                                                                 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2297                                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2298                         }
2299
2300                         /* check audio */
2301                         if (wfd_sink->audio_buffer_count > 0) {
2302                                 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
2303
2304                                 if (wfd_sink->audio_average_gap != 0) {
2305                                         if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
2306                                                 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
2307                                                 audio_minus_compensation = TRUE;
2308                                         } else {
2309                                                 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
2310                                                 audio_minus_compensation = FALSE;
2311                                         }
2312                                 } else {
2313                                         wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
2314                                         wfd_sink->audio_average_gap = audio_avgrage_gap;
2315                                 }
2316                         } else {
2317                                 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
2318                                                                 " ~ %" GST_TIME_FORMAT"",
2319                                                                 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2320                                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2321                         }
2322
2323                         /* selecet average_gap_diff between video and audio */
2324                         /*  which makes no buffer drop in the sink elements */
2325                         if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
2326                                 if (!video_minus_compensation && !audio_minus_compensation) {
2327                                         minus_compensation = FALSE;
2328                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2329                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2330                                         else
2331                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2332                                 } else if (video_minus_compensation && audio_minus_compensation) {
2333                                         minus_compensation = TRUE;
2334                                         if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2335                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2336                                         else
2337                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2338                                 } else {
2339                                         minus_compensation = FALSE;
2340                                         if (!video_minus_compensation)
2341                                                 avgrage_gap_diff = video_avgrage_gap_diff;
2342                                         else
2343                                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2344                                 }
2345                         } else if (video_avgrage_gap_diff) {
2346                                 minus_compensation = video_minus_compensation;
2347                                 avgrage_gap_diff = video_avgrage_gap_diff;
2348                         } else if (audio_avgrage_gap_diff) {
2349                                 minus_compensation = audio_minus_compensation;
2350                                 avgrage_gap_diff = audio_avgrage_gap_diff;
2351                         }
2352
2353                         wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
2354                                                         audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
2355                                                         video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
2356
2357
2358                         /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
2359                         if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
2360                                 if (minus_compensation)
2361                                         ts_offset -= avgrage_gap_diff;
2362                                 else
2363                                         ts_offset += avgrage_gap_diff;
2364
2365                                 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
2366                                                                 GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
2367                                                                 minus_compensation ? "-" : "", avgrage_gap_diff,
2368                                                                 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
2369
2370                                 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2371                                         g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2372                                 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2373                                         g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2374                         } else {
2375                                 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
2376                                                                 minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
2377                         }
2378
2379                         /* reset values*/
2380                         wfd_sink->video_buffer_count = 0;
2381                         wfd_sink->video_accumulated_gap = 0LL;
2382                         wfd_sink->audio_buffer_count = 0;
2383                         wfd_sink->audio_accumulated_gap = 0LL;
2384                         wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2385                 }
2386         } else {
2387                 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
2388                                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2389                 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2390         }
2391
2392         return GST_PAD_PROBE_OK;
2393 }
2394
2395
2396 static void
2397 __mm_wfd_sink_demux_pad_added(GstElement *demux, GstPad *pad, gpointer data)
2398 {
2399         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2400         gchar *name = NULL;
2401         GstElement *pipeline = NULL;
2402         GstElement *valve = NULL;
2403         GstPad *sinkpad = NULL;
2404         GstPad *srcpad = NULL;
2405
2406         wfd_sink_debug_fenter();
2407
2408         wfd_sink_return_if_fail(wfd_sink &&
2409                                                         wfd_sink->pipeline &&
2410                                                         wfd_sink->pipeline->mainbin &&
2411                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2412
2413         name = gst_pad_get_name(pad);
2414         if (name == NULL) {
2415                 wfd_sink_error("fail to get pad");
2416                 goto ERROR;
2417         }
2418
2419         wfd_sink_debug("Mux pad added, session mode = %d, name[0] = %c", wfd_sink->ini.sink_session_mode, name[0]);
2420
2421         //In case of 'audio-only-mirroring', we don't add video pad
2422         if ((wfd_sink->ini.sink_session_mode & WFD_SESSION_MODE_AUDIO_ONLY) && name[0] == 'v') {
2423                 wfd_sink_error("Skip video pad add in audio only mode");
2424                 // Do nothing
2425                 goto done;
2426         }
2427
2428         //In case of none audio codec, we don't add audio pad
2429         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE && name[0] == 'a') {
2430                 wfd_sink_error("Skip audio pad add for none audio codec");
2431                 // Do nothing
2432                 goto done;
2433         }
2434
2435         pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2436
2437         /* take srcpad from demuxer added pad */
2438         srcpad = gst_object_ref(pad);
2439
2440         if (name[0] == 'v') {
2441                 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst)
2442                         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
2443         } else if (name[0] == 'a') {
2444                 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst)
2445                         valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
2446         }
2447
2448         /* add, link and run the valve */
2449         if (valve) {
2450                 wfd_sink_debug("try to add %s to pipeline", GST_ELEMENT_NAME(valve));
2451
2452                 if (!gst_bin_add(GST_BIN(pipeline), valve)) {
2453                         wfd_sink_error("failed to add %s to pipeline",
2454                                                         GST_ELEMENT_NAME(valve));
2455                         goto ERROR;
2456                 }
2457
2458                 sinkpad = gst_element_get_static_pad(valve, "sink");
2459                 if (!sinkpad) {
2460                                 wfd_sink_error("failed to get sink pad from %s",
2461                                                                 GST_ELEMENT_NAME(valve));
2462                         goto ERROR;
2463                 }
2464
2465                 wfd_sink_debug("try to link %s:%s and %s:%s",
2466                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2467                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2468                 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2469                         wfd_sink_error("failed to link %s:%s and %s:%s",
2470                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2471                                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2472                         goto ERROR;
2473                 }
2474                 gst_object_unref(GST_OBJECT(srcpad));
2475                 srcpad = NULL;
2476                 gst_object_unref(GST_OBJECT(sinkpad));
2477                 sinkpad = NULL;
2478
2479                 wfd_sink_debug("try to sync %s's state with parent", GST_ELEMENT_NAME(valve));
2480                 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(valve))) {
2481                         wfd_sink_error("failed to sync %s state with parent",
2482                                                         GST_PAD_NAME(valve));
2483                         goto ERROR;
2484                 }
2485
2486                 srcpad = gst_element_get_static_pad(valve, "src");
2487                 if (!srcpad) {
2488                         wfd_sink_error("failed to get src pad from %s",
2489                                                         GST_ELEMENT_NAME(valve));
2490                         goto ERROR;
2491                 }
2492         }
2493
2494         /* take decodebin/sinkbin */
2495         if (name[0] == 'v') {
2496                 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
2497
2498                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
2499
2500                 gst_pad_add_probe(pad,
2501                                                 GST_PAD_PROBE_TYPE_BUFFER,
2502                                                 _mm_wfd_sink_check_running_time,
2503                                                 (gpointer)wfd_sink,
2504                                                 NULL);
2505
2506                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad)) {
2507                         wfd_sink_error("failed to prepare video pipeline....");
2508                         goto ERROR;
2509                 }
2510         } else if (name[0] == 'a') {
2511                 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
2512
2513                 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL,  NULL);
2514
2515                 gst_pad_add_probe(pad,
2516                                                 GST_PAD_PROBE_TYPE_BUFFER,
2517                                                 _mm_wfd_sink_check_running_time,
2518                                                 (gpointer)wfd_sink,
2519                                                 NULL);
2520
2521                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad)) {
2522                         wfd_sink_error("failed to prepare audio pipeline....");
2523                         goto ERROR;
2524                 }
2525         } else {
2526                 wfd_sink_error("unexceptable pad is added!!!");
2527                 goto ERROR;
2528         }
2529
2530         /* link */
2531         wfd_sink_debug("try to link %s:%s and %s:%s",
2532                                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2533                                         GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2534         if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2535                 wfd_sink_error("failed to link %s:%s and %s:%s",
2536                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2537                                                 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2538                 goto ERROR;
2539         }
2540
2541         if (name[0] == 'v') {
2542                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
2543         } else if (name[0] == 'a') {
2544                 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
2545         }
2546
2547 done:
2548         MMWFDSINK_FREEIF(name);
2549
2550         if (srcpad) {
2551                 gst_object_unref(GST_OBJECT(srcpad));
2552                 srcpad = NULL;
2553         }
2554         if (sinkpad) {
2555                 gst_object_unref(GST_OBJECT(sinkpad));
2556                 sinkpad = NULL;
2557         }
2558         wfd_sink_debug_fleave();
2559
2560         return;
2561
2562         /* ERRORS */
2563 ERROR:
2564         /* need to notify to app */
2565         MMWFDSINK_POST_MESSAGE(wfd_sink,
2566                                                         MM_ERROR_WFD_INTERNAL,
2567                                                         MMWFDSINK_CURRENT_STATE(wfd_sink));
2568
2569         goto done;
2570 }
2571
2572 static void
2573 __mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data)
2574 {
2575         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2576
2577         wfd_sink_debug_fenter();
2578
2579         wfd_sink_return_if_fail(wfd_sink);
2580         wfd_sink_return_if_fail(need_to_flush);
2581
2582         if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
2583                 wfd_sink_debug("need to flush pipeline");
2584                 *need_to_flush = (gpointer) TRUE;
2585         } else {
2586                 wfd_sink_debug("don't need to flush pipeline");
2587                 *need_to_flush = (gpointer) FALSE;
2588         }
2589
2590
2591         wfd_sink_debug_fleave();
2592 }
2593
2594
2595 static void
2596 __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data)
2597 {
2598         mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2599         MMWFDSinkStreamInfo *stream_info = NULL;
2600         gint is_valid_audio_format = FALSE;
2601         gint is_valid_video_format = FALSE;
2602         gchar *audio_format;
2603         gchar *video_format;
2604
2605         wfd_sink_debug_fenter();
2606         wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
2607         wfd_sink_return_if_fail(wfd_sink);
2608
2609         stream_info = &wfd_sink->stream_info;
2610
2611         if (gst_structure_has_field(str, "audio_format")) {
2612                 is_valid_audio_format = TRUE;
2613                 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
2614                 if (g_strrstr(audio_format, "AAC"))
2615                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
2616                 else if (g_strrstr(audio_format, "AC3"))
2617                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
2618                 else if (g_strrstr(audio_format, "LPCM"))
2619                         stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
2620                 else {
2621                         wfd_sink_error("invalid audio format(%s)...", audio_format);
2622                         is_valid_audio_format = FALSE;
2623                 }
2624                 if (is_valid_audio_format == TRUE) {
2625                         if (gst_structure_has_field(str, "audio_rate"))
2626                                 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
2627                         if (gst_structure_has_field(str, "audio_channels"))
2628                                 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
2629                         if (gst_structure_has_field(str, "audio_bitwidth"))
2630                                 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
2631
2632                         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
2633
2634                         wfd_sink_debug("audio_format : %s \n \t rate :  %d \n \t channels :  %d \n \t bitwidth :  %d \n \t      \n",
2635                                                         audio_format,
2636                                                         stream_info->audio_stream_info.sample_rate,
2637                                                         stream_info->audio_stream_info.channels,
2638                                                         stream_info->audio_stream_info.bitwidth);
2639                 }
2640         }
2641         if (gst_structure_has_field(str, "video_format")) {
2642                 is_valid_video_format = TRUE;
2643                 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
2644                 if (g_strrstr(video_format, "H264")) {
2645                         stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
2646                 } else if (g_strrstr(video_format, "H265")) {
2647                         stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H265;
2648                 } else {
2649                         wfd_sink_error("invalid video format(%s)...", video_format);
2650                         is_valid_video_format = FALSE;
2651                 }
2652
2653                 if (is_valid_video_format == TRUE) {
2654                         if (gst_structure_has_field(str, "video_width"))
2655                                 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
2656                         if (gst_structure_has_field(str, "video_height"))
2657                                 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
2658                         if (gst_structure_has_field(str, "video_framerate"))
2659                                 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
2660
2661                         WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
2662
2663                         wfd_sink_debug("video_format : %s \n \t width :  %d \n \t height :  %d \n \t frame_rate :  %d \n \t",
2664                                                         video_format,
2665                                                         stream_info->video_stream_info.width,
2666                                                         stream_info->video_stream_info.height,
2667                                                         stream_info->video_stream_info.frame_rate);
2668                 }
2669         }
2670
2671         WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
2672
2673         wfd_sink_debug_fleave();
2674 }
2675
2676 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint64 *CEA_resolution,
2677                                                                                                         guint64 *VESA_resolution, guint64 *HH_resolution)
2678 {
2679         if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
2680
2681         *CEA_resolution = 0;
2682         *VESA_resolution = 0;
2683         *HH_resolution = 0;
2684
2685         if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
2686                 *CEA_resolution |= WFD_CEA_1920x1080P30;
2687
2688         if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
2689                 *CEA_resolution |= WFD_CEA_1280x720P30;
2690
2691         if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
2692                 *HH_resolution |= WFD_HH_960x540P30;
2693
2694         if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
2695                 *HH_resolution |= WFD_HH_864x480P30;
2696
2697         if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
2698                 *CEA_resolution |= WFD_CEA_720x480P60;
2699
2700         if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
2701                 *CEA_resolution |= WFD_CEA_640x480P60;
2702
2703         if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
2704                 *HH_resolution |= WFD_HH_640x360P30;
2705 }
2706
2707 static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc)
2708 {
2709         GstStructure *wfd_audio_codecs = NULL;
2710         GstStructure *wfd_video_formats = NULL;
2711         GstStructure *wfd_content_protection = NULL;
2712         GstStructure *wfd2_video_formats = NULL;
2713         GstStructure *wfd2_audio_codecs = NULL;
2714         gint hdcp_version = 0;
2715         gint hdcp_port = 0;
2716         guint64 CEA_resolution = 0;
2717         guint64 VESA_resolution = 0;
2718         guint64 HH_resolution = 0;
2719         GObjectClass *klass;
2720
2721         wfd_sink_debug_fenter();
2722
2723         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2724         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2725         wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED);
2726
2727         klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc));
2728
2729         if (g_object_class_find_property(klass, "enable-pad-probe")) /* for common wfdsrc */
2730                 g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.trace_buffers_of_wfdsrc, NULL);
2731         g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
2732         g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
2733         g_object_set(G_OBJECT(wfdsrc), "user-agent", wfd_sink->ini.user_agent, NULL);
2734         g_object_set(G_OBJECT(wfdsrc), "dump-rtsp-message", wfd_sink->ini.dump_rtsp_message, NULL);
2735         if (g_object_class_find_property(klass, "dump-rtp-data"))
2736                 g_object_set(G_OBJECT(wfdsrc), "dump-rtp-data", wfd_sink->ini.dump_rtp_data, NULL);
2737         if (g_object_class_find_property(klass, "trace-first-buffer"))
2738                 g_object_set(G_OBJECT(wfdsrc), "trace-first-buffer", wfd_sink->ini.trace_first_buffer, NULL);
2739         if (g_object_class_find_property(klass, "trace-buffers"))
2740                 g_object_set(G_OBJECT(wfdsrc), "trace-buffers", wfd_sink->ini.trace_buffers, NULL);
2741         if (g_object_class_find_property(klass, "do-request"))
2742                 g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
2743
2744         /* set audio parameter for Wi-Fi Display session negotiation */
2745         wfd_audio_codecs = gst_structure_new("wfd_audio_codecs",
2746                                                                                 "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_codec,
2747                                                                                 "audio_latency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_latency,
2748                                                                                 "audio_channels", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_channel,
2749                                                                                 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_sampling_frequency,
2750                                                                                 NULL);
2751
2752         if (wfd_audio_codecs) {
2753                 g_object_set(G_OBJECT(wfdsrc), "wfd-audio-codecs", wfd_audio_codecs, NULL);
2754                 gst_structure_free(wfd_audio_codecs);
2755                 wfd_audio_codecs = NULL;
2756         }
2757
2758         /* set video parameter for Wi-Fi Display session negotiation */
2759         CEA_resolution = wfd_sink->ini.wfd_video_formats.video_cea_support;
2760         VESA_resolution = wfd_sink->ini.wfd_video_formats.video_vesa_support;
2761         HH_resolution =  wfd_sink->ini.wfd_video_formats.video_hh_support;
2762
2763         __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
2764                                                                                         &CEA_resolution, &VESA_resolution, &HH_resolution);
2765         wfd_video_formats = gst_structure_new("wfd_video_formats",
2766                                                                                 "video_codec", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_codec,
2767                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_native_resolution,
2768                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2769                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2770                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2771                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_profile,
2772                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_level,
2773                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_latency,
2774                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_vertical_resolution,
2775                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_horizontal_resolution,
2776                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_minimum_slicing,
2777                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_slice_enc_param,
2778                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_framerate_control_support,
2779                                                                                 NULL);
2780
2781         if (wfd_video_formats) {
2782                 g_object_set(G_OBJECT(wfdsrc), "wfd-video-formats", wfd_video_formats, NULL);
2783                 gst_structure_free(wfd_video_formats);
2784                 wfd_video_formats = NULL;
2785         }
2786
2787
2788         /* set hdcp parameter for Wi-Fi Display session negotiation */
2789         if (wfd_sink->ini.wfd_content_protection.enable_hdcp) {
2790                 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
2791                 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
2792                 wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
2793
2794                 wfd_content_protection = gst_structure_new("wfd_content_protection",
2795                                                                                                         "hdcp_version", G_TYPE_INT, hdcp_version,
2796                                                                                                         "hdcp_port_no", G_TYPE_INT, hdcp_port,
2797                                                                                                         NULL);
2798
2799                 if (wfd_content_protection) {
2800                         g_object_set(G_OBJECT(wfdsrc), "wfd-content-protection", wfd_content_protection, NULL);
2801                         gst_structure_free(wfd_content_protection);
2802                         wfd_content_protection = NULL;
2803                 }
2804         }
2805
2806         if (g_object_class_find_property(klass, "wfd2-audio-codecs")) {
2807                 /* set audio parameter for Wi-Fi Display R2 session negotiation */
2808                 wfd2_audio_codecs = gst_structure_new("wfd2-audio-codecs",
2809                                                                                         "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_codec,
2810                                                                                         "audio_lpcm_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_lpcm_mode,
2811                                                                                         "audio_aac_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_aac_mode,
2812                                                                                         "audio_ac3_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_ac3_mode,
2813                                                                                         NULL);
2814
2815                 if (wfd2_audio_codecs) {
2816                         g_object_set(G_OBJECT(wfdsrc), "wfd2-audio-codecs", wfd2_audio_codecs, NULL);
2817                         gst_structure_free(wfd2_audio_codecs);
2818                         wfd2_audio_codecs = NULL;
2819                 }
2820         }
2821
2822         if (g_object_class_find_property(klass, "wfd2-video-format-h264")) {
2823                 /* set video parameter for Wi-Fi Display R2 session negotiation */
2824                 CEA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_cea_support;
2825                 VESA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_vesa_support;
2826                 HH_resolution =  wfd_sink->ini.wfd2_video_h264_info.video_hh_support;
2827
2828                 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H264) {
2829                         wfd2_video_formats = gst_structure_new("wfd2-video-format-h264",
2830                                                                                                 "video_codec", G_TYPE_UINT, WFD_VIDEO_H264,
2831                                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2832                                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2833                                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2834                                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2835                                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_profile,
2836                                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_level,
2837                                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_latency,
2838                                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_vertical_resolution,
2839                                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_horizontal_resolution,
2840                                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_minimum_slicing,
2841                                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_slice_enc_param,
2842                                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_framerate_control_support,
2843                                                                                                 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2844                                                                                                 NULL);
2845
2846                         if (wfd2_video_formats) {
2847                                 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h264", wfd2_video_formats, NULL);
2848                                 gst_structure_free(wfd2_video_formats);
2849                                 wfd2_video_formats = NULL;
2850                         }
2851                 }
2852         }
2853
2854         if (g_object_class_find_property(klass, "wfd2-video-format-h265")) {
2855                 /* set video parameter for Wi-Fi Display R2 session negotiation */
2856                 CEA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_cea_support;
2857                 VESA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_vesa_support;
2858                 HH_resolution =  wfd_sink->ini.wfd2_video_h265_info.video_hh_support;
2859
2860                 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H265) {
2861                         wfd2_video_formats = gst_structure_new("wfd2-video-format-h265",
2862                                                                                                 "video_codec", G_TYPE_UINT, WFD_VIDEO_H265,
2863                                                                                                 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2864                                                                                                 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2865                                                                                                 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2866                                                                                                 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2867                                                                                                 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_profile,
2868                                                                                                 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_level,
2869                                                                                                 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_latency,
2870                                                                                                 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_vertical_resolution,
2871                                                                                                 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_horizontal_resolution,
2872                                                                                                 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_minimum_slicing,
2873                                                                                                 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_slice_enc_param,
2874                                                                                                 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_framerate_control_support,
2875                                                                                                 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2876                                                                 NULL);
2877
2878                         if (wfd2_video_formats) {
2879                                 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h265", wfd2_video_formats, NULL);
2880                                 gst_structure_free(wfd2_video_formats);
2881                                 wfd2_video_formats = NULL;
2882                         }
2883                 }
2884         }
2885
2886         wfd_sink->update_stream_info_sig_id = g_signal_connect(wfdsrc, "update-media-info",
2887                                                                                                                 G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
2888
2889         wfd_sink->change_av_format_sig_id = g_signal_connect(wfdsrc, "change-av-format",
2890                                                                                                                 G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
2891
2892         wfd_sink_debug_fleave();
2893
2894         return MM_ERROR_NONE;
2895 }
2896
2897 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
2898 {
2899         wfd_sink_debug_fenter();
2900
2901         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2902         wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
2903
2904         g_signal_connect(demux, "pad-added",
2905                                         G_CALLBACK(__mm_wfd_sink_demux_pad_added),      wfd_sink);
2906
2907         wfd_sink_debug_fleave();
2908
2909         return MM_ERROR_NONE;
2910 }
2911
2912 static void __mm_wfd_sink_queue_overrun(GstElement *queue, gpointer u_data)
2913 {
2914         guint64 time = 0;
2915
2916         wfd_sink_debug_fenter();
2917
2918         return_if_fail(queue);
2919
2920         g_object_get(G_OBJECT(queue), "current-level-time", &time, NULL);
2921
2922         wfd_sink_warning("%s is overrun(%" GST_TIME_FORMAT")",
2923                                                 GST_ELEMENT_NAME(queue), GST_TIME_ARGS(time));
2924
2925         wfd_sink_debug_fleave();
2926
2927         return;
2928 }
2929
2930 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
2931 {
2932         wfd_sink_debug_fenter();
2933
2934         wfd_sink_return_if_fail(wfd_sink);
2935         wfd_sink_return_if_fail(queue);
2936
2937         /* set maximum buffer size of queue as 3sec */
2938         g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
2939         g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
2940         g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
2941         g_signal_connect(queue, "overrun",
2942                                         G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
2943
2944         wfd_sink_debug_fleave();
2945
2946         return;
2947 }
2948
2949
2950 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
2951 {
2952         MMWFDSinkGstElement *mainbin = NULL;
2953         GList *element_bucket = NULL;
2954         GstBus  *bus = NULL;
2955         int i;
2956
2957         wfd_sink_debug_fenter();
2958
2959         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2960         wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2961
2962         /* Create pipeline */
2963         wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
2964         if (wfd_sink->pipeline == NULL)
2965                 goto CREATE_ERROR;
2966
2967         memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
2968
2969         /* create mainbin */
2970         mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2971         if (mainbin == NULL)
2972                 goto CREATE_ERROR;
2973
2974         memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2975
2976         /* create pipeline */
2977         mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
2978         mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
2979         if (!mainbin[WFD_SINK_M_PIPE].gst) {
2980                 wfd_sink_error("failed to create pipeline");
2981                 goto CREATE_ERROR;
2982         }
2983
2984         /* create wfdsrc */
2985         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE);
2986         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst,  "src");
2987         if (mainbin[WFD_SINK_M_SRC].gst) {
2988                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2989                         wfd_sink_error("failed to prepare wfdsrc...");
2990                         goto CREATE_ERROR;
2991                 }
2992         }
2993
2994         /* create rtpmp2tdepay */
2995         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
2996         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2997         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
2998
2999         MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
3000
3001         /* create queue for ts */
3002         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_QUEUE, "queue", "ts_queue", TRUE);
3003         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "src");
3004         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_QUEUE].gst, "sink");
3005         g_object_set(G_OBJECT(mainbin[WFD_SINK_M_QUEUE].gst), "max-size-buffers", 200000, NULL);
3006
3007         /* create valve for demux */
3008         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_D_VALVE, "valve", "demux_valve", TRUE);
3009         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "src");
3010         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_D_VALVE].gst, "sink");
3011
3012         /* create tsdemuxer*/
3013         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
3014         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
3015         if (mainbin[WFD_SINK_M_DEMUX].gst) {
3016                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
3017                         wfd_sink_error("failed to prepare demux...");
3018                         goto CREATE_ERROR;
3019                 }
3020         }
3021
3022         /* create valve for audio */
3023         MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_A_VALVE, "valve", "audio_valve", FALSE);
3024         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "src");
3025         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "sink");
3026
3027         if (wfd_sink->ini.sink_session_mode & (WFD_SESSION_MODE_MIXED | WFD_SESSION_MODE_VIDEO_ONLY)) {
3028                 /* create valve for video */
3029                 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_V_VALVE, "valve", "video_valve", FALSE);
3030                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "src");
3031                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "sink");
3032         }
3033
3034         /* adding created elements to pipeline */
3035         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
3036                 wfd_sink_error("failed to add elements");
3037                 goto CREATE_ERROR;
3038         }
3039
3040         /* linking elements in the bucket by added order. */
3041         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3042                 wfd_sink_error("failed to link elements");
3043                 goto CREATE_ERROR;
3044         }
3045
3046         /* connect bus callback */
3047         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
3048         if (!bus) {
3049                 wfd_sink_error("cannot get bus from pipeline.");
3050                 goto CREATE_ERROR;
3051         }
3052
3053         /* add bus message callback*/
3054         wfd_sink->msg_callback_id = gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
3055
3056         /* set sync handler to get tag synchronously */
3057         gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
3058
3059         g_list_free(element_bucket);
3060         element_bucket = NULL;
3061         gst_object_unref(GST_OBJECT(bus));
3062         bus = NULL;
3063
3064         /* now we have completed mainbin. take it */
3065         wfd_sink->pipeline->mainbin = mainbin;
3066
3067         wfd_sink_debug_fleave();
3068
3069         return MM_ERROR_NONE;
3070
3071         /* ERRORS */
3072 CREATE_ERROR:
3073         wfd_sink_error("ERROR : releasing pipeline");
3074
3075         if (element_bucket) {
3076                 g_list_free(element_bucket);
3077                 element_bucket = NULL;
3078         }
3079
3080         /* release element which are not added to bin */
3081         for (i = 1; i < WFD_SINK_M_NUM; i++) {  /* NOTE : skip pipeline */
3082                 if (mainbin != NULL && mainbin[i].gst) {
3083                         GstObject *parent = NULL;
3084                         parent = gst_element_get_parent(mainbin[i].gst);
3085
3086                         if (!parent) {
3087                                 gst_object_unref(GST_OBJECT(mainbin[i].gst));
3088                                 mainbin[i].gst = NULL;
3089                         } else {
3090                                 gst_object_unref(GST_OBJECT(parent));
3091                                 parent = NULL;
3092                         }
3093                 }
3094         }
3095
3096         /* release mainbin with it's childs */
3097         if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) {
3098                 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3099                 mainbin[WFD_SINK_M_PIPE].gst = NULL;
3100         }
3101
3102         MMWFDSINK_FREEIF(mainbin);
3103
3104         MMWFDSINK_FREEIF(wfd_sink->pipeline);
3105
3106         return MM_ERROR_WFD_INTERNAL;
3107 }
3108
3109 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3110 {
3111         MMWFDSinkGstElement *a_decodebin = NULL;
3112         MMWFDSinkGstElement *first_element = NULL;
3113         MMWFDSinkGstElement *last_element = NULL;
3114         GList *element_bucket = NULL;
3115         GstPad *sinkpad = NULL;
3116         GstPad *srcpad = NULL;
3117         GstPad *ghostpad = NULL;
3118         GList *list_temp = NULL;
3119
3120         wfd_sink_debug_fenter();
3121
3122         wfd_sink_return_val_if_fail(wfd_sink &&
3123                                                                 wfd_sink->pipeline &&
3124                                                                 wfd_sink->pipeline->a_decodebin &&
3125                                                                 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
3126                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3127
3128         if (wfd_sink->audio_decodebin_is_linked) {
3129                 wfd_sink_debug("audio decodebin is already linked... nothing to do");
3130                 return MM_ERROR_NONE;
3131         }
3132
3133         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3134                 wfd_sink_debug("Skip link audio decodebin for none audio codec.");
3135                 wfd_sink_debug_fleave();
3136                 return MM_ERROR_NONE;
3137         }
3138
3139         /* take audio decodebin */
3140         a_decodebin = wfd_sink->pipeline->a_decodebin;
3141
3142         /* check audio queue */
3143         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3144                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]);
3145
3146         /* check audio hdcp */
3147         if (a_decodebin[WFD_SINK_A_D_HDCP].gst)
3148                 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]);
3149
3150         /* check audio codec */
3151         switch (wfd_sink->stream_info.audio_stream_info.codec) {
3152         case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3153                 if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
3154                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
3155                 if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
3156                         GstCaps *caps = NULL;
3157                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
3158                         caps = gst_caps_new_simple("audio/x-raw",
3159                                                 "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
3160                                                 "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
3161                                                 "format", G_TYPE_STRING, "S16BE", NULL);
3162
3163                         g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
3164                         gst_object_unref(GST_OBJECT(caps));
3165                         caps = NULL;
3166                 }
3167                 break;
3168
3169         case MM_WFD_SINK_AUDIO_CODEC_AAC:
3170                 if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
3171                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
3172                 if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
3173                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
3174                 break;
3175
3176         case MM_WFD_SINK_AUDIO_CODEC_AC3:
3177                 if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
3178                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
3179                 if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
3180                         element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
3181                 break;
3182
3183         default:
3184                 wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
3185                 return MM_ERROR_WFD_INTERNAL;
3186                 break;
3187         }
3188
3189         if (element_bucket == NULL) {
3190                 wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it");
3191                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3192                         wfd_sink_error("failed to destroy audio decodebin");
3193                         goto fail_to_link;
3194                 }
3195                 goto done;
3196         }
3197
3198         /* adding elements to audio decodebin */
3199         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) {
3200                 wfd_sink_error("failed to add elements to audio decodebin");
3201                 goto fail_to_link;
3202         }
3203
3204         /* linking elements in the bucket by added order. */
3205         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3206                 wfd_sink_error("failed to link elements of the audio decodebin");
3207                 goto fail_to_link;
3208         }
3209
3210         /* get first element's sinkpad for creating ghostpad */
3211         list_temp = g_list_first(element_bucket);
3212         if (list_temp == NULL) {
3213                 wfd_sink_error("failed to get first list of the element_bucket");
3214                 goto fail_to_link;
3215         }
3216
3217         first_element = (MMWFDSinkGstElement *)list_temp->data;
3218         if (!first_element) {
3219                 wfd_sink_error("failed to get first element of the audio decodebin");
3220                 goto fail_to_link;
3221         }
3222
3223         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3224         if (!sinkpad) {
3225                 wfd_sink_error("failed to get sink pad from element(%s)",
3226                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3227                 goto fail_to_link;
3228         }
3229
3230         ghostpad = gst_ghost_pad_new("sink", sinkpad);
3231         if (!ghostpad) {
3232                 wfd_sink_error("failed to create ghostpad of audio decodebin");
3233                 goto fail_to_link;
3234         }
3235
3236         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3237                 wfd_sink_error("failed to add ghostpad to audio decodebin");
3238                 goto fail_to_link;
3239         }
3240         gst_object_unref(GST_OBJECT(sinkpad));
3241         sinkpad = NULL;
3242
3243
3244         /* get last element's src for creating ghostpad */
3245         list_temp = g_list_last(element_bucket);
3246         if (list_temp == NULL) {
3247                 wfd_sink_error("failed to get last list of the element_bucket");
3248                 goto fail_to_link;
3249         }
3250
3251         last_element = (MMWFDSinkGstElement *)list_temp->data;
3252         if (!last_element) {
3253                 wfd_sink_error("failed to get last element of the audio decodebin");
3254                 goto fail_to_link;
3255         }
3256
3257         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3258         if (!srcpad) {
3259                 wfd_sink_error("failed to get src pad from element(%s)",
3260                                                 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3261                 goto fail_to_link;
3262         }
3263
3264         ghostpad = gst_ghost_pad_new("src", srcpad);
3265         if (!ghostpad) {
3266                 wfd_sink_error("failed to create ghostpad of audio decodebin");
3267                 goto fail_to_link;
3268         }
3269
3270         if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3271                 wfd_sink_error("failed to add ghostpad to audio decodebin");
3272                 goto fail_to_link;
3273         }
3274         gst_object_unref(GST_OBJECT(srcpad));
3275         srcpad = NULL;
3276
3277         g_list_free(element_bucket);
3278
3279 done:
3280         wfd_sink->audio_decodebin_is_linked = TRUE;
3281
3282         wfd_sink_debug_fleave();
3283
3284         return MM_ERROR_NONE;
3285
3286         /* ERRORS*/
3287 fail_to_link:
3288         if (srcpad) {
3289                 gst_object_unref(GST_OBJECT(srcpad));
3290                 srcpad = NULL;
3291         }
3292
3293         if (sinkpad) {
3294                 gst_object_unref(GST_OBJECT(sinkpad));
3295                 sinkpad = NULL;
3296         }
3297
3298         g_list_free(element_bucket);
3299
3300         return MM_ERROR_WFD_INTERNAL;
3301 }
3302
3303 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
3304 {
3305         wfd_sink_debug_fenter();
3306
3307         /* check audiosink is created */
3308         wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
3309         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3310
3311         g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE,  NULL);
3312         g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
3313         g_object_set(G_OBJECT(audio_sink), "slave-method", 2,  NULL);
3314         g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async,  NULL);
3315         g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
3316
3317         wfd_sink_debug_fleave();
3318
3319         return MM_ERROR_NONE;
3320 }
3321
3322 static int  __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3323 {
3324         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3325         MMWFDSinkGstElement *a_decodebin = NULL;
3326         GstObject *parent = NULL;
3327         int i;
3328
3329         wfd_sink_debug_fenter();
3330
3331         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3332
3333         if (wfd_sink->pipeline &&
3334             wfd_sink->pipeline->a_decodebin &&
3335             wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
3336                 a_decodebin = wfd_sink->pipeline->a_decodebin;
3337         } else {
3338                 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
3339                 return MM_ERROR_NONE;
3340         }
3341
3342         parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
3343         if (!parent) {
3344                 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
3345
3346                 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
3347                         wfd_sink_debug("try to change state of audio decodebin to NULL");
3348                         ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
3349                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3350                                 wfd_sink_error("failed to change state of audio decodebin to NULL");
3351                                 return MM_ERROR_WFD_INTERNAL;
3352                         }
3353                 }
3354
3355                 /* release element which are not added to bin */
3356                 for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
3357                         if (a_decodebin[i].gst) {
3358                                 parent = gst_element_get_parent(a_decodebin[i].gst);
3359                                 if (!parent) {
3360                                         wfd_sink_debug("unref %s(current ref %d)",
3361                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3362                                                                         ((GObject *) a_decodebin[i].gst)->ref_count);
3363                                         gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3364                                         a_decodebin[i].gst = NULL;
3365                                 } else {
3366                                         wfd_sink_debug("%s has parent.(current ref %d)",
3367                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3368                                                                         ((GObject *) a_decodebin[i].gst)->ref_count);
3369                                         gst_object_unref(GST_OBJECT(parent));
3370                                         parent = NULL;
3371                                 }
3372                         }
3373                 }
3374
3375                 /* release audio decodebin with it's childs */
3376                 if (a_decodebin[WFD_SINK_A_D_BIN].gst) {
3377                         gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3378                         a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3379                 }
3380
3381         } else {
3382                 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
3383                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3384
3385                 gst_object_unref(GST_OBJECT(parent));
3386                 parent = NULL;
3387         }
3388
3389         wfd_sink->audio_decodebin_is_linked = FALSE;
3390
3391         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
3392
3393         wfd_sink_debug_fleave();
3394
3395         return MM_ERROR_NONE;
3396 }
3397
3398 int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3399 {
3400         MMWFDSinkGstElement *a_decodebin = NULL;
3401         gint audio_codec = WFD_AUDIO_UNKNOWN;
3402         GList *element_bucket = NULL;
3403         gboolean link = TRUE;
3404         gint i = 0;
3405
3406         wfd_sink_debug_fenter();
3407
3408         wfd_sink_return_val_if_fail(wfd_sink &&
3409                                                                 wfd_sink->pipeline,
3410                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3411
3412         if (wfd_sink->pipeline->a_decodebin != NULL) {
3413                 wfd_sink_error("The audio decode bin is already created.");
3414                 return MM_ERROR_NONE;
3415         }
3416
3417         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3418                 wfd_sink_debug("Skip create audio decodebin for none audio codec.");
3419                 wfd_sink_debug_fleave();
3420                 return MM_ERROR_NONE;
3421         }
3422
3423         /* check audio decodebin could be linked now */
3424         switch (wfd_sink->stream_info.audio_stream_info.codec) {
3425         case MM_WFD_SINK_AUDIO_CODEC_AAC:
3426                 audio_codec = WFD_AUDIO_AAC;
3427                 link = TRUE;
3428                 break;
3429         case MM_WFD_SINK_AUDIO_CODEC_AC3:
3430                 audio_codec = WFD_AUDIO_AC3;
3431                 link = TRUE;
3432                 break;
3433         case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3434                 audio_codec = WFD_AUDIO_LPCM;
3435                 link = TRUE;
3436                 break;
3437         case MM_WFD_SINK_AUDIO_CODEC_NONE:
3438         default:
3439                 wfd_sink_debug("audio decodebin could NOT be linked now, just create");
3440                 audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3441                 link = FALSE;
3442                 break;
3443         }
3444
3445         /* alloc handles */
3446         a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3447         if (!a_decodebin) {
3448                 wfd_sink_error("failed to allocate memory for audio decodebin");
3449                 return MM_ERROR_WFD_NO_FREE_SPACE;
3450         }
3451
3452         memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3453
3454         /* create audio decodebin */
3455         a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
3456         a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
3457         if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
3458                 wfd_sink_error("failed to create audio decodebin");
3459                 goto CREATE_ERROR;
3460         }
3461
3462         /* create queue */
3463         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
3464         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "sink");
3465         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst,  "src");
3466         if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3467                 __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
3468
3469         /* create hdcp */
3470         MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
3471         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "sink");
3472         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst,  "src");
3473
3474         /* create codec */
3475         audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3476         if (audio_codec & WFD_AUDIO_LPCM) {
3477                 /* create LPCM converter */
3478                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
3479                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "sink");
3480                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst,  "src");
3481
3482                 /* create LPCM filter */
3483                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
3484                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "sink");
3485                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst,  "src");
3486         }
3487
3488         if (audio_codec & WFD_AUDIO_AAC) {
3489                 /* create AAC parse  */
3490                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
3491                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "sink");
3492                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst,  "src");
3493
3494                 /* create AAC decoder  */
3495                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
3496                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "sink");
3497                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst,  "src");
3498         }
3499
3500         if (audio_codec & WFD_AUDIO_AC3) {
3501                 /* create AC3 parser  */
3502                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
3503                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "sink");
3504                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst,  "src");
3505
3506                 /* create AC3 decoder  */
3507                 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
3508                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "sink");
3509                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst,  "src");
3510         }
3511
3512         g_list_free(element_bucket);
3513
3514         /* take it */
3515         wfd_sink->pipeline->a_decodebin = a_decodebin;
3516
3517         /* link audio decodebin if audio codec is fixed */
3518         if (link) {
3519                 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
3520                         wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
3521                         __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
3522                         return MM_ERROR_WFD_INTERNAL;
3523                 }
3524         }
3525
3526         wfd_sink_debug_fleave();
3527
3528         return MM_ERROR_NONE;
3529
3530 CREATE_ERROR:
3531         wfd_sink_error("failed to create audio decodebin, release all");
3532
3533         g_list_free(element_bucket);
3534
3535         /* release element which are not added to bin */
3536         for (i = 1; i < WFD_SINK_A_D_NUM; i++) {        /* NOTE : skip bin */
3537                 if (a_decodebin != NULL && a_decodebin[i].gst) {
3538                         GstObject *parent = NULL;
3539                         parent = gst_element_get_parent(a_decodebin[i].gst);
3540
3541                         if (!parent) {
3542                                 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3543                                 a_decodebin[i].gst = NULL;
3544                         } else {
3545                                 gst_object_unref(GST_OBJECT(parent));
3546                                 parent = NULL;
3547                         }
3548                 }
3549         }
3550
3551         /* release audio decodebin with it's childs */
3552         if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) {
3553                 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3554                 a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3555         }
3556
3557         MMWFDSINK_FREEIF(a_decodebin);
3558
3559         return MM_ERROR_WFD_INTERNAL;
3560 }
3561
3562 static int  __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3563 {
3564         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3565         MMWFDSinkGstElement *a_sinkbin = NULL;
3566         GstObject *parent = NULL;
3567         int i;
3568
3569         wfd_sink_debug_fenter();
3570
3571         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3572
3573         if (wfd_sink->pipeline &&
3574             wfd_sink->pipeline->a_sinkbin &&
3575             wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3576                 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
3577         } else {
3578                 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
3579                 return MM_ERROR_NONE;
3580         }
3581
3582         parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
3583         if (!parent) {
3584                 wfd_sink_debug("audio sinkbin has no parent.. need to relase by itself");
3585
3586                 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
3587                         wfd_sink_debug("try to change state of audio sinkbin to NULL");
3588                         ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
3589                         if (ret != GST_STATE_CHANGE_SUCCESS) {
3590                                 wfd_sink_error("failed to change state of audio sinkbin to NULL");
3591                                 return MM_ERROR_WFD_INTERNAL;
3592                         }
3593                 }
3594
3595                 /* release element which are not added to bin */
3596                 for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
3597                         if (a_sinkbin[i].gst) {
3598                                 parent = gst_element_get_parent(a_sinkbin[i].gst);
3599                                 if (!parent) {
3600                                         wfd_sink_debug("unref %s(current ref %d)",
3601                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3602                                                                         ((GObject *) a_sinkbin[i].gst)->ref_count);
3603                                         gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3604                                         a_sinkbin[i].gst = NULL;
3605                                 } else {
3606                                         wfd_sink_debug("%s has parent.(current ref %d)",
3607                                                                         GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3608                                                                         ((GObject *) a_sinkbin[i].gst)->ref_count);
3609                                         gst_object_unref(GST_OBJECT(parent));
3610                                         parent = NULL;
3611                                 }
3612                         }
3613                 }
3614
3615                 /* release audio sinkbin with it's childs */
3616                 if (a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3617                         gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3618                         a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3619                 }
3620         } else {
3621                 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
3622                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3623
3624                 gst_object_unref(GST_OBJECT(parent));
3625                 parent = NULL;
3626         }
3627
3628         MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
3629
3630         wfd_sink_debug_fleave();
3631
3632         return MM_ERROR_NONE;
3633 }
3634
3635 int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3636 {
3637         MMWFDSinkGstElement *a_sinkbin = NULL;
3638         MMWFDSinkGstElement *first_element = NULL;
3639         GList *element_bucket = NULL;
3640         GstPad *ghostpad = NULL;
3641         GstPad *pad = NULL;
3642         gint i = 0;
3643         GList *list_temp = NULL;
3644
3645         wfd_sink_debug_fenter();
3646
3647         wfd_sink_return_val_if_fail(wfd_sink &&
3648                                                                 wfd_sink->pipeline,
3649                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3650
3651         if (wfd_sink->pipeline->a_sinkbin != NULL) {
3652                 wfd_sink_error("The audio sink bin is already created.");
3653                 return MM_ERROR_NONE;
3654         }
3655
3656         if (wfd_sink->stream_info.audio_stream_info.codec == MM_WFD_SINK_AUDIO_CODEC_NONE) {
3657                 wfd_sink_error("Skip create audio sink bin for non audio codec. %d", wfd_sink->stream_info.audio_stream_info.codec);
3658                 wfd_sink_debug_fleave();
3659                 return MM_ERROR_NONE;
3660         }
3661
3662         /* alloc handles */
3663         a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3664         if (!a_sinkbin) {
3665                 wfd_sink_error("failed to allocate memory for audio sinkbin");
3666                 return MM_ERROR_WFD_NO_FREE_SPACE;
3667         }
3668
3669         memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3670
3671         /* create audio sinkbin */
3672         a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
3673         a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
3674         if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3675                 wfd_sink_error("failed to create audio sinkbin");
3676                 goto CREATE_ERROR;
3677         }
3678
3679         /* create resampler */
3680         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER,
3681                                                         wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
3682         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "sink");
3683         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst,  "src");
3684
3685         /* create volume */
3686         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME,
3687                                                         wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
3688         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "sink");
3689         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst,  "src");
3690
3691         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_QUEUE,
3692                                                         wfd_sink->ini.name_of_audio_sinkbin_queue, "audio_sinkbin_queue", TRUE);
3693         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "sink");
3694         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst,  "src");
3695
3696         /* create sink */
3697         MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK,
3698                                                         wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
3699         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst,  "sink");
3700         if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
3701                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
3702                         wfd_sink_error("failed to set audio sink property....");
3703                         goto CREATE_ERROR;
3704                 }
3705         }
3706
3707         /* adding created elements to audio sinkbin */
3708         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
3709                 wfd_sink_error("failed to add elements to audio sinkbin");
3710                 goto CREATE_ERROR;
3711         }
3712
3713         /* linking elements in the bucket by added order. */
3714         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3715                 wfd_sink_error("failed to link elements fo the audio sinkbin");
3716                 goto CREATE_ERROR;
3717         }
3718
3719         /* get first element's of the audio sinkbin */
3720         list_temp = g_list_first(element_bucket);
3721         if (list_temp == NULL) {
3722                 wfd_sink_error("failed to get first list of the element_bucket");
3723                 goto CREATE_ERROR;
3724         }
3725
3726         first_element = (MMWFDSinkGstElement *)list_temp->data;
3727         if (!first_element) {
3728                 wfd_sink_error("failed to get first element of the audio sinkbin");
3729                 goto CREATE_ERROR;
3730         }
3731
3732         /* get first element's sinkpad for creating ghostpad */
3733         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3734         if (!pad) {
3735                 wfd_sink_error("failed to get sink pad from element(%s)",
3736                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3737                 goto CREATE_ERROR;
3738         }
3739
3740         ghostpad = gst_ghost_pad_new("sink", pad);
3741         if (!ghostpad) {
3742                 wfd_sink_error("failed to create ghostpad of audio sinkbin");
3743                 goto CREATE_ERROR;
3744         }
3745
3746         if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
3747                 wfd_sink_error("failed to add ghostpad to audio sinkbin");
3748                 goto CREATE_ERROR;
3749         }
3750         gst_object_unref(GST_OBJECT(pad));
3751         pad = NULL;
3752
3753         g_list_free(element_bucket);
3754         element_bucket = NULL;
3755
3756         /* take it */
3757         wfd_sink->pipeline->a_sinkbin = a_sinkbin;
3758
3759         wfd_sink_debug_fleave();
3760
3761         return MM_ERROR_NONE;
3762
3763 CREATE_ERROR:
3764         wfd_sink_error("failed to create audio sinkbin, releasing all");
3765
3766         if (pad) {
3767                 gst_object_unref(GST_OBJECT(pad));
3768                 pad = NULL;
3769         }
3770         if (ghostpad) {
3771                 gst_object_unref(GST_OBJECT(ghostpad));
3772                 ghostpad = NULL;
3773         }
3774         if (element_bucket) {
3775                 g_list_free(element_bucket);
3776                 element_bucket = NULL;
3777         }
3778
3779         /* release element which are not added to bin */
3780         for (i = 1; i < WFD_SINK_A_S_NUM; i++) {        /* NOTE : skip bin */
3781                 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
3782                         GstObject *parent = NULL;
3783                         parent = gst_element_get_parent(a_sinkbin[i].gst);
3784
3785                         if (!parent) {
3786                                 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3787                                 a_sinkbin[i].gst = NULL;
3788                         } else {
3789                                 gst_object_unref(GST_OBJECT(parent));
3790                                 parent = NULL;
3791                         }
3792                 }
3793         }
3794
3795         /* release audio sinkbin with it's childs */
3796         if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3797                 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3798                 a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3799         }
3800         MMWFDSINK_FREEIF(a_sinkbin);
3801
3802         return MM_ERROR_WFD_INTERNAL;
3803 }
3804
3805 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
3806 {
3807         MMWFDSinkGstElement *v_decodebin = NULL;
3808         MMWFDSinkGstElement *first_element = NULL;
3809         MMWFDSinkGstElement *last_element = NULL;
3810         GList *element_bucket = NULL;
3811         GList *list_temp = NULL;
3812         GstPad *sinkpad = NULL;
3813         GstPad *srcpad = NULL;
3814         GstPad *ghostpad = NULL;
3815
3816         wfd_sink_debug_fenter();
3817
3818         wfd_sink_return_val_if_fail(wfd_sink &&
3819                                                                 wfd_sink->pipeline &&
3820                                                                 wfd_sink->pipeline->v_decodebin &&
3821                                                                 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
3822                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
3823
3824         if (wfd_sink->video_decodebin_is_linked) {
3825                 wfd_sink_debug("video decodebin is already linked... nothing to do");
3826                 return MM_ERROR_NONE;
3827         }
3828
3829         /* take video decodebin */
3830         v_decodebin = wfd_sink->pipeline->v_decodebin;
3831
3832         /* check video queue */
3833         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3834                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
3835
3836         /* check video hdcp */
3837         if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
3838                 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
3839
3840         /* check video codec */
3841         switch (wfd_sink->stream_info.video_stream_info.codec) {
3842         case MM_WFD_SINK_VIDEO_CODEC_H264:
3843                 if (v_decodebin[WFD_SINK_V_D_H264_PARSE].gst)
3844                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_PARSE]);
3845                 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst)
3846                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_DEC]);
3847                 break;
3848
3849         case MM_WFD_SINK_VIDEO_CODEC_H265:
3850                 if (v_decodebin[WFD_SINK_V_D_H265_PARSE].gst)
3851                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_PARSE]);
3852                 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst)
3853                         element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_DEC]);
3854                 break;
3855
3856         default:
3857                 wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
3858                 return MM_ERROR_WFD_INTERNAL;
3859                 break;
3860         }
3861
3862         if (element_bucket == NULL) {
3863                 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
3864                 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3865                         wfd_sink_error("failed to destroy video decodebin");
3866                         goto fail_to_link;
3867                 }
3868                 goto done;
3869         }
3870
3871         /* adding elements to video decodebin */
3872         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
3873                 wfd_sink_error("failed to add elements to video decodebin");
3874                 goto fail_to_link;
3875         }
3876
3877         /* linking elements in the bucket by added order. */
3878         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3879                 wfd_sink_error("failed to link elements of the video decodebin");
3880                 goto fail_to_link;
3881         }
3882
3883         /* get first element's sinkpad for creating ghostpad */
3884         list_temp = g_list_first(element_bucket);
3885         if (list_temp == NULL) {
3886                 wfd_sink_error("failed to get first list of the element_bucket");
3887                 goto fail_to_link;
3888         }
3889
3890         first_element = (MMWFDSinkGstElement *)list_temp->data;
3891         if (!first_element) {
3892                 wfd_sink_error("failed to get first element of the video decodebin");
3893                 goto fail_to_link;
3894         }
3895
3896         sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3897         if (!sinkpad) {
3898                 wfd_sink_error("failed to get sink pad from element(%s)",
3899                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3900                 goto fail_to_link;
3901         }
3902
3903         ghostpad = gst_ghost_pad_new("sink", sinkpad);
3904         if (!ghostpad) {
3905                 wfd_sink_error("failed to create ghostpad of video decodebin");
3906                 goto fail_to_link;
3907         }
3908
3909         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3910                 wfd_sink_error("failed to add ghostpad to video decodebin");
3911                 goto fail_to_link;
3912         }
3913         gst_object_unref(GST_OBJECT(sinkpad));
3914         sinkpad = NULL;
3915
3916
3917         /* get last element's src for creating ghostpad */
3918         list_temp = g_list_last(element_bucket);
3919         if (list_temp == NULL) {
3920                 wfd_sink_error("failed to get last list of the element_bucket");
3921                 goto fail_to_link;
3922         }
3923
3924         last_element = (MMWFDSinkGstElement *)list_temp->data;
3925         if (!last_element) {
3926                 wfd_sink_error("failed to get last element of the video decodebin");
3927                 goto fail_to_link;
3928         }
3929
3930         srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3931         if (!srcpad) {
3932                 wfd_sink_error("failed to get src pad from element(%s)",
3933                                                 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3934                 goto fail_to_link;
3935         }
3936
3937         ghostpad = gst_ghost_pad_new("src", srcpad);
3938         if (!ghostpad) {
3939                 wfd_sink_error("failed to create ghostpad of video decodebin");
3940                 goto fail_to_link;
3941         }
3942
3943         if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3944                 wfd_sink_error("failed to add ghostpad to video decodebin");
3945                 goto fail_to_link;
3946         }
3947         gst_object_unref(GST_OBJECT(srcpad));
3948         srcpad = NULL;
3949
3950         g_list_free(element_bucket);
3951
3952 done:
3953         wfd_sink->video_decodebin_is_linked = TRUE;
3954
3955         wfd_sink_debug_fleave();
3956
3957         return MM_ERROR_NONE;
3958
3959         /* ERRORS*/
3960 fail_to_link:
3961         if (srcpad != NULL) {
3962                 gst_object_unref(GST_OBJECT(srcpad));
3963                 srcpad = NULL;
3964         }
3965
3966         if (sinkpad != NULL) {
3967                 gst_object_unref(GST_OBJECT(sinkpad));
3968                 sinkpad = NULL;
3969         }
3970
3971         if (element_bucket != NULL) {
3972                 g_list_free(element_bucket);
3973                 element_bucket = NULL;
3974         }
3975         return MM_ERROR_WFD_INTERNAL;
3976 }
3977
3978 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
3979 {
3980         wfd_sink_debug_fenter();
3981
3982         /* check video decoder is created */
3983         wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
3984         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
3985
3986         wfd_sink_debug_fleave();
3987
3988         return MM_ERROR_NONE;
3989 }
3990
3991 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
3992 {
3993         gboolean visible = TRUE;
3994         gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
3995
3996         wfd_sink_debug_fenter();
3997
3998         /* check videosink is created */
3999         wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
4000         wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
4001
4002         /* update display surface */
4003         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
4004         wfd_sink_info("check display surface type attribute: %d", surface_type);
4005         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
4006         wfd_sink_info("check display visible attribute: %d", visible);
4007
4008         if (FALSE == visible) {
4009                 wfd_sink_info("skipped to prepare video sink. display_visible is FALSE.");
4010                 g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
4011                 return MM_ERROR_NONE;
4012         }
4013
4014         /* configuring display */
4015         switch (surface_type) {
4016                 case MM_DISPLAY_SURFACE_EVAS: {
4017                                 void *object = NULL;
4018                                 gint scaling = 0;
4019
4020                                 /* common case if using evas surface */
4021                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
4022                                 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
4023                                 if (object) {
4024                                         wfd_sink_debug("set video param : evas-object %x", object);
4025                                         g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
4026                                 } else {
4027                                         wfd_sink_error("no evas object");
4028                                         return MM_ERROR_WFD_INTERNAL;
4029                                 }
4030                         }
4031                         break;
4032
4033                 case MM_DISPLAY_SURFACE_OVERLAY: {
4034                                 static unsigned int wl_surface_id = 0;
4035                                 static void *display_overlay = NULL;
4036                                 int wl_window_x = 0;
4037                                 int wl_window_y = 0;
4038                                 int wl_window_width = 0;
4039                                 int wl_window_height = 0;
4040                                 struct wl_surface *wl_surface = NULL;
4041                                 struct wl_display *wl_display = NULL;
4042                                 Ecore_Wl_Window *wl_window = NULL;
4043                                 wl_client *wlclient = NULL;
4044                                 Evas_Object *obj = NULL;
4045                                 void *object = NULL;
4046                                 const char *object_type = NULL;
4047                                 int ret = 0;
4048
4049                                 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
4050
4051                                 if (object != NULL) {
4052                                         obj = (Evas_Object *)object;
4053                                         object_type = evas_object_type_get(obj);
4054                                         wfd_sink_debug("window object type : %s", object_type);
4055
4056                                         /* wayland overlay surface */
4057                                         LOGI("Wayland overlay surface type");
4058                                         evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height);
4059
4060                                         wfd_sink_debug("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y,
4061                                                                         wl_window_width, wl_window_height);
4062
4063                                         wl_window = elm_win_wl_window_get(obj);
4064                                         wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window);
4065
4066                                         /* get wl_display */
4067                                         wl_display = (struct wl_display *) ecore_wl_display_get();
4068
4069                                         wfd_sink_debug("previous display object : %p current object : %p", display_overlay, object);
4070                                         if (wl_surface && wl_display && (wl_surface_id == 0 || display_overlay != object)) {
4071                                                 wfd_sink_debug("surface = %p, wl_display = %p", wl_surface, wl_display);
4072                                                 display_overlay = object;
4073
4074                                                 ret = mm_wfd_sink_wlclient_create(&wlclient);
4075                                                 if (ret != MM_ERROR_NONE) {
4076                                                         wfd_sink_error("Wayland client create failure");
4077                                                         return ret;
4078                                                 }
4079                                                 wfd_sink_debug("Try to get surface id");
4080
4081                                                 wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id(wlclient, wl_surface, wl_display);
4082
4083                                                 wfd_sink_debug("wl_surface_id = %d", wl_surface_id);
4084
4085                                                 if (wlclient) {
4086                                                         g_free(wlclient);
4087                                                         wlclient = NULL;
4088                                                 }
4089                                         }
4090                                         wfd_sink_debug("set video param : surface_id %d", wl_surface_id);
4091
4092                                         if (USE_EXTERNAL_WL_DISPLAY_HANDLE) {
4093                                                 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink),
4094                                                                                                                 wl_surface_id);
4095                                         } else {
4096                                                 gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(video_sink),
4097                                                                                                                                 wl_surface_id);
4098                                         }
4099
4100                                         /* After setting window handle, set render rectangle */
4101                                         gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink),
4102                                                                                                                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
4103                                 } else {
4104                                         wfd_sink_debug("display object is NULL!");
4105                                         return MM_ERROR_WFD_INTERNAL;
4106                                 }
4107                         }
4108                         break;
4109
4110                 case MM_DISPLAY_SURFACE_NULL: {
4111                                 /* do nothing */
4112                                 wfd_sink_error("Not Supported Surface.");
4113                                 return MM_ERROR_WFD_INTERNAL;
4114                         }
4115                         break;
4116                 default: {
4117                                 wfd_sink_error("Not Supported Surface.(default case)");
4118                                 return MM_ERROR_WFD_INTERNAL;
4119                         }
4120                         break;
4121         }
4122
4123         g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
4124         g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
4125         g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
4126         g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
4127         g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
4128
4129         wfd_sink_debug_fleave();
4130
4131         return MM_ERROR_NONE;
4132 }
4133
4134 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
4135 {
4136         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4137         MMWFDSinkGstElement *v_decodebin = NULL;
4138         GstObject *parent = NULL;
4139         int i;
4140
4141         wfd_sink_debug_fenter();
4142
4143         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4144
4145         if (wfd_sink->pipeline &&
4146             wfd_sink->pipeline->v_decodebin &&
4147             wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4148                 v_decodebin = wfd_sink->pipeline->v_decodebin;
4149         } else {
4150                 wfd_sink_debug("video decodebin is not created, nothing to destroy");
4151                 return MM_ERROR_NONE;
4152         }
4153
4154
4155         parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
4156         if (!parent) {
4157                 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
4158
4159                 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
4160                         wfd_sink_debug("try to change state of video decodebin to NULL");
4161                         ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
4162                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4163                                 wfd_sink_error("failed to change state of video decodebin to NULL");
4164                                 return MM_ERROR_WFD_INTERNAL;
4165                         }
4166                 }
4167                 /* release element which are not added to bin */
4168                 for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
4169                         if (v_decodebin[i].gst) {
4170                                 parent = gst_element_get_parent(v_decodebin[i].gst);
4171                                 if (!parent) {
4172                                         wfd_sink_debug("unref %s(current ref %d)",
4173                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4174                                                                         ((GObject *) v_decodebin[i].gst)->ref_count);
4175                                         gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4176                                         v_decodebin[i].gst = NULL;
4177                                 } else {
4178                                         wfd_sink_debug("%s has parent.(current ref %d)",
4179                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4180                                                                         ((GObject *) v_decodebin[i].gst)->ref_count);
4181                                         gst_object_unref(GST_OBJECT(parent));
4182                                         parent = NULL;
4183                                 }
4184                         }
4185                 }
4186                 /* release video decodebin with it's childs */
4187                 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
4188                         wfd_sink_debug("unref %s(current ref %d)",
4189                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
4190                                                         ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
4191
4192                         gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4193                         v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4194                 }
4195         } else {
4196                 wfd_sink_debug("video decodebin has parent(%s), unref it",
4197                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4198
4199                 gst_object_unref(GST_OBJECT(parent));
4200                 parent = NULL;
4201         }
4202
4203         wfd_sink->video_decodebin_is_linked = FALSE;
4204
4205         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
4206
4207         wfd_sink_debug_fleave();
4208
4209         return MM_ERROR_NONE;
4210 }
4211
4212 int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
4213 {
4214         MMWFDSinkGstElement *v_decodebin = NULL;
4215         guint video_codec = WFD_VIDEO_UNKNOWN;
4216         GList *element_bucket = NULL;
4217         gboolean link = TRUE;
4218         gint i = 0;
4219
4220         wfd_sink_debug_fenter();
4221
4222         wfd_sink_return_val_if_fail(wfd_sink &&
4223                                                                 wfd_sink->pipeline,
4224                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
4225
4226         if (wfd_sink->pipeline->v_decodebin) {
4227                 wfd_sink_debug("video decodebin is already created... nothing to do");
4228                 return MM_ERROR_NONE;
4229         }
4230
4231         /* check video decodebin could be linked now */
4232         switch (wfd_sink->stream_info.video_stream_info.codec) {
4233         case MM_WFD_SINK_VIDEO_CODEC_H264:
4234                 video_codec = WFD_VIDEO_H264;
4235                 link = TRUE;
4236                 break;
4237         case MM_WFD_SINK_VIDEO_CODEC_H265:
4238                 video_codec = WFD_VIDEO_H265;
4239                 link = TRUE;
4240                 break;
4241         case MM_WFD_SINK_VIDEO_CODEC_NONE:
4242         default:
4243                 wfd_sink_debug("video decodebin could NOT be linked now, just create");
4244                 video_codec = wfd_sink->ini.wfd_video_formats.video_codec | wfd_sink->ini.wfd2_video_formats.video_codec;
4245                 link = FALSE;
4246                 break;
4247         }
4248
4249         /* alloc handles */
4250         v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4251         if (!v_decodebin) {
4252                 wfd_sink_error("failed to allocate memory for video decodebin");
4253                 return MM_ERROR_WFD_NO_FREE_SPACE;
4254         }
4255
4256         memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4257
4258         /* create video decodebin */
4259         v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
4260         v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
4261         if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
4262                 wfd_sink_error("failed to create video decodebin");
4263                 goto CREATE_ERROR;
4264         }
4265
4266         /* create queue */
4267         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
4268         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "sink");
4269         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst,  "src");
4270         if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
4271                 __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
4272
4273         /* create hdcp */
4274         MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
4275         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "sink");
4276         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst,  "src");
4277
4278         if (video_codec & WFD_VIDEO_H264) {
4279                 /* create parser */
4280                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h264_parser", FALSE);
4281                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "sink");
4282                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst,  "src");
4283
4284                 /* create dec */
4285                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_DEC, wfd_sink->ini.name_of_video_h264_decoder, "video_h264_dec", FALSE);
4286                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "sink");
4287                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst,  "src");
4288                 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst) {
4289                         if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H264_DEC].gst)) {
4290                                 wfd_sink_error("failed to set video decoder property...");
4291                                 goto CREATE_ERROR;
4292                         }
4293                 }
4294         }
4295
4296         if (video_codec & WFD_VIDEO_H265) {
4297                 /* create parser */
4298                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h265_parser", FALSE);
4299                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "sink");
4300                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst,  "src");
4301
4302                 /* create dec */
4303                 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_DEC, wfd_sink->ini.name_of_video_h265_decoder, "video_h265_dec", FALSE);
4304                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "sink");
4305                 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst,  "src");
4306                 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst) {
4307                         if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H265_DEC].gst)) {
4308                                 wfd_sink_error("failed to set video decoder property...");
4309                                 goto CREATE_ERROR;
4310                         }
4311                 }
4312         }
4313
4314         g_list_free(element_bucket);
4315
4316         /* take it */
4317         wfd_sink->pipeline->v_decodebin = v_decodebin;
4318
4319         /* link video decodebin if video codec is fixed */
4320         if (link) {
4321                 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
4322                         wfd_sink_error("failed to link video decodebin, destroy video decodebin");
4323                         __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
4324                         return MM_ERROR_WFD_INTERNAL;
4325                 }
4326         }
4327
4328         wfd_sink_debug_fleave();
4329
4330         return MM_ERROR_NONE;
4331
4332         /* ERRORS */
4333 CREATE_ERROR:
4334         wfd_sink_error("failed to create video decodebin, releasing all");
4335
4336         g_list_free(element_bucket);
4337
4338         /* release element which are not added to bin */
4339         for (i = 1; i < WFD_SINK_V_D_NUM; i++) {        /* NOTE : skip bin */
4340                 if (v_decodebin != NULL && v_decodebin[i].gst) {
4341                         GstObject *parent = NULL;
4342                         parent = gst_element_get_parent(v_decodebin[i].gst);
4343
4344                         if (!parent) {
4345                                 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4346                                 v_decodebin[i].gst = NULL;
4347                         } else {
4348                                 gst_object_unref(GST_OBJECT(parent));
4349                                 parent = NULL;
4350                         }
4351                 }
4352         }
4353
4354         /* release video decodebin with it's childs */
4355         if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) {
4356                 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4357                 v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4358         }
4359
4360         MMWFDSINK_FREEIF(v_decodebin);
4361
4362         return MM_ERROR_WFD_INTERNAL;
4363 }
4364
4365 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4366 {
4367         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4368         MMWFDSinkGstElement *v_sinkbin = NULL;
4369         GstObject *parent = NULL;
4370         int i;
4371
4372         wfd_sink_debug_fenter();
4373
4374         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4375
4376         if (wfd_sink->pipeline &&
4377             wfd_sink->pipeline->v_sinkbin &&
4378             wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4379                 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4380         } else {
4381                 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
4382                 return MM_ERROR_NONE;
4383         }
4384
4385
4386         parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
4387         if (!parent) {
4388                 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
4389
4390                 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
4391                         wfd_sink_debug("try to change state of video sinkbin to NULL");
4392                         ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
4393                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4394                                 wfd_sink_error("failed to change state of video sinkbin to NULL");
4395                                 return MM_ERROR_WFD_INTERNAL;
4396                         }
4397                 }
4398                 /* release element which are not added to bin */
4399                 for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
4400                         if (v_sinkbin[i].gst) {
4401                                 parent = gst_element_get_parent(v_sinkbin[i].gst);
4402                                 if (!parent) {
4403                                         wfd_sink_debug("unref %s(current ref %d)",
4404                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4405                                                                         ((GObject *) v_sinkbin[i].gst)->ref_count);
4406                                         gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4407                                         v_sinkbin[i].gst = NULL;
4408                                 } else {
4409                                         wfd_sink_debug("%s has parent.(current ref %d)",
4410                                                                         GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4411                                                                         ((GObject *) v_sinkbin[i].gst)->ref_count);
4412                                         gst_object_unref(GST_OBJECT(parent));
4413                                         parent = NULL;
4414                                 }
4415                         }
4416                 }
4417                 /* release video sinkbin with it's childs */
4418                 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4419                         gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4420                         v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4421                 }
4422         } else {
4423                 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
4424                                                 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4425
4426                 gst_object_unref(GST_OBJECT(parent));
4427                 parent = NULL;
4428         }
4429
4430         MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
4431
4432         wfd_sink_debug_fleave();
4433
4434         return MM_ERROR_NONE;
4435 }
4436
4437 int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4438 {
4439         MMWFDSinkGstElement *first_element = NULL;
4440         MMWFDSinkGstElement *v_sinkbin = NULL;
4441         GList *element_bucket = NULL;
4442         GstPad *pad = NULL;
4443         GstPad *ghostpad = NULL;
4444         gint i = 0;
4445         gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
4446
4447         wfd_sink_debug_fenter();
4448
4449         wfd_sink_return_val_if_fail(wfd_sink &&
4450                                                                 wfd_sink->pipeline,
4451                                                                 MM_ERROR_WFD_NOT_INITIALIZED);
4452
4453         if (wfd_sink->pipeline->v_sinkbin != NULL) {
4454                 wfd_sink_error("The video sink bin is already created.");
4455                 return MM_ERROR_NONE;
4456         }
4457
4458         /* alloc handles */
4459         v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4460         if (!v_sinkbin) {
4461                 wfd_sink_error("failed to allocate memory for video sinkbin");
4462                 return MM_ERROR_WFD_NO_FREE_SPACE;
4463         }
4464
4465         memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4466
4467         /* create video sinkbin */
4468         v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
4469         v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
4470         if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4471                 wfd_sink_error("failed to create video sinkbin");
4472                 goto CREATE_ERROR;
4473         }
4474
4475         /* create convert */
4476         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
4477         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "sink");
4478         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst,  "src");
4479
4480         /* create filter */
4481         MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
4482         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "sink");
4483         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst,  "src");
4484         if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
4485                 GstCaps *caps = NULL;
4486                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL);
4487                 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
4488                 gst_object_unref(GST_OBJECT(caps));
4489                 caps = NULL;
4490         }
4491
4492         /* create sink */
4493         mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
4494
4495         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
4496                 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
4497         } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) {
4498                 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE);
4499         } else {
4500                 wfd_sink_error("failed to set video sink....");
4501                 goto CREATE_ERROR;
4502         }
4503
4504         MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst,  "sink");
4505         if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
4506                 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
4507                         wfd_sink_error("failed to set video sink property....");
4508                         goto CREATE_ERROR;
4509                 }
4510         }
4511
4512         /* adding created elements to video sinkbin */
4513         if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
4514                 wfd_sink_error("failed to add elements to video sinkbin");
4515                 goto CREATE_ERROR;
4516         }
4517
4518         /* linking elements in the bucket by added order. */
4519         if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
4520                 wfd_sink_error("failed to link elements of the video sinkbin");
4521                 goto CREATE_ERROR;
4522         }
4523
4524         /* get first element's sinkpad for creating ghostpad */
4525         first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
4526         if (!first_element) {
4527                 wfd_sink_error("failed to get first element of the video sinkbin");
4528                 goto CREATE_ERROR;
4529         }
4530
4531         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4532         if (!pad) {
4533                 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
4534                                                 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
4535                 goto CREATE_ERROR;
4536         }
4537
4538         ghostpad = gst_ghost_pad_new("sink", pad);
4539         if (!ghostpad) {
4540                 wfd_sink_error("failed to create ghostpad of the video sinkbin");
4541                 goto CREATE_ERROR;
4542         }
4543
4544         if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
4545                 wfd_sink_error("failed to add ghostpad to video sinkbin");
4546                 goto CREATE_ERROR;
4547         }
4548
4549         gst_object_unref(GST_OBJECT(pad));
4550         pad = NULL;
4551
4552         g_list_free(element_bucket);
4553         element_bucket = NULL;
4554
4555         /* take it */
4556         wfd_sink->pipeline->v_sinkbin = v_sinkbin;
4557
4558         wfd_sink_debug_fleave();
4559
4560         return MM_ERROR_NONE;
4561
4562         /* ERRORS */
4563 CREATE_ERROR:
4564         wfd_sink_error("failed to create video sinkbin, releasing all");
4565
4566         if (pad) {
4567                 gst_object_unref(GST_OBJECT(pad));
4568                 pad = NULL;
4569         }
4570
4571         if (ghostpad) {
4572                 gst_object_unref(GST_OBJECT(ghostpad));
4573                 ghostpad = NULL;
4574         }
4575
4576         if (element_bucket) {
4577                 g_list_free(element_bucket);
4578                 element_bucket = NULL;
4579         }
4580
4581         /* release element which are not added to bin */
4582         for (i = 1; i < WFD_SINK_V_S_NUM; i++) {        /* NOTE : skip bin */
4583                 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
4584                         GstObject *parent = NULL;
4585                         parent = gst_element_get_parent(v_sinkbin[i].gst);
4586
4587                         if (!parent) {
4588                                 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4589                                 v_sinkbin[i].gst = NULL;
4590                         } else {
4591                                 gst_object_unref(GST_OBJECT(parent));
4592                                 parent = NULL;
4593                         }
4594                 }
4595         }
4596
4597         /* release video sinkbin with it's childs */
4598         if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4599                 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4600                 v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4601         }
4602         MMWFDSINK_FREEIF(v_sinkbin);
4603
4604         return MM_ERROR_WFD_INTERNAL;
4605 }
4606
4607 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
4608 {
4609         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4610         GstBus *bus = NULL;
4611
4612         wfd_sink_debug_fenter();
4613
4614         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4615
4616         /* cleanup gst stuffs */
4617         if (wfd_sink->pipeline) {
4618                 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
4619
4620                 if (mainbin) {
4621
4622                         PRINT_WFD_REF_COUNT(wfd_sink);
4623
4624                         ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
4625                         if (ret != GST_STATE_CHANGE_SUCCESS) {
4626                                 wfd_sink_error("failed to change state of pipeline to NULL");
4627                                 return MM_ERROR_WFD_INTERNAL;
4628                         } else {
4629                                 wfd_sink_debug("Successed to change state of pipeline to NULL");
4630                         }
4631
4632                         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
4633                         if (bus) {
4634                                 GstMessage *gst_msg = NULL;
4635                                 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
4636                                         _mm_wfd_sink_msg_callback(bus, gst_msg, (gpointer)wfd_sink);
4637                                         gst_message_unref(gst_msg);
4638                                         gst_msg = NULL;
4639                                 }
4640                                 gst_object_unref(bus);
4641                                 bus = NULL;
4642                         }
4643
4644                         PRINT_WFD_REF_COUNT(wfd_sink);
4645
4646                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
4647                                 wfd_sink_error("failed to destroy video decodebin");
4648                                 return MM_ERROR_WFD_INTERNAL;
4649                         }
4650
4651                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
4652                                 wfd_sink_error("failed to destroy audio decodebin");
4653                                 return MM_ERROR_WFD_INTERNAL;
4654                         }
4655
4656                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
4657                                 wfd_sink_error("failed to destroy video sinkbin");
4658                                 return MM_ERROR_WFD_INTERNAL;
4659                         }
4660
4661                         if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
4662                                 wfd_sink_error("failed to destroy audio sinkbin");
4663                                 return MM_ERROR_WFD_INTERNAL;
4664                         }
4665
4666                         gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
4667                         mainbin[WFD_SINK_M_PIPE].gst = NULL;
4668
4669                         MMWFDSINK_FREEIF(mainbin);
4670                 }
4671
4672                 MMWFDSINK_FREEIF(wfd_sink->pipeline);
4673         }
4674
4675         if (wfd_sink->msg_callback_id > 0) {
4676                 g_source_remove(wfd_sink->msg_callback_id);
4677                 wfd_sink->msg_callback_id = 0;
4678         }
4679
4680         wfd_sink->audio_decodebin_is_linked = FALSE;
4681         wfd_sink->video_decodebin_is_linked = FALSE;
4682         wfd_sink->need_to_reset_basetime = FALSE;
4683
4684         wfd_sink_debug_fleave();
4685
4686         return MM_ERROR_NONE;
4687 }
4688
4689 static void
4690 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
4691 {
4692         GstIterator *iter = NULL;
4693         gboolean done = FALSE;
4694
4695         GstElement *item = NULL;
4696         GstElementFactory *factory = NULL;
4697
4698         GstState state = GST_STATE_VOID_PENDING;
4699         GstState pending = GST_STATE_VOID_PENDING;
4700         GstClockTime time = 200 * GST_MSECOND;
4701
4702         wfd_sink_debug_fenter();
4703
4704         wfd_sink_return_if_fail(wfd_sink &&
4705                                                         wfd_sink->pipeline &&
4706                                                         wfd_sink->pipeline->mainbin &&
4707                                                         wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4708
4709         iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
4710
4711         if (iter != NULL) {
4712                 while (!done) {
4713                         switch (gst_iterator_next(iter, (gpointer)&item)) {
4714                         case GST_ITERATOR_OK:
4715                                 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4716
4717                                 factory = gst_element_get_factory(item) ;
4718                                 if (factory) {
4719                                         wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4720                                                 GST_STR_NULL(GST_OBJECT_NAME(factory)),
4721                                                 GST_STR_NULL(GST_ELEMENT_NAME(item)),
4722                                                 gst_element_state_get_name(state),
4723                                                 gst_element_state_get_name(pending),
4724                                                 GST_OBJECT_REFCOUNT_VALUE(item));
4725                                 }
4726                                 gst_object_unref(item);
4727                                 item = NULL;
4728                                 break;
4729                         case GST_ITERATOR_RESYNC:
4730                                 gst_iterator_resync(iter);
4731                                 break;
4732                         case GST_ITERATOR_ERROR:
4733                                 done = TRUE;
4734                                 break;
4735                         case GST_ITERATOR_DONE:
4736                                 done = TRUE;
4737                                 break;
4738                         default:
4739                                 done = TRUE;
4740                                 break;
4741                         }
4742                 }
4743         }
4744
4745         item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4746
4747         gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4748
4749         factory = gst_element_get_factory(item) ;
4750         if (factory) {
4751                 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4752                                                 GST_OBJECT_NAME(factory),
4753                                                 GST_ELEMENT_NAME(item),
4754                                                 gst_element_state_get_name(state),
4755                                                 gst_element_state_get_name(pending),
4756                                                 GST_OBJECT_REFCOUNT_VALUE(item));
4757         }
4758
4759         if (iter)
4760                 gst_iterator_free(iter);
4761
4762         wfd_sink_debug_fleave();
4763
4764         return;
4765 }
4766
4767 const gchar *
4768 _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
4769 {
4770         switch (state) {
4771         case MM_WFD_SINK_STATE_NONE:
4772                 return "NONE";
4773         case MM_WFD_SINK_STATE_NULL:
4774                 return "NULL";
4775         case MM_WFD_SINK_STATE_PREPARED:
4776                 return "PREPARED";
4777         case MM_WFD_SINK_STATE_CONNECTED:
4778                 return "CONNECTED";
4779         case MM_WFD_SINK_STATE_PLAYING:
4780                 return "PLAYING";
4781         case MM_WFD_SINK_STATE_PAUSED:
4782                 return "PAUSED";
4783         case MM_WFD_SINK_STATE_DISCONNECTED:
4784                 return "DISCONNECTED";
4785         default:
4786                 return "INVAID";
4787         }
4788 }
4789
4790 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
4791 {
4792         MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
4793
4794         wfd_sink_debug_fenter();
4795
4796         wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4797
4798         MMWFDSINK_PRINT_STATE(wfd_sink);
4799         cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
4800         if (cur_state != MM_WFD_SINK_STATE_NULL) {
4801                 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
4802                 return MM_ERROR_WFD_INVALID_STATE;
4803         }
4804
4805         wfd_sink->supportive_resolution = resolution;
4806
4807         wfd_sink_debug_fleave();
4808
4809         return MM_ERROR_NONE;
4810 }
4811
4812 void __mm_wfd_sink_print_ref_count(mm_wfd_sink_t *wfd_sink)
4813 {
4814         int i = 0;
4815         MMWFDSinkGstElement *mainbin = NULL;
4816         MMWFDSinkGstElement *v_decodebin = NULL;
4817         MMWFDSinkGstElement *a_decodebin = NULL;
4818         MMWFDSinkGstElement *v_sinkbin = NULL;
4819         MMWFDSinkGstElement *a_sinkbin = NULL;
4820
4821         wfd_sink_debug_fenter();
4822
4823         wfd_sink_return_if_fail(wfd_sink);
4824         wfd_sink_return_if_fail(wfd_sink->pipeline);
4825
4826         wfd_sink_debug("************* wfd pipeline ref count start *************");
4827         wfd_sink_debug("try to check mainbin");
4828
4829         if (wfd_sink->pipeline->mainbin &&
4830             wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) {
4831                 mainbin = wfd_sink->pipeline->mainbin;
4832
4833                 for (i = 0; i < WFD_SINK_M_NUM; i++) {
4834                         if (mainbin[i].gst) {
4835                                 wfd_sink_debug("%s(current ref %d)",
4836                                                                 GST_ELEMENT_NAME(mainbin[i].gst),
4837                                                                 GST_OBJECT_REFCOUNT(mainbin[i].gst));
4838                         }
4839                 }
4840         }
4841
4842         wfd_sink_debug("try to check a_decodebin");
4843
4844         if (wfd_sink->pipeline->a_decodebin &&
4845             wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
4846                 a_decodebin = wfd_sink->pipeline->a_decodebin;
4847
4848                 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
4849                         if (a_decodebin[i].gst) {
4850                                 wfd_sink_debug("%s(current ref %d)",
4851                                                                 GST_ELEMENT_NAME(a_decodebin[i].gst),
4852                                                                 GST_OBJECT_REFCOUNT(a_decodebin[i].gst));
4853                         }
4854                 }
4855         }
4856
4857         wfd_sink_debug("try to check a_sinkbin");
4858
4859         if (wfd_sink->pipeline->a_sinkbin &&
4860             wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
4861                 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
4862
4863                 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
4864                         if (a_sinkbin[i].gst) {
4865                                 wfd_sink_debug("%s(current ref %d)",
4866                                                                 GST_ELEMENT_NAME(a_sinkbin[i].gst),
4867                                                                 GST_OBJECT_REFCOUNT(a_sinkbin[i].gst));
4868                         }
4869                 }
4870         }
4871
4872         wfd_sink_debug("try to check v_decodebin");
4873
4874         if (wfd_sink->pipeline->v_decodebin &&
4875             wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4876                 v_decodebin = wfd_sink->pipeline->v_decodebin;
4877
4878                 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
4879                         if (v_decodebin[i].gst) {
4880                                 wfd_sink_debug("%s(current ref %d)",
4881                                                                 GST_ELEMENT_NAME(v_decodebin[i].gst),
4882                                                                 GST_OBJECT_REFCOUNT(v_decodebin[i].gst));
4883                         }
4884                 }
4885         }
4886
4887         wfd_sink_debug("try to check v_sinkbin");
4888
4889         if (wfd_sink->pipeline->v_sinkbin &&
4890             wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4891                 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4892
4893                 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
4894                         if (v_sinkbin[i].gst) {
4895                                 wfd_sink_debug("%s(current ref %d)",
4896                                                                 GST_ELEMENT_NAME(v_sinkbin[i].gst),
4897                                                                 GST_OBJECT_REFCOUNT(v_sinkbin[i].gst));
4898                         }
4899                 }
4900         }
4901         wfd_sink_debug("************* wfd pipeline ref count end *************");
4902         wfd_sink_debug_fleave();
4903 }