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>
25 #include <Elementary.h>
26 #include <Ecore_Wayland.h>
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"
35 #define PRINT_WFD_REF_COUNT(wfd_sink)\
37 wfd_sink_debug("PRINT WFD REF COUNT");\
38 __mm_wfd_sink_print_ref_count(wfd_sink);\
42 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
43 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
44 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
45 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
46 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
47 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink);
48 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
49 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
50 static gboolean _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data);
53 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
56 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
58 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink, const char *ini_path)
60 int result = MM_ERROR_NONE;
62 wfd_sink_debug_fenter();
64 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
65 if (ini_path == NULL) {
66 ini_path = MM_WFD_SINK_INI_DEFAULT_PATH;
67 wfd_sink_debug("The wfd ini file path is set as defalut[%s]", ini_path);
70 mm_wfd_sink_t *new_wfd_sink = NULL;
73 new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
75 wfd_sink_error("failed to allocate memory for wi-fi display sink");
76 return MM_ERROR_WFD_NO_FREE_SPACE;
79 /* Initialize gstreamer related */
80 new_wfd_sink->attrs = 0;
82 new_wfd_sink->pipeline = NULL;
83 new_wfd_sink->audio_decodebin_is_linked = FALSE;
84 new_wfd_sink->video_decodebin_is_linked = FALSE;
86 /* Initialize timestamp compensation related */
87 new_wfd_sink->need_to_reset_basetime = FALSE;
88 new_wfd_sink->clock = NULL;
89 new_wfd_sink->video_buffer_count = 0LL;
90 new_wfd_sink->video_average_gap = 0LL;
91 new_wfd_sink->video_accumulated_gap = 0LL;
92 new_wfd_sink->audio_buffer_count = 0LL;
93 new_wfd_sink->audio_average_gap = 0LL;
94 new_wfd_sink->audio_accumulated_gap = 0LL;
95 new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
97 /* Initialize all states */
98 MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
99 MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
100 MMWFDSINK_PENDING_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
102 /* initialize audio/video information */
103 new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
104 new_wfd_sink->stream_info.audio_stream_info.channels = 0;
105 new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
106 new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
107 new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
108 new_wfd_sink->stream_info.video_stream_info.width = 0;
109 new_wfd_sink->stream_info.video_stream_info.height = 0;
110 new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
112 /* Initialize command */
113 new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
114 new_wfd_sink->waiting_cmd = FALSE;
116 /* Initialize manager related */
117 new_wfd_sink->manager_thread = NULL;
118 new_wfd_sink->manager_thread_cmd = NULL;
119 new_wfd_sink->manager_thread_exit = FALSE;
121 /* Initialize video resolution */
122 new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
124 /* construct attributes */
125 new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
126 if (!new_wfd_sink->attrs) {
127 MMWFDSINK_FREEIF(new_wfd_sink);
128 wfd_sink_error("failed to set attribute");
129 return MM_ERROR_WFD_INTERNAL;
132 /* load ini for initialize */
133 result = mm_wfd_sink_ini_load(&new_wfd_sink->ini, ini_path);
134 if (result != MM_ERROR_NONE) {
135 wfd_sink_error("failed to load ini file[%s]", ini_path);
136 goto fail_to_load_ini;
138 new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
140 /* initialize manager */
141 result = _mm_wfd_sink_init_manager(new_wfd_sink);
142 if (result < MM_ERROR_NONE) {
143 wfd_sink_error("failed to init manager : %d", result);
147 /* initialize gstreamer */
148 result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
149 if (result < MM_ERROR_NONE) {
150 wfd_sink_error("failed to init gstreamer : %d", result);
155 __mm_wfd_sink_set_state(new_wfd_sink, MM_WFD_SINK_STATE_NULL);
157 /* now take handle */
158 *wfd_sink = new_wfd_sink;
160 wfd_sink_debug_fleave();
166 mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
168 _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
169 MMWFDSINK_FREEIF(new_wfd_sink);
176 int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink)
178 int result = MM_ERROR_NONE;
180 wfd_sink_debug_fenter();
182 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
184 /* check current wi-fi display sink state */
185 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
187 /* construct pipeline */
188 /* create main pipeline */
189 result = __mm_wfd_sink_create_pipeline(wfd_sink);
190 if (result < MM_ERROR_NONE) {
191 wfd_sink_error("failed to create pipeline : %d", result);
195 /* create video decodebin */
196 result = __mm_wfd_sink_create_video_decodebin(wfd_sink);
197 if (result < MM_ERROR_NONE) {
198 wfd_sink_error("failed to create video decodebin %d", result);
202 /* create video sinkbin */
203 result = __mm_wfd_sink_create_video_sinkbin(wfd_sink);
204 if (result < MM_ERROR_NONE) {
205 wfd_sink_error("failed to create video sinkbin %d", result);
209 /* create audio decodebin */
210 result = __mm_wfd_sink_create_audio_decodebin(wfd_sink);
211 if (result < MM_ERROR_NONE) {
212 wfd_sink_error("fail to create audio decodebin : %d", result);
216 /* create audio sinkbin */
217 result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink);
218 if (result < MM_ERROR_NONE) {
219 wfd_sink_error("fail to create audio sinkbin : %d", result);
223 /* set pipeline READY state */
224 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
225 if (result < MM_ERROR_NONE) {
226 wfd_sink_error("failed to set state : %d", result);
231 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PREPARED);
233 wfd_sink_debug_fleave();
239 /* need to destroy pipeline already created */
240 __mm_wfd_sink_destroy_pipeline(wfd_sink);
244 int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
246 int result = MM_ERROR_NONE;
248 wfd_sink_debug_fenter();
250 wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"),
251 MM_ERROR_WFD_INVALID_ARGUMENT);
252 wfd_sink_return_val_if_fail(wfd_sink &&
253 wfd_sink->pipeline &&
254 wfd_sink->pipeline->mainbin &&
255 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
256 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
257 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
258 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
259 MM_ERROR_WFD_NOT_INITIALIZED);
261 /* check current wi-fi display sink state */
262 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
264 wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
266 /* set uri to wfdsrc */
267 g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
269 /* set pipeline PAUSED state */
270 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
271 if (result < MM_ERROR_NONE) {
272 wfd_sink_error("failed to set state : %d", result);
276 wfd_sink_debug_fleave();
281 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
283 int result = MM_ERROR_NONE;
285 wfd_sink_debug_fenter();
287 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
289 /* check current wi-fi display sink state */
290 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
292 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
293 wfd_sink_debug("check pipeline is ready to start");
294 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
296 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
297 if (result < MM_ERROR_NONE) {
298 wfd_sink_error("failed to set state : %d", result);
302 wfd_sink_debug_fleave();
307 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
309 int result = MM_ERROR_NONE;
311 wfd_sink_debug_fenter();
313 wfd_sink_return_val_if_fail(wfd_sink &&
314 wfd_sink->pipeline &&
315 wfd_sink->pipeline->mainbin &&
316 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
317 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
318 MM_ERROR_WFD_NOT_INITIALIZED);
320 /* check current wi-fi display sink state */
321 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
323 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-pause", NULL);
325 wfd_sink_debug_fleave();
330 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
332 int result = MM_ERROR_NONE;
334 wfd_sink_debug_fenter();
336 wfd_sink_return_val_if_fail(wfd_sink &&
337 wfd_sink->pipeline &&
338 wfd_sink->pipeline->mainbin &&
339 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
340 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
341 MM_ERROR_WFD_NOT_INITIALIZED);
343 /* check current wi-fi display sink state */
344 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
346 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-resume", NULL);
348 wfd_sink_debug_fleave();
353 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
355 int result = MM_ERROR_NONE;
357 wfd_sink_debug_fenter();
359 wfd_sink_return_val_if_fail(wfd_sink &&
360 wfd_sink->pipeline &&
361 wfd_sink->pipeline->mainbin &&
362 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
363 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
364 MM_ERROR_WFD_NOT_INITIALIZED);
366 /* check current wi-fi display sink state */
367 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
369 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
370 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
372 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "request-close", NULL);
374 wfd_sink_debug_fleave();
379 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
381 int result = MM_ERROR_NONE;
383 wfd_sink_debug_fenter();
385 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
387 /* check current wi-fi display sink state */
388 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
390 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
391 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
393 /* release pipeline */
394 result = __mm_wfd_sink_destroy_pipeline(wfd_sink);
395 if (result != MM_ERROR_NONE) {
396 wfd_sink_error("failed to destory pipeline");
397 return MM_ERROR_WFD_INTERNAL;
399 wfd_sink_debug("success to destory pipeline");
403 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL);
405 wfd_sink_debug_fleave();
410 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
412 int result = MM_ERROR_NONE;
414 wfd_sink_debug_fenter();
416 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
418 /* check current wi-fi display sink state */
419 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
422 mm_wfd_sink_ini_unload(&wfd_sink->ini);
424 /* release attributes */
425 _mmwfd_deconstruct_attribute(wfd_sink->attrs);
427 /* release manager thread */
428 if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
429 wfd_sink_error("failed to release manager");
430 return MM_ERROR_WFD_INTERNAL;
434 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE);
436 wfd_sink_debug_fleave();
441 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
443 int result = MM_ERROR_NONE;
445 wfd_sink_debug_fenter();
447 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
449 wfd_sink->msg_cb = callback;
450 wfd_sink->msg_user_data = user_data;
452 wfd_sink_debug_fleave();
457 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
459 int result = MM_ERROR_NONE;
462 static const int max_argc = 50;
466 wfd_sink_debug_fenter();
469 argc = calloc(1, sizeof(gint));
470 argv = calloc(max_argc, sizeof(gchar *));
471 if (!argc || !argv) {
472 wfd_sink_error("failed to allocate memory for wfdsink");
474 MMWFDSINK_FREEIF(argv);
475 MMWFDSINK_FREEIF(argc);
477 return MM_ERROR_WFD_NO_FREE_SPACE;
480 /* we would not do fork for scanning plugins */
481 argv[*argc] = g_strdup("--gst-disable-registry-fork");
484 /* check disable registry scan */
485 argv[*argc] = g_strdup("--gst-disable-registry-update");
488 /* check disable segtrap */
489 argv[*argc] = g_strdup("--gst-disable-segtrap");
493 for (i = 0; i < 5; i++) {
494 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
495 wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
496 argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
501 wfd_sink_debug("initializing gstreamer with following parameter");
502 wfd_sink_debug("argc : %d", *argc);
504 for (i = 0; i < *argc; i++)
505 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
507 /* initializing gstreamer */
508 if (!gst_init_check(argc, &argv, &err)) {
509 wfd_sink_error("failed to initialize gstreamer: %s",
510 err ? err->message : "unknown error occurred");
514 result = MM_ERROR_WFD_INTERNAL;
518 for (i = 0; i < *argc; i++)
519 MMWFDSINK_FREEIF(argv[i]);
521 MMWFDSINK_FREEIF(argv);
522 MMWFDSINK_FREEIF(argc);
524 wfd_sink_debug_fleave();
529 static GstBusSyncReply
530 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
532 GstBusSyncReply ret = GST_BUS_PASS;
534 wfd_sink_return_val_if_fail(message &&
535 GST_IS_MESSAGE(message) &&
536 GST_MESSAGE_SRC(message),
539 wfd_sink_debug("get message %p, %s from %p, %s", message,
540 GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC(message), GST_MESSAGE_SRC_NAME(message));
542 switch (GST_MESSAGE_TYPE(message)) {
543 case GST_MESSAGE_TAG:
545 case GST_MESSAGE_DURATION:
547 case GST_MESSAGE_STATE_CHANGED:
548 /* we only handle state change messages from pipeline */
549 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
550 _mm_wfd_sink_msg_callback(bus, message, data);
554 case GST_MESSAGE_ASYNC_DONE:
555 if (GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
556 _mm_wfd_sink_msg_callback(bus, message, data);
564 if (ret == GST_BUS_DROP) {
565 gst_message_unref(message);
572 int __mm_wfd_sink_activate_audio_stream(mm_wfd_sink_t *wfd_sink)
574 GstElement *valve = NULL;
575 GstPad *sinkpad = NULL;
576 GstPad *srcpad = NULL;
577 int result = MM_ERROR_NONE;
579 wfd_sink_debug_fenter();
581 wfd_sink_return_val_if_fail(wfd_sink &&
582 wfd_sink->pipeline &&
583 wfd_sink->pipeline->mainbin &&
584 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
585 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
586 MM_ERROR_WFD_NOT_INITIALIZED);
588 valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
589 srcpad = gst_element_get_static_pad(valve, "src");
591 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
595 if (gst_pad_is_linked(srcpad)) {
596 wfd_sink_debug("%s:%s is already linked to %s:%s",
597 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
601 result = __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad);
602 if (MM_ERROR_NONE != result) {
603 wfd_sink_error("failed to prepare audio pipeline....");
607 wfd_sink_debug("try to link %s:%s and %s:%s",
608 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
609 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
610 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
611 wfd_sink_error("failed 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));
617 if (sinkpad != NULL) {
618 gst_object_unref(GST_OBJECT(sinkpad));
623 if (srcpad != NULL) {
624 gst_object_unref(GST_OBJECT(srcpad));
627 /* drop all the audio buffers using valve */
628 g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
630 wfd_sink_debug_fleave();
632 return MM_ERROR_NONE;
635 if (srcpad != NULL) {
636 gst_object_unref(GST_OBJECT(srcpad));
640 if (sinkpad != NULL) {
641 gst_object_unref(GST_OBJECT(sinkpad));
645 wfd_sink_debug_fleave();
646 return MM_ERROR_WFD_INTERNAL;
649 int __mm_wfd_sink_activate_video_stream(mm_wfd_sink_t *wfd_sink)
651 GstElement *valve = NULL;
652 GstPad *sinkpad = NULL;
653 GstPad *srcpad = NULL;
654 int result = MM_ERROR_NONE;
656 wfd_sink_debug_fenter();
658 wfd_sink_return_val_if_fail(wfd_sink &&
659 wfd_sink->pipeline &&
660 wfd_sink->pipeline->mainbin &&
661 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
662 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
663 MM_ERROR_WFD_NOT_INITIALIZED);
665 valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
666 srcpad = gst_element_get_static_pad(valve, "src");
668 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(valve));
672 if (gst_pad_is_linked(srcpad)) {
673 wfd_sink_debug("%s is already linked",
674 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
678 result = __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad);
679 if (MM_ERROR_NONE != result) {
680 wfd_sink_error("failed to prepare video pipeline....");
684 wfd_sink_debug("try to link %s:%s and %s:%s",
685 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
686 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
687 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
688 wfd_sink_error("failed 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));
693 if (sinkpad != NULL) {
694 gst_object_unref(GST_OBJECT(sinkpad));
699 if (srcpad != NULL) {
700 gst_object_unref(GST_OBJECT(srcpad));
703 /* drop all the video buffers using valve */
704 g_object_set(G_OBJECT(valve), "drop", FALSE, NULL);
706 wfd_sink_debug_fleave();
708 return MM_ERROR_NONE;
711 if (srcpad != NULL) {
712 gst_object_unref(GST_OBJECT(srcpad));
716 if (sinkpad != NULL) {
717 gst_object_unref(GST_OBJECT(sinkpad));
721 wfd_sink_debug_fleave();
722 return MM_ERROR_WFD_INTERNAL;
725 int __mm_wfd_sink_deactivate_audio_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
727 int ret = MM_ERROR_NONE;
729 wfd_sink_debug_fenter();
731 wfd_sink_return_val_if_fail(wfd_sink &&
732 wfd_sink->pipeline &&
733 wfd_sink->pipeline->mainbin &&
734 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
735 wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst,
736 MM_ERROR_WFD_NOT_INITIALIZED);
738 /* drop all the audio buffers using valve */
739 g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst), "drop", TRUE, NULL);
742 /* unprepare audio pipeline */
743 ret = __mm_wfd_sink_unprepare_audio_pipeline(wfd_sink);
744 if (ret != MM_ERROR_NONE) {
745 wfd_sink_error("failed to unprepare audio pipeline...");
746 return MM_ERROR_WFD_INTERNAL;
750 wfd_sink_debug_fleave();
752 return MM_ERROR_NONE;
755 int __mm_wfd_sink_deactivate_video_stream(mm_wfd_sink_t *wfd_sink, gboolean unprepare)
757 int ret = MM_ERROR_NONE;
759 wfd_sink_debug_fenter();
761 wfd_sink_return_val_if_fail(wfd_sink &&
762 wfd_sink->pipeline &&
763 wfd_sink->pipeline->mainbin &&
764 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
765 wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst,
766 MM_ERROR_WFD_NOT_INITIALIZED);
768 /* drop all the video buffers using valve */
769 g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst), "drop", TRUE, NULL);
772 /* unprepare video pipeline */
773 ret = __mm_wfd_sink_unprepare_video_pipeline(wfd_sink);
774 if (ret != MM_ERROR_NONE) {
775 wfd_sink_error("failed to unprepare video pipeline...");
776 return MM_ERROR_WFD_INTERNAL;
780 wfd_sink_debug_fleave();
782 return MM_ERROR_NONE;
787 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
789 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
790 const GstStructure *message_structure = gst_message_get_structure(msg);
793 wfd_sink_return_val_if_fail(wfd_sink, FALSE);
794 wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
796 wfd_sink_debug("got %s(%d) from %s",
797 GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
798 GST_MESSAGE_TYPE(msg),
799 GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
801 switch (GST_MESSAGE_TYPE(msg)) {
802 case GST_MESSAGE_ERROR: {
803 GError *error = NULL;
807 gst_message_parse_error(msg, &error, &debug);
809 wfd_sink_error("error : %s", error->message);
810 wfd_sink_error("debug : %s", debug);
812 MMWFDSINK_FREEIF(debug);
817 case GST_MESSAGE_WARNING: {
819 GError *error = NULL;
821 gst_message_parse_warning(msg, &error, &debug);
823 wfd_sink_error("warning : %s", error->message);
824 wfd_sink_error("debug : %s", debug);
826 MMWFDSINK_FREEIF(debug);
831 case GST_MESSAGE_STATE_CHANGED: {
832 const GValue *voldstate, *vnewstate, *vpending;
833 GstState oldstate, newstate, pending;
834 const GstStructure *structure;
836 /* get state info from msg */
837 structure = gst_message_get_structure(msg);
838 if (structure == NULL)
841 voldstate = gst_structure_get_value(structure, "old-state");
842 vnewstate = gst_structure_get_value(structure, "new-state");
843 vpending = gst_structure_get_value(structure, "pending-state");
844 if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
847 oldstate = (GstState)voldstate->data[0].v_int;
848 newstate = (GstState)vnewstate->data[0].v_int;
849 pending = (GstState)vpending->data[0].v_int;
851 wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
852 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
853 gst_element_state_get_name((GstState)oldstate),
854 gst_element_state_get_name((GstState)newstate),
855 gst_element_state_get_name((GstState)pending));
857 /* we only handle messages from pipeline */
858 if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
861 if (oldstate == newstate) {
862 wfd_sink_debug("pipeline reports state transition to old state");
867 case GST_STATE_VOID_PENDING:
869 case GST_STATE_READY:
870 case GST_STATE_PAUSED:
871 case GST_STATE_PLAYING:
878 case GST_MESSAGE_CLOCK_LOST: {
879 GstClock *clock = NULL;
880 gst_message_parse_clock_lost(msg, &clock);
881 wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
882 (clock ? GST_OBJECT_NAME(clock) : "NULL"));
886 case GST_MESSAGE_NEW_CLOCK: {
887 GstClock *clock = NULL;
888 gst_message_parse_new_clock(msg, &clock);
892 if (wfd_sink->clock) {
893 if (wfd_sink->clock != clock)
894 wfd_sink_debug("clock is changed! [%s] -->[%s]",
895 GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
896 GST_STR_NULL(GST_OBJECT_NAME(clock)));
898 wfd_sink_debug("same clock is selected again! [%s]",
899 GST_STR_NULL(GST_OBJECT_NAME(clock)));
901 wfd_sink_debug("new clock [%s] was selected in the pipeline",
902 (GST_STR_NULL(GST_OBJECT_NAME(clock))));
905 wfd_sink->clock = clock;
909 case GST_MESSAGE_APPLICATION: {
910 const gchar *message_structure_name;
912 message_structure_name = gst_structure_get_name(message_structure);
913 if (!message_structure_name)
916 wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
920 case GST_MESSAGE_ELEMENT: {
921 const gchar *structure_name = NULL;
923 structure_name = gst_structure_get_name(message_structure);
924 if (structure_name) {
925 wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
926 if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
927 wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
928 MMWFDSINK_POST_MESSAGE(wfd_sink,
929 MM_ERROR_WFD_INTERNAL,
930 MMWFDSINK_CURRENT_STATE(wfd_sink));
931 } else if (g_strrstr(structure_name, "GstWFDSessionTimeout")) {
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 MM_WFD_SINK_STATE_DISCONNECTED);
941 case GST_MESSAGE_PROGRESS: {
942 GstProgressType type = GST_PROGRESS_TYPE_ERROR;
943 gchar *category = NULL, *text = NULL;
945 gst_message_parse_progress(msg, &type, &category, &text);
946 wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
949 case GST_PROGRESS_TYPE_START:
951 case GST_PROGRESS_TYPE_COMPLETE:
952 if (category && !strcmp(category, "open")) {
953 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED);
954 } else if (category && !strcmp(category, "play")) {
955 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING);
956 /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
957 } else if (category && !strcmp(category, "pause")) {
958 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED);
959 } else if (category && !strcmp(category, "close")) {
960 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED);
963 case GST_PROGRESS_TYPE_CANCELED:
965 case GST_PROGRESS_TYPE_ERROR:
966 if (category && !strcmp(category, "open")) {
967 wfd_sink_error("got error : %s", GST_STR_NULL(text));
968 /*_mm_wfd_sink_disconnect (wfd_sink); */
969 MMWFDSINK_POST_MESSAGE(wfd_sink,
970 MM_ERROR_WFD_INTERNAL,
971 MMWFDSINK_CURRENT_STATE(wfd_sink));
972 } else if (category && !strcmp(category, "play")) {
973 wfd_sink_error("got error : %s", GST_STR_NULL(text));
974 /*_mm_wfd_sink_disconnect (wfd_sink); */
975 MMWFDSINK_POST_MESSAGE(wfd_sink,
976 MM_ERROR_WFD_INTERNAL,
977 MMWFDSINK_CURRENT_STATE(wfd_sink));
978 } else if (category && !strcmp(category, "pause")) {
979 wfd_sink_error("got error : %s", GST_STR_NULL(text));
980 /*_mm_wfd_sink_disconnect (wfd_sink); */
981 MMWFDSINK_POST_MESSAGE(wfd_sink,
982 MM_ERROR_WFD_INTERNAL,
983 MMWFDSINK_CURRENT_STATE(wfd_sink));
984 } else if (category && !strcmp(category, "close")) {
985 wfd_sink_error("got error : %s", GST_STR_NULL(text));
986 /*_mm_wfd_sink_disconnect (wfd_sink); */
987 MMWFDSINK_POST_MESSAGE(wfd_sink,
988 MM_ERROR_WFD_INTERNAL,
989 MMWFDSINK_CURRENT_STATE(wfd_sink));
991 wfd_sink_error("got error : %s", GST_STR_NULL(text));
995 wfd_sink_error("progress message has no type");
999 MMWFDSINK_FREEIF(category);
1000 MMWFDSINK_FREEIF(text);
1004 case GST_MESSAGE_ASYNC_START:
1005 wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1007 case GST_MESSAGE_ASYNC_DONE:
1008 wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1010 case GST_MESSAGE_UNKNOWN:
1011 case GST_MESSAGE_INFO:
1012 case GST_MESSAGE_TAG:
1013 case GST_MESSAGE_BUFFERING:
1014 case GST_MESSAGE_EOS:
1015 case GST_MESSAGE_STATE_DIRTY:
1016 case GST_MESSAGE_STEP_DONE:
1017 case GST_MESSAGE_CLOCK_PROVIDE:
1018 case GST_MESSAGE_STRUCTURE_CHANGE:
1019 case GST_MESSAGE_STREAM_STATUS:
1020 case GST_MESSAGE_SEGMENT_START:
1021 case GST_MESSAGE_SEGMENT_DONE:
1022 case GST_MESSAGE_DURATION:
1023 case GST_MESSAGE_LATENCY:
1024 case GST_MESSAGE_REQUEST_STATE:
1025 case GST_MESSAGE_STEP_START:
1026 case GST_MESSAGE_QOS:
1027 case GST_MESSAGE_ANY:
1030 wfd_sink_debug("unhandled message");
1038 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
1040 GList *bucket = element_bucket;
1041 MMWFDSinkGstElement *element = NULL;
1042 int successful_add_count = 0;
1044 wfd_sink_debug_fenter();
1046 wfd_sink_return_val_if_fail(element_bucket, 0);
1047 wfd_sink_return_val_if_fail(bin, 0);
1049 for (; bucket; bucket = bucket->next) {
1050 element = (MMWFDSinkGstElement *)bucket->data;
1052 if (element && element->gst) {
1054 gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY);
1056 if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
1057 wfd_sink_error("failed to add element [%s] to bin [%s]",
1058 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1059 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1063 wfd_sink_debug("add element [%s] to bin [%s]",
1064 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
1065 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
1067 successful_add_count++;
1071 wfd_sink_debug_fleave();
1073 return successful_add_count;
1077 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
1079 GList *bucket = element_bucket;
1080 MMWFDSinkGstElement *element = NULL;
1081 MMWFDSinkGstElement *prv_element = NULL;
1082 gint successful_link_count = 0;
1084 wfd_sink_debug_fenter();
1086 wfd_sink_return_val_if_fail(element_bucket, -1);
1088 prv_element = (MMWFDSinkGstElement *)bucket->data;
1089 bucket = bucket->next;
1091 for (; bucket; bucket = bucket->next) {
1092 element = (MMWFDSinkGstElement *)bucket->data;
1094 if (element && element->gst) {
1095 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
1096 wfd_sink_debug("linking [%s] to [%s] success",
1097 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1098 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1099 successful_link_count++;
1101 wfd_sink_error("linking [%s] to [%s] failed",
1102 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
1103 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
1108 prv_element = element;
1111 wfd_sink_debug_fleave();
1113 return successful_link_count;
1117 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
1119 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
1121 wfd_sink_debug_fenter();
1123 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1125 MMWFDSINK_PRINT_STATE(wfd_sink);
1127 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
1130 case MM_WFD_SINK_COMMAND_CREATE:
1131 if (cur_state != MM_WFD_SINK_STATE_NONE)
1134 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1137 case MM_WFD_SINK_COMMAND_PREPARE:
1138 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
1140 else if (cur_state != MM_WFD_SINK_STATE_NULL)
1143 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
1146 case MM_WFD_SINK_COMMAND_CONNECT:
1147 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
1149 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
1152 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
1155 case MM_WFD_SINK_COMMAND_START:
1156 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1158 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
1161 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1164 case MM_WFD_SINK_COMMAND_PAUSE:
1165 if (cur_state == MM_WFD_SINK_STATE_PAUSED)
1167 else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
1170 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
1173 case MM_WFD_SINK_COMMAND_RESUME:
1174 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
1176 else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
1179 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
1182 case MM_WFD_SINK_COMMAND_DISCONNECT:
1183 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1184 cur_state == MM_WFD_SINK_STATE_NULL ||
1185 cur_state == MM_WFD_SINK_STATE_PREPARED ||
1186 cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
1188 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
1189 cur_state != MM_WFD_SINK_STATE_CONNECTED &&
1190 cur_state != MM_WFD_SINK_STATE_PAUSED)
1193 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
1196 case MM_WFD_SINK_COMMAND_UNPREPARE:
1197 if (cur_state == MM_WFD_SINK_STATE_NONE ||
1198 cur_state == MM_WFD_SINK_STATE_NULL)
1201 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
1204 case MM_WFD_SINK_COMMAND_DESTROY:
1205 if (cur_state == MM_WFD_SINK_STATE_NONE)
1208 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1215 wfd_sink->cmd = cmd;
1217 wfd_sink_debug_fleave();
1219 return MM_ERROR_NONE;
1222 wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state));
1223 return MM_ERROR_WFD_NO_OP;
1227 wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
1228 return MM_ERROR_WFD_INVALID_STATE;
1231 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
1233 wfd_sink_debug_fenter();
1235 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1237 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) {
1238 wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state));
1239 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1240 return MM_ERROR_NONE;
1243 /* update wi-fi display state */
1244 MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1245 MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1247 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
1248 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1250 /* post state message to application */
1251 MMWFDSINK_POST_MESSAGE(wfd_sink,
1253 MMWFDSINK_CURRENT_STATE(wfd_sink));
1256 MMWFDSINK_PRINT_STATE(wfd_sink);
1258 wfd_sink_debug_fleave();
1260 return MM_ERROR_NONE;
1264 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
1266 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1267 GstState cur_state = GST_STATE_VOID_PENDING;
1268 GstState pending_state = GST_STATE_VOID_PENDING;
1270 wfd_sink_debug_fenter();
1272 wfd_sink_return_val_if_fail(wfd_sink &&
1273 wfd_sink->pipeline &&
1274 wfd_sink->pipeline->mainbin &&
1275 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1276 MM_ERROR_WFD_NOT_INITIALIZED);
1278 wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING,
1279 MM_ERROR_WFD_INVALID_ARGUMENT);
1281 wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1283 result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1284 if (result == GST_STATE_CHANGE_FAILURE) {
1285 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1286 return MM_ERROR_WFD_INTERNAL;
1290 wfd_sink_debug("wait for changing state is completed ");
1292 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1293 &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1294 if (result == GST_STATE_CHANGE_FAILURE) {
1295 wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1297 __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1299 return MM_ERROR_WFD_INTERNAL;
1300 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1301 wfd_sink_debug("successfully changed state but is not able to provide data yet");
1304 wfd_sink_debug("cur state is %s, pending state is %s",
1305 gst_element_state_get_name(cur_state),
1306 gst_element_state_get_name(pending_state));
1310 wfd_sink_debug_fleave();
1312 return MM_ERROR_NONE;
1316 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1318 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1321 wfd_sink_debug_fenter();
1323 wfd_sink_return_if_fail(wfd_sink &&
1324 wfd_sink->pipeline &&
1325 wfd_sink->pipeline->mainbin &&
1326 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1327 wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1330 if (wfd_sink->clock)
1331 base_time = gst_clock_get_time(wfd_sink->clock);
1333 if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1335 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1337 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1338 if (wfd_sink->pipeline->mainbin[i].gst)
1339 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1342 if (wfd_sink->pipeline->v_decodebin) {
1343 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1344 if (wfd_sink->pipeline->v_decodebin[i].gst)
1345 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1349 if (wfd_sink->pipeline->v_sinkbin) {
1350 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1351 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1352 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1356 if (wfd_sink->pipeline->a_decodebin) {
1357 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1358 if (wfd_sink->pipeline->a_decodebin[i].gst)
1359 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1363 if (wfd_sink->pipeline->a_sinkbin) {
1364 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1365 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1366 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1370 wfd_sink->need_to_reset_basetime = FALSE;
1373 wfd_sink_debug_fleave();
1379 __mm_wfd_sink_unprepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1381 GstElement *pipeline = NULL;
1382 GstElement *v_decodebin = NULL;
1383 GstElement *v_sinkbin = NULL;
1384 GstPad *sinkpad = NULL;
1385 GstPad *srcpad = NULL;
1386 int ret = MM_ERROR_NONE;
1388 wfd_sink_debug_fenter();
1390 wfd_sink_return_val_if_fail(wfd_sink &&
1392 MM_ERROR_WFD_NOT_INITIALIZED);
1394 PRINT_WFD_REF_COUNT(wfd_sink);
1395 wfd_sink_error("No-error:unprepare video sink bin");
1396 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1397 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1399 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin)))) {
1400 sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1402 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_sinkbin));
1406 if (gst_pad_is_linked(sinkpad)) {
1407 srcpad = gst_pad_get_peer(sinkpad);
1409 wfd_sink_error("failed to get peer pad of %s:%s",
1410 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1414 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1415 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1416 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1417 if (!gst_pad_unlink(srcpad, sinkpad)) {
1418 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1419 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1420 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1423 gst_object_unref(srcpad);
1426 wfd_sink_debug("video sinkbin's sinkpad is not linked, no need to unlink it");
1428 gst_object_unref(sinkpad);
1431 gst_object_ref(v_sinkbin);
1432 if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1433 wfd_sink_error("failed to remove %s from %s",
1434 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1438 gst_object_unref(pipeline);
1442 ret = __mm_wfd_sink_destroy_video_sinkbin(wfd_sink);
1443 if (ret != MM_ERROR_NONE) {
1444 wfd_sink_error("failed to destroy video sinkbin");
1448 PRINT_WFD_REF_COUNT(wfd_sink);
1450 wfd_sink_error("No-error:unprepare video decode bin");
1451 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1452 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1454 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin)))) {
1455 sinkpad = gst_element_get_static_pad(v_decodebin, "sink");
1457 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(v_decodebin));
1461 if (gst_pad_is_linked(sinkpad)) {
1462 srcpad = gst_pad_get_peer(sinkpad);
1464 wfd_sink_error("failed to get peer pad of %s:%s",
1465 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1469 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1470 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1471 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1472 if (!gst_pad_unlink(srcpad, sinkpad)) {
1473 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1474 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1475 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1478 gst_object_unref(srcpad);
1481 wfd_sink_debug("video decodebin's sinkpad is not linked, no need to unlink it");
1483 gst_object_unref(sinkpad);
1486 srcpad = gst_element_get_static_pad(v_decodebin, "src");
1488 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(v_decodebin));
1492 if (gst_pad_is_linked(srcpad)) {
1493 sinkpad = gst_pad_get_peer(srcpad);
1495 wfd_sink_error("failed to get peer pad of %s:%s",
1496 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1500 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1501 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1502 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1503 if (!gst_pad_unlink(srcpad, sinkpad)) {
1504 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1505 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1506 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1509 gst_object_unref(sinkpad);
1512 wfd_sink_debug("video decodebin's srcpad is not linked, no need to unlink it");
1514 gst_object_unref(srcpad);
1517 wfd_sink_error("try to remove %s from %s",
1518 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1519 gst_object_ref(v_decodebin);
1520 if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1521 wfd_sink_error("failed to remove %s from %s",
1522 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1526 gst_object_unref(pipeline);
1530 ret = __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
1531 if (ret != MM_ERROR_NONE) {
1532 wfd_sink_error("failed to destroy video decodebin");
1536 PRINT_WFD_REF_COUNT(wfd_sink);
1538 wfd_sink_debug_fleave();
1545 gst_object_unref(pipeline);
1550 gst_object_unref(sinkpad);
1555 gst_object_unref(srcpad);
1559 /* need to notify to app */
1560 MMWFDSINK_POST_MESSAGE(wfd_sink,
1561 MM_ERROR_WFD_INTERNAL,
1562 MMWFDSINK_CURRENT_STATE(wfd_sink));
1564 return MM_ERROR_WFD_INTERNAL;
1568 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1570 GstElement *pipeline = NULL;
1571 GstElement *v_decodebin = NULL;
1572 GstElement *v_sinkbin = NULL;
1573 GstPad *srcpad = NULL;
1574 GstPad *sinkpad = NULL;
1576 wfd_sink_debug_fenter();
1578 wfd_sink_return_val_if_fail(wfd_sink &&
1579 wfd_sink->pipeline &&
1580 wfd_sink->pipeline->mainbin &&
1581 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1582 MM_ERROR_WFD_NOT_INITIALIZED);
1584 /* check video decodebin is linked */
1585 if (!wfd_sink->video_decodebin_is_linked) {
1586 /* check video decodebin is created */
1587 if (wfd_sink->pipeline->v_decodebin == NULL) {
1588 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1589 wfd_sink_error("failed to create video decodebin....");
1594 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1595 wfd_sink_error("failed to link video decodebin.....");
1600 /* check video sinkbin is created */
1601 if (wfd_sink->pipeline->v_sinkbin == NULL) {
1602 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1603 wfd_sink_error("failed to create video sinkbin....");
1607 /* add video decodebin to pipeline */
1608 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1609 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1611 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_decodebin));
1613 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1615 if (GST_STATE(v_decodebin) <= GST_STATE_NULL) {
1616 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_decodebin));
1617 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_decodebin, GST_STATE_READY)) {
1618 wfd_sink_error("failed to set state(READY) to video decodebin");
1623 wfd_sink_debug("try to add %s to %s",
1624 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1625 if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_decodebin))) {
1626 wfd_sink_error("failed to add %s to %s",
1627 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1631 wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_decodebin));
1632 if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_decodebin))) {
1633 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_decodebin));
1637 wfd_sink_debug("%s is already added to %s",
1638 GST_ELEMENT_NAME(v_decodebin), GST_ELEMENT_NAME(pipeline));
1639 gst_object_unref(pipeline);
1643 wfd_sink_warning("going on without video decodebin....");
1646 /* add video sinkbin to pipeline */
1647 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1648 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1650 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(v_sinkbin));
1652 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1654 /* prepare video sinkbin before adding */
1655 if (GST_STATE(v_sinkbin) <= GST_STATE_NULL) {
1656 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(v_sinkbin));
1657 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(v_sinkbin, GST_STATE_READY)) {
1658 wfd_sink_error("failed to set state(READY) to video sinkbin");
1662 /* add video sinkbin to pipeline */
1663 wfd_sink_debug("try to add %s to %s",
1664 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1665 if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(v_sinkbin))) {
1666 wfd_sink_error("failed to add %s to %s",
1667 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1671 /* sync state with parent */
1672 wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(v_sinkbin));
1673 if (!gst_element_sync_state_with_parent(GST_ELEMENT(v_sinkbin))) {
1674 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(v_sinkbin));
1678 wfd_sink_debug("%s is already added to %s",
1679 GST_ELEMENT_NAME(v_sinkbin), GST_ELEMENT_NAME(pipeline));
1680 gst_object_unref(pipeline);
1684 wfd_sink_warning("going on without video sinkbin....");
1688 /* link video decodebin and sinkbin */
1689 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1690 v_decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1693 *pad = gst_element_get_static_pad(v_decodebin, "sink");
1695 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1697 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1699 srcpad = gst_element_get_static_pad(v_decodebin, "src");
1701 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(v_decodebin));
1705 if (!gst_pad_is_linked(srcpad)) {
1706 sinkpad = gst_element_get_static_pad(v_sinkbin, "sink");
1708 wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(v_sinkbin));
1712 wfd_sink_debug("try to link %s:%s and %s:%s",
1713 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1714 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1715 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
1716 wfd_sink_error("failed to link %s:%s and %s:%s",
1717 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1718 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1721 gst_object_unref(sinkpad);
1724 gst_object_unref(srcpad);
1727 } else if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1728 v_sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1730 *pad = gst_element_get_static_pad(v_sinkbin, "sink");
1733 wfd_sink_debug_fleave();
1735 return MM_ERROR_NONE;
1739 if (sinkpad != NULL) {
1740 gst_object_unref(sinkpad);
1744 if (srcpad != NULL) {
1745 gst_object_unref(srcpad);
1749 /* need to notify to app */
1750 MMWFDSINK_POST_MESSAGE(wfd_sink,
1751 MM_ERROR_WFD_INTERNAL,
1752 MMWFDSINK_CURRENT_STATE(wfd_sink));
1754 return MM_ERROR_WFD_INTERNAL;
1758 __mm_wfd_sink_unprepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1760 GstElement *pipeline = NULL;
1761 GstElement *a_decodebin = NULL;
1762 GstElement *a_sinkbin = NULL;
1763 GstPad *sinkpad = NULL;
1764 GstPad *srcpad = NULL;
1765 int ret = MM_ERROR_NONE;
1767 wfd_sink_debug_fenter();
1769 wfd_sink_return_val_if_fail(wfd_sink &&
1771 MM_ERROR_WFD_NOT_INITIALIZED);
1773 wfd_sink_error("No-error:unprepare audio sink bin");
1774 PRINT_WFD_REF_COUNT(wfd_sink);
1776 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1777 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1779 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin)))) {
1780 sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
1782 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_sinkbin));
1786 if (gst_pad_is_linked(sinkpad)) {
1787 srcpad = gst_pad_get_peer(sinkpad);
1789 wfd_sink_error("failed to get peer pad of %s:%s",
1790 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1794 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1795 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1796 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1797 if (!gst_pad_unlink(srcpad, sinkpad)) {
1798 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1799 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1800 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1803 gst_object_unref(srcpad);
1806 wfd_sink_debug("audio sinkbin's sinkpad is not linked, no need to unlink it");
1808 gst_object_unref(sinkpad);
1811 gst_object_ref(a_sinkbin);
1812 if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
1813 wfd_sink_error("failed to remove %s from %s",
1814 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
1818 gst_object_unref(pipeline);
1822 ret = __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink);
1823 if (ret != MM_ERROR_NONE) {
1824 wfd_sink_error("failed to destroy audio sinkbin");
1828 PRINT_WFD_REF_COUNT(wfd_sink);
1830 wfd_sink_error("No-error:unprepare audio decode bin");
1831 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1832 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1834 if ((pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin)))) {
1835 sinkpad = gst_element_get_static_pad(a_decodebin, "sink");
1837 wfd_sink_error("failed to get sink pad from %s", GST_ELEMENT_NAME(a_decodebin));
1841 if (gst_pad_is_linked(sinkpad)) {
1842 srcpad = gst_pad_get_peer(sinkpad);
1844 wfd_sink_error("failed to get peer pad of %s:%s",
1845 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1849 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1850 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1851 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1852 if (!gst_pad_unlink(srcpad, sinkpad)) {
1853 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1854 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1855 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1858 gst_object_unref(srcpad);
1861 wfd_sink_debug("audio decodebin's sinkpad is not linked, no need to unlink it");
1863 gst_object_unref(sinkpad);
1866 srcpad = gst_element_get_static_pad(a_decodebin, "src");
1868 wfd_sink_error("failed to get src pad from %s", GST_ELEMENT_NAME(a_decodebin));
1872 if (gst_pad_is_linked(srcpad)) {
1873 sinkpad = gst_pad_get_peer(srcpad);
1875 wfd_sink_error("failed to get peer pad of %s:%s",
1876 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad));
1877 return MM_ERROR_WFD_INTERNAL;
1880 wfd_sink_debug("try to unlink %s:%s and %s:%s",
1881 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1882 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1883 if (!gst_pad_unlink(srcpad, sinkpad)) {
1884 wfd_sink_error("failed to unlink %s:%s and %s:%s",
1885 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
1886 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
1887 return MM_ERROR_WFD_INTERNAL;
1889 gst_object_unref(sinkpad);
1892 wfd_sink_debug("audio decodebin's srcpad is not linked, no need to unlink it");
1894 gst_object_unref(srcpad);
1897 wfd_sink_error("try to remove %s from %s",
1898 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1899 gst_object_ref(a_decodebin);
1900 if (!gst_bin_remove(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
1901 wfd_sink_error("failed to remove %s from %s",
1902 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
1906 gst_object_unref(pipeline);
1910 ret = __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
1911 if (ret != MM_ERROR_NONE) {
1912 wfd_sink_error("failed to destroy audio decodebin");
1916 PRINT_WFD_REF_COUNT(wfd_sink);
1918 wfd_sink_debug_fleave();
1925 gst_object_unref(pipeline);
1929 gst_object_unref(sinkpad);
1934 gst_object_unref(srcpad);
1938 /* need to notify to app */
1939 MMWFDSINK_POST_MESSAGE(wfd_sink,
1940 MM_ERROR_WFD_INTERNAL,
1941 MMWFDSINK_CURRENT_STATE(wfd_sink));
1943 return MM_ERROR_WFD_INTERNAL;
1947 __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink, GstPad **pad)
1949 GstElement *pipeline = NULL;
1950 GstElement *a_decodebin = NULL;
1951 GstElement *a_sinkbin = NULL;
1952 GstPad *srcpad = NULL;
1953 GstPad *sinkpad = NULL;
1955 wfd_sink_debug_fenter();
1957 wfd_sink_return_val_if_fail(wfd_sink &&
1958 wfd_sink->pipeline &&
1959 wfd_sink->pipeline->mainbin &&
1960 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1961 MM_ERROR_WFD_NOT_INITIALIZED);
1963 /* check audio decodebin is linked */
1964 if (!wfd_sink->audio_decodebin_is_linked) {
1965 /* check audio decodebin is created */
1966 if (wfd_sink->pipeline->a_decodebin == NULL) {
1967 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1968 wfd_sink_error("failed to create audio decodebin....");
1973 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1974 wfd_sink_error("failed to link audio decodebin.....");
1979 /* check audio sinkbin is created */
1980 if (wfd_sink->pipeline->a_sinkbin == NULL) {
1981 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
1982 wfd_sink_error("failed to create audio sinkbin....");
1987 /* add audio decodebin to pipeline */
1988 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1989 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1991 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_decodebin));
1993 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1995 if (GST_STATE(a_decodebin) <= GST_STATE_NULL) {
1996 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_decodebin));
1997 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_decodebin, GST_STATE_READY)) {
1998 wfd_sink_error("failed to set state(READY) to audio decodebin");
2003 wfd_sink_debug("try to add %s to %s",
2004 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2005 if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_decodebin))) {
2006 wfd_sink_error("failed to add %s to %s",
2007 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2011 wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_decodebin));
2012 if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_decodebin))) {
2013 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_decodebin));
2017 wfd_sink_debug("%s is already added to %s",
2018 GST_ELEMENT_NAME(a_decodebin), GST_ELEMENT_NAME(pipeline));
2019 gst_object_unref(pipeline);
2023 wfd_sink_warning("going on without audio decodebin....");
2026 /* add audio sinkbin to pipeline */
2027 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2028 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2030 pipeline = GST_ELEMENT_CAST(gst_element_get_parent(a_sinkbin));
2032 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2034 /* prepare audio sinkbin before adding */
2035 if (GST_STATE(a_sinkbin) <= GST_STATE_NULL) {
2036 wfd_sink_debug("need to prepare %s", GST_ELEMENT_NAME(a_sinkbin));
2037 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(a_sinkbin, GST_STATE_READY)) {
2038 wfd_sink_error("failed to set state(READY) to audio sinkbin");
2043 /* add audio sinkbin to pipeline */
2044 wfd_sink_debug("try to add %s to %s",
2045 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2046 if (!gst_bin_add(GST_BIN(pipeline), GST_ELEMENT(a_sinkbin))) {
2047 wfd_sink_error("failed to add %s to %s",
2048 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2052 /* sync state with parent */
2053 wfd_sink_debug("need to sync state %s with its parent", GST_ELEMENT_NAME(a_sinkbin));
2054 if (!gst_element_sync_state_with_parent(GST_ELEMENT(a_sinkbin))) {
2055 wfd_sink_error("failed to sync %s state with parent", GST_ELEMENT_NAME(a_sinkbin));
2059 wfd_sink_debug("%s is already added to %s",
2060 GST_ELEMENT_NAME(a_sinkbin), GST_ELEMENT_NAME(pipeline));
2061 gst_object_unref(pipeline);
2065 wfd_sink_warning("going on without audio sinkbin....");
2069 /* link audio decodebin and sinkbin */
2070 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2071 a_decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
2074 *pad = gst_element_get_static_pad(a_decodebin, "sink");
2076 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2078 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2080 srcpad = gst_element_get_static_pad(a_decodebin, "src");
2082 wfd_sink_error("faied to get srcpad from %s", GST_ELEMENT_NAME(a_decodebin));
2086 if (!gst_pad_is_linked(srcpad)) {
2087 sinkpad = gst_element_get_static_pad(a_sinkbin, "sink");
2089 wfd_sink_error("faied to get sinkpad from %s", GST_ELEMENT_NAME(a_sinkbin));
2093 wfd_sink_debug("try to link %s:%s and %s:%s",
2094 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2095 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2096 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2097 wfd_sink_error("failed to link %s:%s and %s:%s",
2098 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2099 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2103 gst_object_unref(sinkpad);
2106 gst_object_unref(srcpad);
2109 } else if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2110 a_sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
2112 *pad = gst_element_get_static_pad(a_sinkbin, "sink");
2115 wfd_sink_debug_fleave();
2117 return MM_ERROR_NONE;
2122 gst_object_unref(pipeline);
2127 gst_object_unref(sinkpad);
2132 gst_object_unref(srcpad);
2136 /* need to notify to app */
2137 MMWFDSINK_POST_MESSAGE(wfd_sink,
2138 MM_ERROR_WFD_INTERNAL,
2139 MMWFDSINK_CURRENT_STATE(wfd_sink));
2141 return MM_ERROR_WFD_INTERNAL;
2144 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
2145 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND) /* 30 sec */
2147 static GstPadProbeReturn
2148 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
2150 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
2151 GstClockTime current_time = GST_CLOCK_TIME_NONE;
2152 GstClockTime start_time = GST_CLOCK_TIME_NONE;
2153 GstClockTime running_time = GST_CLOCK_TIME_NONE;
2154 GstClockTime base_time = GST_CLOCK_TIME_NONE;
2155 GstClockTime render_time = GST_CLOCK_TIME_NONE;
2156 GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
2157 GstBuffer *buffer = NULL;
2158 gint64 ts_offset = 0LL;
2160 wfd_sink_return_val_if_fail(info, FALSE);
2161 wfd_sink_return_val_if_fail(wfd_sink &&
2162 wfd_sink->pipeline &&
2163 wfd_sink->pipeline->mainbin &&
2164 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
2165 GST_PAD_PROBE_DROP);
2167 if (!wfd_sink->clock) {
2168 wfd_sink_warning("pipeline did not select clock, yet");
2169 return GST_PAD_PROBE_OK;
2172 if (wfd_sink->need_to_reset_basetime)
2173 _mm_wfd_sink_reset_basetime(wfd_sink);
2175 /* calculate current runninig time */
2176 current_time = gst_clock_get_time(wfd_sink->clock);
2177 if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
2178 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
2179 else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
2180 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
2181 start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2182 if (GST_CLOCK_TIME_IS_VALID(current_time) &&
2183 GST_CLOCK_TIME_IS_VALID(start_time) &&
2184 GST_CLOCK_TIME_IS_VALID(base_time)) {
2185 running_time = current_time - (start_time + base_time);
2187 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
2188 " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
2189 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
2190 return GST_PAD_PROBE_OK;
2193 /* calculate this buffer rendering time */
2194 buffer = gst_pad_probe_info_get_buffer(info);
2195 if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
2196 wfd_sink_warning("buffer timestamp is invalid.");
2197 return GST_PAD_PROBE_OK;
2200 if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2201 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2202 g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2203 } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2204 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2205 g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
2208 render_time = GST_BUFFER_TIMESTAMP(buffer);
2209 render_time += ts_offset;
2211 /* chekc this buffer could be rendered or not */
2212 if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
2213 diff = GST_CLOCK_DIFF(running_time, render_time);
2215 /* this buffer could be NOT rendered */
2216 wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
2217 GST_STR_NULL((GST_OBJECT_NAME(pad))),
2218 GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
2220 /* this buffer could be rendered */
2221 /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "", */
2222 /* GST_STR_NULL((GST_OBJECT_NAME(pad))), */
2223 /* GST_TIME_ARGS(diff)); */
2227 /* update buffer count and gap */
2228 if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
2229 wfd_sink->video_buffer_count++;
2230 wfd_sink->video_accumulated_gap += diff;
2231 } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
2232 wfd_sink->audio_buffer_count++;
2233 wfd_sink->audio_accumulated_gap += diff;
2235 wfd_sink_warning("invalid buffer type.. ");
2236 return GST_PAD_PROBE_DROP;
2239 if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
2240 /* fisrt 60sec, just calculate the gap between source device and sink device */
2241 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
2242 return GST_PAD_PROBE_OK;
2244 /* every 10sec, calculate the gap between source device and sink device */
2245 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
2246 > COMPENSATION_CHECK_PERIOD) {
2247 gint64 audio_avgrage_gap = 0LL;
2248 gint64 video_avgrage_gap = 0LL;
2249 gint64 audio_avgrage_gap_diff = 0LL;
2250 gint64 video_avgrage_gap_diff = 0LL;
2251 gboolean video_minus_compensation = FALSE;
2252 gboolean audio_minus_compensation = FALSE;
2253 gint64 avgrage_gap_diff = 0LL;
2254 gboolean minus_compensation = FALSE;
2257 if (wfd_sink->video_buffer_count > 0) {
2258 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
2260 if (wfd_sink->video_average_gap != 0) {
2261 if (video_avgrage_gap > wfd_sink->video_average_gap) {
2262 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
2263 video_minus_compensation = TRUE;
2265 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
2266 video_minus_compensation = FALSE;
2269 wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
2270 wfd_sink->video_average_gap = video_avgrage_gap;
2273 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
2274 " ~ %" GST_TIME_FORMAT"",
2275 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2276 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2280 if (wfd_sink->audio_buffer_count > 0) {
2281 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
2283 if (wfd_sink->audio_average_gap != 0) {
2284 if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
2285 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
2286 audio_minus_compensation = TRUE;
2288 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
2289 audio_minus_compensation = FALSE;
2292 wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
2293 wfd_sink->audio_average_gap = audio_avgrage_gap;
2296 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
2297 " ~ %" GST_TIME_FORMAT"",
2298 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
2299 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2302 /* selecet average_gap_diff between video and audio */
2303 /* which makes no buffer drop in the sink elements */
2304 if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
2305 if (!video_minus_compensation && !audio_minus_compensation) {
2306 minus_compensation = FALSE;
2307 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2308 avgrage_gap_diff = video_avgrage_gap_diff;
2310 avgrage_gap_diff = audio_avgrage_gap_diff;
2311 } else if (video_minus_compensation && audio_minus_compensation) {
2312 minus_compensation = TRUE;
2313 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
2314 avgrage_gap_diff = audio_avgrage_gap_diff;
2316 avgrage_gap_diff = video_avgrage_gap_diff;
2318 minus_compensation = FALSE;
2319 if (!video_minus_compensation)
2320 avgrage_gap_diff = video_avgrage_gap_diff;
2322 avgrage_gap_diff = audio_avgrage_gap_diff;
2324 } else if (video_avgrage_gap_diff) {
2325 minus_compensation = video_minus_compensation;
2326 avgrage_gap_diff = video_avgrage_gap_diff;
2327 } else if (audio_avgrage_gap_diff) {
2328 minus_compensation = audio_minus_compensation;
2329 avgrage_gap_diff = audio_avgrage_gap_diff;
2332 wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
2333 audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
2334 video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
2337 /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
2338 if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
2339 if (minus_compensation)
2340 ts_offset -= avgrage_gap_diff;
2342 ts_offset += avgrage_gap_diff;
2344 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
2345 GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
2346 minus_compensation ? "-" : "", avgrage_gap_diff,
2347 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
2349 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
2350 g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2351 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
2352 g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
2354 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
2355 minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
2359 wfd_sink->video_buffer_count = 0;
2360 wfd_sink->video_accumulated_gap = 0LL;
2361 wfd_sink->audio_buffer_count = 0;
2362 wfd_sink->audio_accumulated_gap = 0LL;
2363 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2366 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
2367 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
2368 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
2371 return GST_PAD_PROBE_OK;
2376 __mm_wfd_sink_demux_pad_added(GstElement *demux, GstPad *pad, gpointer data)
2378 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2379 gchar *name = gst_pad_get_name(pad);
2380 GstElement *pipeline = NULL;
2381 GstElement *valve = NULL;
2382 GstPad *sinkpad = NULL;
2383 GstPad *srcpad = NULL;
2385 wfd_sink_debug_fenter();
2387 wfd_sink_return_if_fail(wfd_sink &&
2388 wfd_sink->pipeline &&
2389 wfd_sink->pipeline->mainbin &&
2390 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
2392 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
2394 /* take srcpad from demuxer added pad */
2395 srcpad = gst_object_ref(pad);
2397 if (name[0] == 'v') {
2398 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst)
2399 valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_V_VALVE].gst;
2400 } else if (name[0] == 'a') {
2401 if (wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst)
2402 valve = wfd_sink->pipeline->mainbin[WFD_SINK_M_A_VALVE].gst;
2405 /* add, link and run the valve */
2407 wfd_sink_debug("try to add %s to pipeline", GST_ELEMENT_NAME(valve));
2409 if (!gst_bin_add(GST_BIN(pipeline), valve)) {
2410 wfd_sink_error("failed to add %s to pipeline",
2411 GST_ELEMENT_NAME(valve));
2415 sinkpad = gst_element_get_static_pad(valve, "sink");
2417 wfd_sink_error("failed to get sink pad from %s",
2418 GST_ELEMENT_NAME(valve));
2422 wfd_sink_debug("try to link %s:%s and %s:%s",
2423 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2424 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2425 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2426 wfd_sink_error("failed to link %s:%s and %s:%s",
2427 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2428 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2431 gst_object_unref(GST_OBJECT(srcpad));
2433 gst_object_unref(GST_OBJECT(sinkpad));
2436 wfd_sink_debug("try to sync %s's state with parent", GST_ELEMENT_NAME(valve));
2437 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(valve))) {
2438 wfd_sink_error("failed to sync %s state with parent",
2439 GST_PAD_NAME(valve));
2443 srcpad = gst_element_get_static_pad(valve, "src");
2445 wfd_sink_error("failed to get src pad from %s",
2446 GST_ELEMENT_NAME(valve));
2451 /* take decodebin/sinkbin */
2452 if (name[0] == 'v') {
2453 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
2455 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
2457 gst_pad_add_probe(pad,
2458 GST_PAD_PROBE_TYPE_BUFFER,
2459 _mm_wfd_sink_check_running_time,
2463 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink, &sinkpad)) {
2464 wfd_sink_error("failed to prepare video pipeline....");
2467 } else if (name[0] == 'a') {
2468 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
2470 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
2472 gst_pad_add_probe(pad,
2473 GST_PAD_PROBE_TYPE_BUFFER,
2474 _mm_wfd_sink_check_running_time,
2478 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink, &sinkpad)) {
2479 wfd_sink_error("failed to prepare audio pipeline....");
2483 wfd_sink_error("unexceptable pad is added!!!");
2488 wfd_sink_debug("try to link %s:%s and %s:%s",
2489 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2490 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2491 if (GST_PAD_LINK_OK != gst_pad_link_full(srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING)) {
2492 wfd_sink_error("failed to link %s:%s and %s:%s",
2493 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), GST_PAD_NAME(srcpad),
2494 GST_ELEMENT_NAME(GST_PAD_PARENT(sinkpad)), GST_PAD_NAME(sinkpad));
2498 if (name[0] == 'v') {
2499 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
2500 } else if (name[0] == 'a') {
2501 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
2505 MMWFDSINK_FREEIF(name);
2508 gst_object_unref(GST_OBJECT(srcpad));
2512 gst_object_unref(GST_OBJECT(sinkpad));
2515 wfd_sink_debug_fleave();
2521 /* need to notify to app */
2522 MMWFDSINK_POST_MESSAGE(wfd_sink,
2523 MM_ERROR_WFD_INTERNAL,
2524 MMWFDSINK_CURRENT_STATE(wfd_sink));
2530 __mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data)
2532 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2534 wfd_sink_debug_fenter();
2536 wfd_sink_return_if_fail(wfd_sink);
2537 wfd_sink_return_if_fail(need_to_flush);
2539 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
2540 wfd_sink_debug("need to flush pipeline");
2541 *need_to_flush = (gpointer) TRUE;
2543 wfd_sink_debug("don't need to flush pipeline");
2544 *need_to_flush = (gpointer) FALSE;
2548 wfd_sink_debug_fleave();
2553 __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data)
2555 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
2556 MMWFDSinkStreamInfo *stream_info = NULL;
2557 gint is_valid_audio_format = FALSE;
2558 gint is_valid_video_format = FALSE;
2559 gchar *audio_format;
2560 gchar *video_format;
2562 wfd_sink_debug_fenter();
2564 wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
2565 wfd_sink_return_if_fail(wfd_sink);
2567 stream_info = &wfd_sink->stream_info;
2569 if (gst_structure_has_field(str, "audio_format")) {
2570 is_valid_audio_format = TRUE;
2571 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
2572 if (g_strrstr(audio_format, "AAC"))
2573 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
2574 else if (g_strrstr(audio_format, "AC3"))
2575 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
2576 else if (g_strrstr(audio_format, "LPCM"))
2577 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
2579 wfd_sink_error("invalid audio format(%s)...", audio_format);
2580 is_valid_audio_format = FALSE;
2583 if (is_valid_audio_format == TRUE) {
2584 if (gst_structure_has_field(str, "audio_rate"))
2585 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
2586 if (gst_structure_has_field(str, "audio_channels"))
2587 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
2588 if (gst_structure_has_field(str, "audio_bitwidth"))
2589 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
2591 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
2593 wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t \n",
2595 stream_info->audio_stream_info.sample_rate,
2596 stream_info->audio_stream_info.channels,
2597 stream_info->audio_stream_info.bitwidth);
2601 if (gst_structure_has_field(str, "video_format")) {
2602 is_valid_video_format = TRUE;
2603 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
2604 if (g_strrstr(video_format, "H264")) {
2605 stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
2606 } else if (g_strrstr(video_format, "H265")) {
2607 stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H265;
2609 wfd_sink_error("invalid video format(%s)...", video_format);
2610 is_valid_video_format = FALSE;
2613 if (is_valid_video_format == TRUE) {
2614 if (gst_structure_has_field(str, "video_width"))
2615 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
2616 if (gst_structure_has_field(str, "video_height"))
2617 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
2618 if (gst_structure_has_field(str, "video_framerate"))
2619 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
2621 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
2623 wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t",
2625 stream_info->video_stream_info.width,
2626 stream_info->video_stream_info.height,
2627 stream_info->video_stream_info.frame_rate);
2631 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
2633 wfd_sink_debug_fleave();
2636 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint64 *CEA_resolution,
2637 guint64 *VESA_resolution, guint64 *HH_resolution)
2639 if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
2641 *CEA_resolution = 0;
2642 *VESA_resolution = 0;
2645 if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
2646 *CEA_resolution |= WFD_CEA_1920x1080P30;
2648 if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
2649 *CEA_resolution |= WFD_CEA_1280x720P30;
2651 if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
2652 *HH_resolution |= WFD_HH_960x540P30;
2654 if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
2655 *HH_resolution |= WFD_HH_864x480P30;
2657 if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
2658 *CEA_resolution |= WFD_CEA_720x480P60;
2660 if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
2661 *CEA_resolution |= WFD_CEA_640x480P60;
2663 if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
2664 *HH_resolution |= WFD_HH_640x360P30;
2667 static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc)
2669 GstStructure *wfd_audio_codecs = NULL;
2670 GstStructure *wfd_video_formats = NULL;
2671 GstStructure *wfd_content_protection = NULL;
2672 GstStructure *wfd2_video_formats = NULL;
2673 GstStructure *wfd2_audio_codecs = NULL;
2674 gint hdcp_version = 0;
2676 guint64 CEA_resolution = 0;
2677 guint64 VESA_resolution = 0;
2678 guint64 HH_resolution = 0;
2679 GObjectClass *klass;
2681 wfd_sink_debug_fenter();
2683 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2684 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2685 wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED);
2687 klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc));
2689 if (g_object_class_find_property(klass, "enable-pad-probe")) /* for common wfdsrc */
2690 g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.trace_buffers_of_wfdsrc, NULL);
2691 g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
2692 g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
2693 g_object_set(G_OBJECT(wfdsrc), "user-agent", wfd_sink->ini.user_agent, NULL);
2694 g_object_set(G_OBJECT(wfdsrc), "dump-rtsp-message", wfd_sink->ini.dump_rtsp_message, NULL);
2695 if (g_object_class_find_property(klass, "dump-rtp-data"))
2696 g_object_set(G_OBJECT(wfdsrc), "dump-rtp-data", wfd_sink->ini.dump_rtp_data, NULL);
2697 if (g_object_class_find_property(klass, "trace-first-buffer"))
2698 g_object_set(G_OBJECT(wfdsrc), "trace-first-buffer", wfd_sink->ini.trace_first_buffer, NULL);
2699 if (g_object_class_find_property(klass, "trace-buffers"))
2700 g_object_set(G_OBJECT(wfdsrc), "trace-buffers", wfd_sink->ini.trace_buffers, NULL);
2701 if (g_object_class_find_property(klass, "do-request"))
2702 g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
2704 /* set audio parameter for Wi-Fi Display session negotiation */
2705 wfd_audio_codecs = gst_structure_new("wfd_audio_codecs",
2706 "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_codec,
2707 "audio_latency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_latency,
2708 "audio_channels", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_channel,
2709 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.wfd_audio_codecs.audio_sampling_frequency,
2712 if (wfd_audio_codecs) {
2713 g_object_set(G_OBJECT(wfdsrc), "wfd-audio-codecs", wfd_audio_codecs, NULL);
2714 gst_structure_free(wfd_audio_codecs);
2715 wfd_audio_codecs = NULL;
2718 /* set video parameter for Wi-Fi Display session negotiation */
2719 CEA_resolution = wfd_sink->ini.wfd_video_formats.video_cea_support;
2720 VESA_resolution = wfd_sink->ini.wfd_video_formats.video_vesa_support;
2721 HH_resolution = wfd_sink->ini.wfd_video_formats.video_hh_support;
2723 __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
2724 &CEA_resolution, &VESA_resolution, &HH_resolution);
2725 wfd_video_formats = gst_structure_new("wfd_video_formats",
2726 "video_codec", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_codec,
2727 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_native_resolution,
2728 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2729 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2730 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2731 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_profile,
2732 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_level,
2733 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd_video_formats.video_latency,
2734 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_vertical_resolution,
2735 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_horizontal_resolution,
2736 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_minimum_slicing,
2737 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_slice_enc_param,
2738 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd_video_formats.video_framerate_control_support,
2741 if (wfd_video_formats) {
2742 g_object_set(G_OBJECT(wfdsrc), "wfd-video-formats", wfd_video_formats, NULL);
2743 gst_structure_free(wfd_video_formats);
2744 wfd_video_formats = NULL;
2748 /* set hdcp parameter for Wi-Fi Display session negotiation */
2749 if (wfd_sink->ini.wfd_content_protection.enable_hdcp) {
2750 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
2751 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
2752 wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
2754 wfd_content_protection = gst_structure_new("wfd_content_protection",
2755 "hdcp_version", G_TYPE_INT, hdcp_version,
2756 "hdcp_port_no", G_TYPE_INT, hdcp_port,
2759 if (wfd_content_protection) {
2760 g_object_set(G_OBJECT(wfdsrc), "wfd-content-protection", wfd_content_protection, NULL);
2761 gst_structure_free(wfd_content_protection);
2762 wfd_content_protection = NULL;
2766 if (g_object_class_find_property(klass, "wfd2-audio-codecs")) {
2767 /* set audio parameter for Wi-Fi Display R2 session negotiation */
2768 wfd2_audio_codecs = gst_structure_new("wfd2-audio-codecs",
2769 "audio_codec", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_codec,
2770 "audio_lpcm_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_lpcm_mode,
2771 "audio_aac_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_aac_mode,
2772 "audio_ac3_mode", G_TYPE_UINT, wfd_sink->ini.wfd2_audio_codecs.audio_ac3_mode,
2775 if (wfd2_audio_codecs) {
2776 g_object_set(G_OBJECT(wfdsrc), "wfd2-audio-codecs", wfd2_audio_codecs, NULL);
2777 gst_structure_free(wfd2_audio_codecs);
2778 wfd2_audio_codecs = NULL;
2782 if (g_object_class_find_property(klass, "wfd2-video-format-h264")) {
2783 /* set video parameter for Wi-Fi Display R2 session negotiation */
2784 CEA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_cea_support;
2785 VESA_resolution = wfd_sink->ini.wfd2_video_h264_info.video_vesa_support;
2786 HH_resolution = wfd_sink->ini.wfd2_video_h264_info.video_hh_support;
2788 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H264) {
2789 wfd2_video_formats = gst_structure_new("wfd2-video-format-h264",
2790 "video_codec", G_TYPE_UINT, WFD_VIDEO_H264,
2791 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2792 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2793 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2794 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2795 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_profile,
2796 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_level,
2797 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h264_info.video_latency,
2798 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_vertical_resolution,
2799 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_horizontal_resolution,
2800 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_minimum_slicing,
2801 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_slice_enc_param,
2802 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h264_info.video_framerate_control_support,
2803 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2806 if (wfd2_video_formats) {
2807 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h264", wfd2_video_formats, NULL);
2808 gst_structure_free(wfd2_video_formats);
2809 wfd2_video_formats = NULL;
2814 if (g_object_class_find_property(klass, "wfd2-video-format-h265")) {
2815 /* set video parameter for Wi-Fi Display R2 session negotiation */
2816 CEA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_cea_support;
2817 VESA_resolution = wfd_sink->ini.wfd2_video_h265_info.video_vesa_support;
2818 HH_resolution = wfd_sink->ini.wfd2_video_h265_info.video_hh_support;
2820 if (wfd_sink->ini.wfd2_video_formats.video_codec & WFD_VIDEO_H265) {
2821 wfd2_video_formats = gst_structure_new("wfd2-video-format-h265",
2822 "video_codec", G_TYPE_UINT, WFD_VIDEO_H265,
2823 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.wfd2_video_formats.video_native_resolution,
2824 "video_cea_support", G_TYPE_UINT64, CEA_resolution,
2825 "video_vesa_support", G_TYPE_UINT64, VESA_resolution,
2826 "video_hh_support", G_TYPE_UINT64, HH_resolution,
2827 "video_profile", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_profile,
2828 "video_level", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_level,
2829 "video_latency", G_TYPE_UINT, wfd_sink->ini.wfd2_video_h265_info.video_latency,
2830 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_vertical_resolution,
2831 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_horizontal_resolution,
2832 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_minimum_slicing,
2833 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_slice_enc_param,
2834 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_h265_info.video_framerate_control_support,
2835 "video_non_transcoding_support", G_TYPE_INT, wfd_sink->ini.wfd2_video_formats.video_non_transcoding_support,
2838 if (wfd2_video_formats) {
2839 g_object_set(G_OBJECT(wfdsrc), "wfd2-video-format-h265", wfd2_video_formats, NULL);
2840 gst_structure_free(wfd2_video_formats);
2841 wfd2_video_formats = NULL;
2846 wfd_sink->update_stream_info_sig_id = g_signal_connect(wfdsrc, "update-media-info",
2847 G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
2849 wfd_sink->change_av_format_sig_id = g_signal_connect(wfdsrc, "change-av-format",
2850 G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
2852 wfd_sink_debug_fleave();
2854 return MM_ERROR_NONE;
2857 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
2859 wfd_sink_debug_fenter();
2861 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2862 wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
2864 g_signal_connect(demux, "pad-added",
2865 G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink);
2867 wfd_sink_debug_fleave();
2869 return MM_ERROR_NONE;
2872 static void __mm_wfd_sink_queue_overrun(GstElement *queue, gpointer u_data)
2876 wfd_sink_debug_fenter();
2878 return_if_fail(queue);
2880 g_object_get(G_OBJECT(queue), "current-level-time", &time, NULL);
2882 wfd_sink_warning("%s is overrun(%" GST_TIME_FORMAT")",
2883 GST_ELEMENT_NAME(queue), GST_TIME_ARGS(time));
2885 wfd_sink_debug_fleave();
2890 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
2892 wfd_sink_debug_fenter();
2894 wfd_sink_return_if_fail(wfd_sink);
2895 wfd_sink_return_if_fail(queue);
2897 /* set maximum buffer size of queue as 3sec */
2898 g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
2899 g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
2900 g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
2901 g_signal_connect(queue, "overrun",
2902 G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
2904 wfd_sink_debug_fleave();
2910 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
2912 MMWFDSinkGstElement *mainbin = NULL;
2913 GList *element_bucket = NULL;
2917 wfd_sink_debug_fenter();
2919 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2920 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2922 /* Create pipeline */
2923 wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
2924 if (wfd_sink->pipeline == NULL)
2927 memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
2929 /* create mainbin */
2930 mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2931 if (mainbin == NULL)
2934 memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
2936 /* create pipeline */
2937 mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
2938 mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
2939 if (!mainbin[WFD_SINK_M_PIPE].gst) {
2940 wfd_sink_error("failed to create pipeline");
2945 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE);
2946 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src");
2947 if (mainbin[WFD_SINK_M_SRC].gst) {
2948 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2949 wfd_sink_error("failed to prepare wfdsrc...");
2954 /* create rtpmp2tdepay */
2955 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
2956 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2957 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
2959 MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2961 /* create tsdemuxer*/
2962 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
2963 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
2964 if (mainbin[WFD_SINK_M_DEMUX].gst) {
2965 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
2966 wfd_sink_error("failed to prepare demux...");
2971 /* create valve for audio */
2972 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_A_VALVE, "valve", "audio_valve", FALSE);
2973 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "src");
2974 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_A_VALVE].gst, "sink");
2976 /* create valve for video */
2977 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_V_VALVE, "valve", "video_valve", FALSE);
2978 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "src");
2979 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_V_VALVE].gst, "sink");
2981 /* adding created elements to pipeline */
2982 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
2983 wfd_sink_error("failed to add elements");
2987 /* linking elements in the bucket by added order. */
2988 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2989 wfd_sink_error("failed to link elements");
2993 /* connect bus callback */
2994 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
2996 wfd_sink_error("cannot get bus from pipeline.");
3000 /* add bus message callback*/
3001 wfd_sink->msg_callback_id = gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
3003 /* set sync handler to get tag synchronously */
3004 gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
3006 g_list_free(element_bucket);
3007 element_bucket = NULL;
3008 gst_object_unref(GST_OBJECT(bus));
3011 /* now we have completed mainbin. take it */
3012 wfd_sink->pipeline->mainbin = mainbin;
3014 wfd_sink_debug_fleave();
3016 return MM_ERROR_NONE;
3020 wfd_sink_error("ERROR : releasing pipeline");
3023 g_list_free(element_bucket);
3024 element_bucket = NULL;
3028 gst_object_unref(GST_OBJECT(bus));
3031 /* release element which are not added to bin */
3032 for (i = 1; i < WFD_SINK_M_NUM; i++) { /* NOTE : skip pipeline */
3033 if (mainbin != NULL && mainbin[i].gst) {
3034 GstObject *parent = NULL;
3035 parent = gst_element_get_parent(mainbin[i].gst);
3038 gst_object_unref(GST_OBJECT(mainbin[i].gst));
3039 mainbin[i].gst = NULL;
3041 gst_object_unref(GST_OBJECT(parent));
3047 /* release mainbin with it's childs */
3048 if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) {
3049 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3050 mainbin[WFD_SINK_M_PIPE].gst = NULL;
3053 MMWFDSINK_FREEIF(mainbin);
3055 MMWFDSINK_FREEIF(wfd_sink->pipeline);
3057 return MM_ERROR_WFD_INTERNAL;
3060 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3062 MMWFDSinkGstElement *a_decodebin = NULL;
3063 MMWFDSinkGstElement *first_element = NULL;
3064 MMWFDSinkGstElement *last_element = NULL;
3065 GList *element_bucket = NULL;
3066 GstPad *sinkpad = NULL;
3067 GstPad *srcpad = NULL;
3068 GstPad *ghostpad = NULL;
3069 GList *list_temp = NULL;
3071 wfd_sink_debug_fenter();
3073 wfd_sink_return_val_if_fail(wfd_sink &&
3074 wfd_sink->pipeline &&
3075 wfd_sink->pipeline->a_decodebin &&
3076 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
3077 MM_ERROR_WFD_NOT_INITIALIZED);
3079 if (wfd_sink->audio_decodebin_is_linked) {
3080 wfd_sink_debug("audio decodebin is already linked... nothing to do");
3081 return MM_ERROR_NONE;
3084 /* take audio decodebin */
3085 a_decodebin = wfd_sink->pipeline->a_decodebin;
3087 /* check audio queue */
3088 if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3089 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]);
3091 /* check audio hdcp */
3092 if (a_decodebin[WFD_SINK_A_D_HDCP].gst)
3093 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]);
3095 /* check audio codec */
3096 switch (wfd_sink->stream_info.audio_stream_info.codec) {
3097 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3098 if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
3099 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
3100 if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
3101 GstCaps *caps = NULL;
3102 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
3103 caps = gst_caps_new_simple("audio/x-raw",
3104 "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
3105 "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
3106 "format", G_TYPE_STRING, "S16BE", NULL);
3108 g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
3109 gst_object_unref(GST_OBJECT(caps));
3114 case MM_WFD_SINK_AUDIO_CODEC_AAC:
3115 if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
3116 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
3117 if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
3118 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
3121 case MM_WFD_SINK_AUDIO_CODEC_AC3:
3122 if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
3123 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
3124 if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
3125 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
3129 wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
3130 return MM_ERROR_WFD_INTERNAL;
3134 if (element_bucket == NULL) {
3135 wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it");
3136 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3137 wfd_sink_error("failed to destroy audio decodebin");
3143 /* adding elements to audio decodebin */
3144 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) {
3145 wfd_sink_error("failed to add elements to audio decodebin");
3149 /* linking elements in the bucket by added order. */
3150 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3151 wfd_sink_error("failed to link elements of the audio decodebin");
3155 /* get first element's sinkpad for creating ghostpad */
3156 list_temp = g_list_first(element_bucket);
3157 if (list_temp == NULL) {
3158 wfd_sink_error("failed to get first list of the element_bucket");
3162 first_element = (MMWFDSinkGstElement *)list_temp->data;
3163 if (!first_element) {
3164 wfd_sink_error("failed to get first element of the audio decodebin");
3168 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3170 wfd_sink_error("failed to get sink pad from element(%s)",
3171 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3175 ghostpad = gst_ghost_pad_new("sink", sinkpad);
3177 wfd_sink_error("failed to create ghostpad of audio decodebin");
3181 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3182 wfd_sink_error("failed to add ghostpad to audio decodebin");
3185 gst_object_unref(GST_OBJECT(sinkpad));
3189 /* get last element's src for creating ghostpad */
3190 list_temp = g_list_last(element_bucket);
3191 if (list_temp == NULL) {
3192 wfd_sink_error("failed to get last list of the element_bucket");
3196 last_element = (MMWFDSinkGstElement *)list_temp->data;
3197 if (!last_element) {
3198 wfd_sink_error("failed to get last element of the audio decodebin");
3202 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3204 wfd_sink_error("failed to get src pad from element(%s)",
3205 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3209 ghostpad = gst_ghost_pad_new("src", srcpad);
3211 wfd_sink_error("failed to create ghostpad of audio decodebin");
3215 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
3216 wfd_sink_error("failed to add ghostpad to audio decodebin");
3219 gst_object_unref(GST_OBJECT(srcpad));
3222 g_list_free(element_bucket);
3225 wfd_sink->audio_decodebin_is_linked = TRUE;
3227 wfd_sink_debug_fleave();
3229 return MM_ERROR_NONE;
3234 gst_object_unref(GST_OBJECT(srcpad));
3239 gst_object_unref(GST_OBJECT(sinkpad));
3243 g_list_free(element_bucket);
3245 return MM_ERROR_WFD_INTERNAL;
3248 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
3250 wfd_sink_debug_fenter();
3252 /* check audiosink is created */
3253 wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
3254 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3256 g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE, NULL);
3257 g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
3258 g_object_set(G_OBJECT(audio_sink), "slave-method", 2, NULL);
3259 g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL);
3260 g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
3262 wfd_sink_debug_fleave();
3264 return MM_ERROR_NONE;
3267 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3269 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3270 MMWFDSinkGstElement *a_decodebin = NULL;
3271 GstObject *parent = NULL;
3274 wfd_sink_debug_fenter();
3276 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3278 if (wfd_sink->pipeline &&
3279 wfd_sink->pipeline->a_decodebin &&
3280 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
3281 a_decodebin = wfd_sink->pipeline->a_decodebin;
3283 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
3284 return MM_ERROR_NONE;
3287 parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
3289 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
3291 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
3292 wfd_sink_debug("try to change state of audio decodebin to NULL");
3293 ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
3294 if (ret != GST_STATE_CHANGE_SUCCESS) {
3295 wfd_sink_error("failed to change state of audio decodebin to NULL");
3296 return MM_ERROR_WFD_INTERNAL;
3300 /* release element which are not added to bin */
3301 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
3302 if (a_decodebin[i].gst) {
3303 parent = gst_element_get_parent(a_decodebin[i].gst);
3305 wfd_sink_debug("unref %s(current ref %d)",
3306 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3307 ((GObject *) a_decodebin[i].gst)->ref_count);
3308 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3309 a_decodebin[i].gst = NULL;
3311 wfd_sink_debug("%s has parent.(current ref %d)",
3312 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
3313 ((GObject *) a_decodebin[i].gst)->ref_count);
3314 gst_object_unref(GST_OBJECT(parent));
3320 /* release audio decodebin with it's childs */
3321 if (a_decodebin[WFD_SINK_A_D_BIN].gst) {
3322 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3323 a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3327 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
3328 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3330 gst_object_unref(GST_OBJECT(parent));
3334 wfd_sink->audio_decodebin_is_linked = FALSE;
3336 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
3338 wfd_sink_debug_fleave();
3340 return MM_ERROR_NONE;
3343 int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
3345 MMWFDSinkGstElement *a_decodebin = NULL;
3346 gint audio_codec = WFD_AUDIO_UNKNOWN;
3347 GList *element_bucket = NULL;
3348 gboolean link = TRUE;
3351 wfd_sink_debug_fenter();
3353 wfd_sink_return_val_if_fail(wfd_sink &&
3355 MM_ERROR_WFD_NOT_INITIALIZED);
3357 if (wfd_sink->pipeline->a_decodebin != NULL) {
3358 wfd_sink_error("The audio decode bin is already created.");
3359 return MM_ERROR_NONE;
3362 /* check audio decodebin could be linked now */
3363 switch (wfd_sink->stream_info.audio_stream_info.codec) {
3364 case MM_WFD_SINK_AUDIO_CODEC_AAC:
3365 audio_codec = WFD_AUDIO_AAC;
3368 case MM_WFD_SINK_AUDIO_CODEC_AC3:
3369 audio_codec = WFD_AUDIO_AC3;
3372 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
3373 audio_codec = WFD_AUDIO_LPCM;
3376 case MM_WFD_SINK_AUDIO_CODEC_NONE:
3378 wfd_sink_debug("audio decodebin could NOT be linked now, just create");
3379 audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3385 a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3387 wfd_sink_error("failed to allocate memory for audio decodebin");
3388 return MM_ERROR_WFD_NO_FREE_SPACE;
3391 memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
3393 /* create audio decodebin */
3394 a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
3395 a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
3396 if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
3397 wfd_sink_error("failed to create audio decodebin");
3402 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
3403 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink");
3404 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "src");
3405 if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
3406 __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
3409 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
3410 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink");
3411 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "src");
3414 audio_codec = wfd_sink->ini.wfd_audio_codecs.audio_codec;
3415 if (audio_codec & WFD_AUDIO_LPCM) {
3416 /* create LPCM converter */
3417 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
3418 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink");
3419 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src");
3421 /* create LPCM filter */
3422 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
3423 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink");
3424 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src");
3427 if (audio_codec & WFD_AUDIO_AAC) {
3428 /* create AAC parse */
3429 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
3430 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink");
3431 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src");
3433 /* create AAC decoder */
3434 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
3435 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink");
3436 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src");
3439 if (audio_codec & WFD_AUDIO_AC3) {
3440 /* create AC3 parser */
3441 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
3442 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink");
3443 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src");
3445 /* create AC3 decoder */
3446 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
3447 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink");
3448 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src");
3451 g_list_free(element_bucket);
3454 wfd_sink->pipeline->a_decodebin = a_decodebin;
3456 /* link audio decodebin if audio codec is fixed */
3458 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
3459 wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
3460 __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
3461 return MM_ERROR_WFD_INTERNAL;
3465 wfd_sink_debug_fleave();
3467 return MM_ERROR_NONE;
3470 wfd_sink_error("failed to create audio decodebin, release all");
3472 g_list_free(element_bucket);
3474 /* release element which are not added to bin */
3475 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
3476 if (a_decodebin != NULL && a_decodebin[i].gst) {
3477 GstObject *parent = NULL;
3478 parent = gst_element_get_parent(a_decodebin[i].gst);
3481 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
3482 a_decodebin[i].gst = NULL;
3484 gst_object_unref(GST_OBJECT(parent));
3490 /* release audio decodebin with it's childs */
3491 if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) {
3492 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
3493 a_decodebin[WFD_SINK_A_D_BIN].gst = NULL;
3496 MMWFDSINK_FREEIF(a_decodebin);
3498 return MM_ERROR_WFD_INTERNAL;
3501 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3503 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3504 MMWFDSinkGstElement *a_sinkbin = NULL;
3505 GstObject *parent = NULL;
3508 wfd_sink_debug_fenter();
3510 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3512 if (wfd_sink->pipeline &&
3513 wfd_sink->pipeline->a_sinkbin &&
3514 wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3515 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
3517 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
3518 return MM_ERROR_NONE;
3521 parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
3523 wfd_sink_debug("audio sinkbin has no parent.. need to relase by itself");
3525 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
3526 wfd_sink_debug("try to change state of audio sinkbin to NULL");
3527 ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
3528 if (ret != GST_STATE_CHANGE_SUCCESS) {
3529 wfd_sink_error("failed to change state of audio sinkbin to NULL");
3530 return MM_ERROR_WFD_INTERNAL;
3534 /* release element which are not added to bin */
3535 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
3536 if (a_sinkbin[i].gst) {
3537 parent = gst_element_get_parent(a_sinkbin[i].gst);
3539 wfd_sink_debug("unref %s(current ref %d)",
3540 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3541 ((GObject *) a_sinkbin[i].gst)->ref_count);
3542 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3543 a_sinkbin[i].gst = NULL;
3545 wfd_sink_debug("%s has parent.(current ref %d)",
3546 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
3547 ((GObject *) a_sinkbin[i].gst)->ref_count);
3548 gst_object_unref(GST_OBJECT(parent));
3554 /* release audio sinkbin with it's childs */
3555 if (a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3556 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3557 a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3560 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
3561 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3563 gst_object_unref(GST_OBJECT(parent));
3567 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
3569 wfd_sink_debug_fleave();
3571 return MM_ERROR_NONE;
3574 int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
3576 MMWFDSinkGstElement *a_sinkbin = NULL;
3577 MMWFDSinkGstElement *first_element = NULL;
3578 GList *element_bucket = NULL;
3579 GstPad *ghostpad = NULL;
3582 GList *list_temp = NULL;
3584 wfd_sink_debug_fenter();
3586 wfd_sink_return_val_if_fail(wfd_sink &&
3588 MM_ERROR_WFD_NOT_INITIALIZED);
3590 if (wfd_sink->pipeline->a_sinkbin != NULL) {
3591 wfd_sink_error("The audio sink bin is already created.");
3592 return MM_ERROR_NONE;
3596 a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3598 wfd_sink_error("failed to allocate memory for audio sinkbin");
3599 return MM_ERROR_WFD_NO_FREE_SPACE;
3602 memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
3604 /* create audio sinkbin */
3605 a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
3606 a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
3607 if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3608 wfd_sink_error("failed to create audio sinkbin");
3612 /* create resampler */
3613 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER,
3614 wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
3615 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink");
3616 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src");
3619 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME,
3620 wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
3621 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink");
3622 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src");
3624 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_QUEUE,
3625 wfd_sink->ini.name_of_audio_sinkbin_queue, "audio_sinkbin_queue", TRUE);
3626 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst, "sink");
3627 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_QUEUE].gst, "src");
3630 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK,
3631 wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
3632 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink");
3633 if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
3634 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
3635 wfd_sink_error("failed to set audio sink property....");
3640 /* adding created elements to audio sinkbin */
3641 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
3642 wfd_sink_error("failed to add elements to audio sinkbin");
3646 /* linking elements in the bucket by added order. */
3647 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3648 wfd_sink_error("failed to link elements fo the audio sinkbin");
3652 /* get first element's of the audio sinkbin */
3653 list_temp = g_list_first(element_bucket);
3654 if (list_temp == NULL) {
3655 wfd_sink_error("failed to get first list of the element_bucket");
3659 first_element = (MMWFDSinkGstElement *)list_temp->data;
3660 if (!first_element) {
3661 wfd_sink_error("failed to get first element of the audio sinkbin");
3665 /* get first element's sinkpad for creating ghostpad */
3666 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3668 wfd_sink_error("failed to get sink pad from element(%s)",
3669 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3673 ghostpad = gst_ghost_pad_new("sink", pad);
3675 wfd_sink_error("failed to create ghostpad of audio sinkbin");
3679 if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
3680 wfd_sink_error("failed to add ghostpad to audio sinkbin");
3683 gst_object_unref(GST_OBJECT(pad));
3686 g_list_free(element_bucket);
3687 element_bucket = NULL;
3690 wfd_sink->pipeline->a_sinkbin = a_sinkbin;
3692 wfd_sink_debug_fleave();
3694 return MM_ERROR_NONE;
3697 wfd_sink_error("failed to create audio sinkbin, releasing all");
3700 gst_object_unref(GST_OBJECT(pad));
3704 gst_object_unref(GST_OBJECT(ghostpad));
3707 if (element_bucket) {
3708 g_list_free(element_bucket);
3709 element_bucket = NULL;
3712 /* release element which are not added to bin */
3713 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
3714 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
3715 GstObject *parent = NULL;
3716 parent = gst_element_get_parent(a_sinkbin[i].gst);
3719 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
3720 a_sinkbin[i].gst = NULL;
3722 gst_object_unref(GST_OBJECT(parent));
3728 /* release audio sinkbin with it's childs */
3729 if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) {
3730 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
3731 a_sinkbin[WFD_SINK_A_S_BIN].gst = NULL;
3733 MMWFDSINK_FREEIF(a_sinkbin);
3735 return MM_ERROR_WFD_INTERNAL;
3738 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
3740 MMWFDSinkGstElement *v_decodebin = NULL;
3741 MMWFDSinkGstElement *first_element = NULL;
3742 MMWFDSinkGstElement *last_element = NULL;
3743 GList *element_bucket = NULL;
3744 GList *list_temp = NULL;
3745 GstPad *sinkpad = NULL;
3746 GstPad *srcpad = NULL;
3747 GstPad *ghostpad = NULL;
3749 wfd_sink_debug_fenter();
3751 wfd_sink_return_val_if_fail(wfd_sink &&
3752 wfd_sink->pipeline &&
3753 wfd_sink->pipeline->v_decodebin &&
3754 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
3755 MM_ERROR_WFD_NOT_INITIALIZED);
3757 if (wfd_sink->video_decodebin_is_linked) {
3758 wfd_sink_debug("video decodebin is already linked... nothing to do");
3759 return MM_ERROR_NONE;
3762 /* take video decodebin */
3763 v_decodebin = wfd_sink->pipeline->v_decodebin;
3765 /* check video queue */
3766 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3767 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
3769 /* check video hdcp */
3770 if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
3771 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
3773 /* check video codec */
3774 switch (wfd_sink->stream_info.video_stream_info.codec) {
3775 case MM_WFD_SINK_VIDEO_CODEC_H264:
3776 if (v_decodebin[WFD_SINK_V_D_H264_PARSE].gst)
3777 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_PARSE]);
3778 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst)
3779 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H264_DEC]);
3782 case MM_WFD_SINK_VIDEO_CODEC_H265:
3783 if (v_decodebin[WFD_SINK_V_D_H265_PARSE].gst)
3784 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_PARSE]);
3785 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst)
3786 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_H265_DEC]);
3790 wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
3791 return MM_ERROR_WFD_INTERNAL;
3795 if (element_bucket == NULL) {
3796 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
3797 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3798 wfd_sink_error("failed to destroy video decodebin");
3804 /* adding elements to video decodebin */
3805 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
3806 wfd_sink_error("failed to add elements to video decodebin");
3810 /* linking elements in the bucket by added order. */
3811 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3812 wfd_sink_error("failed to link elements of the video decodebin");
3816 /* get first element's sinkpad for creating ghostpad */
3817 list_temp = g_list_first(element_bucket);
3818 if (list_temp == NULL) {
3819 wfd_sink_error("failed to get first list of the element_bucket");
3823 first_element = (MMWFDSinkGstElement *)list_temp->data;
3824 if (!first_element) {
3825 wfd_sink_error("failed to get first element of the video decodebin");
3829 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3831 wfd_sink_error("failed to get sink pad from element(%s)",
3832 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3836 ghostpad = gst_ghost_pad_new("sink", sinkpad);
3838 wfd_sink_error("failed to create ghostpad of video decodebin");
3842 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3843 wfd_sink_error("failed to add ghostpad to video decodebin");
3846 gst_object_unref(GST_OBJECT(sinkpad));
3850 /* get last element's src for creating ghostpad */
3851 list_temp = g_list_last(element_bucket);
3852 if (list_temp == NULL) {
3853 wfd_sink_error("failed to get last list of the element_bucket");
3857 last_element = (MMWFDSinkGstElement *)list_temp->data;
3858 if (!last_element) {
3859 wfd_sink_error("failed to get last element of the video decodebin");
3863 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
3865 wfd_sink_error("failed to get src pad from element(%s)",
3866 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
3870 ghostpad = gst_ghost_pad_new("src", srcpad);
3872 wfd_sink_error("failed to create ghostpad of video decodebin");
3876 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
3877 wfd_sink_error("failed to add ghostpad to video decodebin");
3880 gst_object_unref(GST_OBJECT(srcpad));
3883 g_list_free(element_bucket);
3886 wfd_sink->video_decodebin_is_linked = TRUE;
3888 wfd_sink_debug_fleave();
3890 return MM_ERROR_NONE;
3894 if (srcpad != NULL) {
3895 gst_object_unref(GST_OBJECT(srcpad));
3899 if (sinkpad != NULL) {
3900 gst_object_unref(GST_OBJECT(sinkpad));
3904 if (element_bucket != NULL) {
3905 g_list_free(element_bucket);
3906 element_bucket = NULL;
3908 return MM_ERROR_WFD_INTERNAL;
3911 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
3913 wfd_sink_debug_fenter();
3915 /* check video decoder is created */
3916 wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
3917 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
3919 wfd_sink_debug_fleave();
3921 return MM_ERROR_NONE;
3924 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
3926 gboolean visible = TRUE;
3927 gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
3929 wfd_sink_debug_fenter();
3931 /* check videosink is created */
3932 wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
3933 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
3935 /* update display surface */
3936 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
3937 wfd_sink_debug("check display surface type attribute: %d", surface_type);
3938 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
3939 wfd_sink_debug("check display visible attribute: %d", visible);
3941 /* configuring display */
3942 switch (surface_type) {
3943 case MM_DISPLAY_SURFACE_EVAS: {
3944 void *object = NULL;
3947 /* common case if using evas surface */
3948 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
3949 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
3951 wfd_sink_debug("set video param : evas-object %x", object);
3952 g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
3954 wfd_sink_error("no evas object");
3955 return MM_ERROR_WFD_INTERNAL;
3960 case MM_DISPLAY_SURFACE_OVERLAY: {
3961 static unsigned int wl_surface_id = 0;
3962 static void *display_overlay = NULL;
3963 int wl_window_x = 0;
3964 int wl_window_y = 0;
3965 int wl_window_width = 0;
3966 int wl_window_height = 0;
3967 struct wl_surface *wl_surface = NULL;
3968 struct wl_display *wl_display = NULL;
3969 Ecore_Wl_Window *wl_window = NULL;
3970 wl_client *wlclient = NULL;
3971 Evas_Object *obj = NULL;
3972 void *object = NULL;
3973 const char *object_type = NULL;
3976 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
3978 if (object != NULL) {
3979 obj = (Evas_Object *)object;
3980 object_type = evas_object_type_get(obj);
3981 wfd_sink_debug("window object type : %s", object_type);
3983 /* wayland overlay surface */
3984 LOGI("Wayland overlay surface type");
3985 evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height);
3987 wfd_sink_debug("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y,
3988 wl_window_width, wl_window_height);
3990 wl_window = elm_win_wl_window_get(obj);
3991 wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window);
3993 /* get wl_display */
3994 wl_display = (struct wl_display *) ecore_wl_display_get();
3996 wfd_sink_debug("previous display object : %p current object : %p", display_overlay, object);
3997 if (wl_surface && wl_display && (wl_surface_id == 0 || display_overlay != object)) {
3998 wfd_sink_debug("surface = %p, wl_display = %p", wl_surface, wl_display);
3999 display_overlay = object;
4001 ret = mm_wfd_sink_wlclient_create(&wlclient);
4002 if (ret != MM_ERROR_NONE) {
4003 wfd_sink_error("Wayland client create failure");
4006 wfd_sink_debug("Try to get surface id");
4008 wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id(wlclient, wl_surface, wl_display);
4010 wfd_sink_debug("wl_surface_id = %d", wl_surface_id);
4017 wfd_sink_debug("set video param : surface_id %d", wl_surface_id);
4018 gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(video_sink),
4020 /* After setting window handle, set render rectangle */
4021 gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink),
4022 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
4024 wfd_sink_debug("display object is NULL!");
4025 return MM_ERROR_WFD_INTERNAL;
4030 case MM_DISPLAY_SURFACE_NULL: {
4032 wfd_sink_error("Not Supported Surface.");
4033 return MM_ERROR_WFD_INTERNAL;
4037 wfd_sink_error("Not Supported Surface.(default case)");
4038 return MM_ERROR_WFD_INTERNAL;
4043 g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
4044 g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
4045 g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
4046 g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
4047 g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
4049 wfd_sink_debug_fleave();
4051 return MM_ERROR_NONE;
4054 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
4056 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4057 MMWFDSinkGstElement *v_decodebin = NULL;
4058 GstObject *parent = NULL;
4061 wfd_sink_debug_fenter();
4063 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4065 if (wfd_sink->pipeline &&
4066 wfd_sink->pipeline->v_decodebin &&
4067 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4068 v_decodebin = wfd_sink->pipeline->v_decodebin;
4070 wfd_sink_debug("video decodebin is not created, nothing to destroy");
4071 return MM_ERROR_NONE;
4075 parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
4077 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
4079 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
4080 wfd_sink_debug("try to change state of video decodebin to NULL");
4081 ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
4082 if (ret != GST_STATE_CHANGE_SUCCESS) {
4083 wfd_sink_error("failed to change state of video decodebin to NULL");
4084 return MM_ERROR_WFD_INTERNAL;
4087 /* release element which are not added to bin */
4088 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
4089 if (v_decodebin[i].gst) {
4090 parent = gst_element_get_parent(v_decodebin[i].gst);
4092 wfd_sink_debug("unref %s(current ref %d)",
4093 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4094 ((GObject *) v_decodebin[i].gst)->ref_count);
4095 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4096 v_decodebin[i].gst = NULL;
4098 wfd_sink_debug("%s has parent.(current ref %d)",
4099 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
4100 ((GObject *) v_decodebin[i].gst)->ref_count);
4101 gst_object_unref(GST_OBJECT(parent));
4106 /* release video decodebin with it's childs */
4107 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
4108 wfd_sink_debug("unref %s(current ref %d)",
4109 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
4110 ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
4112 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4113 v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4116 wfd_sink_debug("video decodebin has parent(%s), unref it",
4117 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4119 gst_object_unref(GST_OBJECT(parent));
4123 wfd_sink->video_decodebin_is_linked = FALSE;
4125 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
4127 wfd_sink_debug_fleave();
4129 return MM_ERROR_NONE;
4132 int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
4134 MMWFDSinkGstElement *v_decodebin = NULL;
4135 guint video_codec = WFD_VIDEO_UNKNOWN;
4136 GList *element_bucket = NULL;
4137 gboolean link = TRUE;
4140 wfd_sink_debug_fenter();
4142 wfd_sink_return_val_if_fail(wfd_sink &&
4144 MM_ERROR_WFD_NOT_INITIALIZED);
4146 if (wfd_sink->pipeline->v_decodebin) {
4147 wfd_sink_debug("video decodebin is already created... nothing to do");
4148 return MM_ERROR_NONE;
4151 /* check video decodebin could be linked now */
4152 switch (wfd_sink->stream_info.video_stream_info.codec) {
4153 case MM_WFD_SINK_VIDEO_CODEC_H264:
4154 video_codec = WFD_VIDEO_H264;
4157 case MM_WFD_SINK_VIDEO_CODEC_H265:
4158 video_codec = WFD_VIDEO_H265;
4161 case MM_WFD_SINK_VIDEO_CODEC_NONE:
4163 wfd_sink_debug("video decodebin could NOT be linked now, just create");
4164 video_codec = wfd_sink->ini.wfd_video_formats.video_codec | wfd_sink->ini.wfd2_video_formats.video_codec;
4170 v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4172 wfd_sink_error("failed to allocate memory for video decodebin");
4173 return MM_ERROR_WFD_NO_FREE_SPACE;
4176 memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
4178 /* create video decodebin */
4179 v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
4180 v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
4181 if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
4182 wfd_sink_error("failed to create video decodebin");
4187 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
4188 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink");
4189 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "src");
4190 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
4191 __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
4194 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
4195 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink");
4196 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src");
4198 if (video_codec & WFD_VIDEO_H264) {
4200 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h264_parser", FALSE);
4201 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst, "sink");
4202 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_PARSE].gst, "src");
4205 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H264_DEC, wfd_sink->ini.name_of_video_h264_decoder, "video_h264_dec", FALSE);
4206 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst, "sink");
4207 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H264_DEC].gst, "src");
4208 if (v_decodebin[WFD_SINK_V_D_H264_DEC].gst) {
4209 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H264_DEC].gst)) {
4210 wfd_sink_error("failed to set video decoder property...");
4216 if (video_codec & WFD_VIDEO_H265) {
4218 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_PARSE, wfd_sink->ini.name_of_video_h264_parser, "video_h265_parser", FALSE);
4219 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst, "sink");
4220 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_PARSE].gst, "src");
4223 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_H265_DEC, wfd_sink->ini.name_of_video_h265_decoder, "video_h265_dec", FALSE);
4224 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst, "sink");
4225 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_H265_DEC].gst, "src");
4226 if (v_decodebin[WFD_SINK_V_D_H265_DEC].gst) {
4227 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_H265_DEC].gst)) {
4228 wfd_sink_error("failed to set video decoder property...");
4234 g_list_free(element_bucket);
4237 wfd_sink->pipeline->v_decodebin = v_decodebin;
4239 /* link video decodebin if video codec is fixed */
4241 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
4242 wfd_sink_error("failed to link video decodebin, destroy video decodebin");
4243 __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
4244 return MM_ERROR_WFD_INTERNAL;
4248 wfd_sink_debug_fleave();
4250 return MM_ERROR_NONE;
4254 wfd_sink_error("failed to create video decodebin, releasing all");
4256 g_list_free(element_bucket);
4258 /* release element which are not added to bin */
4259 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
4260 if (v_decodebin != NULL && v_decodebin[i].gst) {
4261 GstObject *parent = NULL;
4262 parent = gst_element_get_parent(v_decodebin[i].gst);
4265 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
4266 v_decodebin[i].gst = NULL;
4268 gst_object_unref(GST_OBJECT(parent));
4274 /* release video decodebin with it's childs */
4275 if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) {
4276 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
4277 v_decodebin[WFD_SINK_V_D_BIN].gst = NULL;
4280 MMWFDSINK_FREEIF(v_decodebin);
4282 return MM_ERROR_WFD_INTERNAL;
4285 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4287 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4288 MMWFDSinkGstElement *v_sinkbin = NULL;
4289 GstObject *parent = NULL;
4292 wfd_sink_debug_fenter();
4294 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4296 if (wfd_sink->pipeline &&
4297 wfd_sink->pipeline->v_sinkbin &&
4298 wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4299 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4301 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
4302 return MM_ERROR_NONE;
4306 parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
4308 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
4310 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
4311 wfd_sink_debug("try to change state of video sinkbin to NULL");
4312 ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
4313 if (ret != GST_STATE_CHANGE_SUCCESS) {
4314 wfd_sink_error("failed to change state of video sinkbin to NULL");
4315 return MM_ERROR_WFD_INTERNAL;
4318 /* release element which are not added to bin */
4319 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
4320 if (v_sinkbin[i].gst) {
4321 parent = gst_element_get_parent(v_sinkbin[i].gst);
4323 wfd_sink_debug("unref %s(current ref %d)",
4324 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4325 ((GObject *) v_sinkbin[i].gst)->ref_count);
4326 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4327 v_sinkbin[i].gst = NULL;
4329 wfd_sink_debug("%s has parent.(current ref %d)",
4330 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
4331 ((GObject *) v_sinkbin[i].gst)->ref_count);
4332 gst_object_unref(GST_OBJECT(parent));
4337 /* release video sinkbin with it's childs */
4338 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4339 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4340 v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4343 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
4344 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
4346 gst_object_unref(GST_OBJECT(parent));
4350 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
4352 wfd_sink_debug_fleave();
4354 return MM_ERROR_NONE;
4357 int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
4359 MMWFDSinkGstElement *first_element = NULL;
4360 MMWFDSinkGstElement *v_sinkbin = NULL;
4361 GList *element_bucket = NULL;
4363 GstPad *ghostpad = NULL;
4365 gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
4367 wfd_sink_debug_fenter();
4369 wfd_sink_return_val_if_fail(wfd_sink &&
4371 MM_ERROR_WFD_NOT_INITIALIZED);
4373 if (wfd_sink->pipeline->v_sinkbin != NULL) {
4374 wfd_sink_error("The video sink bin is already created.");
4375 return MM_ERROR_NONE;
4379 v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4381 wfd_sink_error("failed to allocate memory for video sinkbin");
4382 return MM_ERROR_WFD_NO_FREE_SPACE;
4385 memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
4387 /* create video sinkbin */
4388 v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
4389 v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
4390 if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4391 wfd_sink_error("failed to create video sinkbin");
4395 /* create convert */
4396 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
4397 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink");
4398 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src");
4401 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
4402 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink");
4403 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src");
4404 if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
4405 GstCaps *caps = NULL;
4406 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL);
4407 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
4408 gst_object_unref(GST_OBJECT(caps));
4413 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
4415 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
4416 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
4417 } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) {
4418 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE);
4420 wfd_sink_error("failed to set video sink....");
4424 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink");
4425 if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
4426 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
4427 wfd_sink_error("failed to set video sink property....");
4432 /* adding created elements to video sinkbin */
4433 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
4434 wfd_sink_error("failed to add elements to video sinkbin");
4438 /* linking elements in the bucket by added order. */
4439 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
4440 wfd_sink_error("failed to link elements of the video sinkbin");
4444 /* get first element's sinkpad for creating ghostpad */
4445 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
4446 if (!first_element) {
4447 wfd_sink_error("failed to get first element of the video sinkbin");
4451 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4453 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
4454 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
4458 ghostpad = gst_ghost_pad_new("sink", pad);
4460 wfd_sink_error("failed to create ghostpad of the video sinkbin");
4464 if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
4465 wfd_sink_error("failed to add ghostpad to video sinkbin");
4469 gst_object_unref(GST_OBJECT(pad));
4472 g_list_free(element_bucket);
4473 element_bucket = NULL;
4476 wfd_sink->pipeline->v_sinkbin = v_sinkbin;
4478 wfd_sink_debug_fleave();
4480 return MM_ERROR_NONE;
4484 wfd_sink_error("failed to create video sinkbin, releasing all");
4487 gst_object_unref(GST_OBJECT(pad));
4492 gst_object_unref(GST_OBJECT(ghostpad));
4496 if (element_bucket) {
4497 g_list_free(element_bucket);
4498 element_bucket = NULL;
4501 /* release element which are not added to bin */
4502 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
4503 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
4504 GstObject *parent = NULL;
4505 parent = gst_element_get_parent(v_sinkbin[i].gst);
4508 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
4509 v_sinkbin[i].gst = NULL;
4511 gst_object_unref(GST_OBJECT(parent));
4517 /* release video sinkbin with it's childs */
4518 if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4519 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
4520 v_sinkbin[WFD_SINK_V_S_BIN].gst = NULL;
4522 MMWFDSINK_FREEIF(v_sinkbin);
4524 return MM_ERROR_WFD_INTERNAL;
4527 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
4529 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4532 wfd_sink_debug_fenter();
4534 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4536 /* cleanup gst stuffs */
4537 if (wfd_sink->pipeline) {
4538 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
4542 PRINT_WFD_REF_COUNT(wfd_sink);
4544 ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
4545 if (ret != GST_STATE_CHANGE_SUCCESS) {
4546 wfd_sink_error("failed to change state of pipeline to NULL");
4547 return MM_ERROR_WFD_INTERNAL;
4549 wfd_sink_debug("Successed to change state of pipeline to NULL");
4552 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
4554 GstMessage *gst_msg = NULL;
4555 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
4556 _mm_wfd_sink_msg_callback(bus, gst_msg, (gpointer)wfd_sink);
4557 gst_message_unref(gst_msg);
4560 gst_object_unref(bus);
4564 PRINT_WFD_REF_COUNT(wfd_sink);
4566 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
4567 wfd_sink_error("failed to destroy video decodebin");
4568 return MM_ERROR_WFD_INTERNAL;
4571 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
4572 wfd_sink_error("failed to destroy audio decodebin");
4573 return MM_ERROR_WFD_INTERNAL;
4576 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
4577 wfd_sink_error("failed to destroy video sinkbin");
4578 return MM_ERROR_WFD_INTERNAL;
4581 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
4582 wfd_sink_error("failed to destroy audio sinkbin");
4583 return MM_ERROR_WFD_INTERNAL;
4586 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
4587 mainbin[WFD_SINK_M_PIPE].gst = NULL;
4589 MMWFDSINK_FREEIF(mainbin);
4592 MMWFDSINK_FREEIF(wfd_sink->pipeline);
4595 if (wfd_sink->msg_callback_id > 0) {
4596 g_source_remove(wfd_sink->msg_callback_id);
4597 wfd_sink->msg_callback_id = 0;
4600 wfd_sink->audio_decodebin_is_linked = FALSE;
4601 wfd_sink->video_decodebin_is_linked = FALSE;
4602 wfd_sink->need_to_reset_basetime = FALSE;
4604 wfd_sink_debug_fleave();
4606 return MM_ERROR_NONE;
4610 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
4612 GstIterator *iter = NULL;
4613 gboolean done = FALSE;
4615 GstElement *item = NULL;
4616 GstElementFactory *factory = NULL;
4618 GstState state = GST_STATE_VOID_PENDING;
4619 GstState pending = GST_STATE_VOID_PENDING;
4620 GstClockTime time = 200 * GST_MSECOND;
4622 wfd_sink_debug_fenter();
4624 wfd_sink_return_if_fail(wfd_sink &&
4625 wfd_sink->pipeline &&
4626 wfd_sink->pipeline->mainbin &&
4627 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4629 iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
4633 switch (gst_iterator_next(iter, (gpointer)&item)) {
4634 case GST_ITERATOR_OK:
4635 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4637 factory = gst_element_get_factory(item) ;
4639 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4640 GST_STR_NULL(GST_OBJECT_NAME(factory)),
4641 GST_STR_NULL(GST_ELEMENT_NAME(item)),
4642 gst_element_state_get_name(state),
4643 gst_element_state_get_name(pending),
4644 GST_OBJECT_REFCOUNT_VALUE(item));
4646 gst_object_unref(item);
4649 case GST_ITERATOR_RESYNC:
4650 gst_iterator_resync(iter);
4652 case GST_ITERATOR_ERROR:
4655 case GST_ITERATOR_DONE:
4665 item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
4667 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
4669 factory = gst_element_get_factory(item) ;
4671 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
4672 GST_OBJECT_NAME(factory),
4673 GST_ELEMENT_NAME(item),
4674 gst_element_state_get_name(state),
4675 gst_element_state_get_name(pending),
4676 GST_OBJECT_REFCOUNT_VALUE(item));
4680 gst_iterator_free(iter);
4682 wfd_sink_debug_fleave();
4688 _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
4691 case MM_WFD_SINK_STATE_NONE:
4693 case MM_WFD_SINK_STATE_NULL:
4695 case MM_WFD_SINK_STATE_PREPARED:
4697 case MM_WFD_SINK_STATE_CONNECTED:
4699 case MM_WFD_SINK_STATE_PLAYING:
4701 case MM_WFD_SINK_STATE_PAUSED:
4703 case MM_WFD_SINK_STATE_DISCONNECTED:
4704 return "DISCONNECTED";
4710 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
4712 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
4714 wfd_sink_debug_fenter();
4716 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
4718 MMWFDSINK_PRINT_STATE(wfd_sink);
4719 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
4720 if (cur_state != MM_WFD_SINK_STATE_NULL) {
4721 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
4722 return MM_ERROR_WFD_INVALID_STATE;
4725 wfd_sink->supportive_resolution = resolution;
4727 wfd_sink_debug_fleave();
4729 return MM_ERROR_NONE;
4732 void __mm_wfd_sink_print_ref_count(mm_wfd_sink_t *wfd_sink)
4735 MMWFDSinkGstElement *mainbin = NULL;
4736 MMWFDSinkGstElement *v_decodebin = NULL;
4737 MMWFDSinkGstElement *a_decodebin = NULL;
4738 MMWFDSinkGstElement *v_sinkbin = NULL;
4739 MMWFDSinkGstElement *a_sinkbin = NULL;
4741 wfd_sink_debug_fenter();
4743 wfd_sink_return_if_fail(wfd_sink);
4744 wfd_sink_return_if_fail(wfd_sink->pipeline);
4746 wfd_sink_debug("************* wfd pipeline ref count start *************");
4747 wfd_sink_debug("try to check mainbin");
4749 if (wfd_sink->pipeline->mainbin &&
4750 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) {
4751 mainbin = wfd_sink->pipeline->mainbin;
4753 for (i = 0; i < WFD_SINK_M_NUM; i++) {
4754 if (mainbin[i].gst) {
4755 wfd_sink_debug("%s(current ref %d)",
4756 GST_ELEMENT_NAME(mainbin[i].gst),
4757 GST_OBJECT_REFCOUNT(mainbin[i].gst));
4762 wfd_sink_debug("try to check a_decodebin");
4764 if (wfd_sink->pipeline->a_decodebin &&
4765 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
4766 a_decodebin = wfd_sink->pipeline->a_decodebin;
4768 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
4769 if (a_decodebin[i].gst) {
4770 wfd_sink_debug("%s(current ref %d)",
4771 GST_ELEMENT_NAME(a_decodebin[i].gst),
4772 GST_OBJECT_REFCOUNT(a_decodebin[i].gst));
4777 wfd_sink_debug("try to check a_sinkbin");
4779 if (wfd_sink->pipeline->a_sinkbin &&
4780 wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
4781 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
4783 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
4784 if (a_sinkbin[i].gst) {
4785 wfd_sink_debug("%s(current ref %d)",
4786 GST_ELEMENT_NAME(a_sinkbin[i].gst),
4787 GST_OBJECT_REFCOUNT(a_sinkbin[i].gst));
4792 wfd_sink_debug("try to check v_decodebin");
4794 if (wfd_sink->pipeline->v_decodebin &&
4795 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
4796 v_decodebin = wfd_sink->pipeline->v_decodebin;
4798 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
4799 if (v_decodebin[i].gst) {
4800 wfd_sink_debug("%s(current ref %d)",
4801 GST_ELEMENT_NAME(v_decodebin[i].gst),
4802 GST_OBJECT_REFCOUNT(v_decodebin[i].gst));
4807 wfd_sink_debug("try to check v_sinkbin");
4809 if (wfd_sink->pipeline->v_sinkbin &&
4810 wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
4811 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
4813 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
4814 if (v_sinkbin[i].gst) {
4815 wfd_sink_debug("%s(current ref %d)",
4816 GST_ELEMENT_NAME(v_sinkbin[i].gst),
4817 GST_OBJECT_REFCOUNT(v_sinkbin[i].gst));
4821 wfd_sink_debug("************* wfd pipeline ref count end *************");
4822 wfd_sink_debug_fleave();