4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <gst/video/videooverlay.h>
26 #include "mm_wfd_sink_util.h"
27 #include "mm_wfd_sink_priv.h"
28 #include "mm_wfd_sink_manager.h"
29 #include "mm_wfd_sink_dlog.h"
33 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
34 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
35 static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink);
36 static int __mm_wfd_sink_create_audiobin(mm_wfd_sink_t *wfd_sink);
37 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t* wfd_sink);
38 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t* wfd_sink, GstState state, gboolean async);
41 static int __mm_wfd_sink_check_state(mm_wfd_sink_t* wfd_sink, MMWFDSinkCommandType cmd);
42 static int __mm_wfd_sink_set_state(mm_wfd_sink_t* wfd_sink, MMWFDSinkStateType state);
45 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
46 const gchar * __mm_wfds_sink_get_state_name ( MMWFDSinkStateType state );
48 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
50 int result = MM_ERROR_NONE;
52 wfd_sink_debug_fenter();
54 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
56 mm_wfd_sink_t *new_wfd_sink = NULL;
59 new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
62 wfd_sink_error("failed to allocate memory for wi-fi display sink\n");
63 return MM_ERROR_WFD_NO_FREE_SPACE;
66 /* Initialize gstreamer related */
67 new_wfd_sink->attrs = 0;
69 new_wfd_sink->pipeline = NULL;
70 new_wfd_sink->added_av_pad_num = 0;
71 new_wfd_sink->audio_bin_is_linked = FALSE;
72 new_wfd_sink->video_bin_is_linked = FALSE;
73 new_wfd_sink->prev_audio_dec_src_pad = NULL;
74 new_wfd_sink->next_audio_dec_sink_pad = NULL;
76 /* Initialize timestamp compensation related */
77 new_wfd_sink->need_to_reset_basetime = FALSE;
78 new_wfd_sink->clock = NULL;
79 new_wfd_sink->video_buffer_count = 0LL;
80 new_wfd_sink->video_average_gap = 0LL;
81 new_wfd_sink->video_accumulated_gap = 0LL;
82 new_wfd_sink->audio_buffer_count = 0LL;
83 new_wfd_sink->audio_average_gap = 0LL;
84 new_wfd_sink->audio_accumulated_gap = 0LL;
85 new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
87 /* Initialize all states */
88 MMWFDSINK_CURRENT_STATE (new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
89 MMWFDSINK_PREVIOUS_STATE (new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
90 MMWFDSINK_PENDING_STATE (new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
92 /* initialize audio/video information */
93 new_wfd_sink->stream_info.audio_stream_info.codec = WFD_SINK_AUDIO_CODEC_NONE;
94 new_wfd_sink->stream_info.audio_stream_info.channels = 0;
95 new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
96 new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
97 new_wfd_sink->stream_info.video_stream_info.codec = WFD_SINK_VIDEO_CODEC_NONE;
98 new_wfd_sink->stream_info.video_stream_info.width = 0;
99 new_wfd_sink->stream_info.video_stream_info.height = 0;
100 new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
102 /* Initialize command */
103 new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
104 new_wfd_sink->waiting_cmd = FALSE;
106 /* Initialize resource related */
107 new_wfd_sink->resource_list = NULL;
109 /* Initialize manager related */
110 new_wfd_sink->manager_thread = NULL;
111 new_wfd_sink->manager_thread_cmd = WFD_SINK_MANAGER_CMD_NONE;
113 /* construct attributes */
114 new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
115 if (!new_wfd_sink->attrs)
117 MMWFDSINK_FREEIF (new_wfd_sink);
118 wfd_sink_error("failed to set attribute\n");
119 return MM_ERROR_WFD_INTERNAL;
122 /* load ini for initialize */
123 result = mm_wfd_sink_ini_load(&new_wfd_sink->ini);
124 if (result != MM_ERROR_NONE)
126 wfd_sink_error("failed to load ini file\n");
127 goto fail_to_load_ini;
129 new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
131 /* initialize manager */
132 result = _mm_wfd_sink_init_manager(new_wfd_sink);
133 if (result < MM_ERROR_NONE)
135 wfd_sink_error("failed to init manager : %d\n", result);
139 /* initialize gstreamer */
140 result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
141 if (result < MM_ERROR_NONE)
143 wfd_sink_error("failed to init gstreamer : %d\n", result);
148 __mm_wfd_sink_set_state(new_wfd_sink, MM_WFD_SINK_STATE_NULL);
150 /* now take handle */
151 *wfd_sink = new_wfd_sink;
153 wfd_sink_debug_fleave();
159 mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
161 _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
162 MMWFDSINK_FREEIF (new_wfd_sink);
169 int _mm_wfd_sink_prepare (mm_wfd_sink_t *wfd_sink)
171 int result = MM_ERROR_NONE;
173 wfd_sink_debug_fenter();
175 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
177 /* check current wi-fi display sink state */
178 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
180 /* construct pipeline */
181 /* create main pipeline */
182 result = __mm_wfd_sink_create_pipeline(wfd_sink);
183 if (result < MM_ERROR_NONE)
185 wfd_sink_error("failed to create pipeline : %d\n", result);
189 /* create videobin */
190 result = __mm_wfd_sink_create_videobin(wfd_sink);
191 if (result < MM_ERROR_NONE)
193 wfd_sink_error("failed to create videobin : %d\n", result);
197 /* create audiobin */
198 result = __mm_wfd_sink_create_audiobin(wfd_sink);
199 if (result < MM_ERROR_NONE)
201 wfd_sink_error("fail to create audiobin : %d\n", result);
205 /* set pipeline READY state */
206 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
207 if (result < MM_ERROR_NONE)
209 wfd_sink_error("failed to set state : %d\n", result);
214 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PREPARED);
216 wfd_sink_debug_fleave();
222 /* need to destroy pipeline already created */
223 __mm_wfd_sink_destroy_pipeline(wfd_sink);
227 int _mm_wfd_sink_connect (mm_wfd_sink_t *wfd_sink, const char *uri)
229 int result = MM_ERROR_NONE;
231 wfd_sink_debug_fenter();
233 wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
234 MM_ERROR_WFD_INVALID_ARGUMENT);
235 wfd_sink_return_val_if_fail (wfd_sink &&
236 wfd_sink->pipeline &&
237 wfd_sink->pipeline->mainbin &&
238 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
239 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
240 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
241 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
242 MM_ERROR_WFD_NOT_INITIALIZED);
244 /* check current wi-fi display sink state */
245 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
247 wfd_sink_debug ("try to connect to %s.....\n", GST_STR_NULL(uri));
249 /* set uri to wfdrtspsrc */
250 g_object_set (G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
252 /* set pipeline PAUSED state */
253 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
254 if (result < MM_ERROR_NONE)
256 wfd_sink_error("failed to set state : %d\n", result);
260 wfd_sink_debug_fleave();
265 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
267 int result = MM_ERROR_NONE;
269 wfd_sink_debug_fenter();
271 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
273 /* check current wi-fi display sink state */
274 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_START);
276 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
277 wfd_sink_debug("check pipeline is ready to start");
278 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
280 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
281 if (result < MM_ERROR_NONE)
283 wfd_sink_error("failed to set state : %d\n", result);
287 wfd_sink_debug_fleave();
292 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
294 int result = MM_ERROR_NONE;
296 wfd_sink_debug_fenter();
298 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
300 /* check current wi-fi display sink state */
301 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
303 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
304 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
305 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
307 result = __mm_wfd_sink_set_pipeline_state (wfd_sink, GST_STATE_READY, FALSE);
308 if (result < MM_ERROR_NONE)
310 wfd_sink_error("fail to set state : %d\n", result);
315 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED);
317 wfd_sink_debug_fleave();
322 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
324 int result = MM_ERROR_NONE;
326 wfd_sink_debug_fenter();
328 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
330 /* check current wi-fi display sink state */
331 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
333 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
334 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
335 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
337 /* release pipeline */
338 result = __mm_wfd_sink_destroy_pipeline (wfd_sink);
339 if ( result != MM_ERROR_NONE)
341 wfd_sink_error("failed to destory pipeline\n");
342 return MM_ERROR_WFD_INTERNAL;
346 wfd_sink_debug("success to destory pipeline\n");
350 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL);
352 wfd_sink_debug_fleave();
357 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
359 int result = MM_ERROR_NONE;
361 wfd_sink_debug_fenter();
363 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
365 /* check current wi-fi display sink state */
366 MMWFDSINK_CHECK_STATE (wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
369 mm_wfd_sink_ini_unload(&wfd_sink->ini);
371 /* release attributes */
372 _mmwfd_deconstruct_attribute(wfd_sink->attrs);
374 if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink))
376 wfd_sink_error("failed to release manager\n");
377 return MM_ERROR_WFD_INTERNAL;
382 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE);
384 wfd_sink_debug_fleave();
389 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
391 int result = MM_ERROR_NONE;
393 wfd_sink_debug_fenter();
395 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
397 wfd_sink->msg_cb = callback;
398 wfd_sink->msg_user_data = user_data;
400 wfd_sink_debug_fleave();
405 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
407 int result = MM_ERROR_NONE;
410 static const int max_argc = 50;
414 wfd_sink_debug_fenter();
417 argc = calloc(1, sizeof(gint) );
418 argv = calloc(max_argc, sizeof(gchar*));
421 wfd_sink_error("failed to allocate memory for wfdsink\n");
423 MMWFDSINK_FREEIF(argv);
424 MMWFDSINK_FREEIF(argc);
426 return MM_ERROR_WFD_NO_FREE_SPACE;
429 /* we would not do fork for scanning plugins */
430 argv[*argc] = g_strdup("--gst-disable-registry-fork");
433 /* check disable registry scan */
434 argv[*argc] = g_strdup("--gst-disable-registry-update");
437 /* check disable segtrap */
438 argv[*argc] = g_strdup("--gst-disable-segtrap");
444 if (strlen( wfd_sink->ini.gst_param[i] ) > 2)
446 wfd_sink_debug("set %s\n", wfd_sink->ini.gst_param[i]);
447 argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
452 wfd_sink_debug("initializing gstreamer with following parameter\n");
453 wfd_sink_debug("argc : %d\n", *argc);
455 for ( i = 0; i < *argc; i++ )
457 wfd_sink_debug("argv[%d] : %s\n", i, argv[i]);
460 /* initializing gstreamer */
461 if ( ! gst_init_check (argc, &argv, &err))
463 wfd_sink_error("failed to initialize gstreamer: %s\n",
464 err ? err->message : "unknown error occurred");
468 result = MM_ERROR_WFD_INTERNAL;
472 for ( i = 0; i < *argc; i++ )
474 MMWFDSINK_FREEIF( argv[i] );
476 MMWFDSINK_FREEIF(argv);
477 MMWFDSINK_FREEIF(argc);
479 wfd_sink_debug_fleave();
485 _mm_wfd_sink_correct_pipeline_latency (mm_wfd_sink_t *wfd_sink)
488 GstClockTime min_latency;
490 qlatency = gst_query_new_latency();
491 gst_element_query (wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, qlatency);
492 gst_query_parse_latency (qlatency, NULL, &min_latency, NULL);
494 debug_msg ("Correct manually pipeline latency: current=%"GST_TIME_FORMAT, GST_TIME_ARGS (min_latency));
495 g_object_set (wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst, "ts-offset", -(gint64)(min_latency*9/10), NULL);
496 g_object_set (wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst, "ts-offset", -(gint64)(min_latency*9/10), NULL);
497 gst_query_unref(qlatency);
500 static GstBusSyncReply
501 _mm_wfd_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
503 GstBusSyncReply ret = GST_BUS_PASS;
505 wfd_sink_return_val_if_fail (message &&
506 GST_IS_MESSAGE(message) &&
507 GST_MESSAGE_SRC(message),
510 switch (GST_MESSAGE_TYPE (message))
512 case GST_MESSAGE_TAG:
514 case GST_MESSAGE_DURATION:
516 case GST_MESSAGE_STATE_CHANGED:
518 /* we only handle state change messages from pipeline */
519 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
523 case GST_MESSAGE_ASYNC_DONE:
525 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
537 _mm_wfd_sink_msg_callback (GstBus *bus, GstMessage *msg, gpointer data)
539 mm_wfd_sink_t* wfd_sink = (mm_wfd_sink_t*) data;
540 const GstStructure* message_structure = gst_message_get_structure(msg);
543 wfd_sink_return_val_if_fail (wfd_sink, FALSE);
544 wfd_sink_return_val_if_fail (msg && GST_IS_MESSAGE(msg), FALSE);
546 wfd_sink_debug("got %s from %s \n",
547 GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
548 GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
550 switch (GST_MESSAGE_TYPE (msg))
552 case GST_MESSAGE_ERROR:
554 GError *error = NULL;
558 gst_message_parse_error( msg, &error, &debug );
560 wfd_sink_error("error : %s\n", error->message);
561 wfd_sink_error("debug : %s\n", debug);
563 MMWFDSINK_FREEIF( debug );
564 g_error_free( error );
568 case GST_MESSAGE_WARNING:
571 GError* error = NULL;
573 gst_message_parse_warning(msg, &error, &debug);
575 wfd_sink_error("warning : %s\n", error->message);
576 wfd_sink_error("debug : %s\n", debug);
578 MMWFDSINK_FREEIF (debug);
579 g_error_free (error);
583 case GST_MESSAGE_STATE_CHANGED:
585 const GValue *voldstate, *vnewstate, *vpending;
586 GstState oldstate, newstate, pending;
587 const GstStructure *structure;
589 /* we only handle messages from pipeline */
590 if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst )
593 /* get state info from msg */
594 structure = gst_message_get_structure(msg);
595 voldstate = gst_structure_get_value (structure, "old-state");
596 vnewstate = gst_structure_get_value (structure, "new-state");
597 vpending = gst_structure_get_value (structure, "pending-state");
599 oldstate = (GstState)voldstate->data[0].v_int;
600 newstate = (GstState)vnewstate->data[0].v_int;
601 pending = (GstState)vpending->data[0].v_int;
603 wfd_sink_debug("state changed [%s] : %s ---> %s final : %s\n",
604 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
605 gst_element_state_get_name( (GstState)oldstate ),
606 gst_element_state_get_name( (GstState)newstate ),
607 gst_element_state_get_name( (GstState)pending ) );
609 if (oldstate == newstate)
611 wfd_sink_error("pipeline reports state transition to old state\n");
617 case GST_STATE_VOID_PENDING:
619 case GST_STATE_READY:
620 case GST_STATE_PAUSED:
621 case GST_STATE_PLAYING:
628 case GST_MESSAGE_CLOCK_LOST:
630 GstClock *clock = NULL;
631 gst_message_parse_clock_lost (msg, &clock);
632 wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
633 (clock ? GST_OBJECT_NAME (clock) : "NULL"));
637 case GST_MESSAGE_NEW_CLOCK:
639 GstClock *clock = NULL;
640 gst_message_parse_new_clock (msg, &clock);
646 if (wfd_sink->clock != clock)
647 wfd_sink_debug("clock is changed! [%s] --> [%s]\n",
648 GST_STR_NULL(GST_OBJECT_NAME (wfd_sink->clock)),
649 GST_STR_NULL(GST_OBJECT_NAME (clock)));
651 wfd_sink_debug("same clock is selected again! [%s] \n",
652 GST_STR_NULL(GST_OBJECT_NAME (clock)));
656 wfd_sink_debug("new clock [%s] was selected in the pipeline\n",
657 (GST_STR_NULL(GST_OBJECT_NAME (clock))));
660 wfd_sink->clock = clock;
664 case GST_MESSAGE_APPLICATION:
666 const gchar* message_structure_name;
668 message_structure_name = gst_structure_get_name(message_structure);
669 if (!message_structure_name)
672 wfd_sink_debug ("message name : %s", GST_STR_NULL(message_structure_name));
676 case GST_MESSAGE_ELEMENT:
678 const gchar *structure_name = NULL;
679 const GstStructure* message_structure = NULL;
681 message_structure = gst_message_get_structure(msg);
682 structure_name = gst_structure_get_name(message_structure);
685 wfd_sink_debug("got element specific message[%s]\n", GST_STR_NULL(structure_name));
686 if(g_strrstr(structure_name, "GstUDPSrcTimeout"))
688 wfd_sink_error("Got %s, post error message\n", GST_STR_NULL(structure_name));
689 MMWFDSINK_POST_MESSAGE(wfd_sink,
690 MM_ERROR_WFD_INTERNAL,
691 MMWFDSINK_CURRENT_STATE(wfd_sink));
697 case GST_MESSAGE_PROGRESS:
699 GstProgressType type = GST_PROGRESS_TYPE_ERROR;
700 gchar *category=NULL, *text=NULL;
702 gst_message_parse_progress (msg, &type, &category, &text);
703 wfd_sink_debug("%s : %s \n", GST_STR_NULL(category), GST_STR_NULL(text));
707 case GST_PROGRESS_TYPE_START:
709 case GST_PROGRESS_TYPE_COMPLETE:
710 if (category && !strcmp (category, "open"))
711 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED);
712 else if (category && !strcmp (category, "play"))
714 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING);
715 //_mm_wfd_sink_correct_pipeline_latency (wfd_sink);
717 else if (category && !strcmp (category, "pause"))
718 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED);
719 else if (category && !strcmp (category, "close"))
720 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED);
724 case GST_PROGRESS_TYPE_CANCELED:
726 case GST_PROGRESS_TYPE_ERROR:
727 if (category && !strcmp (category, "open"))
729 wfd_sink_error("got error : %s\n", GST_STR_NULL(text));
730 //_mm_wfd_sink_disconnect (wfd_sink);
731 MMWFDSINK_POST_MESSAGE(wfd_sink,
732 MM_ERROR_WFD_INTERNAL,
733 MMWFDSINK_CURRENT_STATE(wfd_sink));
735 else if (category && !strcmp (category, "play"))
737 wfd_sink_error("got error : %s\n", GST_STR_NULL(text));
738 //_mm_wfd_sink_disconnect (wfd_sink);
739 MMWFDSINK_POST_MESSAGE(wfd_sink,
740 MM_ERROR_WFD_INTERNAL,
741 MMWFDSINK_CURRENT_STATE(wfd_sink));
743 else if (category && !strcmp (category, "pause"))
745 wfd_sink_error("got error : %s\n", GST_STR_NULL(text));
746 //_mm_wfd_sink_disconnect (wfd_sink);
747 MMWFDSINK_POST_MESSAGE(wfd_sink,
748 MM_ERROR_WFD_INTERNAL,
749 MMWFDSINK_CURRENT_STATE(wfd_sink));
751 else if (category && !strcmp (category, "close"))
753 wfd_sink_error("got error : %s\n", GST_STR_NULL(text));
754 //_mm_wfd_sink_disconnect (wfd_sink);
755 MMWFDSINK_POST_MESSAGE(wfd_sink,
756 MM_ERROR_WFD_INTERNAL,
757 MMWFDSINK_CURRENT_STATE(wfd_sink));
761 wfd_sink_error("got error : %s\n", GST_STR_NULL(text));
765 wfd_sink_error("progress message has no type\n");
769 MMWFDSINK_FREEIF (category);
770 MMWFDSINK_FREEIF (text);
773 case GST_MESSAGE_ASYNC_START:
774 wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
776 case GST_MESSAGE_ASYNC_DONE:
777 wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
779 case GST_MESSAGE_UNKNOWN:
780 case GST_MESSAGE_INFO:
781 case GST_MESSAGE_TAG:
782 case GST_MESSAGE_BUFFERING:
783 case GST_MESSAGE_EOS:
784 case GST_MESSAGE_STATE_DIRTY:
785 case GST_MESSAGE_STEP_DONE:
786 case GST_MESSAGE_CLOCK_PROVIDE:
787 case GST_MESSAGE_STRUCTURE_CHANGE:
788 case GST_MESSAGE_STREAM_STATUS:
789 case GST_MESSAGE_SEGMENT_START:
790 case GST_MESSAGE_SEGMENT_DONE:
791 case GST_MESSAGE_DURATION:
792 case GST_MESSAGE_LATENCY:
793 case GST_MESSAGE_REQUEST_STATE:
794 case GST_MESSAGE_STEP_START:
795 case GST_MESSAGE_QOS:
796 case GST_MESSAGE_ANY:
799 wfd_sink_debug("unhandled message\n");
807 __mm_wfd_sink_gst_element_add_bucket_to_bin (GstBin* bin, GList* element_bucket, gboolean need_prepare)
809 GList* bucket = element_bucket;
810 MMWFDSinkGstElement* element = NULL;
811 int successful_add_count = 0;
813 wfd_sink_debug_fenter();
815 wfd_sink_return_val_if_fail (element_bucket, 0);
816 wfd_sink_return_val_if_fail (bin, 0);
818 for (; bucket; bucket = bucket->next)
820 element = (MMWFDSinkGstElement*)bucket->data;
822 if (element && element->gst)
825 gst_element_set_state (GST_ELEMENT(element->gst), GST_STATE_READY);
827 if (!gst_bin_add (bin, GST_ELEMENT(element->gst)))
829 wfd_sink_error("failed to add element [%s] to bin [%s]\n",
830 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
831 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin) )));
835 wfd_sink_debug("add element [%s] to bin [%s]\n",
836 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
837 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin) )));
839 successful_add_count ++;
843 wfd_sink_debug_fleave();
845 return successful_add_count;
849 __mm_wfd_sink_gst_element_link_bucket (GList* element_bucket)
851 GList* bucket = element_bucket;
852 MMWFDSinkGstElement* element = NULL;
853 MMWFDSinkGstElement* prv_element = NULL;
854 gint successful_link_count = 0;
856 wfd_sink_debug_fenter();
858 wfd_sink_return_val_if_fail (element_bucket, -1);
860 prv_element = (MMWFDSinkGstElement*)bucket->data;
861 bucket = bucket->next;
863 for ( ; bucket; bucket = bucket->next )
865 element = (MMWFDSinkGstElement*)bucket->data;
867 if (element && element->gst)
869 if ( gst_element_link (GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
871 wfd_sink_debug("linking [%s] to [%s] success\n",
872 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
873 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
874 successful_link_count ++;
878 wfd_sink_error("linking [%s] to [%s] failed\n",
879 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
880 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
885 prv_element = element;
888 wfd_sink_debug_fleave();
890 return successful_link_count;
894 __mm_wfd_sink_check_state(mm_wfd_sink_t* wfd_sink, MMWFDSinkCommandType cmd)
896 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
898 wfd_sink_debug_fenter();
900 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
902 MMWFDSINK_PRINT_STATE(wfd_sink);
904 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
908 case MM_WFD_SINK_COMMAND_CREATE:
910 if (cur_state != MM_WFD_SINK_STATE_NONE)
913 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
917 case MM_WFD_SINK_COMMAND_PREPARE:
919 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
921 else if (cur_state != MM_WFD_SINK_STATE_NULL)
924 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
928 case MM_WFD_SINK_COMMAND_CONNECT:
930 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
932 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
935 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
939 case MM_WFD_SINK_COMMAND_START:
941 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
943 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
946 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
950 case MM_WFD_SINK_COMMAND_DISCONNECT:
952 if (cur_state == MM_WFD_SINK_STATE_NONE ||
953 cur_state == MM_WFD_SINK_STATE_NULL ||
954 cur_state == MM_WFD_SINK_STATE_PREPARED ||
955 cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
957 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
958 cur_state != MM_WFD_SINK_STATE_CONNECTED &&
959 cur_state != MM_WFD_SINK_STATE_PAUSED)
962 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
966 case MM_WFD_SINK_COMMAND_UNPREPARE:
968 if (cur_state == MM_WFD_SINK_STATE_NONE ||
969 cur_state == MM_WFD_SINK_STATE_NULL)
972 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
976 case MM_WFD_SINK_COMMAND_DESTROY:
978 if (cur_state == MM_WFD_SINK_STATE_NONE)
981 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
991 wfd_sink_debug_fleave();
993 return MM_ERROR_NONE;
996 wfd_sink_debug ("already %s state, nothing to do.\n", MMWFDSINK_STATE_GET_NAME(cur_state));
997 return MM_ERROR_WFD_NO_OP;
1001 wfd_sink_error ("current state is invalid.\n", MMWFDSINK_STATE_GET_NAME(cur_state));
1002 return MM_ERROR_WFD_INVALID_STATE;
1005 static int __mm_wfd_sink_set_state(mm_wfd_sink_t* wfd_sink, MMWFDSinkStateType state)
1007 wfd_sink_debug_fenter();
1009 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1011 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state )
1013 wfd_sink_error("already state(%s)\n", MMWFDSINK_STATE_GET_NAME(state));
1014 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1015 return MM_ERROR_NONE;
1018 /* update wi-fi display state */
1019 MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1020 MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1022 if ( MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink) )
1023 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1025 /* poset state message to application */
1026 MMWFDSINK_POST_MESSAGE(wfd_sink,
1028 MMWFDSINK_CURRENT_STATE(wfd_sink));
1031 MMWFDSINK_PRINT_STATE(wfd_sink);
1033 wfd_sink_debug_fleave();
1035 return MM_ERROR_NONE;
1039 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t* wfd_sink, GstState state, gboolean async)
1041 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1042 GstState cur_state = GST_STATE_VOID_PENDING;
1043 GstState pending_state = GST_STATE_VOID_PENDING;
1045 wfd_sink_debug_fenter();
1047 wfd_sink_return_val_if_fail (wfd_sink &&
1048 wfd_sink->pipeline &&
1049 wfd_sink->pipeline->mainbin &&
1050 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1051 MM_ERROR_WFD_NOT_INITIALIZED);
1053 wfd_sink_return_val_if_fail (state > GST_STATE_VOID_PENDING,
1054 MM_ERROR_WFD_INVALID_ARGUMENT);
1056 wfd_sink_debug ("try to set %s state \n", gst_element_state_get_name(state));
1058 result = gst_element_set_state (wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1059 if (result == GST_STATE_CHANGE_FAILURE)
1061 wfd_sink_error ("fail to set %s state....\n", gst_element_state_get_name(state));
1062 return MM_ERROR_WFD_INTERNAL;
1067 wfd_sink_debug ("wait for changing state is completed \n");
1069 result = gst_element_get_state (wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1070 &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1071 if (result == GST_STATE_CHANGE_FAILURE)
1073 wfd_sink_error ("fail to get state within %d seconds....\n", wfd_sink->ini.state_change_timeout);
1075 __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1077 return MM_ERROR_WFD_INTERNAL;
1079 else if (result == GST_STATE_CHANGE_NO_PREROLL)
1081 wfd_sink_debug ("successfully changed state but is not able to provide data yet\n");
1084 wfd_sink_debug("cur state is %s, pending state is %s\n",
1085 gst_element_state_get_name(cur_state),
1086 gst_element_state_get_name(pending_state));
1090 wfd_sink_debug_fleave();
1092 return MM_ERROR_NONE;
1096 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1098 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1101 wfd_sink_debug_fenter();
1103 wfd_sink_return_if_fail (wfd_sink &&
1104 wfd_sink->pipeline &&
1105 wfd_sink->pipeline->mainbin &&
1106 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1107 wfd_sink_return_if_fail (wfd_sink->need_to_reset_basetime);
1110 if (wfd_sink->clock)
1111 base_time = gst_clock_get_time (wfd_sink->clock);
1113 if (GST_CLOCK_TIME_IS_VALID(base_time))
1116 wfd_sink_debug ("set pipeline base_time as now [%"GST_TIME_FORMAT"]\n",GST_TIME_ARGS(base_time));
1118 for (i=0; i<WFD_SINK_M_NUM; i++)
1120 if (wfd_sink->pipeline->mainbin[i].gst)
1121 gst_element_set_base_time(GST_ELEMENT_CAST (wfd_sink->pipeline->mainbin[i].gst), base_time);
1124 if (wfd_sink->pipeline->videobin)
1126 for (i=0; i<WFD_SINK_V_NUM; i++)
1128 if (wfd_sink->pipeline->videobin[i].gst)
1129 gst_element_set_base_time(GST_ELEMENT_CAST (wfd_sink->pipeline->videobin[i].gst), base_time);
1133 if (wfd_sink->pipeline->audiobin)
1135 for (i=0; i<WFD_SINK_A_NUM; i++)
1137 if (wfd_sink->pipeline->audiobin[i].gst)
1138 gst_element_set_base_time(GST_ELEMENT_CAST (wfd_sink->pipeline->audiobin[i].gst), base_time);
1141 wfd_sink->need_to_reset_basetime = FALSE;
1144 wfd_sink_debug_fleave();
1150 __mm_wfd_sink_prepare_videobin (mm_wfd_sink_t *wfd_sink)
1152 GstElement* videobin = NULL;
1154 wfd_sink_debug_fenter();
1156 wfd_sink_return_val_if_fail (wfd_sink &&
1158 MM_ERROR_WFD_NOT_INITIALIZED);
1160 if (wfd_sink->pipeline->videobin == NULL)
1162 if (MM_ERROR_NONE !=__mm_wfd_sink_create_videobin (wfd_sink))
1164 wfd_sink_error ("failed to create videobin....\n");
1170 wfd_sink_debug ("videobin is already created.\n");
1173 videobin = wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst;
1175 if (GST_STATE(videobin) <= GST_STATE_NULL)
1177 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (videobin, GST_STATE_READY))
1179 wfd_sink_error("failed to set state(READY) to %s\n", GST_STR_NULL(GST_ELEMENT_NAME(videobin)));
1184 wfd_sink_debug_fleave();
1186 return MM_ERROR_NONE;
1190 /* need to notify to app */
1191 MMWFDSINK_POST_MESSAGE(wfd_sink,
1192 MM_ERROR_WFD_INTERNAL,
1193 MMWFDSINK_CURRENT_STATE(wfd_sink));
1195 return MM_ERROR_WFD_INTERNAL;
1199 __mm_wfd_sink_prepare_audiobin (mm_wfd_sink_t *wfd_sink)
1201 MMWFDSinkGstElement* audiobin = NULL;
1203 wfd_sink_debug_fenter();
1205 wfd_sink_return_val_if_fail (wfd_sink &&
1207 MM_ERROR_WFD_NOT_INITIALIZED);
1209 if (wfd_sink->pipeline->audiobin == NULL)
1211 if (MM_ERROR_NONE !=__mm_wfd_sink_create_audiobin (wfd_sink))
1213 wfd_sink_error ("failed to create audiobin....\n");
1218 if (!wfd_sink->audio_bin_is_linked)
1220 if (MM_ERROR_NONE !=__mm_wfd_sink_link_audiobin(wfd_sink))
1222 wfd_sink_error ("failed to link audio decoder.....\n");
1227 audiobin = wfd_sink->pipeline->audiobin;
1229 if (GST_STATE(audiobin) <= GST_STATE_NULL)
1231 if (GST_STATE_CHANGE_FAILURE ==gst_element_set_state (audiobin[WFD_SINK_A_BIN].gst, GST_STATE_READY))
1233 wfd_sink_error("failed to set state(READY) to %s\n",
1234 GST_STR_NULL(GST_ELEMENT_NAME(audiobin)));
1239 wfd_sink_debug_fleave();
1241 return MM_ERROR_NONE;
1245 /* need to notify to app */
1246 MMWFDSINK_POST_MESSAGE(wfd_sink,
1247 MM_ERROR_WFD_INTERNAL,
1248 MMWFDSINK_CURRENT_STATE(wfd_sink));
1250 return MM_ERROR_WFD_INTERNAL;
1253 #define COMPENSATION_CRETERIA_VALUE 1000000 // 1 msec
1254 #define COMPENSATION_CHECK_PERIOD 30*GST_SECOND // 30 sec
1256 static GstPadProbeReturn
1257 _mm_wfd_sink_check_running_time(GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
1259 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
1260 GstClockTime current_time = GST_CLOCK_TIME_NONE;
1261 GstClockTime start_time = GST_CLOCK_TIME_NONE;
1262 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1263 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1264 GstClockTime render_time = GST_CLOCK_TIME_NONE;
1265 GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
1266 GstBuffer * buffer = NULL;
1267 gint64 ts_offset = 0LL;
1269 wfd_sink_return_val_if_fail (info, FALSE);
1270 wfd_sink_return_val_if_fail (wfd_sink &&
1271 wfd_sink->pipeline &&
1272 wfd_sink->pipeline->mainbin &&
1273 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1274 GST_PAD_PROBE_DROP);
1276 if (!wfd_sink->clock)
1278 wfd_sink_warning ("pipeline did not select clock, yet\n");
1279 return GST_PAD_PROBE_OK;
1282 if (wfd_sink->need_to_reset_basetime)
1283 _mm_wfd_sink_reset_basetime(wfd_sink);
1285 /* calculate current runninig time */
1286 current_time = gst_clock_get_time(wfd_sink->clock);
1287 if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1288 base_time = gst_element_get_base_time(wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst);
1289 else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1290 base_time = gst_element_get_base_time(wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst);
1291 start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1292 if (GST_CLOCK_TIME_IS_VALID(current_time) &&
1293 GST_CLOCK_TIME_IS_VALID(start_time) &&
1294 GST_CLOCK_TIME_IS_VALID(base_time))
1296 running_time = current_time - (start_time + base_time);
1300 wfd_sink_debug ("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
1301 " base time %"GST_TIME_FORMAT"\n", GST_TIME_ARGS(current_time),
1302 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
1303 return GST_PAD_PROBE_OK;
1306 /* calculate this buffer rendering time */
1307 buffer = gst_pad_probe_info_get_buffer (info);
1308 if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer))
1310 wfd_sink_error ("buffer timestamp is invalid.\n");
1311 return GST_PAD_PROBE_OK;
1314 if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1316 if (wfd_sink->pipeline && wfd_sink->pipeline->audiobin && wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst)
1317 g_object_get(G_OBJECT(wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst), "ts-offset", &ts_offset, NULL);
1319 else if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1321 if (wfd_sink->pipeline && wfd_sink->pipeline->videobin && wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst)
1322 g_object_get(G_OBJECT(wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst), "ts-offset", &ts_offset, NULL);
1325 render_time = GST_BUFFER_TIMESTAMP(buffer);
1326 render_time += ts_offset;
1328 /* chekc this buffer could be rendered or not */
1329 if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time))
1331 diff=GST_CLOCK_DIFF(running_time, render_time);
1334 /* this buffer could be NOT rendered */
1335 wfd_sink_debug ("%s : diff time : -%" GST_TIME_FORMAT "\n",
1336 GST_STR_NULL((GST_OBJECT_NAME(pad))),
1337 GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
1341 /* this buffer could be rendered */
1342 //wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n",
1343 // GST_STR_NULL((GST_OBJECT_NAME(pad))),
1344 // GST_TIME_ARGS(diff));
1348 /* update buffer count and gap */
1349 if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1351 wfd_sink->video_buffer_count ++;
1352 wfd_sink->video_accumulated_gap += diff;
1354 else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1356 wfd_sink->audio_buffer_count ++;
1357 wfd_sink->audio_accumulated_gap += diff;
1361 wfd_sink_warning("invalid buffer type.. \n");
1362 return GST_PAD_PROBE_DROP;
1365 if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp))
1367 /* fisrt 60sec, just calculate the gap between source device and sink device */
1368 if (GST_BUFFER_TIMESTAMP(buffer) < 60*GST_SECOND)
1369 return GST_PAD_PROBE_OK;
1371 /* every 10sec, calculate the gap between source device and sink device */
1372 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
1373 > COMPENSATION_CHECK_PERIOD)
1375 gint64 audio_avgrage_gap = 0LL;
1376 gint64 video_avgrage_gap = 0LL;
1377 gint64 audio_avgrage_gap_diff = 0LL;
1378 gint64 video_avgrage_gap_diff = 0LL;
1379 gboolean video_minus_compensation = FALSE;
1380 gboolean audio_minus_compensation = FALSE;
1381 gint64 avgrage_gap_diff = 0LL;
1382 gboolean minus_compensation = FALSE;
1385 if (wfd_sink->video_buffer_count > 0)
1387 video_avgrage_gap = wfd_sink->video_accumulated_gap /wfd_sink->video_buffer_count;
1389 if (wfd_sink->video_average_gap !=0)
1391 if (video_avgrage_gap > wfd_sink->video_average_gap)
1393 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
1394 video_minus_compensation = TRUE;
1398 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
1399 video_minus_compensation = FALSE;
1404 wfd_sink_debug ("first update video average gap (%lld) \n", video_avgrage_gap);
1405 wfd_sink->video_average_gap = video_avgrage_gap;
1410 wfd_sink_debug ("there is no video buffer flow during %"GST_TIME_FORMAT
1411 " ~ %" GST_TIME_FORMAT"\n",
1412 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1413 GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer)));
1417 if (wfd_sink->audio_buffer_count > 0)
1419 audio_avgrage_gap = wfd_sink->audio_accumulated_gap /wfd_sink->audio_buffer_count;
1421 if (wfd_sink->audio_average_gap !=0)
1423 if (audio_avgrage_gap > wfd_sink->audio_average_gap)
1425 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
1426 audio_minus_compensation = TRUE;
1430 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
1431 audio_minus_compensation = FALSE;
1436 wfd_sink_debug ("first update audio average gap (%lld) \n", audio_avgrage_gap);
1437 wfd_sink->audio_average_gap = audio_avgrage_gap;
1442 wfd_sink_debug ("there is no audio buffer flow during %"GST_TIME_FORMAT
1443 " ~ %" GST_TIME_FORMAT"\n",
1444 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1445 GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer)));
1448 /* selecet average_gap_diff between video and audio */
1449 /* which makes no buffer drop in the sink elements */
1450 if (video_avgrage_gap_diff && audio_avgrage_gap_diff)
1452 if (!video_minus_compensation && !audio_minus_compensation)
1454 minus_compensation = FALSE;
1455 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1456 avgrage_gap_diff = video_avgrage_gap_diff;
1458 avgrage_gap_diff = audio_avgrage_gap_diff;
1460 else if (video_minus_compensation && audio_minus_compensation)
1462 minus_compensation = TRUE;
1463 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1464 avgrage_gap_diff = audio_avgrage_gap_diff;
1466 avgrage_gap_diff = video_avgrage_gap_diff;
1470 minus_compensation = FALSE;
1471 if (!video_minus_compensation)
1472 avgrage_gap_diff = video_avgrage_gap_diff;
1474 avgrage_gap_diff = audio_avgrage_gap_diff;
1477 else if (video_avgrage_gap_diff)
1479 minus_compensation = video_minus_compensation;
1480 avgrage_gap_diff = video_avgrage_gap_diff;
1482 else if (audio_avgrage_gap_diff)
1484 minus_compensation = audio_minus_compensation;
1485 avgrage_gap_diff = audio_avgrage_gap_diff;
1488 wfd_sink_debug ("average diff gap difference beween audio:%s%lld and video:%s%lld \n",
1489 audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
1490 video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
1493 /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
1494 if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE)
1496 if (minus_compensation)
1497 ts_offset -= avgrage_gap_diff;
1499 ts_offset += avgrage_gap_diff;
1501 wfd_sink_debug ("do timestamp compensation : %s%lld (ts-offset : %"
1502 GST_TIME_FORMAT") at (%" GST_TIME_FORMAT")\n",
1503 minus_compensation? "-" : "", avgrage_gap_diff,
1504 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
1506 if (wfd_sink->pipeline && wfd_sink->pipeline->audiobin && wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst)
1507 g_object_set(G_OBJECT(wfd_sink->pipeline->audiobin[WFD_SINK_A_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1508 if (wfd_sink->pipeline && wfd_sink->pipeline->videobin && wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst)
1509 g_object_set(G_OBJECT(wfd_sink->pipeline->videobin[WFD_SINK_V_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1513 wfd_sink_debug ("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")\n",
1514 minus_compensation? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
1518 wfd_sink->video_buffer_count = 0;
1519 wfd_sink->video_accumulated_gap = 0LL;
1520 wfd_sink->audio_buffer_count = 0;
1521 wfd_sink->audio_accumulated_gap = 0LL;
1522 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1527 wfd_sink_debug ("first update last buffer timestamp :%" GST_TIME_FORMAT" \n",
1528 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1529 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1532 return GST_PAD_PROBE_OK;
1537 __mm_wfd_sink_demux_pad_added (GstElement* ele, GstPad* pad, gpointer data)
1539 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1540 gchar* name = gst_pad_get_name (pad);
1541 GstElement* sinkbin = NULL;
1542 GstPad* sinkpad = NULL;
1544 wfd_sink_debug_fenter();
1546 wfd_sink_return_if_fail (wfd_sink && wfd_sink->pipeline);
1550 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...\n");
1552 MMWFDSINK_PAD_PROBE( wfd_sink, pad, NULL, NULL );
1554 gst_pad_add_probe(pad,
1555 GST_PAD_PROBE_TYPE_BUFFER,
1556 _mm_wfd_sink_check_running_time,
1560 if (GST_STATE(wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst) <= GST_STATE_NULL)
1562 wfd_sink_debug ("need to prepare videobin" );
1563 if (MM_ERROR_NONE !=__mm_wfd_sink_prepare_videobin (wfd_sink))
1565 wfd_sink_error ("failed to prepare videobin....\n");
1570 sinkbin = wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst;
1572 wfd_sink->added_av_pad_num++;
1574 else if (name[0] == 'a')
1576 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...\n");
1578 MMWFDSINK_PAD_PROBE( wfd_sink, pad, NULL, NULL );
1580 gst_pad_add_probe(pad,
1581 GST_PAD_PROBE_TYPE_BUFFER,
1582 _mm_wfd_sink_check_running_time,
1586 if (GST_STATE(wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst) <= GST_STATE_NULL)
1588 wfd_sink_debug ("need to prepare audiobin" );
1589 if (MM_ERROR_NONE !=__mm_wfd_sink_prepare_audiobin (wfd_sink))
1591 wfd_sink_error ("failed to prepare audiobin....\n");
1596 sinkbin = wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst;
1598 wfd_sink->added_av_pad_num++;
1602 wfd_sink_error("not handling.....\n\n\n");
1608 wfd_sink_debug("add %s to pipeline.\n",
1609 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1612 if(!gst_bin_add (GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst), sinkbin))
1614 wfd_sink_error("failed to add sinkbin to pipeline\n");
1618 wfd_sink_debug("link %s .\n", GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1621 sinkpad = gst_element_get_static_pad (GST_ELEMENT_CAST(sinkbin), "sink");
1624 wfd_sink_error("failed to get pad from sinkbin\n");
1628 if (GST_PAD_LINK_OK != gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING))
1630 wfd_sink_error("failed to link sinkbin\n");
1634 wfd_sink_debug("sync state %s with pipeline .\n",
1635 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1638 if (!gst_element_sync_state_with_parent (GST_ELEMENT_CAST(sinkbin)))
1640 wfd_sink_error ("failed to sync sinkbin state with parent \n");
1644 gst_object_unref(GST_OBJECT(sinkpad));
1649 if (wfd_sink->added_av_pad_num == 2)
1651 wfd_sink_debug("whole pipeline is constructed. \n");
1653 /* generate dot file of the constructed pipeline of wifi display sink */
1654 MMWFDSINK_GENERATE_DOT_IF_ENABLED( wfd_sink, "constructed-pipeline" );
1657 MMWFDSINK_FREEIF(name);
1659 wfd_sink_debug_fleave();
1665 MMWFDSINK_FREEIF(name);
1668 gst_object_unref(GST_OBJECT(sinkpad));
1671 /* need to notify to app */
1672 MMWFDSINK_POST_MESSAGE (wfd_sink,
1673 MM_ERROR_WFD_INTERNAL,
1674 MMWFDSINK_CURRENT_STATE(wfd_sink));
1680 __mm_wfd_sink_change_av_format (GstElement* wfdrtspsrc, gpointer* need_to_flush, gpointer data)
1682 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1684 wfd_sink_debug_fenter();
1686 wfd_sink_return_if_fail (wfd_sink);
1687 wfd_sink_return_if_fail (need_to_flush);
1689 if (MMWFDSINK_CURRENT_STATE(wfd_sink)==MM_WFD_SINK_STATE_PLAYING)
1691 wfd_sink_debug("need to flush pipeline");
1692 *need_to_flush = (gpointer) TRUE;
1696 wfd_sink_debug("don't need to flush pipeline");
1697 *need_to_flush = (gpointer) FALSE;
1701 wfd_sink_debug_fleave();
1706 __mm_wfd_sink_update_stream_info (GstElement* wfdrtspsrc, GstStructure* str, gpointer data)
1708 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1709 WFDSinkManagerCMDType cmd = WFD_SINK_MANAGER_CMD_NONE;
1710 MMWFDSinkStreamInfo * stream_info = NULL;
1711 gint is_valid_audio_format = FALSE;
1712 gint is_valid_video_format = FALSE;
1713 gchar * audio_format;
1714 gchar * video_format;
1716 wfd_sink_debug_fenter();
1718 wfd_sink_return_if_fail (str && GST_IS_STRUCTURE(str));
1719 wfd_sink_return_if_fail (wfd_sink);
1721 stream_info = &wfd_sink->stream_info;
1723 if (gst_structure_has_field (str, "audio_format"))
1725 is_valid_audio_format = TRUE;
1726 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
1727 if (g_strrstr(audio_format,"AAC"))
1728 stream_info->audio_stream_info.codec = WFD_SINK_AUDIO_CODEC_AAC;
1729 else if (g_strrstr(audio_format,"AC3"))
1730 stream_info->audio_stream_info.codec = WFD_SINK_AUDIO_CODEC_AC3;
1731 else if (g_strrstr(audio_format,"LPCM"))
1732 stream_info->audio_stream_info.codec = WFD_SINK_AUDIO_CODEC_LPCM;
1735 wfd_sink_error ("invalid audio format(%s)...\n", audio_format);
1736 is_valid_audio_format = FALSE;
1739 if (is_valid_audio_format == TRUE)
1741 if (gst_structure_has_field (str, "audio_rate"))
1742 gst_structure_get_int (str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
1743 if (gst_structure_has_field (str, "audio_channels"))
1744 gst_structure_get_int (str, "audio_channels", &stream_info->audio_stream_info.channels);
1745 if (gst_structure_has_field (str, "audio_bitwidth"))
1746 gst_structure_get_int (str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
1748 cmd = cmd | WFD_SINK_MANAGER_CMD_LINK_A_BIN;
1750 wfd_sink_debug ("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t \n",
1752 stream_info->audio_stream_info.sample_rate,
1753 stream_info->audio_stream_info.channels,
1754 stream_info->audio_stream_info.bitwidth);
1758 if (gst_structure_has_field (str, "video_format"))
1760 is_valid_video_format = TRUE;
1761 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
1762 if (!g_strrstr(video_format,"H264"))
1764 wfd_sink_error ("invalid video format(%s)...\n", video_format);
1765 is_valid_video_format = FALSE;
1768 if(is_valid_video_format == TRUE)
1770 stream_info->video_stream_info.codec = WFD_SINK_VIDEO_CODEC_H264;
1772 if (gst_structure_has_field (str, "video_width"))
1773 gst_structure_get_int (str, "video_width", &stream_info->video_stream_info.width);
1774 if (gst_structure_has_field (str, "video_height"))
1775 gst_structure_get_int (str, "video_height", &stream_info->video_stream_info.height);
1776 if (gst_structure_has_field (str, "video_framerate"))
1777 gst_structure_get_int (str, "video_framerate", &stream_info->video_stream_info.frame_rate);
1779 cmd = cmd | WFD_SINK_MANAGER_CMD_LINK_V_BIN;
1781 wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t \n",
1783 stream_info->video_stream_info.width,
1784 stream_info->video_stream_info.height,
1785 stream_info->video_stream_info.frame_rate);
1789 if (cmd != WFD_SINK_MANAGER_CMD_NONE)
1791 WFD_SINK_MANAGER_LOCK(wfd_sink);
1792 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink, cmd);
1793 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
1796 wfd_sink_debug_fleave();
1799 static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement *wfdrtspsrc)
1801 GstStructure *audio_param = NULL;
1802 GstStructure *video_param = NULL;
1803 GstStructure *hdcp_param = NULL;
1804 void *hdcp_handle = NULL;
1805 gint hdcp_version = 0;
1808 wfd_sink_debug_fenter();
1810 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1811 wfd_sink_return_val_if_fail (wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1812 wfd_sink_return_val_if_fail (wfdrtspsrc, MM_ERROR_WFD_NOT_INITIALIZED);
1814 g_object_set (G_OBJECT(wfdrtspsrc), "debug", wfd_sink->ini.set_debug_property, NULL);
1815 g_object_set (G_OBJECT(wfdrtspsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
1817 g_object_set (G_OBJECT(wfdrtspsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
1819 g_object_set (G_OBJECT(wfdrtspsrc), "udp-buffer-size", 2097152, NULL);
1820 g_object_set (G_OBJECT(wfdrtspsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdrtspsrc_pad_probe, NULL);
1822 audio_param = gst_structure_new ("audio_param",
1823 "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec,
1824 "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency,
1825 "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel,
1826 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency,
1829 video_param = gst_structure_new ("video_param",
1830 "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec,
1831 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution,
1832 "video_cea_support", G_TYPE_UINT, wfd_sink->ini.video_cea_support,
1833 "video_vesa_support", G_TYPE_UINT, wfd_sink->ini.video_vesa_support,
1834 "video_hh_support", G_TYPE_UINT, wfd_sink->ini.video_hh_support,
1835 "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile,
1836 "video_level", G_TYPE_UINT, wfd_sink->ini.video_level,
1837 "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency,
1838 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution,
1839 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution,
1840 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing,
1841 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param,
1842 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support,
1845 mm_attrs_get_data_by_name(wfd_sink->attrs, "hdcp_handle", &hdcp_handle);
1846 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
1847 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
1848 wfd_sink_debug("set hdcp version %d with %d port\n", hdcp_version, hdcp_port);
1850 hdcp_param = gst_structure_new ("hdcp_param",
1851 "hdcp_version", G_TYPE_INT, hdcp_version,
1852 "hdcp_port_no", G_TYPE_INT, hdcp_port,
1855 g_object_set (G_OBJECT(wfdrtspsrc), "audio-param", audio_param, NULL);
1856 g_object_set (G_OBJECT(wfdrtspsrc), "video-param", video_param, NULL);
1857 g_object_set (G_OBJECT(wfdrtspsrc), "hdcp-param", hdcp_param, NULL);
1859 g_signal_connect (wfdrtspsrc, "update-media-info",
1860 G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
1862 g_signal_connect (wfdrtspsrc, "change-av-format",
1863 G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
1865 wfd_sink_debug_fleave();
1867 return MM_ERROR_NONE;
1870 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
1872 wfd_sink_debug_fenter();
1874 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1875 wfd_sink_return_val_if_fail (demux, MM_ERROR_WFD_NOT_INITIALIZED);
1877 g_signal_connect (demux, "pad-added",
1878 G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink);
1880 wfd_sink_debug_fleave();
1882 return MM_ERROR_NONE;
1885 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
1887 MMWFDSinkGstElement *mainbin = NULL;
1888 GList* element_bucket = NULL;
1892 wfd_sink_debug_fenter();
1894 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1895 wfd_sink_return_val_if_fail (wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1897 /* Create pipeline */
1898 wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo*) g_malloc0 (sizeof(MMWFDSinkGstPipelineInfo));
1899 if (wfd_sink->pipeline == NULL)
1902 memset (wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
1904 /* create mainbin */
1905 mainbin = (MMWFDSinkGstElement*) g_malloc0 (sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1906 if (mainbin == NULL)
1909 memset (mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1911 /* create pipeline */
1912 mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
1913 mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new ("wfdsink");
1914 if (!mainbin[WFD_SINK_M_PIPE].gst)
1916 wfd_sink_error ("failed to create pipeline\n");
1920 /* create wfdrtspsrc */
1921 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, "wfdrtspsrc", "wfdsink_source", TRUE);
1922 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src" );
1923 if (mainbin[WFD_SINK_M_SRC].gst)
1925 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_wfdrtspsrc (wfd_sink, mainbin[WFD_SINK_M_SRC].gst))
1927 wfd_sink_error ("failed to prepare wfdrtspsrc...\n");
1932 /* create rtpmp2tdepay */
1933 MMWFDSINK_CREATE_ELEMENT (mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
1934 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src" );
1935 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink" );
1937 MMWFDSINK_TS_DATA_DUMP( wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src" );
1939 /* create tsdemuxer*/
1940 MMWFDSINK_CREATE_ELEMENT (mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
1941 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink" );
1942 if (mainbin[WFD_SINK_M_DEMUX].gst)
1944 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux (wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst))
1946 wfd_sink_error ("failed to prepare demux...\n");
1951 /* adding created elements to pipeline */
1952 if( !__mm_wfd_sink_gst_element_add_bucket_to_bin (GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE))
1954 wfd_sink_error ("failed to add elements\n");
1958 /* linking elements in the bucket by added order. */
1959 if ( __mm_wfd_sink_gst_element_link_bucket (element_bucket) == -1 )
1961 wfd_sink_error("failed to link elements\n");
1965 /* connect bus callback */
1966 bus = gst_pipeline_get_bus (GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
1969 wfd_sink_error ("cannot get bus from pipeline.\n");
1973 /* add bus message callback*/
1974 gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
1976 /* set sync handler to get tag synchronously */
1977 gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
1979 g_list_free(element_bucket);
1980 gst_object_unref(GST_OBJECT(bus));
1982 /* now we have completed mainbin. take it */
1983 wfd_sink->pipeline->mainbin = mainbin;
1985 wfd_sink_debug_fleave();
1987 return MM_ERROR_NONE;
1991 wfd_sink_error("ERROR : releasing pipeline\n");
1994 g_list_free (element_bucket);
1995 element_bucket = NULL;
1999 gst_object_unref(GST_OBJECT(bus));
2002 /* release element which are not added to bin */
2003 for (i = 1; i < WFD_SINK_M_NUM; i++) /* NOTE : skip pipeline */
2005 if (mainbin != NULL && mainbin[i].gst)
2007 GstObject* parent = NULL;
2008 parent = gst_element_get_parent (mainbin[i].gst);
2012 gst_object_unref(GST_OBJECT(mainbin[i].gst));
2013 mainbin[i].gst = NULL;
2017 gst_object_unref(GST_OBJECT(parent));
2022 /* release audiobin with it's childs */
2023 if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst )
2025 gst_object_unref (GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
2028 MMWFDSINK_FREEIF (mainbin);
2030 MMWFDSINK_FREEIF (wfd_sink->pipeline);
2032 return MM_ERROR_WFD_INTERNAL;
2035 int __mm_wfd_sink_link_audiobin(mm_wfd_sink_t *wfd_sink)
2037 MMWFDSinkGstElement *audiobin = NULL;
2038 MMWFDSinkGstElement *first_element = NULL;
2039 MMWFDSinkGstElement *last_element = NULL;
2040 gint audio_codec = WFD_SINK_AUDIO_CODEC_NONE;
2041 GList* element_bucket = NULL;
2042 GstPad *sinkpad = NULL;
2043 GstPad *srcpad = NULL;
2045 wfd_sink_debug_fenter();
2047 wfd_sink_return_val_if_fail (wfd_sink &&
2048 wfd_sink->pipeline &&
2049 wfd_sink->pipeline->audiobin &&
2050 wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst,
2051 MM_ERROR_WFD_NOT_INITIALIZED );
2052 wfd_sink_return_val_if_fail (wfd_sink->prev_audio_dec_src_pad &&
2053 wfd_sink->next_audio_dec_sink_pad,
2054 MM_ERROR_WFD_INTERNAL);
2056 if (wfd_sink->audio_bin_is_linked)
2058 wfd_sink_debug ("audiobin is already linked... nothing to do\n");
2059 return MM_ERROR_NONE;
2063 audiobin = wfd_sink->pipeline->audiobin;
2065 /* check audio codec */
2066 audio_codec = wfd_sink->stream_info.audio_stream_info.codec;
2067 switch (audio_codec)
2069 case WFD_SINK_AUDIO_CODEC_LPCM:
2070 if (audiobin[WFD_SINK_A_LPCM_CONVERTER].gst)
2071 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_LPCM_CONVERTER]);
2072 if (audiobin[WFD_SINK_A_LPCM_FILTER].gst)
2073 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_LPCM_FILTER]);
2076 case WFD_SINK_AUDIO_CODEC_AAC:
2077 if (audiobin[WFD_SINK_A_AAC_PARSE].gst)
2078 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AAC_PARSE]);
2079 if (audiobin[WFD_SINK_A_AAC_DEC].gst)
2080 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AAC_DEC]);
2083 case WFD_SINK_AUDIO_CODEC_AC3:
2084 if (audiobin[WFD_SINK_A_AC3_PARSE].gst)
2085 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AC3_PARSE]);
2086 if (audiobin[WFD_SINK_A_AC3_DEC].gst)
2087 element_bucket = g_list_append(element_bucket, &audiobin[WFD_SINK_A_AC3_DEC]);
2091 wfd_sink_error("audio type is not decied yet. cannot link audio decoder...\n");
2092 return MM_ERROR_WFD_INTERNAL;
2096 if (!element_bucket)
2098 wfd_sink_debug ("there is no additional elements to be linked... just link audiobin.\n");
2099 if (GST_PAD_LINK_OK != gst_pad_link_full(wfd_sink->prev_audio_dec_src_pad, wfd_sink->next_audio_dec_sink_pad, GST_PAD_LINK_CHECK_NOTHING))
2101 wfd_sink_error("failed to link audiobin....\n");
2107 /* adding elements to audiobin */
2108 if( !__mm_wfd_sink_gst_element_add_bucket_to_bin (GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), element_bucket, FALSE))
2110 wfd_sink_error ("failed to add elements to audiobin\n");
2114 /* linking elements in the bucket by added order. */
2115 if ( __mm_wfd_sink_gst_element_link_bucket (element_bucket) == -1 )
2117 wfd_sink_error("failed to link elements\n");
2122 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
2125 wfd_sink_error("failed to get first element to be linked....\n");
2129 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2132 wfd_sink_error("failed to get sink pad from element(%s)\n", GST_ELEMENT_NAME(first_element->gst));
2136 if (GST_PAD_LINK_OK != gst_pad_link_full(wfd_sink->prev_audio_dec_src_pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING))
2138 wfd_sink_error("failed to link audiobin....\n");
2142 gst_object_unref(GST_OBJECT(sinkpad));
2147 last_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, g_list_length(element_bucket)-1);
2150 wfd_sink_error("failed to get last element to be linked....\n");
2154 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2157 wfd_sink_error("failed to get src pad from element(%s)\n", GST_ELEMENT_NAME(last_element->gst));
2161 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, wfd_sink->next_audio_dec_sink_pad, GST_PAD_LINK_CHECK_NOTHING))
2163 wfd_sink_error("failed to link audiobin....\n");
2167 gst_object_unref(GST_OBJECT(srcpad));
2170 g_list_free (element_bucket);
2173 wfd_sink->audio_bin_is_linked = TRUE;
2175 wfd_sink_debug_fleave();
2177 return MM_ERROR_NONE;
2182 gst_object_unref(GST_OBJECT(srcpad));
2186 gst_object_unref(GST_OBJECT(sinkpad));
2189 g_list_free (element_bucket);
2191 return MM_ERROR_WFD_INTERNAL;
2194 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
2196 wfd_sink_debug_fenter();
2198 /* check audiosink is created */
2199 wfd_sink_return_val_if_fail (audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2200 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2202 g_object_set (G_OBJECT(audio_sink), "provide-clock", FALSE, NULL);
2203 g_object_set (G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
2204 g_object_set (G_OBJECT(audio_sink), "query-position-support", FALSE, NULL);
2205 g_object_set (G_OBJECT(audio_sink), "slave-method", 2, NULL);
2206 g_object_set (G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL);
2207 g_object_set (G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL );
2209 wfd_sink_debug_fleave();
2211 return MM_ERROR_NONE;
2215 __mm_wfd_sink_queue_overrun (GstElement* element, gpointer u_data)
2219 return_if_fail(element);
2221 wfd_sink_warning ("%s is overrun\n",
2222 GST_STR_NULL(GST_ELEMENT_NAME(element)));
2229 static int __mm_wfd_sink_destroy_audiobin(mm_wfd_sink_t* wfd_sink)
2231 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2232 MMWFDSinkGstElement* audiobin = NULL;
2233 GstObject* parent = NULL;
2236 wfd_sink_debug_fenter ();
2238 wfd_sink_return_val_if_fail (wfd_sink,
2239 MM_ERROR_WFD_NOT_INITIALIZED);
2241 if (wfd_sink->pipeline &&
2242 wfd_sink->pipeline->audiobin &&
2243 wfd_sink->pipeline->audiobin[WFD_SINK_A_BIN].gst)
2245 audiobin = wfd_sink->pipeline->audiobin;
2249 wfd_sink_debug("audiobin is not created, nothing to destroy\n");
2250 return MM_ERROR_NONE;
2254 parent = gst_element_get_parent (audiobin[WFD_SINK_A_BIN].gst);
2257 wfd_sink_debug("audiobin has no parent.. need to relase by itself\n");
2259 if (GST_STATE(audiobin[WFD_SINK_A_BIN].gst)>=GST_STATE_READY)
2261 wfd_sink_debug("try to change state of audiobin to NULL\n");
2262 ret = gst_element_set_state (audiobin[WFD_SINK_A_BIN].gst, GST_STATE_NULL);
2263 if ( ret != GST_STATE_CHANGE_SUCCESS )
2265 wfd_sink_error("failed to change state of audiobin to NULL\n");
2266 return MM_ERROR_WFD_INTERNAL;
2270 /* release element which are not added to bin */
2271 for (i = 1; i < WFD_SINK_A_NUM; i++) /* NOTE : skip bin */
2273 if (audiobin[i].gst)
2275 parent = gst_element_get_parent (audiobin[i].gst);
2278 wfd_sink_debug("unref %s(current ref %d)\n",
2279 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[i].gst)),
2280 ((GObject *) audiobin[i].gst)->ref_count);
2281 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2282 audiobin[i].gst = NULL;
2286 wfd_sink_debug("unref %s(current ref %d)\n",
2287 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[i].gst)),
2288 ((GObject *) audiobin[i].gst)->ref_count);
2289 gst_object_unref(GST_OBJECT(parent));
2294 /* release audiobin with it's childs */
2295 if (audiobin[WFD_SINK_A_BIN].gst )
2297 gst_object_unref (GST_OBJECT(audiobin[WFD_SINK_A_BIN].gst));
2302 wfd_sink_debug("audiobin has parent (%s), unref it \n",
2303 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2305 gst_object_unref (GST_OBJECT(parent));
2308 wfd_sink_debug_fleave();
2310 return MM_ERROR_NONE;
2313 static int __mm_wfd_sink_create_audiobin(mm_wfd_sink_t *wfd_sink)
2315 MMWFDSinkGstElement* audiobin = NULL;
2316 gint audio_codec = WFD_SINK_AUDIO_CODEC_NONE;
2317 gboolean link_audio_dec = TRUE;
2318 GList* element_bucket = NULL;
2320 GstPad *ghostpad = NULL;
2321 GstCaps *caps = NULL;
2323 wfd_sink_debug_fenter();
2325 wfd_sink_return_val_if_fail (wfd_sink &&
2326 wfd_sink->pipeline &&
2327 wfd_sink->pipeline->mainbin,
2328 MM_ERROR_WFD_NOT_INITIALIZED );
2331 audiobin = (MMWFDSinkGstElement*)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_NUM);
2334 wfd_sink_error ("failed to allocate memory for audiobin\n");
2335 return MM_ERROR_WFD_NO_FREE_SPACE;
2338 /* create audiobin */
2339 audiobin[WFD_SINK_A_BIN].id = WFD_SINK_A_BIN;
2340 audiobin[WFD_SINK_A_BIN].gst = gst_bin_new("audiobin");
2341 if ( !audiobin[WFD_SINK_A_BIN].gst )
2343 wfd_sink_error ("failed to create audiobin\n");
2347 /* check audio decoder could be linked or not */
2348 switch (wfd_sink->stream_info.audio_stream_info.codec)
2350 case WFD_SINK_AUDIO_CODEC_AAC:
2351 audio_codec = WFD_AUDIO_AAC;
2353 case WFD_SINK_AUDIO_CODEC_AC3:
2354 audio_codec = WFD_AUDIO_AC3;
2356 case WFD_SINK_AUDIO_CODEC_LPCM:
2357 audio_codec = WFD_AUDIO_LPCM;
2359 case WFD_SINK_AUDIO_CODEC_NONE:
2361 wfd_sink_debug ("audio decoder could NOT be linked now, just prepare.\n");
2362 audio_codec = wfd_sink->ini.audio_codec;
2363 link_audio_dec = FALSE;
2367 /* set need to link audio decoder flag*/
2368 wfd_sink->audio_bin_is_linked = link_audio_dec;
2370 /* queue - drm - parse - dec/capsfilter - audioconvert- volume - sink */
2372 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_QUEUE, "queue", "audio_queue", link_audio_dec);
2373 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_QUEUE].gst, "sink" );
2374 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_QUEUE].gst, "src" );
2375 if (audiobin[WFD_SINK_A_QUEUE].gst)
2377 g_object_set(G_OBJECT (audiobin[WFD_SINK_A_QUEUE].gst), "max-size-bytes", 0, NULL);
2378 g_object_set(G_OBJECT (audiobin[WFD_SINK_A_QUEUE].gst), "max-size-buffers", 0, NULL);
2379 g_object_set(G_OBJECT (audiobin[WFD_SINK_A_QUEUE].gst), "max-size-time", (guint64)3000000000ULL, NULL);
2380 g_signal_connect (audiobin[WFD_SINK_A_QUEUE].gst, "overrun",
2381 G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
2383 if (!link_audio_dec)
2385 if (!gst_bin_add (GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), audiobin[WFD_SINK_A_QUEUE].gst))
2387 wfd_sink_error("failed to add %s to audiobin\n",
2388 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_QUEUE].gst)));
2392 if (audiobin[WFD_SINK_A_HDCP].gst)
2394 if (!gst_bin_add (GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), audiobin[WFD_SINK_A_HDCP].gst))
2396 wfd_sink_error("failed to add %s to audiobin\n",
2397 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_HDCP].gst)));
2401 if (!gst_element_link (audiobin[WFD_SINK_A_QUEUE].gst, audiobin[WFD_SINK_A_HDCP].gst) )
2403 wfd_sink_error("failed to link [%s] to [%s] success\n",
2404 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_QUEUE].gst)),
2405 GST_STR_NULL(GST_ELEMENT_NAME(audiobin[WFD_SINK_A_HDCP].gst)));
2409 wfd_sink->prev_audio_dec_src_pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_HDCP].gst, "src");
2413 wfd_sink->prev_audio_dec_src_pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_QUEUE].gst, "src");
2416 if (!wfd_sink->prev_audio_dec_src_pad)
2418 wfd_sink_error ("failed to get src pad from previous element of audio decoder\n");
2422 wfd_sink_debug ("take src pad from previous element of audio decoder for linking\n");
2425 if (audio_codec & WFD_AUDIO_LPCM)
2427 /* create LPCM converter */
2428 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", link_audio_dec);
2429 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_CONVERTER].gst, "sink" );
2430 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_CONVERTER].gst, "src" );
2432 /* create LPCM filter */
2433 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", link_audio_dec);
2434 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_FILTER].gst, "sink" );
2435 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_LPCM_FILTER].gst, "src" );
2436 if (audiobin[WFD_SINK_A_LPCM_FILTER].gst)
2438 caps = gst_caps_new_simple("audio/x-raw",
2439 "rate", G_TYPE_INT, 48000,
2440 "channels", G_TYPE_INT, 2,
2441 "format", G_TYPE_STRING, "S16LE", NULL);
2443 g_object_set (G_OBJECT(audiobin[WFD_SINK_A_LPCM_FILTER].gst), "caps", caps, NULL);
2444 gst_object_unref (GST_OBJECT(caps));
2448 if (audio_codec & WFD_AUDIO_AAC )
2450 /* create AAC parse */
2451 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", link_audio_dec);
2452 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_PARSE].gst, "sink" );
2453 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_PARSE].gst, "src" );
2455 /* create AAC decoder */
2456 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", link_audio_dec);
2457 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_DEC].gst, "sink" );
2458 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AAC_DEC].gst, "src" );
2461 if (audio_codec & WFD_AUDIO_AC3)
2463 /* create AC3 parser */
2464 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", link_audio_dec);
2465 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_PARSE].gst, "sink" );
2466 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_PARSE].gst, "src" );
2468 /* create AC3 decoder */
2469 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", link_audio_dec);
2470 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_DEC].gst, "sink" );
2471 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_AC3_DEC].gst, "src" );
2474 /* create resampler */
2475 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
2476 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_RESAMPLER].gst, "sink" );
2477 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_RESAMPLER].gst, "src" );
2480 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
2481 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_VOLUME].gst, "sink" );
2482 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_VOLUME].gst, "src" );
2484 //TODO gstreamer-1.0 alsasink does not want process not S16LE format.
2485 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_CAPSFILTER, "capsfilter", "audio_capsfilter", TRUE);
2486 if (audiobin[WFD_SINK_A_CAPSFILTER].gst)
2488 caps = gst_caps_from_string("audio/x-raw, format=(string)S16LE");
2489 g_object_set (G_OBJECT(audiobin[WFD_SINK_A_CAPSFILTER].gst), "caps", caps, NULL);
2490 gst_caps_unref (caps);
2494 MMWFDSINK_CREATE_ELEMENT (audiobin, WFD_SINK_A_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
2495 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, audiobin[WFD_SINK_A_SINK].gst, "sink" );
2496 if (audiobin[WFD_SINK_A_SINK].gst)
2498 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, audiobin[WFD_SINK_A_SINK].gst))
2500 wfd_sink_error ("failed to set audio sink property....\n");
2505 if (!link_audio_dec)
2507 MMWFDSinkGstElement* first_element = NULL;
2509 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
2512 wfd_sink_error("failed to get first element\n");
2516 wfd_sink->next_audio_dec_sink_pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2517 if (!wfd_sink->next_audio_dec_sink_pad)
2519 wfd_sink_error("failed to get sink pad from next element of audio decoder\n");
2523 wfd_sink_debug ("take sink pad from next element of audio decoder for linking\n");
2526 /* adding created elements to audiobin */
2527 if( !__mm_wfd_sink_gst_element_add_bucket_to_bin (GST_BIN_CAST(audiobin[WFD_SINK_A_BIN].gst), element_bucket, FALSE))
2529 wfd_sink_error ("failed to add elements\n");
2533 /* linking elements in the bucket by added order. */
2534 if ( __mm_wfd_sink_gst_element_link_bucket (element_bucket) == -1 )
2536 wfd_sink_error("failed to link elements\n");
2540 /* get queue's sinkpad for creating ghostpad */
2541 pad = gst_element_get_static_pad(audiobin[WFD_SINK_A_QUEUE].gst, "sink");
2544 wfd_sink_error("failed to get pad from queue of audiobin\n");
2548 ghostpad = gst_ghost_pad_new ("sink", pad);
2551 wfd_sink_error("failed to create ghostpad\n");
2555 if (FALSE == gst_element_add_pad (audiobin[WFD_SINK_A_BIN].gst, ghostpad) )
2557 wfd_sink_error("failed to add ghostpad to audiobin\n");
2561 gst_object_unref(GST_OBJECT(pad));
2563 g_list_free(element_bucket);
2566 wfd_sink->pipeline->audiobin = audiobin;
2568 wfd_sink_debug_fleave();
2570 return MM_ERROR_NONE;
2573 wfd_sink_error("failed to create audiobin, releasing all\n");
2575 if (wfd_sink->next_audio_dec_sink_pad)
2576 gst_object_unref (GST_OBJECT(wfd_sink->next_audio_dec_sink_pad));
2577 wfd_sink->next_audio_dec_sink_pad = NULL;
2579 if (wfd_sink->prev_audio_dec_src_pad)
2580 gst_object_unref (GST_OBJECT(wfd_sink->prev_audio_dec_src_pad));
2581 wfd_sink->prev_audio_dec_src_pad = NULL;
2584 gst_object_unref (GST_OBJECT(pad));
2588 gst_object_unref (GST_OBJECT(ghostpad));
2592 g_list_free (element_bucket);
2593 element_bucket = NULL;
2595 /* release element which are not added to bin */
2596 __mm_wfd_sink_destroy_audiobin(wfd_sink);
2598 MMWFDSINK_FREEIF (audiobin);
2600 return MM_ERROR_WFD_INTERNAL;
2603 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
2605 wfd_sink_debug_fenter();
2607 /* check video decoder is created */
2608 wfd_sink_return_val_if_fail ( video_dec, MM_ERROR_WFD_INVALID_ARGUMENT );
2609 wfd_sink_return_val_if_fail ( wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED );
2611 g_object_set (G_OBJECT(video_dec), "error-concealment", TRUE, NULL );
2613 wfd_sink_debug_fleave();
2615 return MM_ERROR_NONE;
2618 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
2620 gboolean visible = TRUE;
2621 gint surface_type = MM_DISPLAY_SURFACE_X;
2624 wfd_sink_debug_fenter();
2626 /* check videosink is created */
2627 wfd_sink_return_val_if_fail ( video_sink, MM_ERROR_WFD_INVALID_ARGUMENT );
2628 wfd_sink_return_val_if_fail ( wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED );
2630 /* update display surface */
2631 // mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
2632 wfd_sink_debug("check display surface type attribute: %d", surface_type);
2633 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
2634 wfd_sink_debug("check display visible attribute: %d", visible);
2636 /* configuring display */
2637 switch ( surface_type )
2639 case MM_DISPLAY_SURFACE_EVAS:
2641 void *object = NULL;
2644 /* common case if using evas surface */
2645 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
2646 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
2649 wfd_sink_debug("set video param : evas-object %x", object);
2650 g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
2654 wfd_sink_error("no evas object");
2655 return MM_ERROR_WFD_INTERNAL;
2660 case MM_DISPLAY_SURFACE_X:
2665 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", (void**)&object);
2669 wfd_sink_debug("xid = %lu", xid);
2670 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), xid);
2674 wfd_sink_warning("Handle is NULL. Set xid as 0.. but, it's not recommended.");
2675 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), 0);
2680 case MM_DISPLAY_SURFACE_NULL:
2683 wfd_sink_error("Not Supported Surface.");
2684 return MM_ERROR_WFD_INTERNAL;
2689 g_object_set (G_OBJECT(video_sink), "qos", FALSE, NULL );
2690 g_object_set (G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
2691 g_object_set (G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL );
2692 g_object_set (G_OBJECT(video_sink), "visible", visible, NULL);
2693 g_object_set (G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL );
2695 wfd_sink_debug_fleave();
2697 return MM_ERROR_NONE;
2700 static int __mm_wfd_sink_destroy_videobin(mm_wfd_sink_t* wfd_sink)
2702 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2703 MMWFDSinkGstElement* videobin = NULL;
2704 GstObject* parent = NULL;
2707 wfd_sink_debug_fenter ();
2709 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED );
2711 if (wfd_sink->pipeline &&
2712 wfd_sink->pipeline->videobin &&
2713 wfd_sink->pipeline->videobin[WFD_SINK_V_BIN].gst)
2715 videobin = wfd_sink->pipeline->videobin;
2719 wfd_sink_debug("videobin is not created, nothing to destroy\n");
2720 return MM_ERROR_NONE;
2724 parent = gst_element_get_parent (videobin[WFD_SINK_V_BIN].gst);
2727 wfd_sink_debug("videobin has no parent.. need to relase by itself\n");
2729 if (GST_STATE(videobin[WFD_SINK_V_BIN].gst) >= GST_STATE_READY)
2731 wfd_sink_debug("try to change state of videobin to NULL\n");
2732 ret = gst_element_set_state (videobin[WFD_SINK_V_BIN].gst, GST_STATE_NULL);
2733 if ( ret != GST_STATE_CHANGE_SUCCESS )
2735 wfd_sink_error("failed to change state of videobin to NULL\n");
2736 return MM_ERROR_WFD_INTERNAL;
2739 /* release element which are not added to bin */
2740 for (i = 1; i < WFD_SINK_V_NUM; i++) /* NOTE : skip bin */
2742 if (videobin[i].gst)
2744 parent = gst_element_get_parent (videobin[i].gst);
2747 wfd_sink_debug("unref %s(current ref %d)\n",
2748 GST_STR_NULL(GST_ELEMENT_NAME(videobin[i].gst)),
2749 ((GObject *) videobin[i].gst)->ref_count);
2750 gst_object_unref(GST_OBJECT(videobin[i].gst));
2751 videobin[i].gst = NULL;
2755 wfd_sink_debug("unref %s(current ref %d)\n",
2756 GST_STR_NULL(GST_ELEMENT_NAME(videobin[i].gst)),
2757 ((GObject *) videobin[i].gst)->ref_count);
2758 gst_object_unref(GST_OBJECT(parent));
2762 /* release audiobin with it's childs */
2763 if (videobin[WFD_SINK_V_BIN].gst )
2765 gst_object_unref (GST_OBJECT(videobin[WFD_SINK_V_BIN].gst));
2770 wfd_sink_debug("videobin has parent (%s), unref it \n",
2771 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2773 gst_object_unref (GST_OBJECT(parent));
2776 wfd_sink_debug_fleave();
2778 return MM_ERROR_NONE;
2782 static int __mm_wfd_sink_create_videobin(mm_wfd_sink_t *wfd_sink)
2784 MMWFDSinkGstElement* first_element = NULL;
2785 MMWFDSinkGstElement* videobin = NULL;
2786 GList* element_bucket = NULL;
2788 GstPad *ghostpad = NULL;
2790 wfd_sink_debug_fenter();
2792 wfd_sink_return_val_if_fail (wfd_sink &&
2793 wfd_sink->pipeline &&
2794 wfd_sink->pipeline->mainbin,
2795 MM_ERROR_WFD_NOT_INITIALIZED );
2798 videobin = (MMWFDSinkGstElement*)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_NUM);
2801 wfd_sink_error ("failed to allocate memory for videobin\n");
2802 return MM_ERROR_WFD_NO_FREE_SPACE;
2805 /* create videobin */
2806 videobin[WFD_SINK_V_BIN].id = WFD_SINK_V_BIN;
2807 videobin[WFD_SINK_V_BIN].gst = gst_bin_new("videobin");
2808 if ( !videobin[WFD_SINK_V_BIN].gst )
2810 wfd_sink_error ("failed to create videobin\n");
2814 /* queue - drm - parse - dec - sink */
2816 MMWFDSINK_CREATE_ELEMENT (videobin, WFD_SINK_V_QUEUE, "queue", "video_queue", TRUE);
2817 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_QUEUE].gst, "sink" );
2818 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_QUEUE].gst, "src" );
2819 if (videobin[WFD_SINK_V_QUEUE].gst)
2821 g_object_set(G_OBJECT (videobin[WFD_SINK_V_QUEUE].gst), "max-size-bytes", 0, NULL);
2822 g_object_set(G_OBJECT (videobin[WFD_SINK_V_QUEUE].gst), "max-size-buffers", 0, NULL);
2823 g_object_set(G_OBJECT (videobin[WFD_SINK_V_QUEUE].gst), "max-size-time", (guint64)3000000000ULL, NULL);
2824 g_signal_connect (videobin[WFD_SINK_V_QUEUE].gst, "overrun",
2825 G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
2829 MMWFDSINK_CREATE_ELEMENT (videobin, WFD_SINK_V_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", TRUE);
2830 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_PARSE].gst, "sink" );
2831 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_PARSE].gst, "src" );
2832 if (videobin[WFD_SINK_V_PARSE].gst)
2833 g_object_set (G_OBJECT(videobin[WFD_SINK_V_PARSE].gst), "wfd-mode", TRUE, NULL );
2836 MMWFDSINK_CREATE_ELEMENT (videobin, WFD_SINK_V_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", TRUE);
2837 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_DEC].gst, "sink" );
2838 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_DEC].gst, "src" );
2839 if (videobin[WFD_SINK_V_DEC].gst)
2841 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, videobin[WFD_SINK_V_DEC].gst))
2843 wfd_sink_error ("failed to set video sink property....\n");
2849 MMWFDSINK_CREATE_ELEMENT (videobin, WFD_SINK_V_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
2850 MMWFDSINK_PAD_PROBE( wfd_sink, NULL, videobin[WFD_SINK_V_SINK].gst, "sink" );
2851 if (videobin[WFD_SINK_V_SINK].gst)
2853 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, videobin[WFD_SINK_V_SINK].gst))
2855 wfd_sink_error ("failed to set video sink property....\n");
2860 /* adding created elements to videobin */
2861 if( !__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(videobin[WFD_SINK_V_BIN].gst), element_bucket, FALSE))
2863 wfd_sink_error ("failed to add elements\n");
2867 /* linking elements in the bucket by added order. */
2868 if ( __mm_wfd_sink_gst_element_link_bucket (element_bucket) == -1 )
2870 wfd_sink_error("failed to link elements\n");
2874 /* get first element's sinkpad for creating ghostpad */
2875 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
2878 wfd_sink_error("failed to get first element of videobin\n");
2882 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2885 wfd_sink_error("failed to get pad from first element(%s) of videobin\n", GST_ELEMENT_NAME(first_element->gst));
2889 ghostpad = gst_ghost_pad_new ("sink", pad);
2892 wfd_sink_error("failed to create ghostpad\n");
2896 if (FALSE == gst_element_add_pad (videobin[WFD_SINK_V_BIN].gst, ghostpad) )
2898 wfd_sink_error("failed to add ghostpad to videobin\n");
2902 gst_object_unref(GST_OBJECT(pad));
2904 g_list_free(element_bucket);
2906 wfd_sink->video_bin_is_linked = TRUE;
2909 wfd_sink->pipeline->videobin = videobin;
2911 if (wfd_sink->ini.video_sink_async)
2914 bus = gst_element_get_bus(videobin[WFD_SINK_V_BIN].gst );
2916 gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
2917 gst_object_unref(bus);
2920 wfd_sink_debug_fleave();
2922 return MM_ERROR_NONE;
2926 wfd_sink_error("failed to create videobin, releasing all\n");
2929 gst_object_unref (GST_OBJECT(pad));
2933 gst_object_unref (GST_OBJECT(ghostpad));
2936 g_list_free (element_bucket);
2938 __mm_wfd_sink_destroy_videobin(wfd_sink);
2940 MMWFDSINK_FREEIF (videobin);
2942 return MM_ERROR_WFD_INTERNAL;
2945 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t* wfd_sink)
2947 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2949 wfd_sink_debug_fenter ();
2951 wfd_sink_return_val_if_fail (wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED );
2953 if (wfd_sink->prev_audio_dec_src_pad)
2954 gst_object_unref(GST_OBJECT(wfd_sink->prev_audio_dec_src_pad));
2955 wfd_sink->prev_audio_dec_src_pad = NULL;
2957 if (wfd_sink->next_audio_dec_sink_pad)
2958 gst_object_unref(GST_OBJECT(wfd_sink->next_audio_dec_sink_pad));
2959 wfd_sink->next_audio_dec_sink_pad = NULL;
2961 /* cleanup gst stuffs */
2962 if ( wfd_sink->pipeline )
2964 MMWFDSinkGstElement* mainbin = wfd_sink->pipeline->mainbin;
2968 MMWFDSinkGstElement* audiobin = wfd_sink->pipeline->audiobin;
2969 MMWFDSinkGstElement* videobin = wfd_sink->pipeline->videobin;
2971 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_videobin(wfd_sink))
2973 wfd_sink_error("failed to destroy videobin\n");
2974 return MM_ERROR_WFD_INTERNAL;
2977 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audiobin(wfd_sink))
2979 wfd_sink_error("failed to destroy audiobin\n");
2980 return MM_ERROR_WFD_INTERNAL;
2983 ret = gst_element_set_state (mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
2984 if ( ret != GST_STATE_CHANGE_SUCCESS )
2986 wfd_sink_error("failed to change state of mainbin to NULL\n");
2987 return MM_ERROR_WFD_INTERNAL;
2990 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
2992 MMWFDSINK_FREEIF( audiobin );
2993 MMWFDSINK_FREEIF( videobin );
2994 MMWFDSINK_FREEIF( mainbin );
2997 MMWFDSINK_FREEIF( wfd_sink->pipeline );
3000 wfd_sink->added_av_pad_num = 0;
3001 wfd_sink->audio_bin_is_linked = FALSE;
3002 wfd_sink->video_bin_is_linked = FALSE;
3003 wfd_sink->need_to_reset_basetime = FALSE;
3005 wfd_sink_debug_fleave();
3007 return MM_ERROR_NONE;
3011 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
3013 GstIterator*iter = NULL;
3014 gboolean done = FALSE;
3016 GstElement *item = NULL;
3017 GstElementFactory *factory = NULL;
3019 GstState state = GST_STATE_VOID_PENDING;
3020 GstState pending = GST_STATE_VOID_PENDING;
3021 GstClockTime time = 200*GST_MSECOND;
3023 wfd_sink_debug_fenter();
3025 wfd_sink_return_if_fail ( wfd_sink &&
3026 wfd_sink->pipeline &&
3027 wfd_sink->pipeline->mainbin &&
3028 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3030 iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
3036 switch ( gst_iterator_next (iter, (gpointer)&item) )
3038 case GST_ITERATOR_OK:
3039 gst_element_get_state(GST_ELEMENT (item),&state, &pending, time);
3041 factory = gst_element_get_factory (item) ;
3044 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d\n",
3045 GST_STR_NULL(GST_OBJECT_NAME(factory)),
3046 GST_STR_NULL(GST_ELEMENT_NAME(item)),
3047 gst_element_state_get_name(state),
3048 gst_element_state_get_name(pending),
3049 GST_OBJECT_REFCOUNT_VALUE(item));
3051 gst_object_unref (item);
3053 case GST_ITERATOR_RESYNC:
3054 gst_iterator_resync (iter);
3056 case GST_ITERATOR_ERROR:
3059 case GST_ITERATOR_DONE:
3066 item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3068 gst_element_get_state(GST_ELEMENT (item),&state, &pending, time);
3070 factory = gst_element_get_factory (item) ;
3073 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d\n",
3074 GST_OBJECT_NAME(factory),
3075 GST_ELEMENT_NAME(item),
3076 gst_element_state_get_name(state),
3077 gst_element_state_get_name(pending),
3078 GST_OBJECT_REFCOUNT_VALUE(item) );
3082 gst_iterator_free (iter);
3084 wfd_sink_debug_fleave();
3090 __mm_wfds_sink_get_state_name ( MMWFDSinkStateType state )
3094 case MM_WFD_SINK_STATE_NONE:
3096 case MM_WFD_SINK_STATE_NULL:
3098 case MM_WFD_SINK_STATE_PREPARED:
3100 case MM_WFD_SINK_STATE_CONNECTED:
3102 case MM_WFD_SINK_STATE_PLAYING:
3104 case MM_WFD_SINK_STATE_PAUSED:
3106 case MM_WFD_SINK_STATE_DISCONNECTED:
3107 return "DISCONNECTED";