From: SeokHoon Lee Date: Wed, 15 Jun 2016 04:16:13 +0000 (+0900) Subject: Change directory structure for code integration X-Git-Tag: submit/tizen/20160616.065630~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F28%2F74628%2F1;p=platform%2Fcore%2Fmultimedia%2Flibmm-wfd.git Change directory structure for code integration Signed-off-by: SeokHoon Lee Change-Id: Ic18ee6c8185315aff848e814ec928ec622f82cda --- diff --git a/Makefile.am b/Makefile.am index 1c508a9..295c304 100755 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ACLOCAL_AMFLAGS='-I m4' -SUBDIRS = common sink +SUBDIRS = src pcfiles = mm-wfd.pc pkgconfigdir = $(libdir)/pkgconfig diff --git a/common/Makefile.am b/common/Makefile.am deleted file mode 100755 index acc19c8..0000000 --- a/common/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -lib_LTLIBRARIES = libwfdcommon.la - -includelibwfdcommondir = $(includedir)/mmf - -libwfdcommon_la_SOURCES = mm_wfd_attrs.c mm_wfd_sink_ini.c - -libwfdcommon_la_CFLAGS = -I$(srcdir)/include \ - $(GLIB_CFLAGS) \ - $(TZPLATFORM_CONFIG_CFLAGS) \ - $(MMCOMMON_CFLAGS) - -libwfdcommon_la_LIBADD = $(GLIB_LIBS) \ - $(MMCOMMON_LIBS) \ - $(TZPLATFORM_CONFIG_LIBS) \ - $(INIPARSER_LIBS) diff --git a/common/include/mm_wfd_attrs.h b/common/include/mm_wfd_attrs.h deleted file mode 100755 index 1c6fc48..0000000 --- a/common/include/mm_wfd_attrs.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Manoj Kumar K , Hyunil Park - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef __MM_WFD_ATTRS_H__ -#define __MM_WFD_ATTRS_H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* general */ -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif -#define MMWFD_MAX_INT (2147483647) - -/** - * Enumeration for attribute values types. - */ -typedef enum { - MM_WFD_ATTRS_TYPE_INVALID = -1, /**< Type is invalid */ - MM_WFD_ATTRS_TYPE_INT, /**< Integer type */ - MM_WFD_ATTRS_TYPE_DOUBLE, /**< Double type */ - MM_WFD_ATTRS_TYPE_STRING, /**< UTF-8 String type */ - MM_WFD_ATTRS_TYPE_DATA, /**< Pointer type */ - MM_WFD_ATTRS_TYPE_ARRAY, /**< Array type */ - MM_WFD_ATTRS_TYPE_RANGE, /**< Range type */ - MM_WFD_ATTRS_TYPE_NUM, /**< Number of attribute type */ -} MMWfdAttrsType; - -/** - * Enumeration for attribute validation type. - */ -typedef enum { - MM_WFD_ATTRS_VALID_TYPE_INVALID = -1, /**< Invalid validation type */ - MM_WFD_ATTRS_VALID_TYPE_NONE, /**< Do not check validity */ - MM_WFD_ATTRS_VALID_TYPE_INT_ARRAY, /**< validity checking type of integer array */ - MM_WFD_ATTRS_VALID_TYPE_INT_RANGE, /**< validity checking type of integer range */ - MM_WFD_ATTRS_VALID_TYPE_DOUBLE_ARRAY, /**< validity checking type of double array */ - MM_WFD_ATTRS_VALID_TYPE_DOUBLE_RANGE, /**< validity checking type of double range */ -} MMWfdAttrsValidType; - -/** - * Enumeration for attribute access flag. - */ -typedef enum { - MM_WFD_ATTRS_FLAG_NONE = 0, /**< None flag is set */ - MM_WFD_ATTRS_FLAG_READABLE = 1 << 0, /**< Readable */ - MM_WFD_ATTRS_FLAG_WRITABLE = 1 << 1, /**< Writable */ - MM_WFD_ATTRS_FLAG_MODIFIED = 1 << 2, /**< Modified */ - - MM_WFD_ATTRS_FLAG_RW = MM_WFD_ATTRS_FLAG_READABLE | MM_WFD_ATTRS_FLAG_WRITABLE, /**< Readable and Writable */ -} MMWfdAttrsFlag; - -/** - * Attribute validity structure - */ -typedef struct { - MMWfdAttrsType type; - MMWfdAttrsValidType validity_type; - MMWfdAttrsFlag flag; - /** - * a union that describes validity of the attribute. - * Only when type is 'MM_ATTRS_TYPE_INT' or 'MM_ATTRS_TYPE_DOUBLE', - * the attribute can have validity. - */ - union { - /** - * Validity structure for integer array. - */ - struct { - int *array; /**< a pointer of array */ - int count; /**< size of array */ - int d_val; - } int_array; - /** - * Validity structure for integer range. - */ - struct { - int min; /**< minimum range */ - int max; /**< maximum range */ - int d_val; - } int_range; - /** - * Validity structure for double array. - */ - struct { - double *array; /**< a pointer of array */ - int count; /**< size of array */ - double d_val; - } double_array; - /** - * Validity structure for double range. - */ - struct { - double min; /**< minimum range */ - double max; /**< maximum range */ - double d_val; - } double_range; - }; -} MMWfdAttrsInfo; - -MMHandleType _mmwfd_construct_attribute(MMHandleType hwfd); -void _mmwfd_deconstruct_attribute(MMHandleType hwfd); -int _mmwfd_set_attribute(MMHandleType hwfd, char **err_atr_name, const char *attribute_name, va_list args_list); -int _mmwfd_get_attributes_info(MMHandleType handle, const char *attribute_name, MMWfdAttrsInfo *dst_info); -int _mmwfd_get_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list); -#endif /* __MM_WFD_ATTRS_H__ */ \ No newline at end of file diff --git a/common/include/mm_wfd_sink_dlog.h b/common/include/mm_wfd_sink_dlog.h deleted file mode 100755 index 58082e8..0000000 --- a/common/include/mm_wfd_sink_dlog.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __MM_WFD_SINK_DLOG_H__ -#define __MM_WFD_SINK_DLOG_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MM_WFD_SINK" - -#define FONT_COLOR_RESET "\033[0m" -#define FONT_COLOR_RED "\033[31m" -#define FONT_COLOR_GREEN "\033[32m" -#define FONT_COLOR_YELLOW "\033[33m" -#define FONT_COLOR_BLUE "\033[34m" -#define FONT_COLOR_PURPLE "\033[35m" -#define FONT_COLOR_CYAN "\033[36m" -#define FONT_COLOR_GRAY "\033[37m" - -#define wfd_sink_debug(fmt, arg...) do { \ - LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ - } while (0) - -#define wfd_sink_info(fmt, arg...) do { \ - LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ - } while (0) - -#define wfd_sink_error(fmt, arg...) do { \ - LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ - } while (0) - -#define wfd_sink_warning(fmt, arg...) do { \ - LOGW(FONT_COLOR_YELLOW""fmt""FONT_COLOR_RESET, ##arg); \ - } while (0) - -#define wfd_sink_debug_fenter() do { \ - LOGD(FONT_COLOR_RESET""); \ - } while (0) - -#define wfd_sink_debug_fleave() do { \ - LOGD(FONT_COLOR_RESET""); \ - } while (0) - -#define wfd_sink_error_fenter() do { \ - LOGE(FONT_COLOR_RED"NO-ERROR : "FONT_COLOR_RESET); \ - } while (0) - -#define wfd_sink_error_fleave() do { \ - LOGE(FONT_COLOR_RED"NO-ERROR : "FONT_COLOR_RESET); \ - } while (0) - -#define wfd_sink_sucure_info(fmt, arg...) do { \ - SECURE_LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ - } while (0) - -#define wfd_sink_return_if_fail(expr) \ - if(!(expr)) { \ - wfd_sink_error(FONT_COLOR_RED"failed [%s]\n"FONT_COLOR_RESET, #expr); \ - return; \ - } - -#define wfd_sink_return_val_if_fail(expr, val) \ - if (!(expr)) { \ - wfd_sink_error(FONT_COLOR_RED"failed [%s]\n"FONT_COLOR_RESET, #expr); \ - return val; \ - } - -#define wfd_sink_assert_not_reached() \ - { \ - wfd_sink_error(FONT_COLOR_RED"assert_not_reached()"FONT_COLOR_RESET); \ - assert(0); \ - } - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MM_WFD_SINK_DLOG_H__ */ - diff --git a/common/include/mm_wfd_sink_ini.h b/common/include/mm_wfd_sink_ini.h deleted file mode 100755 index 73da585..0000000 --- a/common/include/mm_wfd_sink_ini.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Manoj Kumar K , Hyunil Park - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef __MM_WFD_SINK_INI_H__ -#define __MM_WFD_SINK_INI_H__ - -#include -#include -#include "mm_wfd_sink_wfd_enum.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -enum WFDSinkINIProbeFlags -{ - WFD_SINK_INI_PROBE_DEFAULT = 0, - WFD_SINK_INI_PROBE_TIMESTAMP = (1 << 0), - WFD_SINK_INI_PROBE_BUFFERSIZE = (1 << 1), - WFD_SINK_INI_PROBE_CAPS = (1 << 2), - WFD_SINK_INI_PROBE_BUFFER_DURATION = (1 << 3), -}; - -#define MM_WFD_SINK_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_wfd_sink.ini" - -#define WFD_SINK_INI_MAX_STRLEN 256 -#define WFD_SINK_INI_MAX_ELEMENT 10 - -/* NOTE : MMPlayer has no initalizing API for library itself - * so we cannot decide when those ini values to be released. - * this is the reason of all string items are static array. - * make it do with malloc when MMPlayerInitialize() API created - * before that time, we should be careful with size limitation - * of each string item. - */ -typedef struct __mm_wfd_sink_ini { - /* general */ - gchar gst_param[5][WFD_SINK_INI_MAX_STRLEN]; - gboolean generate_dot; - gboolean enable_pad_probe; - gint state_change_timeout; - gboolean set_debug_property; - gboolean enable_asm; - gint jitter_buffer_latency; - gint video_sink_max_lateness; - gint sink_ts_offset; - gboolean audio_sink_async; - gboolean video_sink_async; - gboolean enable_retransmission; - gboolean enable_reset_basetime; - gboolean enable_ts_data_dump; - gboolean enable_wfdsrc_pad_probe; - - /* pipeline */ - gchar name_of_source[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_tsdemux[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_audio_hdcp[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_aac_parser[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_aac_decoder[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_ac3_parser[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_ac3_decoder[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_lpcm_converter[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_lpcm_filter[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_audio_resampler[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_audio_volume[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_audio_sink[WFD_SINK_INI_MAX_STRLEN]; - - gchar name_of_video_hdcp[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_parser[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_capssetter[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_decoder[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_converter[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_filter[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_sink[WFD_SINK_INI_MAX_STRLEN]; - gchar name_of_video_evas_sink[WFD_SINK_INI_MAX_STRLEN]; - - /* audio parameter for reponse of M3 request */ - guint audio_codec; - guint audio_latency; - guint audio_channel; - guint audio_sampling_frequency; - - /* video parameter for reponse of M3 request */ - guint video_codec; - guint video_native_resolution; - guint video_cea_support; - guint video_vesa_support; - guint video_hh_support; - guint video_profile; - guint video_level; - guint video_latency; - gint video_vertical_resolution; - gint video_horizontal_resolution; - gint video_minimum_slicing; - gint video_slice_enc_param; - gint video_framerate_control_support; - - /* hdcp parameter for reponse of M3 request */ - gint hdcp_content_protection; - gint hdcp_port_no; -} mm_wfd_sink_ini_t; - - -/*Default sink ini values*/ -/* General*/ -#define DEFAULT_GST_PARAM "" -#define DEFAULT_GENERATE_DOT FALSE -#define DEFAULT_ENABLE_PAD_PROBE FALSE -#define DEFAULT_STATE_CHANGE_TIMEOUT 5 /* sec */ -#define DEFAULT_SET_DEBUG_PROPERTY TRUE -#define DEFAULT_ENABLE_ASM FALSE -#define DEFAULT_JITTER_BUFFER_LATENCY 10 /* msec */ -#define DEFAULT_ENABLE_RETRANSMISSION FALSE -#define DEFAULT_ENABLE_RESET_BASETIME TRUE -#define DEFAULT_VIDEO_SINK_MAX_LATENESS 20000000 /* nsec */ -#define DEFAULT_SINK_TS_OFFSET 150000000 /* nsec */ -#define DEFAULT_AUDIO_SINK_ASYNC FALSE -#define DEFAULT_VIDEO_SINK_ASYNC FALSE -#define DEFAULT_ENABLE_TS_DATA_DUMP FALSE -#define DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE FALSE - -/* Pipeline */ -#define DEFAULT_NAME_OF_SOURCE "wfdsrc" -#define DEFAULT_NAME_OF_TSDEMUX "" -#define DEFAULT_NAME_OF_AUDIO_HDCP "" -#define DEFAULT_NAME_OF_AAC_PARSER "" -#define DEFAULT_NAME_OF_AAC_DECODER "" -#define DEFAULT_NAME_OF_AC3_PARSER "" -#define DEFAULT_NAME_OF_AC3_DECODER "" -#define DEFAULT_NAME_OF_LPCM_CONVERTER "" -#define DEFAULT_NAME_OF_LPCM_FILTER "" -#define DEFAULT_NAME_OF_AUDIO_RESAMPLER "" -#define DEFAULT_NAME_OF_AUDIO_VOLUME "" -#define DEFAULT_NAME_OF_AUDIO_SPLITTER "" -#define DEFAULT_NAME_OF_AUDIO_SINK "" -#define DEFAULT_NAME_OF_VIDEO_HDCP "" -#define DEFAULT_NAME_OF_VIDEO_PARSER "" -#define DEFAULT_NAME_OF_VIDEO_CAPSSETTER "" -#define DEFAULT_NAME_OF_VIDEO_DECODER "" -#define DEFAULT_NAME_OF_VIDEO_CONVERTER "" -#define DEFAULT_NAME_OF_VIDEO_FILTER "" -#define DEFAULT_NAME_OF_VIDEO_SINK "" -#define DEFAULT_NAME_OF_EVAS_VIDEO_SINK "" - -/* Audio */ -#define DEFAULT_AUDIO_CODEC WFD_AUDIO_LPCM | WFD_AUDIO_AAC -#define DEFAULT_AUDIO_LATENCY 0x0 -#define DEFAULT_AUDIO_CHANNELS WFD_CHANNEL_2 -#define DEFAULT_AUDIO_SAMP_FREQUENCY WFD_FREQ_44100 | WFD_FREQ_48000 - -/* Video */ -#define DEFAULT_VIDEO_CODEC WFD_VIDEO_H264 -#define DEFAULT_VIDEO_NATIVE_RESOLUTION 0x20 -/* CEA : WFD_CEA_640x480P60 | WFD_CEA_720x480P60 |WFD_CEA_720x576P50 |WFD_CEA_1280x720P30 | - WFD_CEA_1280x720P25 | WFD_CEA_1280x720P24 */ -#define DEFAULT_VIDEO_CEA_SUPPORT 0x84ab -/* VESA : WFD_VESA_800x600P30 */ -#define DEFAULT_VIDEO_VESA_SUPPORT 0x1 -/* HH : WFD_HH_800x480P30 | WFD_HH_854x480P30 | WFD_HH_864x480P30 | WFD_HH_640x360P30 | WFD_HH_960x540P30 | WFD_HH_848x480P30 */ -#define DEFAULT_VIDEO_HH_SUPPORT 0x555 -#define DEFAULT_VIDEO_PROFILE WFD_H264_BASE_PROFILE -#define DEFAULT_VIDEO_LEVEL WFD_H264_LEVEL_3_2 -#define DEFAULT_VIDEO_LATENCY 0x0 -#define DEFAULT_VIDEO_VERTICAL_RESOLUTION 720 -#define DEFAULT_VIDEO_HORIZONTAL_RESOLUTION 1280 -#define DEFAULT_VIDEO_MIN_SLICESIZE 0 -#define DEFAULT_VIDEO_SLICE_ENC_PARAM 200 -#define DEFAULT_VIDEO_FRAMERATE_CONTROL 11 - -/* HDCP */ -#define DEFAULT_HDCP_CONTENT_PROTECTION 0x0 -#define DEFAULT_HDCP_PORT_NO 0 - - -#define MM_WFD_SINK_DEFAULT_INI \ -" \ -[general]\n\ -; parameters for initializing gstreamer\n\ -; DEFAULT SET(--gst-debug=2, *wfd*:5)\n\ -gstparam1 = --gst-debug=2, *wfd*:5, *wfdtsdemux:1, *wfdrtpbuffer:1\n\ -gstparam2 =\n\ -gstparam3 =\n\ -gstparam4 =\n\ -gstparam5 =\n\ -\n\ -; generating dot file representing pipeline state\n\ -; do export GST_DEBUG_DUMP_DOT_DIR=[dot file path] in the shell\n\ -generate dot = no\n\ -\n\ -; enable pad probe\n\ -enable pad probe = no\n\ -\n\ -; enable wfdsrc inner pad probe\n\ -enable wfdsrc pad probe = no\n\ -\n\ -; enable ts data dump(eg. /var/tmp/*.ts)\n\ -enable ts data dump = no\n\ -\n\ -; allowed timeout for changing pipeline state\n\ -state change timeout = 5 ; sec\n\ -\n\ -; set debug property to wfdsrc plugin for debugging rtsp message\n\ -set debug property = yes\n\ -\n\ -; for asm function enable = yes, disable = no\n\ -enable asm = no\n\ -\n\ -; 0: default value set by wfdsrc element, other: user define value.\n\ -jitter buffer latency=10\n\ -\n\ -; for retransmission request enable = yes, disable = no\n\ -enable retransmission = no\n\ -\n\ -; for reset basetime, enable = yes, disable = no\n\ -enable reset basetime = yes\n\ -\n\ -; Maximum number of nanoseconds that a buffer can be late before it is dropped by videosink(-1 unlimited)\n\ -video sink max lateness=20000000\n\ -\n\ -; nanoseconds to be added to buffertimestamp by sink elements\n\ -sink ts offset=150000000\n\ -\n\ -; if no, go asynchronously to PAUSED without preroll \n\ -audio sink async=no\n\ -\n\ -; if no, go asynchronously to PAUSED without preroll \n\ -video sink async=no\n\ -\n\ -\n\ -\n\ -[pipeline]\n\ -wfdsrc element = wfdsrc\n\ -\n\ -tsdemux element = wfdtsdemux\n\ -\n\ -aac parser element = aacparse\n\ -\n\ -aac decoder element = avdec_aac\n\ -\n\ -ac3 parser element = ac3parse\n\ -\n\ -ac3 decoder element =\n\ -\n\ -lpcm converter element =\n\ -\n\ -lpcm filter element = capsfilter\n\ -\n\ -audio resampler element = audioconvert\n\ -\n\ -audio volume element =\n\ -\n\ -audio sink element = pulsesink\n\ -\n\ -video parser element = h264parse\n\ -\n\ -video capssetter element = capssetter\n\ -\n\ -video decoder element = avdec_h264;sprddec_h264;omxh264dec\n\ -\n\ -video converter element =\n\ -\n\ -video filter element =\n\ -\n\ -video sink element = waylandsink;xvimagesink\n\ -\n\ -\n\ -\n\ -[audio param]\n\ -; 0x1: LPCM, 0x2: aac, 0x4: ac3\n\ -;default aac and LPCM\n\ -audio codec=0x3\n\ -\n\ -audio latency=0x0\n\ -\n\ -;0x1 : 48000khz, 0x2: 44100khz\n\ -audio sampling frequency=0x3\n\ -\n\ -; 0x1:2 channels, 0x2:4 channels, 0x4:6channels, 0x8:8channels\n\ -audio channels=0x1\n\ -\n\ -\n\ -\n\ -[video param]\n\ -; 0: H264CBP 1: H264CHP\n\ -video codec=0x1\n\ -\n\ -video native resolution = 0x20\n\ -\n\ -video cea support=0x842b\n\ -\n\ -video vesa support=0x1\n\ -\n\ -video hh support=0x555\n\ -\n\ -; 0x1:base, 0x2:high\n\ -video profile=0x1\n\ -\n\ -; 0x1:level_3_1, 0x2:level_3_2, 0x4:level_4, 0x8:level_4_1, 0x10:level_4_2\n\ -video level=0x2\n\ -\n\ -video latency=0x0\n\ -\n\ -video vertical resolution=720\n\ -\n\ -video horizontal resolution=1280\n\ -\n\ -video minimum slicesize=0\n\ -\n\ -video slice encoding params=200\n\ -\n\ -video framerate control support=11\n\ -\n\ -\n\ -\n\ -[hdcp param]\n\ -;0x0:none, 0x1:HDCP_2.0, 0x2:HDCP_2.1\n\ -hdcp content protection=0x0\n\ -\n\ -hdcp port no=0\n\ -\n\ -" - -int -mm_wfd_sink_ini_load(mm_wfd_sink_ini_t *ini); - -int -mm_wfd_sink_ini_unload(mm_wfd_sink_ini_t *ini); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/common/include/mm_wfd_sink_wfd_enum.h b/common/include/mm_wfd_sink_wfd_enum.h deleted file mode 100755 index c88cc8b..0000000 --- a/common/include/mm_wfd_sink_wfd_enum.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Enumeration for WFD - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _MM_WFD_SINK_WFD_ENUM_H_ -#define _MM_WFD_SINK_WFD_ENUM_H_ - -typedef enum { - WFD_AUDIO_UNKNOWN = 0, - WFD_AUDIO_LPCM = (1 << 0), - WFD_AUDIO_AAC = (1 << 1), - WFD_AUDIO_AC3 = (1 << 2) -} WFDAudioFormats; - -typedef enum { - WFD_FREQ_UNKNOWN = 0, - WFD_FREQ_44100 = (1 << 0), - WFD_FREQ_48000 = (1 << 1) -} WFDAudioFreq; - -typedef enum { - WFD_CHANNEL_UNKNOWN = 0, - WFD_CHANNEL_2 = (1 << 0), - WFD_CHANNEL_4 = (1 << 1), - WFD_CHANNEL_6 = (1 << 2), - WFD_CHANNEL_8 = (1 << 3) -} WFDAudioChannels; - - -typedef enum { - WFD_VIDEO_UNKNOWN = 0, - WFD_VIDEO_H264 = (1 << 0) -} WFDVideoCodecs; - -typedef enum { - WFD_VIDEO_CEA_RESOLUTION = 0, - WFD_VIDEO_VESA_RESOLUTION, - WFD_VIDEO_HH_RESOLUTION -} WFDVideoNativeResolution; - -typedef enum { - WFD_CEA_UNKNOWN = 0, - WFD_CEA_640x480P60 = (1 << 0), - WFD_CEA_720x480P60 = (1 << 1), - WFD_CEA_720x480I60 = (1 << 2), - WFD_CEA_720x576P50 = (1 << 3), - WFD_CEA_720x576I50 = (1 << 4), - WFD_CEA_1280x720P30 = (1 << 5), - WFD_CEA_1280x720P60 = (1 << 6), - WFD_CEA_1920x1080P30 = (1 << 7), - WFD_CEA_1920x1080P60 = (1 << 8), - WFD_CEA_1920x1080I60 = (1 << 9), - WFD_CEA_1280x720P25 = (1 << 10), - WFD_CEA_1280x720P50 = (1 << 11), - WFD_CEA_1920x1080P25 = (1 << 12), - WFD_CEA_1920x1080P50 = (1 << 13), - WFD_CEA_1920x1080I50 = (1 << 14), - WFD_CEA_1280x720P24 = (1 << 15), - WFD_CEA_1920x1080P24 = (1 << 16) -} WFDVideoCEAResolution; - -typedef enum { - WFD_VESA_UNKNOWN = 0, - WFD_VESA_800x600P30 = (1 << 0), - WFD_VESA_800x600P60 = (1 << 1), - WFD_VESA_1024x768P30 = (1 << 2), - WFD_VESA_1024x768P60 = (1 << 3), - WFD_VESA_1152x864P30 = (1 << 4), - WFD_VESA_1152x864P60 = (1 << 5), - WFD_VESA_1280x768P30 = (1 << 6), - WFD_VESA_1280x768P60 = (1 << 7), - WFD_VESA_1280x800P30 = (1 << 8), - WFD_VESA_1280x800P60 = (1 << 9), - WFD_VESA_1360x768P30 = (1 << 10), - WFD_VESA_1360x768P60 = (1 << 11), - WFD_VESA_1366x768P30 = (1 << 12), - WFD_VESA_1366x768P60 = (1 << 13), - WFD_VESA_1280x1024P30 = (1 << 14), - WFD_VESA_1280x1024P60 = (1 << 15), - WFD_VESA_1400x1050P30 = (1 << 16), - WFD_VESA_1400x1050P60 = (1 << 17), - WFD_VESA_1440x900P30 = (1 << 18), - WFD_VESA_1440x900P60 = (1 << 19), - WFD_VESA_1600x900P30 = (1 << 20), - WFD_VESA_1600x900P60 = (1 << 21), - WFD_VESA_1600x1200P30 = (1 << 22), - WFD_VESA_1600x1200P60 = (1 << 23), - WFD_VESA_1680x1024P30 = (1 << 24), - WFD_VESA_1680x1024P60 = (1 << 25), - WFD_VESA_1680x1050P30 = (1 << 26), - WFD_VESA_1680x1050P60 = (1 << 27), - WFD_VESA_1920x1200P30 = (1 << 28), - WFD_VESA_1920x1200P60 = (1 << 29) -} WFDVideoVESAResolution; - -typedef enum { - WFD_HH_UNKNOWN = 0, - WFD_HH_800x480P30 = (1 << 0), - WFD_HH_800x480P60 = (1 << 1), - WFD_HH_854x480P30 = (1 << 2), - WFD_HH_854x480P60 = (1 << 3), - WFD_HH_864x480P30 = (1 << 4), - WFD_HH_864x480P60 = (1 << 5), - WFD_HH_640x360P30 = (1 << 6), - WFD_HH_640x360P60 = (1 << 7), - WFD_HH_960x540P30 = (1 << 8), - WFD_HH_960x540P60 = (1 << 9), - WFD_HH_848x480P30 = (1 << 10), - WFD_HH_848x480P60 = (1 << 11) -} WFDVideoHHResolution; - -typedef enum { - WFD_H264_UNKNOWN_PROFILE = 0, - WFD_H264_BASE_PROFILE = (1 << 0), - WFD_H264_HIGH_PROFILE = (1 << 1) -} WFDVideoH264Profile; - -typedef enum { - WFD_H264_LEVEL_UNKNOWN = 0, - WFD_H264_LEVEL_3_1 = (1 << 0), - WFD_H264_LEVEL_3_2 = (1 << 1), - WFD_H264_LEVEL_4 = (1 << 2), - WFD_H264_LEVEL_4_1 = (1 << 3), - WFD_H264_LEVEL_4_2 = (1 << 4) -} WFDVideoH264Level; - -#endif /*_MM_WFD_SINK_WFD_ENUM_H_*/ diff --git a/common/mm_wfd_attrs.c b/common/mm_wfd_attrs.c deleted file mode 100755 index e42c914..0000000 --- a/common/mm_wfd_attrs.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Manoj Kumar K , Hyunil Park - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "mm_wfd_attrs.h" - -typedef struct { - char *name; - int value_type; - int flags; /* r, w */ - void *default_value; - int valid_type; - int value_min; - int value_max; -} MMWfdAttrsSpec; - -/*static gboolean __mmwfd_apply_attribute(MMHandleType handle, const char *attribute_name); */ - -MMHandleType -_mmwfd_construct_attribute(MMHandleType handle) -{ - int idx = 0; - MMHandleType attrs = 0; - int num_of_attrs = 0; - mmf_attrs_construct_info_t *base = NULL; - - debug_fenter(); - - return_val_if_fail(handle, (MMHandleType) NULL); - - MMWfdAttrsSpec wfd_attrs[] = { - { - (char *)"server_ip", - MM_ATTRS_TYPE_STRING, - MM_ATTRS_FLAG_RW, - (void *)"127.0.0.1", - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - - { - (char *)"server_port", - MM_ATTRS_TYPE_STRING, - MM_ATTRS_FLAG_RW, - (void *)"8554", - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - - { - (char *)"max_client_count", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *)1, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 10 - }, - /* Initialized with invalid native type, if a valid value is set then only this atribute will be considered */ - { - (char *)"native_resolution", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *)0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 3 - }, - /* Initialized with invalid resolution, if a valid value is set then only this atribute will be considered */ - { - (char *)"prefered_resolutions", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *)2147483647, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 2147483647 - }, - /* Initialized with invalid uibc option, if a valid value is set then only this atribute will be considered */ - { - (char *)"set_hdcp", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *)2, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 2 - }, - { - (char *)"display_rotate", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *)0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 3 - }, - { - (char *)"display_src_crop_x", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_src_crop_y", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_src_crop_width", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_src_crop_height", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_roi_x", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_roi_y", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_roi_width", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 480, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_roi_height", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 800, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_roi_mode", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) MM_DISPLAY_METHOD_CUSTOM_ROI_FULL_SCREEN, - MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_DISPLAY_METHOD_CUSTOM_ROI_FULL_SCREEN, - MM_DISPLAY_METHOD_CUSTOM_ROI_LETER_BOX - }, - { - (char *)"display_rotation", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) MM_DISPLAY_ROTATION_NONE, - MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_DISPLAY_ROTATION_NONE, - MM_DISPLAY_ROTATION_270 - }, - { - (char *)"display_visible", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) TRUE, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 1 - }, - { - (char *)"display_method", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) MM_DISPLAY_METHOD_LETTER_BOX, - MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_DISPLAY_METHOD_LETTER_BOX, - MM_DISPLAY_METHOD_CUSTOM_ROI - }, - { - (char *)"display_overlay", - MM_ATTRS_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - { - (char *)"display_overlay_user_data", - MM_ATTRS_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - { - (char *)"display_zoom", - MM_ATTRS_TYPE_DOUBLE, - MM_ATTRS_FLAG_RW, - (void *) 1, - MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, - 1.0, - 9.0 - }, - { - (char *)"display_surface_type", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) MM_DISPLAY_SURFACE_OVERLAY, - MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_DISPLAY_SURFACE_OVERLAY, - MM_DISPLAY_SURFACE_REMOTE - }, - { - (char *)"display_width", /* dest width of fimcconvert ouput */ - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_height", /* dest height of fimcconvert ouput */ - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_evas_do_scaling", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) TRUE, - MM_ATTRS_VALID_TYPE_INT_RANGE, - FALSE, - TRUE - }, - { - (char *)"display_x", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"display_y", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 4096 - }, - { - (char *)"hdcp_version", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 2 - }, - { - (char *)"hdcp_port", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - 2147483647 - }, - }; - - num_of_attrs = ARRAY_SIZE(wfd_attrs); - - base = (mmf_attrs_construct_info_t *)malloc(num_of_attrs * sizeof(mmf_attrs_construct_info_t)); - - if (!base) { - debug_error("Cannot create mmwfd attribute\n"); - goto ERROR; - } - - /* initialize values of attributes */ - for (idx = 0; idx < num_of_attrs; idx++) { - base[idx].name = wfd_attrs[idx].name; - base[idx].value_type = wfd_attrs[idx].value_type; - base[idx].flags = wfd_attrs[idx].flags; - base[idx].default_value = wfd_attrs[idx].default_value; - } - - attrs = mmf_attrs_new_from_data( - "mmwfd_attrs", - base, - num_of_attrs, - NULL, - NULL); - - if (base) { - g_free(base); - base = NULL; - } - - if (!attrs) { - debug_error("Cannot create mmwfd attribute\n"); - goto ERROR; - } - - /* set validity type and range */ - for (idx = 0; idx < num_of_attrs; idx++) { - switch (wfd_attrs[idx].valid_type) { - case MM_ATTRS_VALID_TYPE_INT_RANGE: { - mmf_attrs_set_valid_type(attrs, idx, MM_ATTRS_VALID_TYPE_INT_RANGE); - mmf_attrs_set_valid_range(attrs, idx, - wfd_attrs[idx].value_min, - wfd_attrs[idx].value_max, - (int)wfd_attrs[idx].default_value); - } - break; - - case MM_ATTRS_VALID_TYPE_INT_ARRAY: - case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: - case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: - default: - break; - } - } - - debug_fleave(); - - return attrs; - -ERROR: - _mmwfd_deconstruct_attribute(attrs); - - return (MMHandleType)NULL; -} - -void -_mmwfd_deconstruct_attribute(MMHandleType handle) -{ - debug_fenter(); - - return_if_fail(handle); - - if (handle) - mmf_attrs_free(handle); - - debug_fleave(); -} - -int -_mmwfd_get_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list) -{ - int result = MM_ERROR_NONE; - MMHandleType attrs = 0; - - debug_fenter(); - - /* NOTE : Don't need to check err_attr_name because it can be set NULL */ - /* if it's not want to know it. */ - return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - - attrs = handle; - - return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); - - result = mm_attrs_get_valist(attrs, err_attr_name, attribute_name, args_list); - - if (result != MM_ERROR_NONE) - debug_error("failed to get %s attribute\n", attribute_name); - - debug_fleave(); - - return result; -} - -int -_mmwfd_set_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list) -{ - int result = MM_ERROR_NONE; - MMHandleType attrs = 0; - - debug_fenter(); - - /* NOTE : Don't need to check err_attr_name because it can be set NULL */ - /* if it's not want to know it. */ - return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - - attrs = handle; - - return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); - - /* set attributes and commit them */ - result = mm_attrs_set_valist(attrs, err_attr_name, attribute_name, args_list); - - if (result != MM_ERROR_NONE) { - debug_error("failed to set %s attribute\n", attribute_name); - return result; - } - - /*__mmwfd_apply_attribute(handle, attribute_name); */ - - debug_fleave(); - - return result; -} - -/* Currently not used. */ -/*static gboolean -__mmwfd_apply_attribute(MMHandleType handle, const char *attribute_name) -{ - MMHandleType attrs = 0; - mm_wfd_t* wfd = 0; - - debug_fenter(); - - return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - - attrs = handle; - - return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); - - wfd = (mm_wfd_t*)handle; - - // TODO: This function is not useful at this moment - - debug_fleave(); - - return TRUE; -}*/ - -int -_mmwfd_get_attributes_info(MMHandleType handle, const char *attribute_name, MMWfdAttrsInfo *dst_info) -{ - int result = MM_ERROR_NONE; - MMHandleType attrs = 0; - MMAttrsInfo src_info = {0, }; - - debug_fenter(); - - return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(dst_info, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - - attrs = handle; - - return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); - - result = mm_attrs_get_info_by_name(attrs, attribute_name, &src_info); - - if (result != MM_ERROR_NONE) { - debug_error("failed to get attribute info\n"); - return result; - } - - memset(dst_info, 0x00, sizeof(MMWfdAttrsInfo)); - - dst_info->type = src_info.type; - dst_info->flag = src_info.flag; - dst_info->validity_type = src_info.validity_type; - - switch (src_info.validity_type) { - case MM_ATTRS_VALID_TYPE_INT_ARRAY: - dst_info->int_array.array = src_info.int_array.array; - dst_info->int_array.count = src_info.int_array.count; - dst_info->int_array.d_val = src_info.int_array.dval; - break; - - case MM_ATTRS_VALID_TYPE_INT_RANGE: - dst_info->int_range.min = src_info.int_range.min; - dst_info->int_range.max = src_info.int_range.max; - dst_info->int_range.d_val = src_info.int_range.dval; - break; - - case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: - dst_info->double_array.array = src_info.double_array.array; - dst_info->double_array.count = src_info.double_array.count; - dst_info->double_array.d_val = src_info.double_array.dval; - break; - - case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: - dst_info->double_range.min = src_info.double_range.min; - dst_info->double_range.max = src_info.double_range.max; - dst_info->double_range.d_val = src_info.double_range.dval; - break; - - default: - break; - } - - debug_fleave(); - - return result; -} - - diff --git a/common/mm_wfd_sink_ini.c b/common/mm_wfd_sink_ini.c deleted file mode 100755 index 24b7de4..0000000 --- a/common/mm_wfd_sink_ini.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Manoj Kumar K , Hyunil Park - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include -#include -#include "mm_wfd_sink_ini.h" -#include "mm_wfd_sink_dlog.h" - -static gboolean loaded = FALSE; - -/* global variables here */ -#ifdef MM_WFD_SINK_DEFAULT_INI -static gboolean __generate_sink_default_ini(void); -#endif - -static void __mm_wfd_sink_ini_check_status(void); - -/* macro */ -#define MM_WFD_SINK_INI_GET_STRING(x_dict, x_item, x_ini, x_default) \ - do { \ - gchar *str = NULL; \ - gint length = 0; \ - \ - str = iniparser_getstring(x_dict, x_ini, (char *)x_default); \ - if (str) { \ - length = strlen(str); \ - if ((length > 1) && (length < WFD_SINK_INI_MAX_STRLEN)) \ - strncpy(x_item, str, WFD_SINK_INI_MAX_STRLEN-1); \ - else \ - strncpy(x_item, x_default, WFD_SINK_INI_MAX_STRLEN-1); \ - } else { \ - strncpy(x_item, x_default, WFD_SINK_INI_MAX_STRLEN-1); \ - } \ - } while (0); - -#ifdef MM_WFD_SINK_DEFAULT_INI -static -gboolean __generate_sink_default_ini(void) -{ - FILE *fp = NULL; - const gchar *default_ini = MM_WFD_SINK_DEFAULT_INI; - - - /* create new file */ - fp = fopen(MM_WFD_SINK_INI_DEFAULT_PATH, "wt"); - - if (!fp) { - return FALSE; - } - - /* writing default ini file */ - if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) { - fclose(fp); - return FALSE; - } - - fclose(fp); - return TRUE; -} -#endif - -int -mm_wfd_sink_ini_load(mm_wfd_sink_ini_t *ini) -{ - dictionary *dict = NULL; - - wfd_sink_debug_fenter(); - - - __mm_wfd_sink_ini_check_status(); - - /* first, try to load existing ini file */ - dict = iniparser_load(MM_WFD_SINK_INI_DEFAULT_PATH); - - /* if no file exists. create one with set of default values */ - if (!dict) { -#ifdef MM_WFD_SINK_DEFAULT_INI - wfd_sink_debug("No inifile found. create default ini file.\n"); - if (FALSE == __generate_sink_default_ini()) { - wfd_sink_error("Creating default ini file failed. Use default values.\n"); - } else { - /* load default ini */ - dict = iniparser_load(MM_WFD_SINK_INI_DEFAULT_PATH); - } -#else - wfd_sink_error("No ini file found. \n"); - - return MM_ERROR_FILE_NOT_FOUND; -#endif - } - - /* get ini values */ - memset(ini, 0, sizeof(mm_wfd_sink_ini_t)); - - if (dict) { /* if dict is available */ - /* general */ - MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[0], "general:gstparam1", DEFAULT_GST_PARAM); - MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[1], "general:gstparam2", DEFAULT_GST_PARAM); - MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[2], "general:gstparam3", DEFAULT_GST_PARAM); - MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[3], "general:gstparam4", DEFAULT_GST_PARAM); - MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[4], "general:gstparam5", DEFAULT_GST_PARAM); - ini->generate_dot = iniparser_getboolean(dict, "general:generate dot", DEFAULT_GENERATE_DOT); - ini->enable_pad_probe = iniparser_getboolean(dict, "general:enable pad probe", DEFAULT_ENABLE_PAD_PROBE); - ini->state_change_timeout = iniparser_getint(dict, "general:state change timeout", DEFAULT_STATE_CHANGE_TIMEOUT); - ini->set_debug_property = iniparser_getboolean(dict, "general:set debug property", DEFAULT_SET_DEBUG_PROPERTY); - ini->enable_asm = iniparser_getboolean(dict, "general:enable asm", DEFAULT_ENABLE_ASM); - ini->jitter_buffer_latency = iniparser_getint(dict, "general:jitter buffer latency", DEFAULT_JITTER_BUFFER_LATENCY); - ini->enable_retransmission = iniparser_getboolean(dict, "general:enable retransmission", DEFAULT_ENABLE_RETRANSMISSION); - ini->enable_reset_basetime = iniparser_getboolean(dict, "general:enable reset basetime", DEFAULT_ENABLE_RESET_BASETIME); - ini->video_sink_max_lateness = iniparser_getint(dict, "general:video sink max lateness", DEFAULT_VIDEO_SINK_MAX_LATENESS); - ini->sink_ts_offset = iniparser_getint(dict, "general:sink ts offset", DEFAULT_SINK_TS_OFFSET); - ini->audio_sink_async = iniparser_getboolean(dict, "general:audio sink async", DEFAULT_AUDIO_SINK_ASYNC); - ini->video_sink_async = iniparser_getboolean(dict, "general:video sink async", DEFAULT_VIDEO_SINK_ASYNC); - ini->enable_ts_data_dump = iniparser_getboolean(dict, "general:enable ts data dump", DEFAULT_ENABLE_TS_DATA_DUMP); - ini->enable_wfdsrc_pad_probe = iniparser_getboolean(dict, "general:enable wfdsrc pad probe", DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE); - - - /* pipeline */ - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_source, "pipeline:wfdsrc element", DEFAULT_NAME_OF_SOURCE); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_tsdemux, "pipeline:tsdemux element", DEFAULT_NAME_OF_TSDEMUX); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_hdcp, "pipeline:audio hdcp element", DEFAULT_NAME_OF_AUDIO_HDCP); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_aac_parser, "pipeline:aac parser element", DEFAULT_NAME_OF_AAC_PARSER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_aac_decoder, "pipeline:aac decoder element", DEFAULT_NAME_OF_AAC_DECODER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_ac3_parser, "pipeline:ac3 parser element", DEFAULT_NAME_OF_AC3_PARSER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_ac3_decoder, "pipeline:ac3 decoder element", DEFAULT_NAME_OF_AC3_DECODER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_lpcm_converter, "pipeline:lpcm converter element", DEFAULT_NAME_OF_LPCM_CONVERTER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_lpcm_filter, "pipeline:lpcm filter element", DEFAULT_NAME_OF_LPCM_FILTER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_resampler, "pipeline:audio resampler element", DEFAULT_NAME_OF_AUDIO_RESAMPLER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_volume, "pipeline:audio volume element", DEFAULT_NAME_OF_AUDIO_VOLUME); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_sink, "pipeline:audio sink element", DEFAULT_NAME_OF_AUDIO_SINK); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_hdcp, "pipeline:video hdcp element", DEFAULT_NAME_OF_VIDEO_HDCP); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_parser, "pipeline:video parser element", DEFAULT_NAME_OF_VIDEO_PARSER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_capssetter, "pipeline:video capssetter element", DEFAULT_NAME_OF_VIDEO_CAPSSETTER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_decoder, "pipeline:video decoder element", DEFAULT_NAME_OF_VIDEO_DECODER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_converter, "pipeline:video converter element", DEFAULT_NAME_OF_VIDEO_CONVERTER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_filter, "pipeline:video filter element", DEFAULT_NAME_OF_VIDEO_FILTER); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_sink, "pipeline:video sink element", DEFAULT_NAME_OF_VIDEO_SINK); - MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_evas_sink, "pipeline:video evas sink element", DEFAULT_NAME_OF_EVAS_VIDEO_SINK); - - /* audio parameter*/ - ini->audio_codec = iniparser_getint(dict, "audio param:audio codec", DEFAULT_AUDIO_CODEC); - ini->audio_latency = iniparser_getint(dict, "audio param:audio latency", DEFAULT_AUDIO_LATENCY); - ini->audio_channel = iniparser_getint(dict, "audio param:audio channels", DEFAULT_AUDIO_CHANNELS); - ini->audio_sampling_frequency = iniparser_getint(dict, "audio param:audio sampling frequency", DEFAULT_AUDIO_SAMP_FREQUENCY); - - /* video parameter*/ - ini->video_codec = iniparser_getint(dict, "video param:video codec", DEFAULT_VIDEO_CODEC); - ini->video_native_resolution = iniparser_getint(dict, "video param:video native resolution", DEFAULT_VIDEO_NATIVE_RESOLUTION); - ini->video_cea_support = iniparser_getint(dict, "video param:video cea support", DEFAULT_VIDEO_CEA_SUPPORT); - ini->video_vesa_support = iniparser_getint(dict, "video param:video vesa support", DEFAULT_VIDEO_VESA_SUPPORT); - ini->video_hh_support = iniparser_getint(dict, "video param:video hh support", DEFAULT_VIDEO_HH_SUPPORT); - ini->video_profile = iniparser_getint(dict, "video param:video profile", DEFAULT_VIDEO_PROFILE); - ini->video_level = iniparser_getint(dict, "video param:video level", DEFAULT_VIDEO_LEVEL); - ini->video_latency = iniparser_getint(dict, "video param:video latency", DEFAULT_VIDEO_LATENCY); - ini->video_vertical_resolution = iniparser_getint(dict, "video param:video vertical resolution", DEFAULT_VIDEO_VERTICAL_RESOLUTION); - ini->video_horizontal_resolution = iniparser_getint(dict, "video param:video horizontal resolution", DEFAULT_VIDEO_HORIZONTAL_RESOLUTION); - ini->video_minimum_slicing = iniparser_getint(dict, "video param:video minimum slicesize", DEFAULT_VIDEO_MIN_SLICESIZE); - ini->video_slice_enc_param = iniparser_getint(dict, "video param:video slice encoding params", DEFAULT_VIDEO_SLICE_ENC_PARAM); - ini->video_framerate_control_support = iniparser_getint(dict, "video param:video framerate control support", DEFAULT_VIDEO_FRAMERATE_CONTROL); - - /* hdcp parameter*/ - ini->hdcp_content_protection = iniparser_getint(dict, "hdcp param:hdcp content protection", DEFAULT_HDCP_CONTENT_PROTECTION); - ini->hdcp_port_no = iniparser_getint(dict, "hdcp param:hdcp port no", DEFAULT_HDCP_PORT_NO); - } else { /* if dict is not available just fill the structure with default value */ - wfd_sink_error("failed to load ini. using hardcoded default\n"); - - /* general */ - strncpy(ini->gst_param[0], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->gst_param[1], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->gst_param[2], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->gst_param[3], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->gst_param[4], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); - ini->generate_dot = DEFAULT_GENERATE_DOT; - ini->enable_pad_probe = DEFAULT_ENABLE_PAD_PROBE; - ini->state_change_timeout = DEFAULT_STATE_CHANGE_TIMEOUT; - ini->set_debug_property = DEFAULT_SET_DEBUG_PROPERTY; - ini->enable_asm = DEFAULT_ENABLE_ASM; - ini->jitter_buffer_latency = DEFAULT_JITTER_BUFFER_LATENCY; - ini->enable_retransmission = DEFAULT_ENABLE_RETRANSMISSION; - ini->enable_reset_basetime = DEFAULT_ENABLE_RESET_BASETIME; - ini->video_sink_max_lateness = DEFAULT_VIDEO_SINK_MAX_LATENESS; - ini->sink_ts_offset = DEFAULT_SINK_TS_OFFSET; - ini->enable_ts_data_dump = DEFAULT_ENABLE_TS_DATA_DUMP; - ini->enable_wfdsrc_pad_probe = DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE; - - /* pipeline */ - strncpy(ini->name_of_source, DEFAULT_NAME_OF_TSDEMUX, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_tsdemux, DEFAULT_NAME_OF_TSDEMUX, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_audio_hdcp, DEFAULT_NAME_OF_AUDIO_HDCP, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_aac_parser, DEFAULT_NAME_OF_AAC_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_aac_decoder, DEFAULT_NAME_OF_AAC_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_ac3_parser, DEFAULT_NAME_OF_AC3_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_ac3_decoder, DEFAULT_NAME_OF_AC3_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_lpcm_converter, DEFAULT_NAME_OF_LPCM_CONVERTER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_lpcm_filter, DEFAULT_NAME_OF_LPCM_FILTER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_audio_resampler, DEFAULT_NAME_OF_AUDIO_RESAMPLER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_audio_volume, DEFAULT_NAME_OF_AUDIO_VOLUME, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_audio_sink, DEFAULT_NAME_OF_AUDIO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_hdcp, DEFAULT_NAME_OF_VIDEO_HDCP, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_parser, DEFAULT_NAME_OF_VIDEO_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_capssetter, DEFAULT_NAME_OF_VIDEO_CAPSSETTER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_decoder, DEFAULT_NAME_OF_VIDEO_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_converter, DEFAULT_NAME_OF_VIDEO_CONVERTER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_filter, DEFAULT_NAME_OF_VIDEO_FILTER, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_sink, DEFAULT_NAME_OF_VIDEO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); - strncpy(ini->name_of_video_evas_sink, DEFAULT_NAME_OF_EVAS_VIDEO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); - - /* audio parameter*/ - ini->audio_codec = DEFAULT_AUDIO_CODEC; - ini->audio_latency = DEFAULT_AUDIO_LATENCY; - ini->audio_channel = DEFAULT_AUDIO_CHANNELS; - ini->audio_sampling_frequency = DEFAULT_AUDIO_SAMP_FREQUENCY; - - /* video parameter*/ - ini->video_codec = DEFAULT_VIDEO_CODEC; - ini->video_native_resolution = DEFAULT_VIDEO_NATIVE_RESOLUTION; - ini->video_cea_support = DEFAULT_VIDEO_CEA_SUPPORT; - ini->video_vesa_support = DEFAULT_VIDEO_VESA_SUPPORT; - ini->video_hh_support = DEFAULT_VIDEO_HH_SUPPORT; - ini->video_profile = DEFAULT_VIDEO_PROFILE; - ini->video_level = DEFAULT_VIDEO_LEVEL; - ini->video_latency = DEFAULT_VIDEO_LATENCY; - ini->video_vertical_resolution = DEFAULT_VIDEO_VERTICAL_RESOLUTION; - ini->video_horizontal_resolution = DEFAULT_VIDEO_HORIZONTAL_RESOLUTION; - ini->video_minimum_slicing = DEFAULT_VIDEO_MIN_SLICESIZE; - ini->video_slice_enc_param = DEFAULT_VIDEO_SLICE_ENC_PARAM; - ini->video_framerate_control_support = DEFAULT_VIDEO_FRAMERATE_CONTROL; - - /* hdcp parameter*/ - ini->hdcp_content_protection = DEFAULT_HDCP_CONTENT_PROTECTION; - ini->hdcp_port_no = DEFAULT_HDCP_PORT_NO; - } - - /* free dict as we got our own structure */ - iniparser_freedict(dict); - - - /* dump structure */ - wfd_sink_debug("W-Fi Display Sink Initial Settings-----------------------------------\n"); - - /* general */ - wfd_sink_debug("gst_param1 : %s\n", ini->gst_param[0]); - wfd_sink_debug("gst_param2 : %s\n", ini->gst_param[1]); - wfd_sink_debug("gst_param3 : %s\n", ini->gst_param[2]); - wfd_sink_debug("gst_param4 : %s\n", ini->gst_param[3]); - wfd_sink_debug("gst_param5 : %s\n", ini->gst_param[4]); - wfd_sink_debug("generate_dot : %d\n", ini->generate_dot); - if (ini->generate_dot == TRUE) { - wfd_sink_debug("generate_dot is TRUE, dot file will be stored into /tmp/\n"); - g_setenv("GST_DEBUG_DUMP_DOT_DIR", "/tmp/", FALSE); - } - wfd_sink_debug("enable_pad_probe : %d\n", ini->enable_pad_probe); - wfd_sink_debug("state_change_timeout(sec) : %d\n", ini->state_change_timeout); - wfd_sink_debug("set_debug_property : %d\n", ini->set_debug_property); - wfd_sink_debug("enable_asm : %d\n", ini->enable_asm); - wfd_sink_debug("jitter_buffer_latency(msec) : %d\n", ini->jitter_buffer_latency); - wfd_sink_debug("enable_retransmission : %d\n", ini->enable_retransmission); - wfd_sink_debug("enable_reset_basetime : %d\n", ini->enable_reset_basetime); - wfd_sink_debug("video_sink_max_lateness(nsec) : %d\n", ini->video_sink_max_lateness); - wfd_sink_debug("sink_ts_offset(nsec) : %d\n", ini->sink_ts_offset); - wfd_sink_debug("audio_sink_async : %d\n", ini->audio_sink_async); - wfd_sink_debug("video_sink_async : %d\n", ini->video_sink_async); - wfd_sink_debug("enable_ts_data_dump : %d\n", ini->enable_ts_data_dump); - wfd_sink_debug("enable_wfdsrc_pad_probe : %d\n", ini->enable_wfdsrc_pad_probe); - - /* pipeline */ - wfd_sink_debug("name_of_source : %s\n", ini->name_of_source); - wfd_sink_debug("name_of_tsdemux : %s\n", ini->name_of_tsdemux); - wfd_sink_debug("name_of_audio_hdcp : %s\n", ini->name_of_audio_hdcp); - wfd_sink_debug("name_of_aac_parser : %s\n", ini->name_of_aac_parser); - wfd_sink_debug("name_of_aac_decoder : %s\n", ini->name_of_aac_decoder); - wfd_sink_debug("name_of_ac3_parser : %s\n", ini->name_of_ac3_parser); - wfd_sink_debug("name_of_ac3_decoder : %s\n", ini->name_of_ac3_decoder); - wfd_sink_debug("name_of_lpcm_converter : %s\n", ini->name_of_lpcm_converter); - wfd_sink_debug("name_of_lpcm_filter : %s\n", ini->name_of_lpcm_filter); - wfd_sink_debug("name_of_audio_resampler : %s\n", ini->name_of_audio_resampler); - wfd_sink_debug("name_of_audio_volume : %s\n", ini->name_of_audio_volume); - wfd_sink_debug("name_of_audio_sink : %s\n", ini->name_of_audio_sink); - wfd_sink_debug("name_of_video_hdcp : %s\n", ini->name_of_video_hdcp); - wfd_sink_debug("name_of_video_parser : %s\n", ini->name_of_video_parser); - wfd_sink_debug("name_of_video_capssetter : %s\n", ini->name_of_video_capssetter); - wfd_sink_debug("name_of_video_decoder : %s\n", ini->name_of_video_decoder); - wfd_sink_debug("name_of_video_converter : %s\n", ini->name_of_video_converter); - wfd_sink_debug("name_of_video_filter : %s\n", ini->name_of_video_filter); - wfd_sink_debug("name_of_video_sink : %s\n", ini->name_of_video_sink); - wfd_sink_debug("name_of_video_evas_sink : %s\n", ini->name_of_video_evas_sink); - - /* audio parameter*/ - wfd_sink_debug("audio_codec : %x\n", ini->audio_codec); - wfd_sink_debug("audio_latency : %d\n", ini->audio_latency); - wfd_sink_debug("audio_channel : %x\n", ini->audio_channel); - wfd_sink_debug("audio_sampling_frequency : %x\n", ini->audio_sampling_frequency); - - /* video parameter*/ - wfd_sink_debug("video_codec : %x\n", ini->video_codec); - wfd_sink_debug("video_native_resolution : %x\n", ini->video_native_resolution); - wfd_sink_debug("video_cea_support : %x\n", ini->video_cea_support); - wfd_sink_debug("video_vesa_support : %x\n", ini->video_vesa_support); - wfd_sink_debug("video_hh_support : %x\n", ini->video_hh_support); - wfd_sink_debug("video_profile : %x\n", ini->video_profile); - wfd_sink_debug("video_level : %x\n", ini->video_level); - wfd_sink_debug("video_latency : %d\n", ini->video_latency); - wfd_sink_debug("video_vertical_resolution : %d\n", ini->video_vertical_resolution); - wfd_sink_debug("video_horizontal_resolution : %d\n", ini->video_horizontal_resolution); - wfd_sink_debug("video_minimum_slicing : %d\n", ini->video_minimum_slicing); - wfd_sink_debug("video_slice_enc_param : %d\n", ini->video_slice_enc_param); - wfd_sink_debug("video_framerate_control_support : %d\n", ini->video_framerate_control_support); - - /* hdcp parameter*/ - wfd_sink_debug("hdcp_content_protection : %x\n", ini->hdcp_content_protection); - wfd_sink_debug("hdcp_port_no : %d\n", ini->hdcp_port_no); - - wfd_sink_debug("---------------------------------------------------\n"); - - loaded = TRUE; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - - -static -void __mm_wfd_sink_ini_check_status(void) -{ - struct stat ini_buff; - - wfd_sink_debug_fenter(); - - if (g_stat(MM_WFD_SINK_INI_DEFAULT_PATH, &ini_buff) < 0) { - wfd_sink_error("failed to get mmfw_wfd_sink ini status\n"); - } else { - if (ini_buff.st_size < 5) { - wfd_sink_error("mmfw_wfd_sink.ini file size=%d, Corrupted! So, Removed\n", (int)ini_buff.st_size); - g_remove(MM_WFD_SINK_INI_DEFAULT_PATH); - } - } - - wfd_sink_debug_fleave(); -} - -int -mm_wfd_sink_ini_unload(mm_wfd_sink_ini_t *ini) -{ - wfd_sink_debug_fenter(); - - loaded = FALSE; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} diff --git a/config/Makefile.am b/config/Makefile.am deleted file mode 100755 index eb1a3b9..0000000 --- a/config/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -installconfiguredir=$(_sysconfdir)/multimedia -installconfigure_DATA=mmfw_wfd_sink.ini diff --git a/config/Makefile.in b/config/Makefile.in deleted file mode 100755 index b3eb062..0000000 --- a/config/Makefile.in +++ /dev/null @@ -1,386 +0,0 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = config -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -SOURCES = -DIST_SOURCES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; -am__installdirs = "$(DESTDIR)$(installconfiguredir)" -installconfigureDATA_INSTALL = $(INSTALL_DATA) -DATA = $(installconfigure_DATA) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -APPFWK_CFLAGS = @APPFWK_CFLAGS@ -APPFWK_LIBS = @APPFWK_LIBS@ -AR = @AR@ -AUDIOSESSIONMGR_CFLAGS = @AUDIOSESSIONMGR_CFLAGS@ -AUDIOSESSIONMGR_LIBS = @AUDIOSESSIONMGR_LIBS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ELEMENTARY_CFLAGS = @ELEMENTARY_CFLAGS@ -ELEMENTARY_LIBS = @ELEMENTARY_LIBS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_LIBS = @GLIB_LIBS@ -GREP = @GREP@ -GST_APP_CFLAGS = @GST_APP_CFLAGS@ -GST_APP_LIBS = @GST_APP_LIBS@ -GST_CFLAGS = @GST_CFLAGS@ -GST_INTERFACE_CFLAGS = @GST_INTERFACE_CFLAGS@ -GST_INTERFACE_LIBS = @GST_INTERFACE_LIBS@ -GST_LIBS = @GST_LIBS@ -GST_PLUGIN_BASE_CFLAGS = @GST_PLUGIN_BASE_CFLAGS@ -GST_PLUGIN_BASE_LIBS = @GST_PLUGIN_BASE_LIBS@ -INIPARSER_CFLAGS = @INIPARSER_CFLAGS@ -INIPARSER_LIBS = @INIPARSER_LIBS@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MMCOMMON_CFLAGS = @MMCOMMON_CFLAGS@ -MMCOMMON_LIBS = @MMCOMMON_LIBS@ -MMSESSION_CFLAGS = @MMSESSION_CFLAGS@ -MMSESSION_LIBS = @MMSESSION_LIBS@ -MMSOUND_CFLAGS = @MMSOUND_CFLAGS@ -MMSOUND_LIBS = @MMSOUND_LIBS@ -MMTA_CFLAGS = @MMTA_CFLAGS@ -MMTA_LIBS = @MMTA_LIBS@ -MMUTIL_CFLAGS = @MMUTIL_CFLAGS@ -MMUTIL_LIBS = @MMUTIL_LIBS@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -RANLIB = @RANLIB@ -SAVSIMGP_CFLAGS = @SAVSIMGP_CFLAGS@ -SAVSIMGP_LIBS = @SAVSIMGP_LIBS@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -installconfiguredir = /opt/etc -installconfigure_DATA = mmfw_player.ini -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign config/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign config/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-installconfigureDATA: $(installconfigure_DATA) - @$(NORMAL_INSTALL) - test -z "$(installconfiguredir)" || $(MKDIR_P) "$(DESTDIR)$(installconfiguredir)" - @list='$(installconfigure_DATA)'; for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(installconfigureDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(installconfiguredir)/$$f'"; \ - $(installconfigureDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(installconfiguredir)/$$f"; \ - done - -uninstall-installconfigureDATA: - @$(NORMAL_UNINSTALL) - @list='$(installconfigure_DATA)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(installconfiguredir)/$$f'"; \ - rm -f "$(DESTDIR)$(installconfiguredir)/$$f"; \ - done -tags: TAGS -TAGS: - -ctags: CTAGS -CTAGS: - - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(DATA) -installdirs: - for dir in "$(DESTDIR)$(installconfiguredir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: install-installconfigureDATA - -install-dvi: install-dvi-am - -install-exec-am: - -install-html: install-html-am - -install-info: install-info-am - -install-man: - -install-pdf: install-pdf-am - -install-ps: install-ps-am - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-installconfigureDATA - -.MAKE: install-am install-strip - -.PHONY: all all-am check check-am clean clean-generic clean-libtool \ - distclean distclean-generic distclean-libtool distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-installconfigureDATA \ - install-man install-pdf install-pdf-am install-ps \ - install-ps-am install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am uninstall uninstall-am uninstall-installconfigureDATA - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/configure.ac b/configure.ac index 7893e7b..8488f12 100755 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.61) AC_INIT([libmm-wfd],[0.0.1]) -AC_CONFIG_SRCDIR([sink/mm_wfd_sink_priv.c]) +AC_CONFIG_SRCDIR([src/mm_wfd_sink_priv.c]) AC_CONFIG_HEADER([config.h]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) @@ -107,8 +107,7 @@ AC_ARG_ENABLE(sdk, AC_HELP_STRING([--enable-sdk], [sdk build]), AM_CONDITIONAL([IS_SDK], [test "x$IS_SDK" = "xyes"]) AC_CONFIG_FILES([Makefile - common/Makefile - sink/Makefile - mm-wfd.pc + src/Makefile + mm-wfd.pc ]) AC_OUTPUT diff --git a/packaging/libmm-wfd.spec b/packaging/libmm-wfd.spec index c1cfb18..8f0a6ba 100755 --- a/packaging/libmm-wfd.spec +++ b/packaging/libmm-wfd.spec @@ -1,6 +1,6 @@ Name: libmm-wfd Summary: Multimedia Framework Wifi-Display Library -Version: 0.2.195 +Version: 0.2.196 Release: 0 Group: System/Libraries License: Apache-2.0 @@ -89,6 +89,11 @@ rm -rf %{buildroot} %defattr(-,root,root,-) %{_libdir}/*.so %{_includedir}/mmf/mm_wfd_sink.h +%{_includedir}/mmf/mm_wfd_sink_priv.h +%{_includedir}/mmf/mm_wfd_sink_dlog.h +%{_includedir}/mmf/mm_wfd_sink_util.h +%{_includedir}/mmf/mm_wfd_sink_ini.h +%{_includedir}/mmf/mm_wfd_sink_attrs.h %{_libdir}/pkgconfig/* #%files factory diff --git a/sink/Makefile.am b/sink/Makefile.am deleted file mode 100755 index 2ee962d..0000000 --- a/sink/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -lib_LTLIBRARIES = libmmfwfdsink.la - -includelibmmfwfdsinkdir = $(includedir)/mmf - -includelibmmfwfdsink_HEADERS = include/mm_wfd_sink.h - -libmmfwfdsink_la_SOURCES = mm_wfd_sink_util.c \ - mm_wfd_sink.c \ - mm_wfd_sink_manager.c \ - mm_wfd_sink_priv.c \ - mm_wfd_sink_wayland.c - - -libmmfwfdsink_la_CFLAGS = -I$(srcdir)/include \ - $(MMCOMMON_CFLAGS) \ - $(GST_CFLAGS) \ - $(EVAS_CFLAGS) \ - $(ELEMENTARY_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_VIDEO_CFLAGS) \ - $(MM_WFD_COMMON_CFLAGS) \ - $(AUDIOSESSIONMGR_CFLAGS) \ - $(TZPLATFORM_CONFIG_CFLAGS) \ - -I$(top_builddir)/common/include - - -libmmfwfdsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -noinst_HEADERS = include/mm_wfd_sink_priv.h \ - include/mm_wfd_sink_util.h \ - include/mm_wfd_sink_manager.h \ - include/mm_wfd_sink_wayland.h - -libmmfwfdsink_la_LIBADD = $(GST_LIBS) \ - $(GST_PLUGINS_BASE_LIBS) \ - $(GST_BASE_LIBS) \ - $(ELEMENTARY_LIBS) \ - $(EVAS_LIBS) \ - $(top_builddir)/common/libwfdcommon.la \ - $(MMCOMMON_LIBS) \ - $(MM_WFD_COMMON_LIBS) \ - $(AUDIOSESSIONMGR_LIBS) \ - $(TZPLATFORM_CONFIG_LIBS) \ - $(GST_VIDEO_LIBS) - - -libmmfwfdsink_la_CFLAGS += $(MMLOG_CFLAGS) -DMMF_LOG_OWNER=0x02000000 -DMMF_DEBUG_PREFIX=\"MMF-WFD-SINK\" -libmmfwfdsink_la_LIBADD += $(MMLOG_LIBS) diff --git a/sink/include/mm_wfd_sink.h b/sink/include/mm_wfd_sink.h deleted file mode 100755 index 620324f..0000000 --- a/sink/include/mm_wfd_sink.h +++ /dev/null @@ -1,484 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _MM_WFD_SINK_H_ -#define _MM_WFD_SINK_H_ - -#include -#include -#include -#include -#include - -/** - * * Enumerations of wifi-display sink state. - * */ -typedef enum { - MM_WFD_SINK_STATE_NONE, /**< wifi-display is not created */ - MM_WFD_SINK_STATE_NULL, /**< wifi-display is created */ - MM_WFD_SINK_STATE_PREPARED, /**< wifi-display is prepared */ - MM_WFD_SINK_STATE_CONNECTED, /**< wifi-display is connected */ - MM_WFD_SINK_STATE_PLAYING, /**< wifi-display is now playing */ - MM_WFD_SINK_STATE_PAUSED, /**< wifi-display is now paused */ - MM_WFD_SINK_STATE_DISCONNECTED, /**< wifi-display is disconnected */ - MM_WFD_SINK_STATE_NUM, /**< Number of wifi-display states */ -} MMWFDSinkStateType; - -/* audio codec : AAC, AC3, LPCM */ -typedef enum { - MM_WFD_SINK_AUDIO_CODEC_NONE, - MM_WFD_SINK_AUDIO_CODEC_AAC = 0x0F, - MM_WFD_SINK_AUDIO_CODEC_AC3 = 0x81, - MM_WFD_SINK_AUDIO_CODEC_LPCM = 0x83 -} MMWFDSinkAudioCodec; - -/* video codec : H264 */ -typedef enum { - MM_WFD_SINK_VIDEO_CODEC_NONE, - MM_WFD_SINK_VIDEO_CODEC_H264 = 0x1b -} MMWFDSinkVideoCodec; - -typedef void(*MMWFDMessageCallback)(int error_type, MMWFDSinkStateType state_type, void *user_data); - -/** - * This function creates a wi-fi display sink object. \n - * The attributes of wi-fi display sink are created to get/set some values with application. \n - * And, mutex, gstreamer and other resources are initialized at this time. \n - * If wi-fi display sink is created, he state will become MM_WFD_SINK_STATE_NULL.. \n - * - * @param wfd_sink [out] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. \n - * Please refer 'mm_error.h' to know it in detail. - * @pre None - * @post MM_WFD_SINK_STATE_NULL - * @see mm_wfd_sink_destroy - * @remark You can create multiple handles on a context at the same time. \n - * However, wi-fi display sink cannot guarantee proper operation because of limitation of resources, \n - * such as audio device or display device. - * - * @par Example - * @code -if (mm_wfd_sink_create(&g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to create wi-fi display sink\n"); -} - -mm_wfd_sink_set_message_callback(g_wfd_sink, msg_callback, (void*)g_wfd_sink); - * @endcode - */ -int mm_wfd_sink_create(MMHandleType *wfd_sink); - -/** - * This function trys to make gstreamer pipeline. \n - * If wi-fi display sink is realized, the state will become MM_WFD_SINK_STATE_READY.. \n - * - * @param wfd_sink [out] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. \n - * Please refer 'mm_error.h' to know it in detail. - * @pre MM_WFD_SINK_STATE_NULL - * @post MM_WFD_SINK_STATE_PREPARED - * @see mm_wfd_sink_unprepare - * @remark None - * @par Example - * @code -if (mm_wfd_sink_prepare(&g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to realize wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_prepare(MMHandleType wfd_sink); - -/** - * This function connect wi-fi display source using uri. \n - * audio type(AC3 AAC, LPCM) is decided at this time. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param uri [in] URI of wi-fi displaysource to be connected - * - * @return This function returns zero on success, or negative value with error code. - * - * @pre wi-fi display sink state should be MM_WFD_SINK_STATE_PREPARED - * @post wi-fi display sink state will be MM_WFD_SINK_STATE_CONNECTED with no preroll. - * @remark None - * @par Example - * @code -if (mm_wfd_sink_connect(g_wfd_sink, g_uri) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to connect to wi-fi display source\n"); -} - * @endcode - */ -int mm_wfd_sink_connect(MMHandleType wfd_sink, const char *uri); - -/** - * This function is to start playing. \n - * Data from wi-fi display source will be received. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @remark - * - * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_CONNECTED. - * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PLAYING. - * @see mm_wfd_sink_disconnect - * @remark None - * @par Example - * @code -if (mm_wfd_sink_start(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to start wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_start(MMHandleType wfd_sink); - -/** - * This function is to pause playing. \n - * The wi-fi display sink pause the current stream being received form wi-fi display source. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @remark - * - * @pre wi-fi display sink state should be MM_WFD_SINK_STATE_PLAYING. - * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PAUSED. - * @see mm_wfd_sink_pause - * @remark None - * @par Example - * @code -if (mm_wfd_sink_pause(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to pause wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_pause(MMHandleType wfd_sink); - -/** - * This function is to resume playing. \n - * Data from wi-fi display source will be received. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @remark - * - * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PAUSED. - * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PLAYING. - * @see mm_wfd_sink_disconnect - * @remark None - * @par Example - * @code -if (mm_wfd_sink_start(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to resume wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_resume(MMHandleType wfd_sink); - -/** - * This function is to stop playing wi-fi display. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * - * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PLAYING. - * @post wi-fi display sink state will be MM_WFD_SINK_STATE_DISCONNECTED. - * @see mm_wfd_sink_start - * @remark None - * @par Example - * @code -if (mm_wfd_sink_disconnect(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to stop wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_disconnect(MMHandleType wfd_sink); - -/** - * This function trys to destroy gstreamer pipeline. \n - * - * @param wfd_sink [out] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. \n - * Please refer 'mm_error.h' to know it in detail. - * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PREPARED or MM_WFD_SINK_STATE_DISCONNECTED. - * But, it can be called in any state. - * @post MM_WFD_SINK_STATE_NULL - * @see mm_wfd_sink_prepare - * @remark None - * @par Example - * @code -if (mm_wfd_sink_unprepare(&g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to unprepare wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_unprepare(MMHandleType wfd_sink); - -/** - * This function releases wi-fi display sink object and all resources which were created by mm_wfd_sink_create(). \n - * And, wi-fi display sink handle will also be destroyed. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state may be MM_WFD_SINK_STATE_NULL. \n - * But, it can be called in any state. - * @post Because handle is released, there is no any state. - * @see mm_wfd_sink_create - * @remark This method can be called with a valid wi-fi display sink handle from any state to \n - * completely shutdown the wi-fi display sink operation. - * - * @par Example - * @code -if (mm_wfd_sink_destroy(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to destroy wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_destroy(MMHandleType wfd_sink); - -/** - * This function sets callback function for receiving messages from wi-fi display sink. \n - * So, player can notify warning, error and normal cases to application. \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param callback [in] Message callback function. - * @param user_param [in] User parameter which is passed to callback function. - * - * @return This function returns zero on success, or negative value with error code. - * @see MMWFDMessageCallback - * @remark None - * @par Example - * @code - -int msg_callback(int error_type, MMWFDSinkStateType state_type, void *user_data) -{ - switch (state_type) - { - case MM_WFD_SINK_STATE_NULL: - //do something - break; - - case MM_WFD_SINK_STATE_PREPARED: - //do something - break; - - case MM_WFD_SINK_STATE_CONNECTED: - //do something - break; - - case MM_WFD_SINK_STATE_PLAYING: - //do something - break; - - case MM_WFD_SINK_STATE_PAUSED: - //do something - break; - - case MM_WFD_SINK_DISCONNECTED: - //do something - break; - - default: - break; - } - return TRUE; -} - -mm_wfd_sink_set_message_callback(g_wfd_sink, msg_callback, (void*)g_wfd_sink); - * @endcode - */ -int mm_wfd_sink_set_message_callback(MMHandleType wfd_sink, MMWFDMessageCallback callback, void *user_param); - -int mm_wfd_sink_set_attribute(MMHandleType wfd_sink, char **err_attr_name, const char *first_attribute_name, ...); - -/** - * This function get resources \n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_READY or MM_WFD_SINK_STATE_PREPARED. \n - * @post N/A - * @remark resources are released when mm_wfd_sink_destory is called - * - * @par Example - * @code -if (mm_wfd_sink_get_resource(g_wfd_sink) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to get resources for wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_get_resource(MMHandleType wfd_sink); - -/** - * This function sets the display surface type for wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param display_surface_type [in] Display surface type - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n - * - * @par Example - * @code -if (mm_wfd_sink_set_display_surface_type(g_wfd_sink, g_display_surface_type) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to set display surface type for wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_set_display_surface_type(MMHandleType wfd_sink, gint display_surface_type); - -/** - * This function sets the display overlay for wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param display_overlay [in] Display overlay - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n - * - * @par Example - * @code -if (mm_wfd_sink_set_display_overlay(g_wfd_sink, g_display_overlay) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to set display overlay for wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_set_display_overlay(MMHandleType wfd_sink, void *display_overlay); - -/** - * This function sets the display method for wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param display_method [in] Display method - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n - * - * @par Example - * @code -if (mm_wfd_sink_set_display_method(g_wfd_sink, g_display_method) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to set display method for wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_set_display_method(MMHandleType wfd_sink, gint display_method); - -/** - * This function sets the display visible for wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param display_visible [in] Display visible - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n - * - * @par Example - * @code -if (mm_wfd_sink_set_display_visible(g_wfd_sink, g_display_visible) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to set display visible for wi-fi display sink\n"); -} - * @endcode - */ -int mm_wfd_sink_set_display_visible(MMHandleType wfd_sink, gint display_visible); - -/** - * This function gets the width and height of video which is played by wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param width [in] Width of video - * @param height [in] Height of video - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_CONNECTED or MM_WFD_SINK_STATE_PLAYING. \n - * - * @par Example - * @code -gint g_width=0, g_height=0; - -if (mm_wfd_sink_get_video_resolution(g_wfd_sink, &g_width, &g_height) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to get video resolution.\n"); -} - * @endcode - */ -int mm_wfd_sink_get_video_resolution(MMHandleType wfd_sink, gint *width, gint *height); - -/** - * This function gets the width and height of video which is played by wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param framerate [in] Framerate of video - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_CONNECTED or MM_WFD_SINK_STATE_PLAYING. \n - * - * @par Example - * @code -gint g_framerate=0; - -if (mm_wfd_sink_get_video_framerate(g_wfd_sink, &g_framerate) != MM_ERROR_NONE) -{ - wfd_sink_error("failed to get video framerate.\n"); -} - * @endcode - */ -int mm_wfd_sink_get_video_framerate(MMHandleType wfd_sink, gint *framerate); - -/** - * This function sets the resolutions for wi-fi display sink\n - * - * @param wfd_sink [in] Handle of wi-fi display sink - * @param resolution [in] Resolutions for wi-fi display sink - * - * @return This function returns zero on success, or negative value with error code. - * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n - * - */ -int mm_wfd_sink_set_resolution(MMHandleType wfd_sink, gint resolution); - -int mm_wfd_sink_get_negotiated_video_codec(MMHandleType wfd_sink, gint *codec); -int mm_wfd_sink_get_negotiated_video_resolution(MMHandleType wfd_sink, gint *width, gint *height); -int mm_wfd_sink_get_negotiated_video_frame_rate(MMHandleType wfd_sink, gint *frame_rate); -int mm_wfd_sink_get_negotiated_audio_codec(MMHandleType wfd_sink, gint *codec); -int mm_wfd_sink_get_negotiated_audio_channel(MMHandleType wfd_sink, gint *channel); -int mm_wfd_sink_get_negotiated_audio_sample_rate(MMHandleType wfd_sink, gint *sample_rate); -int mm_wfd_sink_get_negotiated_audio_bitwidth(MMHandleType wfd_sink, gint *bitwidth); -#endif diff --git a/sink/include/mm_wfd_sink_manager.h b/sink/include/mm_wfd_sink_manager.h deleted file mode 100755 index 47309e3..0000000 --- a/sink/include/mm_wfd_sink_manager.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef __MM_WFD_SINK_MANAGER_H__ -#define __MM_WFD_SINK_MANAGER_H__ - -/*======================================================================================= -| INCLUDE FILES | -========================================================================================*/ -#include "mm_wfd_sink_priv.h" -#include "mm_wfd_sink_util.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define WFD_SINK_MANAGER_LOCK(wfd_sink) \ - do {\ - if (wfd_sink) {\ - g_mutex_lock(&((wfd_sink)->manager_thread_mutex));\ - }\ - } while (0); - -#define WFD_SINK_MANAGER_UNLOCK(wfd_sink) \ - do {\ - if (wfd_sink) {\ - g_mutex_unlock(&((wfd_sink)->manager_thread_mutex));\ - }\ - } while (0); - -#define WFD_SINK_MANAGER_WAIT_CMD(wfd_sink) \ - do {\ - if (wfd_sink->manager_thread_exit == FALSE) {\ - wfd_sink_debug("manager thread is waiting for command signal");\ - wfd_sink->waiting_cmd = TRUE; \ - g_cond_wait(&((wfd_sink)->manager_thread_cond), &((wfd_sink)->manager_thread_mutex)); \ - wfd_sink->waiting_cmd = FALSE; \ - } else {\ - wfd_sink_debug("manager thread is stopped, don't need to wait for command signal");\ - }\ - } while (0); - -#define WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, cmd) \ - do {\ - WFD_SINK_MANAGER_LOCK(wfd_sink);\ - if (cmd == WFD_SINK_MANAGER_CMD_EXIT) {\ - g_list_free(wfd_sink->manager_thread_cmd);\ - wfd_sink->manager_thread_cmd = NULL;\ - wfd_sink->manager_thread_exit = TRUE;\ - }\ - wfd_sink->manager_thread_cmd = g_list_append(wfd_sink->manager_thread_cmd, GINT_TO_POINTER(cmd)); \ - WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ - } while (0); - -#define WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink) \ - do {\ - WFD_SINK_MANAGER_LOCK(wfd_sink);\ - if (wfd_sink->waiting_cmd) {\ - if (wfd_sink->manager_thread_cmd) {\ - wfd_sink_debug("send command signal to manager thread");\ - g_cond_signal(&((wfd_sink)->manager_thread_cond));\ - }\ - }\ - WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ - } while (0); - -/** - * This function is to initialize manager - * - * @param[in] handle Handle of wfd_sink. - * @return This function returns zero on success, or negative value with errors. - * @remarks - * @see - * - */ -int _mm_wfd_sink_init_manager(mm_wfd_sink_t *wfd_sink); -/** - * This function is to release manager - * - * @param[in] handle Handle of wfd_sink. - * @return This function returns zero on success, or negative value with errors. - * @remarks - * @see - * - */ -int _mm_wfd_sink_release_manager(mm_wfd_sink_t *wfd_sink); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sink/include/mm_wfd_sink_priv.h b/sink/include/mm_wfd_sink_priv.h deleted file mode 100755 index 7d55a9a..0000000 --- a/sink/include/mm_wfd_sink_priv.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _MM_WFD_SINK_PRIV_H_ -#define _MM_WFD_SINK_PRIV_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mm_wfd_sink.h" - -/* main pipeline's element id */ -enum WFDSinkMainElementID { - WFD_SINK_M_PIPE = 0, /* NOTE : WFD_SINK_M_PIPE should be zero */ - WFD_SINK_M_SRC, - WFD_SINK_M_DEPAY, - WFD_SINK_M_DEMUX, - WFD_SINK_M_NUM -}; - -/* audio decodebin's element id */ -enum WFDSinkAudioDecodeBinElementID { - WFD_SINK_A_D_BIN = 0, /* NOTE : WFD_SINK_A_D_BIN should be zero */ - WFD_SINK_A_D_QUEUE, - WFD_SINK_A_D_HDCP, - WFD_SINK_A_D_AAC_PARSE, - WFD_SINK_A_D_AAC_DEC, - WFD_SINK_A_D_AC3_PARSE, - WFD_SINK_A_D_AC3_DEC, - WFD_SINK_A_D_LPCM_CONVERTER, - WFD_SINK_A_D_LPCM_FILTER, - WFD_SINK_A_D_NUM -}; - -/* audio sinkbin's element id */ -enum WFDSinkAudioSinkBinElementID { - WFD_SINK_A_S_BIN = 0, /* NOTE : WFD_SINK_A_S_BIN should be zero */ - WFD_SINK_A_S_RESAMPLER, - WFD_SINK_A_S_VOLUME, - WFD_SINK_A_S_SINK, - WFD_SINK_A_S_NUM -}; - -/* video decodebin's element id */ -enum WFDSinkVideoDecodeBinElementID { - WFD_SINK_V_D_BIN = 0, /* NOTE : WFD_SINK_V_D_BIN should be zero */ - WFD_SINK_V_D_QUEUE, - WFD_SINK_V_D_HDCP, - WFD_SINK_V_D_PARSE, - WFD_SINK_V_D_CAPSSETTER, - WFD_SINK_V_D_DEC, - WFD_SINK_V_D_NUM -}; - -/* video sinkbin's element id */ -enum WFDSinkVideoSinkBinElementID { - WFD_SINK_V_S_BIN = 0, /* NOTE : WFD_SINK_V_S_BIN should be zero */ - WFD_SINK_V_S_CONVERT, - WFD_SINK_V_S_FILTER, - WFD_SINK_V_S_SINK, - WFD_SINK_V_S_NUM -}; - -/** - * * Enumerations of wifi-display command. - * */ -typedef enum { - MM_WFD_SINK_COMMAND_NONE, /**< command for nothing */ - MM_WFD_SINK_COMMAND_CREATE, /**< command for creating wifi-display sink */ - MM_WFD_SINK_COMMAND_PREPARE, /**< command for preparing wifi-display sink */ - MM_WFD_SINK_COMMAND_CONNECT, /**< command for connecting wifi-display sink */ - MM_WFD_SINK_COMMAND_START, /**< command for starting wifi-display sink */ - MM_WFD_SINK_COMMAND_PAUSE, /**< command for pausing wifi-display sink */ - MM_WFD_SINK_COMMAND_RESUME, /**< command for resuming wifi-display sink */ - MM_WFD_SINK_COMMAND_DISCONNECT, /**< command for disconnecting wifi-display sink */ - MM_WFD_SINK_COMMAND_UNPREPARE, /**< command for unpreparing wifi-display sink */ - MM_WFD_SINK_COMMAND_DESTROY, /**< command for destroting wifi-display sink */ - MM_WFD_SINK_COMMAND_NUM, /**< Number of wifi-display commands */ -} MMWFDSinkCommandType; - -/** - * * Enumerations of thread command. - * */ -typedef enum { - WFD_SINK_MANAGER_CMD_NONE = 0, - WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN, - WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN, - WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE, - WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE, - WFD_SINK_MANAGER_CMD_EXIT, -} WFDSinkManagerCMDType; - -/** - * * Enumerations of resolution. - * */ -typedef enum { - MM_WFD_SINK_RESOLUTION_UNKNOWN = 0, - MM_WFD_SINK_RESOLUTION_1920x1080_P30 = (1 << 0), /**< W-1920, H-1080, 30 fps*/ - MM_WFD_SINK_RESOLUTION_1280x720_P30 = (1 << 1), /**< W-1280, H-720, 30 fps*/ - MM_WFD_SINK_RESOLUTION_960x540_P30 = (1 << 2), /**< W-960, H-540, 30 fps*/ - MM_WFD_SINK_RESOLUTION_864x480_P30 = (1 << 3), /**< W-864, H-480, 30 fps*/ - MM_WFD_SINK_RESOLUTION_720x480_P60 = (1 << 4), /**< W-720, H-480, 30 fps*/ - MM_WFD_SINK_RESOLUTION_640x480_P60 = (1 << 5), /**< W-640, H-480, 60 fps*/ - MM_WFD_SINK_RESOLUTION_640x360_P30 = (1 << 6), /**< W-640, H-360, 30 fps*/ - MM_WFD_SINK_RESOLUTION_MAX = 128, -} MMWFDSinkResolution; - -typedef struct { - gint codec; - gint width; - gint height; - gint frame_rate; -} MMWFDSinkVideoStreamInfo; - -typedef struct { - gint codec; - gint channels; - gint sample_rate; - gint bitwidth; -} MMWFDSinkAudioStreamInfo; - -typedef struct { - MMWFDSinkAudioStreamInfo audio_stream_info; - MMWFDSinkVideoStreamInfo video_stream_info; -} MMWFDSinkStreamInfo; - - -typedef struct { - gint id; - GstElement *gst; -} MMWFDSinkGstElement; - -typedef struct { - MMWFDSinkGstElement *mainbin; - MMWFDSinkGstElement *a_decodebin; - MMWFDSinkGstElement *v_decodebin; - MMWFDSinkGstElement *a_sinkbin; - MMWFDSinkGstElement *v_sinkbin; -} MMWFDSinkGstPipelineInfo; - -typedef struct { - MMWFDSinkStateType state; /* wfd current state */ - MMWFDSinkStateType prev_state; /* wfd previous state */ - MMWFDSinkStateType pending_state; /* wfd state which is going to now */ -} MMWFDSinkState; - -#define MMWFDSINK_GET_ATTRS(x_wfd) ((x_wfd)? ((mm_wfd_sink_t*)x_wfd)->attrs : (MMHandleType)NULL) - -typedef struct { - /* gstreamer pipeline */ - MMWFDSinkGstPipelineInfo *pipeline; - gboolean audio_decodebin_is_linked; - gboolean video_decodebin_is_linked; - - /* timestamp compensation */ - gboolean need_to_reset_basetime; - - GstClock *clock; - gint64 video_average_gap; - gint64 video_accumulated_gap; - gint64 video_buffer_count; - gint64 audio_average_gap; - gint64 audio_accumulated_gap; - gint64 audio_buffer_count; - GstClockTime last_buffer_timestamp; - - /* attributes */ - MMHandleType attrs; - - /* state */ - MMWFDSinkState state; - - /* initialize values */ - mm_wfd_sink_ini_t ini; - - /* command */ - MMWFDSinkCommandType cmd; - GMutex cmd_lock; - gboolean waiting_cmd; - - /* stream information */ - MMWFDSinkStreamInfo stream_info; - - /* Message handling */ - MMWFDMessageCallback msg_cb; - void *msg_user_data; - - /* video resolution for negotiation */ - MMWFDSinkResolution supportive_resolution; - - GThread *manager_thread; - GMutex manager_thread_mutex; - GCond manager_thread_cond; - GList *manager_thread_cmd; - gboolean manager_thread_exit; -} mm_wfd_sink_t; - - -int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink); -int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri); -int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data); -int _mm_wfd_sink_get_resource(mm_wfd_sink_t *wfd_sink); -int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution); - -int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink); -int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink); - -const gchar *_mm_wfds_sink_get_state_name(MMWFDSinkStateType state); - -#endif - diff --git a/sink/include/mm_wfd_sink_util.h b/sink/include/mm_wfd_sink_util.h deleted file mode 100755 index 870982a..0000000 --- a/sink/include/mm_wfd_sink_util.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _MM_WFD_SINK_UTIL_H_ -#define _MM_WFD_SINK_UTIL_H_ - -#include -#include -#include -#include -#include -#include "mm_wfd_sink_dlog.h" - -#define MMWFDSINK_FREEIF(x) \ - do {\ - if ((x)) \ - g_free((gpointer)(x)); \ - (x) = NULL;\ - } while (0); - -/* lock for commnad */ -#define MMWFDSINK_CMD_LOCK(x_wfd) \ - if (x_wfd) \ - g_mutex_lock(&(((mm_wfd_sink_t *)x_wfd)->cmd_lock)); - -#define MMWFDSINK_CMD_UNLOCK(x_wfd) \ - if (x_wfd) \ - g_mutex_unlock(&(((mm_wfd_sink_t *)x_wfd)->cmd_lock)); - -/* create element */ -#define MMWFDSINK_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \ - do { \ - if (x_name && (strlen(x_factory) > 1)) {\ - x_bin[x_id].id = x_id;\ - x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ - if (! x_bin[x_id].gst) {\ - wfd_sink_error("failed to create %s \n", x_factory);\ - goto CREATE_ERROR;\ - }\ - wfd_sink_debug("%s is created \n", x_factory);\ - if (x_add_bucket)\ - element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\ - }\ - } while (0); - -/* generating dot */ -#define MMWFDSINK_GENERATE_DOT_IF_ENABLED(x_wfd_sink, x_name) \ - if (x_wfd_sink->ini.generate_dot) { \ - wfd_sink_debug("create dot file : %s.dot", x_name);\ - GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(x_wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst), \ - GST_DEBUG_GRAPH_SHOW_ALL, x_name); \ - } - -/* postint message */ -#define MMWFDSINK_POST_MESSAGE(x_wfd_sink, x_error_type, x_state_type) \ - if (x_wfd_sink->msg_cb) { \ - wfd_sink_debug("Message(error : %d, state : %d) will be posted using user callback\n", x_error_type, x_state_type); \ - x_wfd_sink->msg_cb(x_error_type, x_state_type, x_wfd_sink->msg_user_data); \ - } - - -/* state */ -#define MMWFDSINK_CURRENT_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.state -#define MMWFDSINK_PREVIOUS_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.prev_state -#define MMWFDSINK_PENDING_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.pending_state -#define MMWFDSINK_STATE_GET_NAME(x_state) _mm_wfds_sink_get_state_name(x_state) - -#define MMWFDSINK_PRINT_STATE(x_wfd_sink) \ - wfd_sink_debug("--prev %s, current %s, pending %s--\n", \ - MMWFDSINK_STATE_GET_NAME(MMWFDSINK_PREVIOUS_STATE(x_wfd_sink)), \ - MMWFDSINK_STATE_GET_NAME(MMWFDSINK_CURRENT_STATE(x_wfd_sink)), \ - MMWFDSINK_STATE_GET_NAME(MMWFDSINK_PENDING_STATE(x_wfd_sink))); - -#define MMWFDSINK_CHECK_STATE(x_wfd_sink, x_cmd) \ - switch (__mm_wfd_sink_check_state((mm_wfd_sink_t *)x_wfd_sink, x_cmd)) \ - { \ - case MM_ERROR_NONE: \ - break;\ - case MM_ERROR_WFD_NO_OP: \ - return MM_ERROR_NONE; \ - break; \ - default: \ - return MM_ERROR_WFD_INVALID_STATE; \ - break; \ - } - - -/* pad probe */ -void -mm_wfd_sink_util_add_pad_probe(GstPad *pad, GstElement *element, const gchar *pad_name); -void -mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer(GstPad *pad, GstElement *element, const gchar *pad_name); - -#define MMWFDSINK_PAD_PROBE(x_wfd_sink, x_pad, x_element, x_pad_name) \ - if (x_wfd_sink) { \ - if (x_wfd_sink->ini.enable_pad_probe) { \ - mm_wfd_sink_util_add_pad_probe(x_pad, x_element, (const gchar*)x_pad_name); \ - } else {\ - mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer (x_pad, x_element, (const gchar*)x_pad_name); \ - }\ - } - -void -mm_wfd_sink_util_add_pad_probe_for_data_dump(GstElement *element, const gchar *pad_name); - -#define MMWFDSINK_TS_DATA_DUMP(x_wfd_sink, x_element, x_pad_name) \ - if (x_wfd_sink && x_wfd_sink->ini.enable_ts_data_dump) { \ - mm_wfd_sink_util_add_pad_probe_for_data_dump (x_element, (const gchar*)x_pad_name); \ - } - -#endif diff --git a/sink/include/mm_wfd_sink_wayland.h b/sink/include/mm_wfd_sink_wayland.h deleted file mode 100755 index d3e6da6..0000000 --- a/sink/include/mm_wfd_sink_wayland.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -#ifndef __MM_WFD_SINK_WLCLIENT_H__ -#define __MM_WFD_SINK_WLCLIENT_H__ -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct -{ - struct wl_display *display; - struct wl_registry *registry; - struct tizen_surface *tz_surface; - struct tizen_resource *tz_resource; -} wl_client; - -int mm_wfd_sink_wlclient_create (wl_client ** wlclient); -int mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wl_client * wlclient, struct wl_surface *surface, struct wl_display *display); -void mm_wfd_sink_wlclient_finalize (wl_client * wlclient); - -#ifdef __cplusplus -} -#endif - -#endif /* __MM_WFD_SINK_WLCLIENT_H__ */ diff --git a/sink/mm_wfd_sink.c b/sink/mm_wfd_sink.c deleted file mode 100755 index fd0d335..0000000 --- a/sink/mm_wfd_sink.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include "mm_wfd_sink_util.h" -#include "mm_wfd_sink.h" -#include "mm_wfd_sink_priv.h" -#include "mm_wfd_sink_dlog.h" - -int mm_wfd_sink_create(MMHandleType *wfd_sink) -{ - mm_wfd_sink_t *new_wfd_sink = NULL; - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - result = _mm_wfd_sink_create(&new_wfd_sink); - if (result != MM_ERROR_NONE) { - wfd_sink_error("fail to create wi-fi display sink handle. ret[%d]", result); - *wfd_sink = (MMHandleType)NULL; - return result; - } - - /* init wfd lock */ - g_mutex_init(&new_wfd_sink->cmd_lock); - - *wfd_sink = (MMHandleType)new_wfd_sink; - - wfd_sink_debug_fleave(); - - return result; - -} - -int mm_wfd_sink_prepare(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_prepare((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_connect(MMHandleType wfd_sink, const char *uri) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(uri, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_connect((mm_wfd_sink_t *)wfd_sink, uri); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_start(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_start((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_pause(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_pause((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_resume(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_resume((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_disconnect(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_disconnect((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_unprepare(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_unprepare((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_destroy(MMHandleType wfd_sink) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *sink_handle = NULL; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_destroy((mm_wfd_sink_t *)wfd_sink); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - g_mutex_clear(&(((mm_wfd_sink_t *)wfd_sink)->cmd_lock)); - - sink_handle = (mm_wfd_sink_t *)wfd_sink; - MMWFDSINK_FREEIF(sink_handle); - - return result; -} - -int mm_wfd_sink_set_message_callback(MMHandleType wfd_sink, MMWFDMessageCallback callback, void *user_data) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_set_message_callback((mm_wfd_sink_t *)wfd_sink, callback, user_data); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_set_attribute(MMHandleType wfd_sink, char **err_attr_name, const char *first_attribute_name, ...) -{ - int result = MM_ERROR_NONE; - va_list var_args; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(first_attribute_name, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd_sink); - va_start(var_args, first_attribute_name); - result = _mmwfd_set_attribute(MMWFDSINK_GET_ATTRS(wfd_sink), err_attr_name, first_attribute_name, var_args); - va_end(var_args); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_get_video_resolution(MMHandleType wfd_sink, gint *width, gint *height) -{ - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(width, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(height, MM_ERROR_WFD_INVALID_ARGUMENT); - - *width = wfd->stream_info.video_stream_info.width; - *height = wfd->stream_info.video_stream_info.height; - - return MM_ERROR_NONE; -} - -int mm_wfd_sink_get_video_framerate(MMHandleType wfd_sink, gint *frame_rate) -{ - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(frame_rate, MM_ERROR_WFD_INVALID_ARGUMENT); - - *frame_rate = wfd->stream_info.video_stream_info.frame_rate; - - return MM_ERROR_NONE; -} - -int mm_wfd_sink_set_resolution(MMHandleType wfd_sink, gint resolution) -{ - int result = MM_ERROR_NONE; - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - MMWFDSINK_CMD_LOCK(wfd_sink); - result = _mm_wfd_sink_set_resolution((mm_wfd_sink_t *)wfd_sink, resolution); - MMWFDSINK_CMD_UNLOCK(wfd_sink); - - return result; -} - -int mm_wfd_sink_get_negotiated_video_codec(MMHandleType wfd_sink, gint *codec) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(codec, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *codec = wfd->stream_info.video_stream_info.codec; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_video_resolution(MMHandleType wfd_sink, gint *width, gint *height) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(width, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(height, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *width = wfd->stream_info.video_stream_info.width; - *height = wfd->stream_info.video_stream_info.height; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_video_frame_rate(MMHandleType wfd_sink, gint *frame_rate) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(frame_rate, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *frame_rate = wfd->stream_info.video_stream_info.frame_rate; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_audio_codec(MMHandleType wfd_sink, gint *codec) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(codec, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *codec = wfd->stream_info.audio_stream_info.codec; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_audio_channel(MMHandleType wfd_sink, gint *channel) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(channel, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *channel = wfd->stream_info.audio_stream_info.channels; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_audio_sample_rate(MMHandleType wfd_sink, gint *sample_rate) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(sample_rate, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *sample_rate = wfd->stream_info.audio_stream_info.sample_rate; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} - -int mm_wfd_sink_get_negotiated_audio_bitwidth(MMHandleType wfd_sink, gint *bitwidth) -{ - int result = MM_ERROR_NONE; - mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(bitwidth, MM_ERROR_WFD_INVALID_ARGUMENT); - - MMWFDSINK_CMD_LOCK(wfd); - - MMWFDSINK_PRINT_STATE(wfd); - cur_state = MMWFDSINK_CURRENT_STATE(wfd); - if (cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_PAUSED) { - - wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); - result = MM_ERROR_WFD_INVALID_STATE; - } else { - *bitwidth = wfd->stream_info.audio_stream_info.bitwidth; - } - - MMWFDSINK_CMD_UNLOCK(wfd); - - wfd_sink_debug_fleave(); - - return result; -} diff --git a/sink/mm_wfd_sink_manager.c b/sink/mm_wfd_sink_manager.c deleted file mode 100755 index 3eb86f9..0000000 --- a/sink/mm_wfd_sink_manager.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - - -#include "mm_wfd_sink_manager.h" - - -static gpointer __mm_wfd_sink_manager_thread(gpointer data); - -int _mm_wfd_sink_init_manager(mm_wfd_sink_t *wfd_sink) -{ - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* create manager mutex */ - g_mutex_init(&(wfd_sink->manager_thread_mutex)); - - /* create capture cond */ - g_cond_init(&(wfd_sink->manager_thread_cond)); - - wfd_sink->manager_thread_cmd = NULL; - wfd_sink->manager_thread_exit = FALSE; - - /* create manager thread */ - wfd_sink->manager_thread = - g_thread_new("__mm_wfd_sink_manager_thread", __mm_wfd_sink_manager_thread, (gpointer)wfd_sink); - if (wfd_sink->manager_thread == NULL) { - wfd_sink_error("failed to create manager thread\n"); - goto failed_to_init; - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - -failed_to_init: - g_mutex_clear(&(wfd_sink->manager_thread_mutex)); - g_cond_clear(&(wfd_sink->manager_thread_cond)); - - return MM_ERROR_WFD_INTERNAL; -} - -int _mm_wfd_sink_release_manager(mm_wfd_sink_t *wfd_sink) -{ - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* release manager thread */ - if (wfd_sink->manager_thread) { - WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); - - wfd_sink_debug("waitting for manager thread exit"); - g_thread_join(wfd_sink->manager_thread); - g_mutex_clear(&(wfd_sink->manager_thread_mutex)); - g_cond_clear(&(wfd_sink->manager_thread_cond)); - wfd_sink_debug("manager thread released"); - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static gpointer -__mm_wfd_sink_manager_thread(gpointer data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data; - WFDSinkManagerCMDType cmd = WFD_SINK_MANAGER_CMD_NONE; - GList *walk = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, NULL); - - if (wfd_sink->manager_thread_exit) { - wfd_sink_debug("exit manager thread..."); - return NULL; - } - - wfd_sink_debug("manager thread started. waiting for signal"); - - while (TRUE) { - WFD_SINK_MANAGER_LOCK(wfd_sink); - WFD_SINK_MANAGER_WAIT_CMD(wfd_sink); - - for (walk = wfd_sink->manager_thread_cmd; walk; walk = g_list_next(walk)) { - cmd = GPOINTER_TO_INT(walk->data); - - wfd_sink_debug("got command %d", cmd); - - switch (cmd) { - case WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN: - wfd_sink_debug("try to link audio decodebin."); - if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to link audio decodebin.....\n"); - goto EXIT; - } - break; - case WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN: - wfd_sink_debug("try to link video decodebin."); - if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to link video decodebin.....\n"); - goto EXIT; - } - break; - case WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE: - wfd_sink_debug("try to prepare audio pipeline."); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { - wfd_sink_error("failed to prepare audio pipeline.....\n"); - goto EXIT; - } - break; - case WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE: - wfd_sink_debug("try to prepare video pipeline."); - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { - wfd_sink_error("failed to prepare video pipeline.....\n"); - goto EXIT; - } - break; - case WFD_SINK_MANAGER_CMD_EXIT: - wfd_sink_debug("exiting manager thread"); - goto EXIT; - break; - default: - break; - } - } - - g_list_free(wfd_sink->manager_thread_cmd); - wfd_sink->manager_thread_cmd = NULL; - - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - } - - wfd_sink_debug_fleave(); - - return NULL; - -EXIT: - wfd_sink->manager_thread_exit = TRUE; - g_list_free(wfd_sink->manager_thread_cmd); - wfd_sink->manager_thread_cmd = NULL; - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - - return NULL; -} - diff --git a/sink/mm_wfd_sink_priv.c b/sink/mm_wfd_sink_priv.c deleted file mode 100755 index 0dbfd66..0000000 --- a/sink/mm_wfd_sink_priv.c +++ /dev/null @@ -1,3690 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "mm_wfd_sink_util.h" -#include "mm_wfd_sink_priv.h" -#include "mm_wfd_sink_manager.h" -#include "mm_wfd_sink_dlog.h" -#include "mm_wfd_sink_wfd_enum.h" -#include "mm_wfd_sink_wayland.h" - - -/* gstreamer */ -static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink); -static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async); - -/* state */ -static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd); -static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state); - -/* util */ -static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink); -static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution); - -int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - mm_wfd_sink_t *new_wfd_sink = NULL; - - /* create handle */ - new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t)); - if (!new_wfd_sink) { - wfd_sink_error("failed to allocate memory for wi-fi display sink"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - /* Initialize gstreamer related */ - new_wfd_sink->attrs = 0; - - new_wfd_sink->pipeline = NULL; - new_wfd_sink->audio_decodebin_is_linked = FALSE; - new_wfd_sink->video_decodebin_is_linked = FALSE; - - /* Initialize timestamp compensation related */ - new_wfd_sink->need_to_reset_basetime = FALSE; - new_wfd_sink->clock = NULL; - new_wfd_sink->video_buffer_count = 0LL; - new_wfd_sink->video_average_gap = 0LL; - new_wfd_sink->video_accumulated_gap = 0LL; - new_wfd_sink->audio_buffer_count = 0LL; - new_wfd_sink->audio_average_gap = 0LL; - new_wfd_sink->audio_accumulated_gap = 0LL; - new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE; - - /* Initialize all states */ - MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; - MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; - MMWFDSINK_PENDING_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; - - /* initialize audio/video information */ - new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE; - new_wfd_sink->stream_info.audio_stream_info.channels = 0; - new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0; - new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0; - new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE; - new_wfd_sink->stream_info.video_stream_info.width = 0; - new_wfd_sink->stream_info.video_stream_info.height = 0; - new_wfd_sink->stream_info.video_stream_info.frame_rate = 0; - - /* Initialize command */ - new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE; - new_wfd_sink->waiting_cmd = FALSE; - - /* Initialize manager related */ - new_wfd_sink->manager_thread = NULL; - new_wfd_sink->manager_thread_cmd = NULL; - new_wfd_sink->manager_thread_exit = FALSE; - - /* Initialize video resolution */ - new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN; - - /* construct attributes */ - new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink); - if (!new_wfd_sink->attrs) { - MMWFDSINK_FREEIF(new_wfd_sink); - wfd_sink_error("failed to set attribute"); - return MM_ERROR_WFD_INTERNAL; - } - - /* load ini for initialize */ - result = mm_wfd_sink_ini_load(&new_wfd_sink->ini); - if (result != MM_ERROR_NONE) { - wfd_sink_error("failed to load ini file"); - goto fail_to_load_ini; - } - new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime; - - /* initialize manager */ - result = _mm_wfd_sink_init_manager(new_wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to init manager : %d", result); - goto fail_to_init; - } - - /* initialize gstreamer */ - result = __mm_wfd_sink_init_gstreamer(new_wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to init gstreamer : %d", result); - goto fail_to_init; - } - - /* set state */ - __mm_wfd_sink_set_state(new_wfd_sink, MM_WFD_SINK_STATE_NULL); - - /* now take handle */ - *wfd_sink = new_wfd_sink; - - wfd_sink_debug_fleave(); - - return result; - - /* ERRORS */ -fail_to_init: - mm_wfd_sink_ini_unload(&new_wfd_sink->ini); -fail_to_load_ini: - _mmwfd_deconstruct_attribute(new_wfd_sink->attrs); - MMWFDSINK_FREEIF(new_wfd_sink); - - *wfd_sink = NULL; - - return result; -} - -int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE); - - /* construct pipeline */ - /* create main pipeline */ - result = __mm_wfd_sink_create_pipeline(wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to create pipeline : %d", result); - goto fail_to_create; - } - - /* create video decodebin */ - result = __mm_wfd_sink_create_video_decodebin(wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to create video decodebin %d", result); - goto fail_to_create; - } - - /* create video sinkbin */ - result = __mm_wfd_sink_create_video_sinkbin(wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to create video sinkbin %d", result); - goto fail_to_create; - } - - /* create audio decodebin */ - result = __mm_wfd_sink_create_audio_decodebin(wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("fail to create audio decodebin : %d", result); - goto fail_to_create; - } - - /* create audio sinkbin */ - result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink); - if (result < MM_ERROR_NONE) { - wfd_sink_error("fail to create audio sinkbin : %d", result); - goto fail_to_create; - } - - /* set pipeline READY state */ - result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d", result); - goto fail_to_create; - } - - /* set state */ - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PREPARED); - - wfd_sink_debug_fleave(); - - return result; - - /* ERRORS */ -fail_to_create: - /* need to destroy pipeline already created */ - __mm_wfd_sink_destroy_pipeline(wfd_sink); - return result; -} - -int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"), MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT); - - wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri)); - - /* set uri to wfdsrc */ - g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL); - - /* set pipeline PAUSED state */ - result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d", result); - return result; - } - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START); - - WFD_SINK_MANAGER_LOCK(wfd_sink) ; - wfd_sink_debug("check pipeline is ready to start"); - WFD_SINK_MANAGER_UNLOCK(wfd_sink); - - result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE); - if (result < MM_ERROR_NONE) { - wfd_sink_error("failed to set state : %d", result); - return result; - } - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE); - - g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL); - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME); - - g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL); - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && - wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT); - - WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); - - g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL); - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE); - - WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); - - /* release pipeline */ - result = __mm_wfd_sink_destroy_pipeline(wfd_sink); - if (result != MM_ERROR_NONE) { - wfd_sink_error("failed to destory pipeline"); - return MM_ERROR_WFD_INTERNAL; - } else { - wfd_sink_debug("success to destory pipeline"); - } - - /* set state */ - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL); - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* check current wi-fi display sink state */ - MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY); - - /* unload ini */ - mm_wfd_sink_ini_unload(&wfd_sink->ini); - - /* release attributes */ - _mmwfd_deconstruct_attribute(wfd_sink->attrs); - - if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) { - wfd_sink_error("failed to release manager"); - return MM_ERROR_WFD_INTERNAL; - } - - - /* set state */ - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE); - - wfd_sink_debug_fleave(); - - return result; -} - -int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data) -{ - int result = MM_ERROR_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - wfd_sink->msg_cb = callback; - wfd_sink->msg_user_data = user_data; - - wfd_sink_debug_fleave(); - - return result; -} - -static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink) -{ - int result = MM_ERROR_NONE; - gint *argc = NULL; - gchar **argv = NULL; - static const int max_argc = 50; - GError *err = NULL; - gint i = 0; - - wfd_sink_debug_fenter(); - - /* alloc */ - argc = calloc(1, sizeof(gint)); - argv = calloc(max_argc, sizeof(gchar *)); - if (!argc || !argv) { - wfd_sink_error("failed to allocate memory for wfdsink"); - - MMWFDSINK_FREEIF(argv); - MMWFDSINK_FREEIF(argc); - - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - /* we would not do fork for scanning plugins */ - argv[*argc] = g_strdup("--gst-disable-registry-fork"); - (*argc)++; - - /* check disable registry scan */ - argv[*argc] = g_strdup("--gst-disable-registry-update"); - (*argc)++; - - /* check disable segtrap */ - argv[*argc] = g_strdup("--gst-disable-segtrap"); - (*argc)++; - - /* check ini */ - for (i = 0; i < 5; i++) { - if (strlen(wfd_sink->ini.gst_param[i]) > 2) { - wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]); - argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]); - (*argc)++; - } - } - - wfd_sink_debug("initializing gstreamer with following parameter"); - wfd_sink_debug("argc : %d", *argc); - - for (i = 0; i < *argc; i++) { - wfd_sink_debug("argv[%d] : %s", i, argv[i]); - } - - /* initializing gstreamer */ - if (!gst_init_check(argc, &argv, &err)) { - wfd_sink_error("failed to initialize gstreamer: %s", err ? err->message : "unknown error occurred"); - if (err) - g_error_free(err); - - result = MM_ERROR_WFD_INTERNAL; - } - - /* release */ - for (i = 0; i < *argc; i++) { - MMWFDSINK_FREEIF(argv[i]); - } - MMWFDSINK_FREEIF(argv); - MMWFDSINK_FREEIF(argc); - - wfd_sink_debug_fleave(); - - return result; -} - -static GstBusSyncReply -_mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data) -{ - GstBusSyncReply ret = GST_BUS_PASS; - - wfd_sink_return_val_if_fail(message && - GST_IS_MESSAGE(message) && - GST_MESSAGE_SRC(message), - GST_BUS_DROP); - - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_TAG: - break; - case GST_MESSAGE_DURATION: - break; - case GST_MESSAGE_STATE_CHANGED: { - /* we only handle state change messages from pipeline */ - if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message))) - ret = GST_BUS_DROP; - } - break; - case GST_MESSAGE_ASYNC_DONE: { - if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message))) - ret = GST_BUS_DROP; - } - break; - default: - break; - } - - return ret; -} - -static gboolean -_mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data; - const GstStructure *message_structure = gst_message_get_structure(msg); - gboolean ret = TRUE; - - wfd_sink_return_val_if_fail(wfd_sink, FALSE); - wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE); - - wfd_sink_debug("got %s from %s", - GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)), - GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)))); - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_ERROR: { - GError *error = NULL; - gchar *debug = NULL; - - /* get error code */ - gst_message_parse_error(msg, &error, &debug); - - wfd_sink_error("error : %s", error->message); - wfd_sink_error("debug : %s", debug); - - MMWFDSINK_FREEIF(debug); - g_error_free(error); - } - break; - - case GST_MESSAGE_WARNING: { - char *debug = NULL; - GError *error = NULL; - - gst_message_parse_warning(msg, &error, &debug); - - wfd_sink_warning("warning : %s", error->message); - wfd_sink_warning("debug : %s", debug); - - MMWFDSINK_FREEIF(debug); - g_error_free(error); - } - break; - - case GST_MESSAGE_STATE_CHANGED: { - const GValue *voldstate, *vnewstate, *vpending; - GstState oldstate, newstate, pending; - const GstStructure *structure; - - /* we only handle messages from pipeline */ - if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) - break; - - /* get state info from msg */ - structure = gst_message_get_structure(msg); - if (structure == NULL) - break; - - voldstate = gst_structure_get_value(structure, "old-state"); - vnewstate = gst_structure_get_value(structure, "new-state"); - vpending = gst_structure_get_value(structure, "pending-state"); - if (voldstate == NULL || vnewstate == NULL || vpending == NULL) - break; - - oldstate = (GstState)voldstate->data[0].v_int; - newstate = (GstState)vnewstate->data[0].v_int; - pending = (GstState)vpending->data[0].v_int; - - wfd_sink_debug("state changed [%s] : %s--->%s final : %s", - GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), - gst_element_state_get_name((GstState)oldstate), - gst_element_state_get_name((GstState)newstate), - gst_element_state_get_name((GstState)pending)); - - if (oldstate == newstate) { - wfd_sink_debug("pipeline reports state transition to old state"); - break; - } - - switch (newstate) { - case GST_STATE_VOID_PENDING: - case GST_STATE_NULL: - case GST_STATE_READY: - case GST_STATE_PAUSED: - case GST_STATE_PLAYING: - default: - break; - } - } - break; - - case GST_MESSAGE_CLOCK_LOST: { - GstClock *clock = NULL; - gst_message_parse_clock_lost(msg, &clock); - wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.", (clock ? GST_OBJECT_NAME(clock) : "NULL")); - } - break; - - case GST_MESSAGE_NEW_CLOCK: { - GstClock *clock = NULL; - gst_message_parse_new_clock(msg, &clock); - if (!clock) - break; - - if (wfd_sink->clock) { - if (wfd_sink->clock != clock) - wfd_sink_debug("clock is changed! [%s] -->[%s]", - GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)), - GST_STR_NULL(GST_OBJECT_NAME(clock))); - else - wfd_sink_debug("same clock is selected again! [%s]", - GST_STR_NULL(GST_OBJECT_NAME(clock))); - } else { - wfd_sink_debug("new clock [%s] was selected in the pipeline", - (GST_STR_NULL(GST_OBJECT_NAME(clock)))); - } - - wfd_sink->clock = clock; - } - break; - - case GST_MESSAGE_APPLICATION: { - const gchar *message_structure_name; - - message_structure_name = gst_structure_get_name(message_structure); - if (!message_structure_name) - break; - - wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name)); - } - break; - - case GST_MESSAGE_ELEMENT: { - const gchar *structure_name = NULL; - - structure_name = gst_structure_get_name(message_structure); - if (structure_name) { - wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name)); - if (g_strrstr(structure_name, "GstUDPSrcTimeout")) { - wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name)); - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } else if (g_strrstr(structure_name, "GstWFDSrcSessionTimeout")) { - wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name)); - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } - } - } - break; - - case GST_MESSAGE_PROGRESS: { - GstProgressType type = GST_PROGRESS_TYPE_ERROR; - gchar *category = NULL, *text = NULL; - - gst_message_parse_progress(msg, &type, &category, &text); - wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text)); - - switch (type) { - case GST_PROGRESS_TYPE_START: - break; - case GST_PROGRESS_TYPE_COMPLETE: - if (category && !strcmp(category, "open")) - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED); - else if (category && !strcmp(category, "play")) { - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING); - /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */ - } else if (category && !strcmp(category, "pause")) - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED); - else if (category && !strcmp(category, "close")) - __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED); - break; - case GST_PROGRESS_TYPE_CANCELED: - break; - case GST_PROGRESS_TYPE_ERROR: - if (category && !strcmp(category, "open")) { - wfd_sink_error("got error : %s", GST_STR_NULL(text)); - /*_mm_wfd_sink_disconnect (wfd_sink); */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } else if (category && !strcmp(category, "play")) { - wfd_sink_error("got error : %s", GST_STR_NULL(text)); - /*_mm_wfd_sink_disconnect (wfd_sink); */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } else if (category && !strcmp(category, "pause")) { - wfd_sink_error("got error : %s", GST_STR_NULL(text)); - /*_mm_wfd_sink_disconnect (wfd_sink); */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } else if (category && !strcmp(category, "close")) { - wfd_sink_error("got error : %s", GST_STR_NULL(text)); - /*_mm_wfd_sink_disconnect (wfd_sink); */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - } else { - wfd_sink_error("got error : %s", GST_STR_NULL(text)); - } - break; - default: - wfd_sink_error("progress message has no type"); - return ret; - } - - MMWFDSINK_FREEIF(category); - MMWFDSINK_FREEIF(text); - } - break; - case GST_MESSAGE_ASYNC_START: - wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); - break; - case GST_MESSAGE_ASYNC_DONE: - wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); - break; - case GST_MESSAGE_UNKNOWN: - case GST_MESSAGE_INFO: - case GST_MESSAGE_TAG: - case GST_MESSAGE_BUFFERING: - case GST_MESSAGE_EOS: - case GST_MESSAGE_STATE_DIRTY: - case GST_MESSAGE_STEP_DONE: - case GST_MESSAGE_CLOCK_PROVIDE: - case GST_MESSAGE_STRUCTURE_CHANGE: - case GST_MESSAGE_STREAM_STATUS: - case GST_MESSAGE_SEGMENT_START: - case GST_MESSAGE_SEGMENT_DONE: - case GST_MESSAGE_DURATION: - case GST_MESSAGE_LATENCY: - case GST_MESSAGE_REQUEST_STATE: - case GST_MESSAGE_STEP_START: - case GST_MESSAGE_QOS: - case GST_MESSAGE_ANY: - break; - default: - wfd_sink_debug("unhandled message"); - break; - } - - return ret; -} - -static int -__mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare) -{ - GList *bucket = element_bucket; - MMWFDSinkGstElement *element = NULL; - int successful_add_count = 0; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(element_bucket, 0); - wfd_sink_return_val_if_fail(bin, 0); - - for (; bucket; bucket = bucket->next) { - element = (MMWFDSinkGstElement *)bucket->data; - - if (element && element->gst) { - if (need_prepare) - gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY); - - if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) { - wfd_sink_error("failed to add element [%s] to bin [%s]", - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); - return 0; - } - - wfd_sink_debug("add element [%s] to bin [%s]", - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); - - successful_add_count++; - } - } - - wfd_sink_debug_fleave(); - - return successful_add_count; -} - -static int -__mm_wfd_sink_gst_element_link_bucket(GList *element_bucket) -{ - GList *bucket = element_bucket; - MMWFDSinkGstElement *element = NULL; - MMWFDSinkGstElement *prv_element = NULL; - gint successful_link_count = 0; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(element_bucket, -1); - - prv_element = (MMWFDSinkGstElement *)bucket->data; - bucket = bucket->next; - - for (; bucket; bucket = bucket->next) { - element = (MMWFDSinkGstElement *)bucket->data; - - if (element && element->gst) { - if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) { - wfd_sink_debug("linking [%s] to [%s] success", - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); - successful_link_count++; - } else { - wfd_sink_error("linking [%s] to [%s] failed", - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), - GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); - return -1; - } - } - - prv_element = element; - } - - wfd_sink_debug_fleave(); - - return successful_link_count; -} - -static int -__mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd) -{ - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_PRINT_STATE(wfd_sink); - - cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink); - - switch (cmd) { - case MM_WFD_SINK_COMMAND_CREATE: { - if (cur_state != MM_WFD_SINK_STATE_NONE) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL; - } - break; - - case MM_WFD_SINK_COMMAND_PREPARE: { - if (cur_state == MM_WFD_SINK_STATE_PREPARED) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_NULL) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED; - } - break; - - case MM_WFD_SINK_COMMAND_CONNECT: { - if (cur_state == MM_WFD_SINK_STATE_CONNECTED) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_PREPARED) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED; - } - break; - - case MM_WFD_SINK_COMMAND_START: { - if (cur_state == MM_WFD_SINK_STATE_PLAYING) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_CONNECTED) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING; - } - break; - - case MM_WFD_SINK_COMMAND_PAUSE: { - if (cur_state == MM_WFD_SINK_STATE_PAUSED) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_PLAYING) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED; - } - break; - - case MM_WFD_SINK_COMMAND_RESUME: { - if (cur_state == MM_WFD_SINK_STATE_PLAYING) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_PAUSED) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING; - } - break; - - case MM_WFD_SINK_COMMAND_DISCONNECT: { - if (cur_state == MM_WFD_SINK_STATE_NONE || - cur_state == MM_WFD_SINK_STATE_NULL || - cur_state == MM_WFD_SINK_STATE_PREPARED || - cur_state == MM_WFD_SINK_STATE_DISCONNECTED) - goto no_operation; - else if (cur_state != MM_WFD_SINK_STATE_PLAYING && - cur_state != MM_WFD_SINK_STATE_CONNECTED && - cur_state != MM_WFD_SINK_STATE_PAUSED) - goto invalid_state; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED; - } - break; - - case MM_WFD_SINK_COMMAND_UNPREPARE: { - if (cur_state == MM_WFD_SINK_STATE_NONE || - cur_state == MM_WFD_SINK_STATE_NULL) - goto no_operation; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL; - } - break; - - case MM_WFD_SINK_COMMAND_DESTROY: { - if (cur_state == MM_WFD_SINK_STATE_NONE) - goto no_operation; - - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; - } - break; - - default: - break; - } - - wfd_sink->cmd = cmd; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - -no_operation: - wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state)); - return MM_ERROR_WFD_NO_OP; - - /* ERRORS */ -invalid_state: - wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state)); - return MM_ERROR_WFD_INVALID_STATE; -} - -static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state) -{ - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) { - wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state)); - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; - return MM_ERROR_NONE; - } - - /* update wi-fi display state */ - MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink); - MMWFDSINK_CURRENT_STATE(wfd_sink) = state; - - if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink)) - MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; - - /* poset state message to application */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_NONE, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - - /* print state */ - MMWFDSINK_PRINT_STATE(wfd_sink); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int -__mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async) -{ - GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; - GstState cur_state = GST_STATE_VOID_PENDING; - GstState pending_state = GST_STATE_VOID_PENDING; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING, MM_ERROR_WFD_INVALID_ARGUMENT); - - wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state)); - - result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state); - if (result == GST_STATE_CHANGE_FAILURE) { - wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state)); - return MM_ERROR_WFD_INTERNAL; - } - - if (!async) { - wfd_sink_debug("wait for changing state is completed "); - - result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND); - if (result == GST_STATE_CHANGE_FAILURE) { - wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout); - - __mm_wfd_sink_dump_pipeline_state(wfd_sink); - - return MM_ERROR_WFD_INTERNAL; - } else if (result == GST_STATE_CHANGE_NO_PREROLL) { - wfd_sink_debug("successfully changed state but is not able to provide data yet"); - } - - wfd_sink_debug("cur state is %s, pending state is %s", - gst_element_state_get_name(cur_state), - gst_element_state_get_name(pending_state)); - } - - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static void -_mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink) -{ - GstClockTime base_time = GST_CLOCK_TIME_NONE; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); - wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime); - - - if (wfd_sink->clock) - base_time = gst_clock_get_time(wfd_sink->clock); - - if (GST_CLOCK_TIME_IS_VALID(base_time)) { - - wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time)); - - for (i = 0; i < WFD_SINK_M_NUM; i++) { - if (wfd_sink->pipeline->mainbin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time); - } - - if (wfd_sink->pipeline->v_decodebin) { - for (i = 0; i < WFD_SINK_V_D_NUM; i++) { - if (wfd_sink->pipeline->v_decodebin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time); - } - } - - if (wfd_sink->pipeline->v_sinkbin) { - for (i = 0; i < WFD_SINK_V_S_NUM; i++) { - if (wfd_sink->pipeline->v_sinkbin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time); - } - } - - if (wfd_sink->pipeline->a_decodebin) { - for (i = 0; i < WFD_SINK_A_D_NUM; i++) { - if (wfd_sink->pipeline->a_decodebin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time); - } - } - - if (wfd_sink->pipeline->a_sinkbin) { - for (i = 0; i < WFD_SINK_A_S_NUM; i++) { - if (wfd_sink->pipeline->a_sinkbin[i].gst) - gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time); - } - } - - wfd_sink->need_to_reset_basetime = FALSE; - } - - wfd_sink_debug_fleave(); - - return; -} - -int -__mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink) -{ - GstElement *bin = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check video decodebin is linked */ - if (!wfd_sink->video_decodebin_is_linked) { - /* check video decodebin is created */ - if (wfd_sink->pipeline->v_decodebin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to create video decodebin...."); - goto ERROR; - } - } - - if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to link video decodebin....."); - goto ERROR; - } - } - - /* check video sinkbin is created */ - if (wfd_sink->pipeline->v_sinkbin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) { - wfd_sink_error("failed to create video sinkbin...."); - goto ERROR; - } - } - - /* set video decodebin state as READY */ - if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { - bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; - if (GST_STATE(bin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to video decodebin"); - goto ERROR; - } - } - } else { - wfd_sink_warning("going on without video decodebin...."); - } - - /* set video sinkbin state as READY */ - if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { - bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; - if (GST_STATE(bin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to video sinkbin"); - goto ERROR; - } - } - } else { - wfd_sink_warning("going on without video sinkbin...."); - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS */ -ERROR: - /* need to notify to app */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - - return MM_ERROR_WFD_INTERNAL; -} - -int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink) -{ - GstElement *bin = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check audio decodebin is linked */ - if (!wfd_sink->audio_decodebin_is_linked) { - /* check audio decodebin is created */ - if (wfd_sink->pipeline->a_decodebin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to create audio decodebin...."); - goto ERROR; - } - } - - if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to link audio decodebin....."); - goto ERROR; - } - } - - /* check audio sinkbin is created */ - if (wfd_sink->pipeline->a_sinkbin == NULL) { - if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) { - wfd_sink_error("failed to create audio sinkbin...."); - goto ERROR; - } - } - - /* set audio decodebin state as READY */ - if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { - bin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; - if (GST_STATE(bin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to audio decodebin"); - goto ERROR; - } - } - } else { - wfd_sink_warning("going on without audio decodebin...."); - } - - /* set audio sinkbin state as READY */ - if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { - bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; - if (GST_STATE(bin) <= GST_STATE_NULL) { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) { - wfd_sink_error("failed to set state(READY) to audio sinkbin"); - goto ERROR; - } - } - } else { - wfd_sink_warning("going on without audio sinkbin...."); - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS */ -ERROR: - /* need to notify to app */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - - return MM_ERROR_WFD_INTERNAL; -} - -#define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */ -#define COMPENSATION_CHECK_PERIOD (30*GST_SECOND) /* 30 sec */ - -static GstPadProbeReturn -_mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data; - GstClockTime current_time = GST_CLOCK_TIME_NONE; - GstClockTime start_time = GST_CLOCK_TIME_NONE; - GstClockTime running_time = GST_CLOCK_TIME_NONE; - GstClockTime base_time = GST_CLOCK_TIME_NONE; - GstClockTime render_time = GST_CLOCK_TIME_NONE; - GstClockTimeDiff diff = GST_CLOCK_TIME_NONE; - GstBuffer *buffer = NULL; - gint64 ts_offset = 0LL; - - wfd_sink_return_val_if_fail(info, FALSE); - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, - GST_PAD_PROBE_DROP); - - if (!wfd_sink->clock) { - wfd_sink_warning("pipeline did not select clock, yet"); - return GST_PAD_PROBE_OK; - } - - if (wfd_sink->need_to_reset_basetime) - _mm_wfd_sink_reset_basetime(wfd_sink); - - /* calculate current runninig time */ - current_time = gst_clock_get_time(wfd_sink->clock); - if (g_strrstr(GST_OBJECT_NAME(pad), "video")) - base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst); - else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) - base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst); - start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); - if (GST_CLOCK_TIME_IS_VALID(current_time) && - GST_CLOCK_TIME_IS_VALID(start_time) && - GST_CLOCK_TIME_IS_VALID(base_time)) { - running_time = current_time - (start_time + base_time); - } else { - wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT - " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time), - GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time)); - return GST_PAD_PROBE_OK; - } - - /* calculate this buffer rendering time */ - buffer = gst_pad_probe_info_get_buffer(info); - if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) { - wfd_sink_warning("buffer timestamp is invalid."); - return GST_PAD_PROBE_OK; - } - - if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) { - if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) - g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL); - } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) { - if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) - g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL); - } - - render_time = GST_BUFFER_TIMESTAMP(buffer); - render_time += ts_offset; - - /* chekc this buffer could be rendered or not */ - if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) { - diff = GST_CLOCK_DIFF(running_time, render_time); - if (diff < 0) { - /* this buffer could be NOT rendered */ - wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "", - GST_STR_NULL((GST_OBJECT_NAME(pad))), - GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time))); - } else { - /* this buffer could be rendered */ - /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */ - /* GST_STR_NULL((GST_OBJECT_NAME(pad))), */ - /* GST_TIME_ARGS(diff)); */ - } - } - - /* update buffer count and gap */ - if (g_strrstr(GST_OBJECT_NAME(pad), "video")) { - wfd_sink->video_buffer_count++; - wfd_sink->video_accumulated_gap += diff; - } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) { - wfd_sink->audio_buffer_count++; - wfd_sink->audio_accumulated_gap += diff; - } else { - wfd_sink_warning("invalid buffer type.. "); - return GST_PAD_PROBE_DROP; - } - - if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) { - /* fisrt 60sec, just calculate the gap between source device and sink device */ - if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND) - return GST_PAD_PROBE_OK; - - /* every 10sec, calculate the gap between source device and sink device */ - if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer)) - > COMPENSATION_CHECK_PERIOD) { - gint64 audio_avgrage_gap = 0LL; - gint64 video_avgrage_gap = 0LL; - gint64 audio_avgrage_gap_diff = 0LL; - gint64 video_avgrage_gap_diff = 0LL; - gboolean video_minus_compensation = FALSE; - gboolean audio_minus_compensation = FALSE; - gint64 avgrage_gap_diff = 0LL; - gboolean minus_compensation = FALSE; - - /* check video */ - if (wfd_sink->video_buffer_count > 0) { - video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count; - - if (wfd_sink->video_average_gap != 0) { - if (video_avgrage_gap > wfd_sink->video_average_gap) { - video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap; - video_minus_compensation = TRUE; - } else { - video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap; - video_minus_compensation = FALSE; - } - } else { - wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap); - wfd_sink->video_average_gap = video_avgrage_gap; - } - } else { - wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT - " ~ %" GST_TIME_FORMAT"", - GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - } - - /* check audio */ - if (wfd_sink->audio_buffer_count > 0) { - audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count; - - if (wfd_sink->audio_average_gap != 0) { - if (audio_avgrage_gap > wfd_sink->audio_average_gap) { - audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap; - audio_minus_compensation = TRUE; - } else { - audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap; - audio_minus_compensation = FALSE; - } - } else { - wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap); - wfd_sink->audio_average_gap = audio_avgrage_gap; - } - } else { - wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT - " ~ %" GST_TIME_FORMAT"", - GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - } - - /* selecet average_gap_diff between video and audio */ - /* which makes no buffer drop in the sink elements */ - if (video_avgrage_gap_diff && audio_avgrage_gap_diff) { - if (!video_minus_compensation && !audio_minus_compensation) { - minus_compensation = FALSE; - if (video_avgrage_gap_diff > audio_avgrage_gap_diff) - avgrage_gap_diff = video_avgrage_gap_diff; - else - avgrage_gap_diff = audio_avgrage_gap_diff; - } else if (video_minus_compensation && audio_minus_compensation) { - minus_compensation = TRUE; - if (video_avgrage_gap_diff > audio_avgrage_gap_diff) - avgrage_gap_diff = audio_avgrage_gap_diff; - else - avgrage_gap_diff = video_avgrage_gap_diff; - } else { - minus_compensation = FALSE; - if (!video_minus_compensation) - avgrage_gap_diff = video_avgrage_gap_diff; - else - avgrage_gap_diff = audio_avgrage_gap_diff; - } - } else if (video_avgrage_gap_diff) { - minus_compensation = video_minus_compensation; - avgrage_gap_diff = video_avgrage_gap_diff; - } else if (audio_avgrage_gap_diff) { - minus_compensation = audio_minus_compensation; - avgrage_gap_diff = audio_avgrage_gap_diff; - } - - wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ", - audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff, - video_minus_compensation ? "-" : "", video_avgrage_gap_diff); - - - /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */ - if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) { - if (minus_compensation) - ts_offset -= avgrage_gap_diff; - else - ts_offset += avgrage_gap_diff; - - wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %" - GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")", - minus_compensation ? "-" : "", avgrage_gap_diff, - GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time)); - - if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) - g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); - if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) - g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); - } else { - wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")", - minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset)); - } - - /* reset values*/ - wfd_sink->video_buffer_count = 0; - wfd_sink->video_accumulated_gap = 0LL; - wfd_sink->audio_buffer_count = 0; - wfd_sink->audio_accumulated_gap = 0LL; - wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); - } - } else { - wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT, - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); - } - - return GST_PAD_PROBE_OK; -} - - -static void -__mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; - gchar *name = gst_pad_get_name(pad); - GstElement *pipeline = NULL; - GstElement *decodebin = NULL; - GstElement *sinkbin = NULL; - GstPad *sinkpad = NULL; - GstPad *srcpad = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); - - pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst; - - /* take decodebin/sinkbin */ - if (name[0] == 'v') { - wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad..."); - - MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); - - gst_pad_add_probe(pad, - GST_PAD_PROBE_TYPE_BUFFER, - _mm_wfd_sink_check_running_time, - (gpointer)wfd_sink, - NULL); - - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { - wfd_sink_error("failed to prepare video pipeline...."); - goto ERROR; - } - - if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) - decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; - if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) - sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; - } else if (name[0] == 'a') { - wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad..."); - - MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); - - gst_pad_add_probe(pad, - GST_PAD_PROBE_TYPE_BUFFER, - _mm_wfd_sink_check_running_time, - (gpointer)wfd_sink, - NULL); - - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { - wfd_sink_error("failed to prepare audio pipeline...."); - goto ERROR; - } - - if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) - decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; - if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) - sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; - } else { - wfd_sink_error("unexceptable pad is added!!!"); - return; - } - - srcpad = gst_object_ref(pad); - - /* add decodebin and link */ - if (decodebin) { - if (!gst_bin_add(GST_BIN(pipeline), decodebin)) { - wfd_sink_error("failed to add %s to pipeline", - GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); - goto ERROR; - } - - sinkpad = gst_element_get_static_pad(decodebin, "sink"); - if (!sinkpad) { - wfd_sink_error("failed to get sink pad from %s", - GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); - goto ERROR; - } - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - wfd_sink_error("failed to link %s and %s", - GST_STR_NULL(GST_PAD_NAME(srcpad)), - GST_STR_NULL(GST_PAD_NAME(sinkpad))); - goto ERROR; - } - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - srcpad = gst_element_get_static_pad(decodebin, "src"); - if (!srcpad) { - wfd_sink_error("failed to get src pad from %s", - GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); - goto ERROR; - } - } else { - wfd_sink_warning("going on without decodebin..."); - } - - /* add sinkbin and link */ - if (sinkbin) { - if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) { - wfd_sink_error("failed to add %s to pipeline", - GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); - goto ERROR; - } - - sinkpad = gst_element_get_static_pad(sinkbin, "sink"); - if (!sinkpad) { - wfd_sink_error("failed to get sink pad from %s", - GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); - goto ERROR; - } - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - wfd_sink_error("failed to link %s and %s", - GST_STR_NULL(GST_PAD_NAME(srcpad)), - GST_STR_NULL(GST_PAD_NAME(sinkpad))); - goto ERROR; - } - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - } else { - wfd_sink_error("there is no sinkbin..."); - goto ERROR; - } - - - /* run */ - if (decodebin) { - if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) { - wfd_sink_error("failed to sync %s state with parent", - GST_STR_NULL(GST_PAD_NAME(decodebin))); - goto ERROR; - } - } - - if (sinkbin) { - if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) { - wfd_sink_error("failed to sync %s state with parent", - GST_STR_NULL(GST_PAD_NAME(sinkbin))); - goto ERROR; - } - } - - if (name[0] == 'v') { - MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline"); - } else if (name[0] == 'a') { - MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline"); - } - - MMWFDSINK_FREEIF(name); - - wfd_sink_debug_fleave(); - - return; - - /* ERRORS */ -ERROR: - MMWFDSINK_FREEIF(name); - - if (srcpad) - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - - if (sinkpad) - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - /* need to notify to app */ - MMWFDSINK_POST_MESSAGE(wfd_sink, - MM_ERROR_WFD_INTERNAL, - MMWFDSINK_CURRENT_STATE(wfd_sink)); - - return; -} - -static void -__mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; - - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(wfd_sink); - wfd_sink_return_if_fail(need_to_flush); - - if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) { - wfd_sink_debug("need to flush pipeline"); - *need_to_flush = (gpointer) TRUE; - } else { - wfd_sink_debug("don't need to flush pipeline"); - *need_to_flush = (gpointer) FALSE; - } - - - wfd_sink_debug_fleave(); -} - - -static void -__mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data) -{ - mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; - MMWFDSinkStreamInfo *stream_info = NULL; - gint is_valid_audio_format = FALSE; - gint is_valid_video_format = FALSE; - gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; - gint video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE; - gchar *audio_format; - gchar *video_format; - - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str)); - wfd_sink_return_if_fail(wfd_sink); - - stream_info = &wfd_sink->stream_info; - - audio_codec = wfd_sink->stream_info.audio_stream_info.codec; - video_codec = wfd_sink->stream_info.video_stream_info.codec; - - if (gst_structure_has_field(str, "audio_format")) { - is_valid_audio_format = TRUE; - audio_format = g_strdup(gst_structure_get_string(str, "audio_format")); - if (g_strrstr(audio_format, "AAC")) - stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC; - else if (g_strrstr(audio_format, "AC3")) - stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3; - else if (g_strrstr(audio_format, "LPCM")) - stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM; - else { - wfd_sink_error("invalid audio format(%s)...", audio_format); - is_valid_audio_format = FALSE; - } - - if (is_valid_audio_format == TRUE) { - if (gst_structure_has_field(str, "audio_rate")) - gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate); - if (gst_structure_has_field(str, "audio_channels")) - gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels); - if (gst_structure_has_field(str, "audio_bitwidth")) - gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth); - - if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { - if (audio_codec != stream_info->audio_stream_info.codec) { - wfd_sink_debug("audio codec is changed...need to change audio decodebin"); - } - } else { - WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE); - } - - wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t", - audio_format, - stream_info->audio_stream_info.sample_rate, - stream_info->audio_stream_info.channels, - stream_info->audio_stream_info.bitwidth); - } - } - - if (gst_structure_has_field(str, "video_format")) { - is_valid_video_format = TRUE; - video_format = g_strdup(gst_structure_get_string(str, "video_format")); - if (!g_strrstr(video_format, "H264")) { - wfd_sink_error("invalid video format(%s)...", video_format); - is_valid_video_format = FALSE; - } - - if (is_valid_video_format == TRUE) { - stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264; - - if (gst_structure_has_field(str, "video_width")) - gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width); - if (gst_structure_has_field(str, "video_height")) - gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height); - if (gst_structure_has_field(str, "video_framerate")) - gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate); - - if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { - if (video_codec != stream_info->video_stream_info.codec) { - wfd_sink_debug("video codec is changed...need to change video decodebin"); - } - } else { - WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE); - } - - wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t", - video_format, - stream_info->video_stream_info.width, - stream_info->video_stream_info.height, - stream_info->video_stream_info.frame_rate); - } - } - - WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); - - wfd_sink_debug_fleave(); -} - -static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc) -{ - GstStructure *audio_param = NULL; - GstStructure *video_param = NULL; - GstStructure *hdcp_param = NULL; - gint hdcp_version = 0; - gint hdcp_port = 0; - guint CEA_resolution = 0; - guint VESA_resolution = 0; - guint HH_resolution = 0; - GObjectClass *klass; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED); - - klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc)); - - g_object_set(G_OBJECT(wfdsrc), "debug", wfd_sink->ini.set_debug_property, NULL); - g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdsrc_pad_probe, NULL); - if (g_object_class_find_property(klass, "udp-buffer-size")) - g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL); - if (g_object_class_find_property(klass, "do-request")) - g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL); - if (g_object_class_find_property(klass, "latency")) - g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL); - - audio_param = gst_structure_new("audio_param", - "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec, - "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency, - "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel, - "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency, - NULL); - - CEA_resolution = wfd_sink->ini.video_cea_support; - VESA_resolution = wfd_sink->ini.video_vesa_support; - HH_resolution = wfd_sink->ini.video_hh_support; - - __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution, &CEA_resolution, &VESA_resolution, &HH_resolution); - - wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution); - - video_param = gst_structure_new("video_param", - "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec, - "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution, - "video_cea_support", G_TYPE_UINT, CEA_resolution, - "video_vesa_support", G_TYPE_UINT, VESA_resolution, - "video_hh_support", G_TYPE_UINT, HH_resolution, - "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile, - "video_level", G_TYPE_UINT, wfd_sink->ini.video_level, - "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency, - "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution, - "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution, - "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing, - "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param, - "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support, - NULL); - - mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version); - mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port); - wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port); - - hdcp_param = gst_structure_new("hdcp_param", - "hdcp_version", G_TYPE_INT, hdcp_version, - "hdcp_port_no", G_TYPE_INT, hdcp_port, - NULL); - - g_object_set(G_OBJECT(wfdsrc), "audio-param", audio_param, NULL); - g_object_set(G_OBJECT(wfdsrc), "video-param", video_param, NULL); - g_object_set(G_OBJECT(wfdsrc), "hdcp-param", hdcp_param, NULL); - - g_signal_connect(wfdsrc, "update-media-info", G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink); - - g_signal_connect(wfdsrc, "change-av-format", G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux) -{ - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED); - - g_signal_connect(demux, "pad-added", G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data) -{ - wfd_sink_debug_fenter(); - - return_if_fail(element); - - wfd_sink_warning("%s is overrun", - GST_STR_NULL(GST_ELEMENT_NAME(element))); - - wfd_sink_debug_fleave(); - - return; -} - -static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue) -{ - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(wfd_sink); - wfd_sink_return_if_fail(queue); - - /* set maximum buffer size of queue as 3sec */ - g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL); - g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL); - g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL); - g_signal_connect(queue, "overrun", G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink); - - wfd_sink_debug_fleave(); - - return; -} - - -static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *mainbin = NULL; - GList *element_bucket = NULL; - GstBus *bus = NULL; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); - - /* Create pipeline */ - wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo)); - if (wfd_sink->pipeline == NULL) - goto CREATE_ERROR; - - memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo)); - - /* create mainbin */ - mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM); - if (mainbin == NULL) - goto CREATE_ERROR; - - memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM); - - /* create pipeline */ - mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE; - mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink"); - if (!mainbin[WFD_SINK_M_PIPE].gst) { - wfd_sink_error("failed to create pipeline"); - goto CREATE_ERROR; - } - - /* create wfdsrc */ - MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src"); - if (mainbin[WFD_SINK_M_SRC].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) { - wfd_sink_error("failed to prepare wfdsrc..."); - goto CREATE_ERROR; - } - } - - /* create rtpmp2tdepay */ - MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink"); - - MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src"); - - /* create tsdemuxer*/ - MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink"); - if (mainbin[WFD_SINK_M_DEMUX].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) { - wfd_sink_error("failed to prepare demux..."); - goto CREATE_ERROR; - } - } - - /* adding created elements to pipeline */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements"); - goto CREATE_ERROR; - } - - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements"); - goto CREATE_ERROR; - } - - /* connect bus callback */ - bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst)); - if (!bus) { - wfd_sink_error("cannot get bus from pipeline."); - goto CREATE_ERROR; - } - - /* add bus message callback*/ - gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink); - - /* set sync handler to get tag synchronously */ - gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL); - - g_list_free(element_bucket); - gst_object_unref(GST_OBJECT(bus)); - - /* now we have completed mainbin. take it */ - wfd_sink->pipeline->mainbin = mainbin; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS */ -CREATE_ERROR: - wfd_sink_error("ERROR : releasing pipeline"); - - if (element_bucket) - g_list_free(element_bucket); - element_bucket = NULL; - - /* finished */ - if (bus) - gst_object_unref(GST_OBJECT(bus)); - bus = NULL; - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_M_NUM; i++) { /* NOTE : skip pipeline */ - if (mainbin != NULL && mainbin[i].gst) { - GstObject *parent = NULL; - parent = gst_element_get_parent(mainbin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(mainbin[i].gst)); - mainbin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release mainbin with it's childs */ - if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) - gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); - - MMWFDSINK_FREEIF(mainbin); - - MMWFDSINK_FREEIF(wfd_sink->pipeline); - - return MM_ERROR_WFD_INTERNAL; -} - -int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *a_decodebin = NULL; - MMWFDSinkGstElement *first_element = NULL; - MMWFDSinkGstElement *last_element = NULL; - GList *element_bucket = NULL; - GstPad *sinkpad = NULL; - GstPad *srcpad = NULL; - GstPad *ghostpad = NULL; - GList *first_list = NULL; - GList *last_list = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->a_decodebin && - wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->audio_decodebin_is_linked) { - wfd_sink_debug("audio decodebin is already linked... nothing to do"); - return MM_ERROR_NONE; - } - - /* take audio decodebin */ - a_decodebin = wfd_sink->pipeline->a_decodebin; - - /* check audio queue */ - if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]); - - /* check audio hdcp */ - if (a_decodebin[WFD_SINK_A_D_HDCP].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]); - - /* check audio codec */ - switch (wfd_sink->stream_info.audio_stream_info.codec) { - case MM_WFD_SINK_AUDIO_CODEC_LPCM: - if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]); - if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) { - GstCaps *caps = NULL; - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]); - caps = gst_caps_new_simple("audio/x-raw", - "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate, - "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels, - "format", G_TYPE_STRING, "S16BE", NULL); - - g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL); - gst_object_unref(GST_OBJECT(caps)); - } - break; - - case MM_WFD_SINK_AUDIO_CODEC_AAC: - if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]); - if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]); - break; - - case MM_WFD_SINK_AUDIO_CODEC_AC3: - if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]); - if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst) - element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]); - break; - - default: - wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin..."); - return MM_ERROR_WFD_INTERNAL; - break; - } - - if (element_bucket == NULL) { - wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it"); - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to destroy audio decodebin"); - goto fail_to_link; - } - goto done; - } - - /* adding elements to audio decodebin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements to audio decodebin"); - goto fail_to_link; - } - - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements of the audio decodebin"); - goto fail_to_link; - } - - /* get first element's sinkpad for creating ghostpad */ - first_list = g_list_first(element_bucket); - if (first_list == NULL) { - wfd_sink_error("failed to get first list of the element_bucket"); - goto fail_to_link; - } - - first_element = (MMWFDSinkGstElement *)first_list->data; - if (!first_element) { - wfd_sink_error("failed to get first element of the audio decodebin"); - goto fail_to_link; - } - - sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!sinkpad) { - wfd_sink_error("failed to get sink pad from element(%s)", - GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); - goto fail_to_link; - } - - ghostpad = gst_ghost_pad_new("sink", sinkpad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of audio decodebin"); - goto fail_to_link; - } - - if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to audio decodebin"); - goto fail_to_link; - } - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - - /* get last element's src for creating ghostpad */ - last_list = g_list_last(element_bucket); - if (last_list == NULL) { - wfd_sink_error("failed to get last list of the element_bucket"); - goto fail_to_link; - } - - last_element = (MMWFDSinkGstElement *)last_list->data; - if (!last_element) { - wfd_sink_error("failed to get last element of the audio decodebin"); - goto fail_to_link; - } - - srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); - if (!srcpad) { - wfd_sink_error("failed to get src pad from element(%s)", - GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); - goto fail_to_link; - } - - ghostpad = gst_ghost_pad_new("src", srcpad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of audio decodebin"); - goto fail_to_link; - } - - if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to audio decodebin"); - goto fail_to_link; - } - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - - g_list_free(element_bucket); - -done: - wfd_sink->audio_decodebin_is_linked = TRUE; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS*/ -fail_to_link: - if (srcpad) - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - - if (sinkpad) - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - g_list_free(element_bucket); - - return MM_ERROR_WFD_INTERNAL; -} - -static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink) -{ - wfd_sink_debug_fenter(); - - /* check audiosink is created */ - wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE, NULL); - g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL); - g_object_set(G_OBJECT(audio_sink), "slave-method", 2, NULL); - g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL); - g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *a_decodebin = NULL; - GstObject *parent = NULL; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->pipeline && - wfd_sink->pipeline->a_decodebin && - wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { - a_decodebin = wfd_sink->pipeline->a_decodebin; - } else { - wfd_sink_debug("audio decodebin is not created, nothing to destroy"); - return MM_ERROR_NONE; - } - - parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst); - if (!parent) { - wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); - - if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of audio decodebin to NULL"); - ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of audio decodebin to NULL"); - return MM_ERROR_WFD_INTERNAL; - } - } - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ - if (a_decodebin[i].gst) { - parent = gst_element_get_parent(a_decodebin[i].gst); - if (!parent) { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), - ((GObject *) a_decodebin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); - a_decodebin[i].gst = NULL; - } else { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), - ((GObject *) a_decodebin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release audio decodebin with it's childs */ - if (a_decodebin[WFD_SINK_A_D_BIN].gst) - gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); - - } else { - wfd_sink_debug("audio decodebin has parent(%s), unref it ", - GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); - - gst_object_unref(GST_OBJECT(parent)); - } - - wfd_sink->audio_decodebin_is_linked = FALSE; - - MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *a_decodebin = NULL; - gint audio_codec = WFD_AUDIO_UNKNOWN; - GList *element_bucket = NULL; - gboolean link = TRUE; - gint i = 0; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* check audio decodebin could be linked now */ - switch (wfd_sink->stream_info.audio_stream_info.codec) { - case MM_WFD_SINK_AUDIO_CODEC_AAC: - audio_codec = WFD_AUDIO_AAC; - link = TRUE; - break; - case MM_WFD_SINK_AUDIO_CODEC_AC3: - audio_codec = WFD_AUDIO_AC3; - link = TRUE; - break; - case MM_WFD_SINK_AUDIO_CODEC_LPCM: - audio_codec = WFD_AUDIO_LPCM; - link = TRUE; - break; - case MM_WFD_SINK_AUDIO_CODEC_NONE: - default: - wfd_sink_debug("audio decodebin could NOT be linked now, just create"); - audio_codec = wfd_sink->ini.audio_codec; - link = FALSE; - break; - } - - /* alloc handles */ - a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); - if (!a_decodebin) { - wfd_sink_error("failed to allocate memory for audio decodebin"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); - - /* create audio decodebin */ - a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN; - a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin"); - if (!a_decodebin[WFD_SINK_A_D_BIN].gst) { - wfd_sink_error("failed to create audio decodebin"); - goto CREATE_ERROR; - } - - /* create queue */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink"); - if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) - __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst); - - /* create hdcp */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink"); - - /* create codec */ - audio_codec = wfd_sink->ini.audio_codec; - if (audio_codec & WFD_AUDIO_LPCM) { - /* create LPCM converter */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src"); - - /* create LPCM filter */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src"); - } - - if (audio_codec & WFD_AUDIO_AAC) { - /* create AAC parse */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src"); - - /* create AAC decoder */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src"); - } - - if (audio_codec & WFD_AUDIO_AC3) { - /* create AC3 parser */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src"); - - /* create AC3 decoder */ - MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src"); - } - - g_list_free(element_bucket); - - /* take it */ - wfd_sink->pipeline->a_decodebin = a_decodebin; - - /* link audio decodebin if audio codec is fixed */ - if (link) { - if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to link audio decodebin, destroy audio decodebin"); - __mm_wfd_sink_destroy_audio_decodebin(wfd_sink); - return MM_ERROR_WFD_INTERNAL; - } - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - -CREATE_ERROR: - wfd_sink_error("failed to create audio decodebin, release all"); - - g_list_free(element_bucket); - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ - if (a_decodebin != NULL && a_decodebin[i].gst) { - GstObject *parent = NULL; - parent = gst_element_get_parent(a_decodebin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); - a_decodebin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release audioo decodebin with it's childs */ - if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) - gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); - - MMWFDSINK_FREEIF(a_decodebin); - - return MM_ERROR_WFD_INTERNAL; -} - -static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *a_sinkbin = NULL; - GstObject *parent = NULL; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->pipeline && - wfd_sink->pipeline->a_sinkbin && - wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { - a_sinkbin = wfd_sink->pipeline->a_sinkbin; - } else { - wfd_sink_debug("audio sinkbin is not created, nothing to destroy"); - return MM_ERROR_NONE; - } - - parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst); - if (!parent) { - wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); - - if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of audio decodebin to NULL"); - ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of audio decodebin to NULL"); - return MM_ERROR_WFD_INTERNAL; - } - } - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ - if (a_sinkbin[i].gst) { - parent = gst_element_get_parent(a_sinkbin[i].gst); - if (!parent) { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), - ((GObject *) a_sinkbin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); - a_sinkbin[i].gst = NULL; - } else { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), - ((GObject *) a_sinkbin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release audio decodebin with it's childs */ - if (a_sinkbin[WFD_SINK_A_S_BIN].gst) - gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); - - } else { - wfd_sink_debug("audio sinkbin has parent(%s), unref it ", - GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); - - gst_object_unref(GST_OBJECT(parent)); - } - - MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *a_sinkbin = NULL; - MMWFDSinkGstElement *first_element = NULL; - GList *element_bucket = NULL; - GstPad *ghostpad = NULL; - GstPad *pad = NULL; - gint i = 0; - GList *first_list = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* alloc handles */ - a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); - if (!a_sinkbin) { - wfd_sink_error("failed to allocate memory for audio sinkbin"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); - - /* create audio sinkbin */ - a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN; - a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin"); - if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) { - wfd_sink_error("failed to create audio sinkbin"); - goto CREATE_ERROR; - } - - /* create resampler */ - MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src"); - - /* create volume */ - MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src"); - - /* create sink */ - MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink"); - if (a_sinkbin[WFD_SINK_A_S_SINK].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) { - wfd_sink_error("failed to set audio sink property...."); - goto CREATE_ERROR; - } - } - - /* adding created elements to audio sinkbin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements to audio sinkbin"); - goto CREATE_ERROR; - } - - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements fo the audio sinkbin"); - goto CREATE_ERROR; - } - - /* get first element's of the audio sinkbin */ - first_list = g_list_first(element_bucket); - if (first_list == NULL) { - wfd_sink_error("failed to get first list of the element_bucket"); - goto CREATE_ERROR; - } - - first_element = (MMWFDSinkGstElement *)first_list->data; - if (!first_element) { - wfd_sink_error("failed to get first element of the audio sinkbin"); - goto CREATE_ERROR; - } - - /* get first element's sinkpad for creating ghostpad */ - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!pad) { - wfd_sink_error("failed to get sink pad from element(%s)", - GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); - goto CREATE_ERROR; - } - - ghostpad = gst_ghost_pad_new("sink", pad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of audio sinkbin"); - goto CREATE_ERROR; - } - - if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to audio sinkbin"); - goto CREATE_ERROR; - } - gst_object_unref(GST_OBJECT(pad)); - - g_list_free(element_bucket); - - /* take it */ - wfd_sink->pipeline->a_sinkbin = a_sinkbin; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - -CREATE_ERROR: - wfd_sink_error("failed to create audio sinkbin, releasing all"); - - if (pad) - gst_object_unref(GST_OBJECT(pad)); - pad = NULL; - - if (ghostpad) - gst_object_unref(GST_OBJECT(ghostpad)); - ghostpad = NULL; - - if (element_bucket) - g_list_free(element_bucket); - element_bucket = NULL; - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ - if (a_sinkbin != NULL && a_sinkbin[i].gst) { - GstObject *parent = NULL; - parent = gst_element_get_parent(a_sinkbin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); - a_sinkbin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release audio sinkbin with it's childs */ - if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) - gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); - - MMWFDSINK_FREEIF(a_sinkbin); - - return MM_ERROR_WFD_INTERNAL; -} - -int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *v_decodebin = NULL; - MMWFDSinkGstElement *first_element = NULL; - MMWFDSinkGstElement *last_element = NULL; - GList *element_bucket = NULL; - GstPad *sinkpad = NULL; - GstPad *srcpad = NULL; - GstPad *ghostpad = NULL; - GList *first_list = NULL; - GList *last_list = NULL; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->v_decodebin && - wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst, - MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->video_decodebin_is_linked) { - wfd_sink_debug("video decodebin is already linked... nothing to do"); - return MM_ERROR_NONE; - } - - /* take video decodebin */ - v_decodebin = wfd_sink->pipeline->v_decodebin; - - /* check video queue */ - if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) - element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]); - - /* check video hdcp */ - if (v_decodebin[WFD_SINK_V_D_HDCP].gst) - element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]); - - /* check video codec */ - switch (wfd_sink->stream_info.video_stream_info.codec) { - case MM_WFD_SINK_VIDEO_CODEC_H264: - if (v_decodebin[WFD_SINK_V_D_PARSE].gst) - element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]); - if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) { - GstCaps *caps = NULL; - - element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]); - caps = gst_caps_new_simple("video/x-h264", - "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width, - "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height, - "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL); - g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL); - gst_object_unref(GST_OBJECT(caps)); - } - if (v_decodebin[WFD_SINK_V_D_DEC].gst) - element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]); - break; - - default: - wfd_sink_error("video codec is not decied yet. cannot link video decpdebin..."); - return MM_ERROR_WFD_INTERNAL; - break; - } - - if (element_bucket == NULL) { - wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it"); - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to destroy video decodebin"); - goto fail_to_link; - } - goto done; - } - - /* adding elements to video decodebin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements to video decodebin"); - goto fail_to_link; - } - - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements of the video decodebin"); - goto fail_to_link; - } - - /* get first element's sinkpad for creating ghostpad */ - first_list = g_list_first(element_bucket); - if (first_list == NULL) { - wfd_sink_error("failed to get first list of the element_bucket"); - goto fail_to_link; - } - - first_element = (MMWFDSinkGstElement *)first_list->data; - if (!first_element) { - wfd_sink_error("failed to get first element of the video decodebin"); - goto fail_to_link; - } - - sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!sinkpad) { - wfd_sink_error("failed to get sink pad from element(%s)", - GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); - goto fail_to_link; - } - - ghostpad = gst_ghost_pad_new("sink", sinkpad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of video decodebin"); - goto fail_to_link; - } - - if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to video decodebin"); - goto fail_to_link; - } - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - - /* get last element's src for creating ghostpad */ - last_list = g_list_last(element_bucket); - if (last_list == NULL) { - wfd_sink_error("failed to get last list of the element_bucket"); - goto fail_to_link; - } - - last_element = (MMWFDSinkGstElement *)last_list->data; - if (!last_element) { - wfd_sink_error("failed to get last element of the video decodebin"); - goto fail_to_link; - } - - srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); - if (!srcpad) { - wfd_sink_error("failed to get src pad from element(%s)", - GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); - goto fail_to_link; - } - - ghostpad = gst_ghost_pad_new("src", srcpad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of video decodebin"); - goto fail_to_link; - } - - if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to video decodebin"); - goto fail_to_link; - } - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - - g_list_free(element_bucket); - -done: - wfd_sink->video_decodebin_is_linked = TRUE; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS*/ -fail_to_link: - if (srcpad != NULL) - gst_object_unref(GST_OBJECT(srcpad)); - srcpad = NULL; - - if (sinkpad != NULL) - gst_object_unref(GST_OBJECT(sinkpad)); - sinkpad = NULL; - - g_list_free(element_bucket); - - return MM_ERROR_WFD_INTERNAL; -} - -static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec) -{ - wfd_sink_debug_fenter(); - - /* check video decoder is created */ - wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink) -{ - gboolean visible = TRUE; - gint surface_type = MM_DISPLAY_SURFACE_OVERLAY; - - wfd_sink_debug_fenter(); - - /* check videosink is created */ - wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT); - wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); - - /* update display surface */ - mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); - wfd_sink_debug("check display surface type attribute: %d", surface_type); - mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible); - wfd_sink_debug("check display visible attribute: %d", visible); - - /* configuring display */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_EVAS: { - void *object = NULL; - gint scaling = 0; - - /* common case if using evas surface */ - mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object); - mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling); - if (object) { - wfd_sink_debug("set video param : evas-object %x", object); - g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL); - } else { - wfd_sink_error("no evas object"); - return MM_ERROR_WFD_INTERNAL; - } - } - break; - - case MM_DISPLAY_SURFACE_OVERLAY: { - int wl_window_x = 0; - int wl_window_y = 0; - int wl_window_width = 0; - int wl_window_height = 0; - unsigned int wl_surface_id = 0; - struct wl_surface *wl_surface = NULL; - struct wl_display *wl_display = NULL; - Ecore_Wl_Window *wl_window = NULL; - wl_client *wlclient = NULL; - Evas_Object *obj = NULL; - void *object = NULL; - const char *object_type = NULL; - int ret = 0; - - mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object); - - if (object != NULL) { - obj = (Evas_Object *)object; - object_type = evas_object_type_get(obj); - wfd_sink_debug("window object type : %s", object_type); - - /* wayland overlay surface */ - LOGI("Wayland overlay surface type"); - evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height); - - wfd_sink_debug ("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y, - wl_window_width, wl_window_height); - - wl_window = elm_win_wl_window_get(obj); - wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window); - - /* get wl_display */ - wl_display = (struct wl_display *) ecore_wl_display_get(); - - ret = mm_wfd_sink_wlclient_create(&wlclient); - if ( ret != MM_ERROR_NONE) { - wfd_sink_error("Wayland client create failure"); - return ret; - } - - if (wl_surface && wl_display){ - wfd_sink_debug ("surface = %p, wl_display = %p", wl_surface, wl_display); - wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wlclient, wl_surface, wl_display); - wfd_sink_debug ("wl_surface_id = %d", wl_surface_id); - } - if (wlclient) { - g_free(wlclient); - wlclient = NULL; - } - - wfd_sink_debug("set video param : surface_id %d", wl_surface_id); - gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), - wl_surface_id); - /* After setting window handle, set render rectangle */ - gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink), - wl_window_x, wl_window_y, wl_window_width, wl_window_height); - } else { - wfd_sink_debug ("display object is NULL!"); - return MM_ERROR_WFD_INTERNAL; - } - } - break; - - case MM_DISPLAY_SURFACE_NULL: { - /* do nothing */ - wfd_sink_error("Not Supported Surface."); - return MM_ERROR_WFD_INTERNAL; - } - break; - default: { - wfd_sink_error("Not Supported Surface.(default case)"); - return MM_ERROR_WFD_INTERNAL; - } - break; - } - - g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL); - g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL); - g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL); - g_object_set(G_OBJECT(video_sink), "visible", visible, NULL); - g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *v_decodebin = NULL; - GstObject *parent = NULL; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->pipeline && - wfd_sink->pipeline->v_decodebin && - wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { - v_decodebin = wfd_sink->pipeline->v_decodebin; - } else { - wfd_sink_debug("video decodebin is not created, nothing to destroy"); - return MM_ERROR_NONE; - } - - - parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst); - if (!parent) { - wfd_sink_debug("video decodebin has no parent.. need to relase by itself"); - - if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of video decodebin to NULL"); - ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of video decodebin to NULL"); - return MM_ERROR_WFD_INTERNAL; - } - } - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ - if (v_decodebin[i].gst) { - parent = gst_element_get_parent(v_decodebin[i].gst); - if (!parent) { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), - ((GObject *) v_decodebin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); - v_decodebin[i].gst = NULL; - } else { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), - ((GObject *) v_decodebin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(parent)); - } - } - } - /* release video decodebin with it's childs */ - if (v_decodebin[WFD_SINK_V_D_BIN].gst) { - gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)), - ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count); - } - } else { - wfd_sink_debug("video decodebin has parent(%s), unref it", - GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); - - gst_object_unref(GST_OBJECT(parent)); - } - - wfd_sink->video_decodebin_is_linked = FALSE; - - MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *v_decodebin = NULL; - guint video_codec = WFD_VIDEO_UNKNOWN; - GList *element_bucket = NULL; - gboolean link = TRUE; - gint i = 0; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, - MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->pipeline->v_decodebin) { - wfd_sink_debug("video decodebin is already created... nothing to do"); - return MM_ERROR_NONE; - } - - /* check audio decodebin could be linked now */ - switch (wfd_sink->stream_info.video_stream_info.codec) { - case MM_WFD_SINK_VIDEO_CODEC_H264: - video_codec = WFD_VIDEO_H264; - link = TRUE; - break; - case MM_WFD_SINK_VIDEO_CODEC_NONE: - default: - wfd_sink_debug("video decodebin could NOT be linked now, just create"); - video_codec = wfd_sink->ini.video_codec; - link = FALSE; - break; - } - - /* alloc handles */ - v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); - if (!v_decodebin) { - wfd_sink_error("failed to allocate memory for video decodebin"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); - - /* create video decodebin */ - v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN; - v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin"); - if (!v_decodebin[WFD_SINK_V_D_BIN].gst) { - wfd_sink_error("failed to create video decodebin"); - goto CREATE_ERROR; - } - - /* create queue */ - MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink"); - if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) - __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst); - - /* create hdcp */ - MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src"); - - if (video_codec & WFD_VIDEO_H264) { - /* create parser */ - MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "src"); - - /* create capssetter */ - MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "src"); - - /* create dec */ - MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "src"); - if (v_decodebin[WFD_SINK_V_D_DEC].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) { - wfd_sink_error("failed to set video decoder property..."); - goto CREATE_ERROR; - } - } - } - - g_list_free(element_bucket); - - /* take it */ - wfd_sink->pipeline->v_decodebin = v_decodebin; - - /* link video decodebin if video codec is fixed */ - if (link) { - if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to link video decodebin, destroy video decodebin"); - __mm_wfd_sink_destroy_video_decodebin(wfd_sink); - return MM_ERROR_WFD_INTERNAL; - } - } - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS */ -CREATE_ERROR: - wfd_sink_error("failed to create video decodebin, releasing all"); - - g_list_free(element_bucket); - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ - if (v_decodebin != NULL && v_decodebin[i].gst) { - GstObject *parent = NULL; - parent = gst_element_get_parent(v_decodebin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); - v_decodebin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release video decodebin with it's childs */ - if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) - gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); - - MMWFDSINK_FREEIF(v_decodebin); - - return MM_ERROR_WFD_INTERNAL; -} - -static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - MMWFDSinkGstElement *v_sinkbin = NULL; - GstObject *parent = NULL; - int i; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - if (wfd_sink->pipeline && - wfd_sink->pipeline->v_sinkbin && - wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { - v_sinkbin = wfd_sink->pipeline->v_sinkbin; - } else { - wfd_sink_debug("video sinkbin is not created, nothing to destroy"); - return MM_ERROR_NONE; - } - - - parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst); - if (!parent) { - wfd_sink_debug("video sinkbin has no parent.. need to relase by itself"); - - if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) { - wfd_sink_debug("try to change state of video sinkbin to NULL"); - ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of video sinkbin to NULL"); - return MM_ERROR_WFD_INTERNAL; - } - } - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ - if (v_sinkbin[i].gst) { - parent = gst_element_get_parent(v_sinkbin[i].gst); - if (!parent) { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), - ((GObject *) v_sinkbin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); - v_sinkbin[i].gst = NULL; - } else { - wfd_sink_debug("unref %s(current ref %d)", - GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), - ((GObject *) v_sinkbin[i].gst)->ref_count); - gst_object_unref(GST_OBJECT(parent)); - } - } - } - /* release video sinkbin with it's childs */ - if (v_sinkbin[WFD_SINK_V_S_BIN].gst) { - gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); - } - } else { - wfd_sink_debug("video sinkbin has parent(%s), unref it ", - GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); - - gst_object_unref(GST_OBJECT(parent)); - } - - MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin); - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink) -{ - MMWFDSinkGstElement *first_element = NULL; - MMWFDSinkGstElement *v_sinkbin = NULL; - GList *element_bucket = NULL; - GstPad *pad = NULL; - GstPad *ghostpad = NULL; - gint i = 0; - gint surface_type = MM_DISPLAY_SURFACE_OVERLAY; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink && - wfd_sink->pipeline, - MM_ERROR_WFD_NOT_INITIALIZED); - - /* alloc handles */ - v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); - if (!v_sinkbin) { - wfd_sink_error("failed to allocate memory for video sinkbin"); - return MM_ERROR_WFD_NO_FREE_SPACE; - } - - memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); - - /* create video sinkbin */ - v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN; - v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin"); - if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) { - wfd_sink_error("failed to create video sinkbin"); - goto CREATE_ERROR; - } - - /* create convert */ - MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src"); - - /* create filter */ - MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink"); - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src"); - if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) { - GstCaps *caps = NULL; - caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL); - g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL); - gst_object_unref(GST_OBJECT(caps)); - } - - /* create sink */ - mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); - - if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) { - MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE); - } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) { - MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE); - } else { - wfd_sink_error("failed to set video sink...."); - goto CREATE_ERROR; - } - - MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink"); - if (v_sinkbin[WFD_SINK_V_S_SINK].gst) { - if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) { - wfd_sink_error("failed to set video sink property...."); - goto CREATE_ERROR; - } - } - - /* adding created elements to video sinkbin */ - if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) { - wfd_sink_error("failed to add elements to video sinkbin"); - goto CREATE_ERROR; - } - - /* linking elements in the bucket by added order. */ - if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { - wfd_sink_error("failed to link elements of the video sinkbin"); - goto CREATE_ERROR; - } - - /* get first element's sinkpad for creating ghostpad */ - first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0); - if (!first_element) { - wfd_sink_error("failed to get first element of the video sinkbin"); - goto CREATE_ERROR; - } - - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if (!pad) { - wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin", - GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); - goto CREATE_ERROR; - } - - ghostpad = gst_ghost_pad_new("sink", pad); - if (!ghostpad) { - wfd_sink_error("failed to create ghostpad of the video sinkbin"); - goto CREATE_ERROR; - } - - if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) { - wfd_sink_error("failed to add ghostpad to video sinkbin"); - goto CREATE_ERROR; - } - - gst_object_unref(GST_OBJECT(pad)); - - g_list_free(element_bucket); - - - /* take it */ - wfd_sink->pipeline->v_sinkbin = v_sinkbin; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; - - /* ERRORS */ -CREATE_ERROR: - wfd_sink_error("failed to create video sinkbin, releasing all"); - - if (pad) - gst_object_unref(GST_OBJECT(pad)); - pad = NULL; - - if (ghostpad) - gst_object_unref(GST_OBJECT(ghostpad)); - ghostpad = NULL; - - g_list_free(element_bucket); - - /* release element which are not added to bin */ - for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ - if (v_sinkbin != NULL && v_sinkbin[i].gst) { - GstObject *parent = NULL; - parent = gst_element_get_parent(v_sinkbin[i].gst); - - if (!parent) { - gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); - v_sinkbin[i].gst = NULL; - } else { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release video sinkbin with it's childs */ - if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) - gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); - - MMWFDSINK_FREEIF(v_sinkbin); - - return MM_ERROR_WFD_INTERNAL; -} - -static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - /* cleanup gst stuffs */ - if (wfd_sink->pipeline) { - MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin; - - if (mainbin) { - ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) { - wfd_sink_error("failed to change state of mainbin to NULL"); - return MM_ERROR_WFD_INTERNAL; - } - - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { - wfd_sink_error("failed to destroy video decodebin"); - return MM_ERROR_WFD_INTERNAL; - } - - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { - wfd_sink_error("failed to destroy audio decodebin"); - return MM_ERROR_WFD_INTERNAL; - } - - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) { - wfd_sink_error("failed to destroy video sinkbin"); - return MM_ERROR_WFD_INTERNAL; - } - - if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) { - wfd_sink_error("failed to destroy audio sinkbin"); - return MM_ERROR_WFD_INTERNAL; - } - - gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); - - MMWFDSINK_FREEIF(mainbin); - } - - MMWFDSINK_FREEIF(wfd_sink->pipeline); - } - - wfd_sink->audio_decodebin_is_linked = FALSE; - wfd_sink->video_decodebin_is_linked = FALSE; - wfd_sink->need_to_reset_basetime = FALSE; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} - -static void -__mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink) -{ - GstIterator *iter = NULL; - gboolean done = FALSE; - - GstElement *item = NULL; - GstElementFactory *factory = NULL; - - GstState state = GST_STATE_VOID_PENDING; - GstState pending = GST_STATE_VOID_PENDING; - GstClockTime time = 200 * GST_MSECOND; - - wfd_sink_debug_fenter(); - - wfd_sink_return_if_fail(wfd_sink && - wfd_sink->pipeline && - wfd_sink->pipeline->mainbin && - wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); - - iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)); - - if (iter != NULL) { - while (!done) { - switch (gst_iterator_next(iter, (gpointer)&item)) { - case GST_ITERATOR_OK: - gst_element_get_state(GST_ELEMENT(item), &state, &pending, time); - - factory = gst_element_get_factory(item) ; - if (factory) { - wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", - GST_STR_NULL(GST_OBJECT_NAME(factory)), - GST_STR_NULL(GST_ELEMENT_NAME(item)), - gst_element_state_get_name(state), - gst_element_state_get_name(pending), - GST_OBJECT_REFCOUNT_VALUE(item)); - } - gst_object_unref(item); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync(iter); - break; - case GST_ITERATOR_ERROR: - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - default: - done = TRUE; - break; - } - } - } - - item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); - - gst_element_get_state(GST_ELEMENT(item), &state, &pending, time); - - factory = gst_element_get_factory(item) ; - if (factory) { - wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", - GST_OBJECT_NAME(factory), - GST_ELEMENT_NAME(item), - gst_element_state_get_name(state), - gst_element_state_get_name(pending), - GST_OBJECT_REFCOUNT_VALUE(item)); - } - - if (iter) - gst_iterator_free(iter); - - wfd_sink_debug_fleave(); - - return; -} - -const gchar * _mm_wfds_sink_get_state_name(MMWFDSinkStateType state) -{ - switch (state) { - case MM_WFD_SINK_STATE_NONE: - return "NONE"; - case MM_WFD_SINK_STATE_NULL: - return "NULL"; - case MM_WFD_SINK_STATE_PREPARED: - return "PREPARED"; - case MM_WFD_SINK_STATE_CONNECTED: - return "CONNECTED"; - case MM_WFD_SINK_STATE_PLAYING: - return "PLAYING"; - case MM_WFD_SINK_STATE_PAUSED: - return "PAUSED"; - case MM_WFD_SINK_STATE_DISCONNECTED: - return "DISCONNECTED"; - default: - return "INVAID"; - } -} - -static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution) -{ - if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return; - - *CEA_resolution = 0; - *VESA_resolution = 0; - *HH_resolution = 0; - - if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30) - *CEA_resolution |= WFD_CEA_1920x1080P30; - - if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30) - *CEA_resolution |= WFD_CEA_1280x720P30; - - if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30) - *HH_resolution |= WFD_HH_960x540P30; - - if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30) - *HH_resolution |= WFD_HH_864x480P30; - - if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60) - *CEA_resolution |= WFD_CEA_720x480P60; - - if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60) - *CEA_resolution |= WFD_CEA_640x480P60; - - if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30) - *HH_resolution |= WFD_HH_640x360P30; -} - -int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution) -{ - MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; - - wfd_sink_debug_fenter(); - - wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); - - MMWFDSINK_PRINT_STATE(wfd_sink); - cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink); - if (cur_state != MM_WFD_SINK_STATE_NULL) { - wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL"); - return MM_ERROR_WFD_INVALID_STATE; - } - - wfd_sink->supportive_resolution = resolution; - - wfd_sink_debug_fleave(); - - return MM_ERROR_NONE; -} diff --git a/sink/mm_wfd_sink_util.c b/sink/mm_wfd_sink_util.c deleted file mode 100755 index 405a818..0000000 --- a/sink/mm_wfd_sink_util.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * libmm-wfd - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang , - * Maksym Ukhanov , Hyunjun Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "mm_wfd_sink_util.h" -#include -#include - -#define DUMP_TS_DATA_PATH tzplatform_mkpath(TZ_SYS_VAR, "tmp/") - -static GstPadProbeReturn -_mm_wfd_sink_util_dump(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - gint8 *data = NULL; - gint size = 0; - FILE *f = NULL; - char buf[256] = {0, }; - char path[256] = {0, }; - GstElement * parent = NULL; - - parent = gst_pad_get_parent_element(pad); - if (parent == NULL) { - wfd_sink_error("The parent of pad is NULL."); - return GST_PAD_PROBE_OK; - } - - snprintf(path, sizeof(path), "%s%s_%s.ts", DUMP_TS_DATA_PATH, gst_element_get_name(parent), gst_pad_get_name(pad)); - gst_object_unref(parent); - - if (info && info->type & GST_PAD_PROBE_TYPE_BUFFER) { - GstMapInfo buf_info; - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - - gst_buffer_map(buffer, &buf_info, GST_MAP_READ); - - wfd_sink_debug("got buffer %p with size %d", buffer, buf_info.size); - data = (gint8 *)(buf_info.data); - size = buf_info.size; - f = fopen(path, "a"); - if (f == NULL) { - strerror_r(errno, buf, sizeof(buf)); - wfd_sink_error("failed to fopen! : %s", buf); - return GST_PAD_PROBE_OK; - } - fwrite(data, size, 1, f); - fclose(f); - gst_buffer_unmap(buffer, &buf_info); - } - - return GST_PAD_PROBE_OK; -} - -static GstPadProbeReturn -_mm_wfd_sink_util_pad_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - GstElement *parent = NULL; - - wfd_sink_return_val_if_fail(info && - info->type != GST_PAD_PROBE_TYPE_INVALID, - GST_PAD_PROBE_DROP); - wfd_sink_return_val_if_fail(pad, GST_PAD_PROBE_DROP); - - parent = (GstElement *)gst_object_get_parent(GST_OBJECT(pad)); - if (!parent) { - wfd_sink_error("failed to get parent of pad"); - return GST_PAD_PROBE_DROP; - } - - if (info->type & GST_PAD_PROBE_TYPE_BUFFER) { - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - /* show name and timestamp */ - wfd_sink_debug("BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%"G_GSSIZE_FORMAT" bytes)\n", - GST_STR_NULL(GST_ELEMENT_NAME(parent)), - GST_STR_NULL(GST_PAD_NAME(pad)), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), - gst_buffer_get_size(buffer)); - } else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM || - info->type & GST_PAD_PROBE_TYPE_EVENT_UPSTREAM || - info->type & GST_PAD_PROBE_TYPE_EVENT_FLUSH || - info->type & GST_PAD_PROBE_TYPE_EVENT_BOTH) { - GstEvent *event = gst_pad_probe_info_get_event(info); - - /* show name and event type */ - wfd_sink_debug("EVENT PROBE : %s:%s : %s\n", - GST_STR_NULL(GST_ELEMENT_NAME(parent)), - GST_STR_NULL(GST_PAD_NAME(pad)), - GST_EVENT_TYPE_NAME(event)); - - if (GST_EVENT_TYPE(event) == GST_EVENT_SEGMENT) { - const GstSegment *segment = NULL; - gst_event_parse_segment(event, &segment); - if (segment) - wfd_sink_debug("NEWSEGMENT : %" GST_TIME_FORMAT - " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT " \n", - GST_TIME_ARGS(segment->start), GST_TIME_ARGS(segment->stop), - GST_TIME_ARGS(segment->time)); - } - } - - if (parent) - gst_object_unref(parent); - - return GST_PAD_PROBE_OK; -} - -void -mm_wfd_sink_util_add_pad_probe(GstPad *pad, GstElement *element, const gchar *pad_name) -{ - GstPad *probe_pad = NULL; - - if (!pad) { - if (element && pad_name) - probe_pad = gst_element_get_static_pad(element, pad_name); - } else { - probe_pad = pad; - gst_object_ref(probe_pad); - } - - if (probe_pad) { - wfd_sink_debug("add pad(%s) probe", GST_STR_NULL(GST_PAD_NAME(probe_pad))); - gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_DATA_BOTH, _mm_wfd_sink_util_pad_probe_cb, (gpointer)NULL, NULL); - gst_object_unref(probe_pad); - } -} - -void -mm_wfd_sink_util_add_pad_probe_for_data_dump(GstElement *element, const gchar *pad_name) -{ - GstPad *probe_pad = NULL; - - if (element && pad_name) - probe_pad = gst_element_get_static_pad(element, pad_name); - - if (probe_pad) { - wfd_sink_debug("add pad(%s) probe", GST_STR_NULL(GST_PAD_NAME(probe_pad))); - gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_BUFFER, _mm_wfd_sink_util_dump, (gpointer)NULL, NULL); - gst_object_unref(probe_pad); - } -} - -static GstPadProbeReturn -_mm_wfd_sink_util_check_first_buffer_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) -{ - GstElement *parent = NULL; - GstBuffer *buffer = NULL; - guint *probe_id = (guint *)user_data; - - wfd_sink_return_val_if_fail(pad, GST_PAD_PROBE_DROP); - wfd_sink_return_val_if_fail(info, GST_PAD_PROBE_DROP); - - parent = GST_ELEMENT_CAST(gst_object_get_parent(GST_OBJECT(pad))); - if (parent == NULL) { - wfd_sink_error("The parent of pad is NULL."); - return GST_PAD_PROBE_DROP; - } - - buffer = gst_pad_probe_info_get_buffer(info); - - wfd_sink_debug("FIRST BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%"G_GSSIZE_FORMAT" bytes)\n", - GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), gst_buffer_get_size(buffer)); - - if (probe_id && *probe_id > 0) { - wfd_sink_debug("remove buffer probe[%d]\n", *probe_id); - gst_pad_remove_probe(pad, *probe_id); - - MMWFDSINK_FREEIF(probe_id); - } - - if (parent) - gst_object_unref(parent); - - return GST_PAD_PROBE_REMOVE; -} - -void -mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer(GstPad *pad, GstElement *element, const gchar *pad_name) -{ - GstPad *probe_pad = NULL; - guint *probe_id = NULL; - - if (!pad) { - if (element && pad_name) - probe_pad = gst_element_get_static_pad(element, pad_name); - } else { - probe_pad = pad; - gst_object_ref(probe_pad); - } - - if (probe_pad) { - probe_id = g_malloc0(sizeof(guint)); - if (!probe_id) { - wfd_sink_error("failed to allocate memory for probe id\n"); - gst_object_unref(probe_pad); - return; - } - - *probe_id = gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_BUFFER, _mm_wfd_sink_util_check_first_buffer_cb, (gpointer)probe_id, NULL); - wfd_sink_debug("add pad(%s) probe, %d", GST_STR_NULL(GST_PAD_NAME(probe_pad)), *probe_id); - - gst_object_unref(probe_pad); - } - - return; -} - diff --git a/sink/mm_wfd_sink_wayland.c b/sink/mm_wfd_sink_wayland.c deleted file mode 100755 index 787dea8..0000000 --- a/sink/mm_wfd_sink_wayland.c +++ /dev/null @@ -1,148 +0,0 @@ -/* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include - -#include "mm_wfd_sink_dlog.h" -#include "mm_wfd_sink_wayland.h" - -#define goto_if_fail(expr,label) \ -{ \ - if (!(expr)) { \ - wfd_sink_error(" failed [%s]\n", #expr); \ - goto label; \ - } \ -} - -void mm_wfd_sink_handle_resource_id(void *data, struct tizen_resource *tizen_resource, uint32_t id) -{ - unsigned int *wl_surface_id = data; - - *wl_surface_id = id; - - wfd_sink_debug("[CLIENT] got wl_surface_id(%d) from server\n", id); -} - -static const struct tizen_resource_listener tz_resource_listener = -{ - mm_wfd_sink_handle_resource_id, -}; - -static void -mm_wfd_sink_handle_global(void *data, struct wl_registry *registry, - uint32_t name, const char *interface, uint32_t version) -{ - return_if_fail (data != NULL); - wl_client *wlclient = data; - - if (strcmp(interface, "tizen_surface") == 0) - { - wfd_sink_debug("binding tizen_surface"); - wlclient->tz_surface = wl_registry_bind(registry, name, &tizen_surface_interface, version); - return_if_fail (wlclient->tz_surface != NULL); - } -} - -static void mm_wfd_sink_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name) -{ - wfd_sink_debug("wl_registry_handle_global_remove"); -} - -static const struct wl_registry_listener registry_listener = -{ - mm_wfd_sink_handle_global, - mm_wfd_sink_handle_global_remove -}; - -int mm_wfd_sink_wlclient_create (wl_client ** wlclient) -{ - wl_client *ptr = NULL; - - ptr = g_malloc0 (sizeof (wl_client)); - if (!ptr) { - wfd_sink_error ("Cannot allocate memory for wlclient\n"); - goto ERROR; - } else { - *wlclient = ptr; - wfd_sink_debug ("Success create wlclient(%p)", *wlclient); - } - return MM_ERROR_NONE; - -ERROR: - *wlclient = NULL; - return MM_ERROR_WFD_NO_FREE_SPACE; -} - - -int mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wl_client * wlclient, struct wl_surface *surface, struct wl_display *display) -{ - goto_if_fail (wlclient != NULL, failed); - goto_if_fail (surface != NULL, failed); - goto_if_fail (display != NULL, failed); - - unsigned int wl_surface_id = 0; - - wlclient->display = display; - goto_if_fail (wlclient->display != NULL, failed); - - wlclient->registry = wl_display_get_registry(wlclient->display); - goto_if_fail (wlclient->registry != NULL, failed); - - wl_registry_add_listener(wlclient->registry, ®istry_listener, wlclient); - wl_display_dispatch(wlclient->display); - wl_display_roundtrip(wlclient->display); - - /* check global objects */ - goto_if_fail (wlclient->tz_surface != NULL, failed); - - /* Get wl_surface_id which is unique in a entire systemw. */ - wlclient->tz_resource = tizen_surface_get_tizen_resource(wlclient->tz_surface, surface); - goto_if_fail (wlclient->tz_resource != NULL, failed); - - tizen_resource_add_listener(wlclient->tz_resource, &tz_resource_listener, &wl_surface_id); - wl_display_roundtrip(wlclient->display); - goto_if_fail (wl_surface_id > 0, failed); - - mm_wfd_sink_wlclient_finalize(wlclient); - - return wl_surface_id; - -failed: - wfd_sink_error ("Failed to get wl_surface_id"); - - return 0; -} - -void mm_wfd_sink_wlclient_finalize (wl_client * wlclient) -{ - wfd_sink_debug ("start finalize wlclient"); - return_if_fail (wlclient != NULL) - - if (wlclient->tz_surface) - tizen_surface_destroy(wlclient->tz_surface); - - if (wlclient->tz_resource) - tizen_resource_destroy(wlclient->tz_resource); - - /* destroy registry */ - if (wlclient->registry) - wl_registry_destroy(wlclient->registry); - return; -} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100755 index 0000000..5cd4d59 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,48 @@ +lib_LTLIBRARIES = libmmfwfdsink.la + +includelibmmfwfdsinkdir = $(includedir)/mmf + +includelibmmfwfdsink_HEADERS = include/mm_wfd_sink.h \ + include/mm_wfd_sink_ini.h \ + include/mm_wfd_sink_priv.h \ + include/mm_wfd_sink_dlog.h \ + include/mm_wfd_sink_attrs.h \ + include/mm_wfd_sink_util.h + +libmmfwfdsink_la_SOURCES = mm_wfd_sink_attrs.c \ + mm_wfd_sink_ini.c \ + mm_wfd_sink_util.c \ + mm_wfd_sink.c \ + mm_wfd_sink_manager.c \ + mm_wfd_sink_priv.c \ + mm_wfd_sink_wayland.c + + +libmmfwfdsink_la_CFLAGS = -I$(srcdir)/include \ + $(MMCOMMON_CFLAGS) \ + $(GST_CFLAGS) \ + $(EVAS_CFLAGS) \ + $(ELEMENTARY_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_VIDEO_CFLAGS) \ + $(TZPLATFORM_CONFIG_CFLAGS) \ + $(AUDIOSESSIONMGR_CFLAGS) + +libmmfwfdsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = include/mm_wfd_sink_manager.h \ + include/mm_wfd_sink_wayland.h \ + include/mm_wfd_sink_enum.h + +libmmfwfdsink_la_LIBADD = $(GST_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(ELEMENTARY_LIBS) \ + $(EVAS_LIBS) \ + $(MMCOMMON_LIBS) \ + $(AUDIOSESSIONMGR_LIBS) \ + $(TZPLATFORM_CONFIG_LIBS) \ + $(GST_VIDEO_LIBS) + +libmmfwfdsink_la_CFLAGS += $(MMLOG_CFLAGS) -DMMF_LOG_OWNER=0x02000000 -DMMF_DEBUG_PREFIX=\"MMF-WFD-SINK\" +libmmfwfdsink_la_LIBADD += $(MMLOG_LIBS) diff --git a/src/include/mm_wfd_sink.h b/src/include/mm_wfd_sink.h new file mode 100755 index 0000000..620324f --- /dev/null +++ b/src/include/mm_wfd_sink.h @@ -0,0 +1,484 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MM_WFD_SINK_H_ +#define _MM_WFD_SINK_H_ + +#include +#include +#include +#include +#include + +/** + * * Enumerations of wifi-display sink state. + * */ +typedef enum { + MM_WFD_SINK_STATE_NONE, /**< wifi-display is not created */ + MM_WFD_SINK_STATE_NULL, /**< wifi-display is created */ + MM_WFD_SINK_STATE_PREPARED, /**< wifi-display is prepared */ + MM_WFD_SINK_STATE_CONNECTED, /**< wifi-display is connected */ + MM_WFD_SINK_STATE_PLAYING, /**< wifi-display is now playing */ + MM_WFD_SINK_STATE_PAUSED, /**< wifi-display is now paused */ + MM_WFD_SINK_STATE_DISCONNECTED, /**< wifi-display is disconnected */ + MM_WFD_SINK_STATE_NUM, /**< Number of wifi-display states */ +} MMWFDSinkStateType; + +/* audio codec : AAC, AC3, LPCM */ +typedef enum { + MM_WFD_SINK_AUDIO_CODEC_NONE, + MM_WFD_SINK_AUDIO_CODEC_AAC = 0x0F, + MM_WFD_SINK_AUDIO_CODEC_AC3 = 0x81, + MM_WFD_SINK_AUDIO_CODEC_LPCM = 0x83 +} MMWFDSinkAudioCodec; + +/* video codec : H264 */ +typedef enum { + MM_WFD_SINK_VIDEO_CODEC_NONE, + MM_WFD_SINK_VIDEO_CODEC_H264 = 0x1b +} MMWFDSinkVideoCodec; + +typedef void(*MMWFDMessageCallback)(int error_type, MMWFDSinkStateType state_type, void *user_data); + +/** + * This function creates a wi-fi display sink object. \n + * The attributes of wi-fi display sink are created to get/set some values with application. \n + * And, mutex, gstreamer and other resources are initialized at this time. \n + * If wi-fi display sink is created, he state will become MM_WFD_SINK_STATE_NULL.. \n + * + * @param wfd_sink [out] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. \n + * Please refer 'mm_error.h' to know it in detail. + * @pre None + * @post MM_WFD_SINK_STATE_NULL + * @see mm_wfd_sink_destroy + * @remark You can create multiple handles on a context at the same time. \n + * However, wi-fi display sink cannot guarantee proper operation because of limitation of resources, \n + * such as audio device or display device. + * + * @par Example + * @code +if (mm_wfd_sink_create(&g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to create wi-fi display sink\n"); +} + +mm_wfd_sink_set_message_callback(g_wfd_sink, msg_callback, (void*)g_wfd_sink); + * @endcode + */ +int mm_wfd_sink_create(MMHandleType *wfd_sink); + +/** + * This function trys to make gstreamer pipeline. \n + * If wi-fi display sink is realized, the state will become MM_WFD_SINK_STATE_READY.. \n + * + * @param wfd_sink [out] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. \n + * Please refer 'mm_error.h' to know it in detail. + * @pre MM_WFD_SINK_STATE_NULL + * @post MM_WFD_SINK_STATE_PREPARED + * @see mm_wfd_sink_unprepare + * @remark None + * @par Example + * @code +if (mm_wfd_sink_prepare(&g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to realize wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_prepare(MMHandleType wfd_sink); + +/** + * This function connect wi-fi display source using uri. \n + * audio type(AC3 AAC, LPCM) is decided at this time. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param uri [in] URI of wi-fi displaysource to be connected + * + * @return This function returns zero on success, or negative value with error code. + * + * @pre wi-fi display sink state should be MM_WFD_SINK_STATE_PREPARED + * @post wi-fi display sink state will be MM_WFD_SINK_STATE_CONNECTED with no preroll. + * @remark None + * @par Example + * @code +if (mm_wfd_sink_connect(g_wfd_sink, g_uri) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to connect to wi-fi display source\n"); +} + * @endcode + */ +int mm_wfd_sink_connect(MMHandleType wfd_sink, const char *uri); + +/** + * This function is to start playing. \n + * Data from wi-fi display source will be received. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @remark + * + * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_CONNECTED. + * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PLAYING. + * @see mm_wfd_sink_disconnect + * @remark None + * @par Example + * @code +if (mm_wfd_sink_start(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to start wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_start(MMHandleType wfd_sink); + +/** + * This function is to pause playing. \n + * The wi-fi display sink pause the current stream being received form wi-fi display source. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @remark + * + * @pre wi-fi display sink state should be MM_WFD_SINK_STATE_PLAYING. + * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PAUSED. + * @see mm_wfd_sink_pause + * @remark None + * @par Example + * @code +if (mm_wfd_sink_pause(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to pause wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_pause(MMHandleType wfd_sink); + +/** + * This function is to resume playing. \n + * Data from wi-fi display source will be received. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @remark + * + * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PAUSED. + * @post wi-fi display sink state will be MM_WFD_SINK_STATE_PLAYING. + * @see mm_wfd_sink_disconnect + * @remark None + * @par Example + * @code +if (mm_wfd_sink_start(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to resume wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_resume(MMHandleType wfd_sink); + +/** + * This function is to stop playing wi-fi display. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * + * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PLAYING. + * @post wi-fi display sink state will be MM_WFD_SINK_STATE_DISCONNECTED. + * @see mm_wfd_sink_start + * @remark None + * @par Example + * @code +if (mm_wfd_sink_disconnect(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to stop wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_disconnect(MMHandleType wfd_sink); + +/** + * This function trys to destroy gstreamer pipeline. \n + * + * @param wfd_sink [out] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. \n + * Please refer 'mm_error.h' to know it in detail. + * @pre wi-fi display sink state may be MM_WFD_SINK_STATE_PREPARED or MM_WFD_SINK_STATE_DISCONNECTED. + * But, it can be called in any state. + * @post MM_WFD_SINK_STATE_NULL + * @see mm_wfd_sink_prepare + * @remark None + * @par Example + * @code +if (mm_wfd_sink_unprepare(&g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to unprepare wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_unprepare(MMHandleType wfd_sink); + +/** + * This function releases wi-fi display sink object and all resources which were created by mm_wfd_sink_create(). \n + * And, wi-fi display sink handle will also be destroyed. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state may be MM_WFD_SINK_STATE_NULL. \n + * But, it can be called in any state. + * @post Because handle is released, there is no any state. + * @see mm_wfd_sink_create + * @remark This method can be called with a valid wi-fi display sink handle from any state to \n + * completely shutdown the wi-fi display sink operation. + * + * @par Example + * @code +if (mm_wfd_sink_destroy(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to destroy wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_destroy(MMHandleType wfd_sink); + +/** + * This function sets callback function for receiving messages from wi-fi display sink. \n + * So, player can notify warning, error and normal cases to application. \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param callback [in] Message callback function. + * @param user_param [in] User parameter which is passed to callback function. + * + * @return This function returns zero on success, or negative value with error code. + * @see MMWFDMessageCallback + * @remark None + * @par Example + * @code + +int msg_callback(int error_type, MMWFDSinkStateType state_type, void *user_data) +{ + switch (state_type) + { + case MM_WFD_SINK_STATE_NULL: + //do something + break; + + case MM_WFD_SINK_STATE_PREPARED: + //do something + break; + + case MM_WFD_SINK_STATE_CONNECTED: + //do something + break; + + case MM_WFD_SINK_STATE_PLAYING: + //do something + break; + + case MM_WFD_SINK_STATE_PAUSED: + //do something + break; + + case MM_WFD_SINK_DISCONNECTED: + //do something + break; + + default: + break; + } + return TRUE; +} + +mm_wfd_sink_set_message_callback(g_wfd_sink, msg_callback, (void*)g_wfd_sink); + * @endcode + */ +int mm_wfd_sink_set_message_callback(MMHandleType wfd_sink, MMWFDMessageCallback callback, void *user_param); + +int mm_wfd_sink_set_attribute(MMHandleType wfd_sink, char **err_attr_name, const char *first_attribute_name, ...); + +/** + * This function get resources \n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_READY or MM_WFD_SINK_STATE_PREPARED. \n + * @post N/A + * @remark resources are released when mm_wfd_sink_destory is called + * + * @par Example + * @code +if (mm_wfd_sink_get_resource(g_wfd_sink) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to get resources for wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_get_resource(MMHandleType wfd_sink); + +/** + * This function sets the display surface type for wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param display_surface_type [in] Display surface type + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n + * + * @par Example + * @code +if (mm_wfd_sink_set_display_surface_type(g_wfd_sink, g_display_surface_type) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to set display surface type for wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_set_display_surface_type(MMHandleType wfd_sink, gint display_surface_type); + +/** + * This function sets the display overlay for wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param display_overlay [in] Display overlay + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n + * + * @par Example + * @code +if (mm_wfd_sink_set_display_overlay(g_wfd_sink, g_display_overlay) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to set display overlay for wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_set_display_overlay(MMHandleType wfd_sink, void *display_overlay); + +/** + * This function sets the display method for wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param display_method [in] Display method + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n + * + * @par Example + * @code +if (mm_wfd_sink_set_display_method(g_wfd_sink, g_display_method) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to set display method for wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_set_display_method(MMHandleType wfd_sink, gint display_method); + +/** + * This function sets the display visible for wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param display_visible [in] Display visible + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n + * + * @par Example + * @code +if (mm_wfd_sink_set_display_visible(g_wfd_sink, g_display_visible) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to set display visible for wi-fi display sink\n"); +} + * @endcode + */ +int mm_wfd_sink_set_display_visible(MMHandleType wfd_sink, gint display_visible); + +/** + * This function gets the width and height of video which is played by wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param width [in] Width of video + * @param height [in] Height of video + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_CONNECTED or MM_WFD_SINK_STATE_PLAYING. \n + * + * @par Example + * @code +gint g_width=0, g_height=0; + +if (mm_wfd_sink_get_video_resolution(g_wfd_sink, &g_width, &g_height) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to get video resolution.\n"); +} + * @endcode + */ +int mm_wfd_sink_get_video_resolution(MMHandleType wfd_sink, gint *width, gint *height); + +/** + * This function gets the width and height of video which is played by wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param framerate [in] Framerate of video + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_CONNECTED or MM_WFD_SINK_STATE_PLAYING. \n + * + * @par Example + * @code +gint g_framerate=0; + +if (mm_wfd_sink_get_video_framerate(g_wfd_sink, &g_framerate) != MM_ERROR_NONE) +{ + wfd_sink_error("failed to get video framerate.\n"); +} + * @endcode + */ +int mm_wfd_sink_get_video_framerate(MMHandleType wfd_sink, gint *framerate); + +/** + * This function sets the resolutions for wi-fi display sink\n + * + * @param wfd_sink [in] Handle of wi-fi display sink + * @param resolution [in] Resolutions for wi-fi display sink + * + * @return This function returns zero on success, or negative value with error code. + * @pre wi-fi display state should be MM_WFD_SINK_STATE_NULL. \n + * + */ +int mm_wfd_sink_set_resolution(MMHandleType wfd_sink, gint resolution); + +int mm_wfd_sink_get_negotiated_video_codec(MMHandleType wfd_sink, gint *codec); +int mm_wfd_sink_get_negotiated_video_resolution(MMHandleType wfd_sink, gint *width, gint *height); +int mm_wfd_sink_get_negotiated_video_frame_rate(MMHandleType wfd_sink, gint *frame_rate); +int mm_wfd_sink_get_negotiated_audio_codec(MMHandleType wfd_sink, gint *codec); +int mm_wfd_sink_get_negotiated_audio_channel(MMHandleType wfd_sink, gint *channel); +int mm_wfd_sink_get_negotiated_audio_sample_rate(MMHandleType wfd_sink, gint *sample_rate); +int mm_wfd_sink_get_negotiated_audio_bitwidth(MMHandleType wfd_sink, gint *bitwidth); +#endif diff --git a/src/include/mm_wfd_sink_attrs.h b/src/include/mm_wfd_sink_attrs.h new file mode 100755 index 0000000..1c6fc48 --- /dev/null +++ b/src/include/mm_wfd_sink_attrs.h @@ -0,0 +1,132 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Manoj Kumar K , Hyunil Park + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_WFD_ATTRS_H__ +#define __MM_WFD_ATTRS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* general */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif +#define MMWFD_MAX_INT (2147483647) + +/** + * Enumeration for attribute values types. + */ +typedef enum { + MM_WFD_ATTRS_TYPE_INVALID = -1, /**< Type is invalid */ + MM_WFD_ATTRS_TYPE_INT, /**< Integer type */ + MM_WFD_ATTRS_TYPE_DOUBLE, /**< Double type */ + MM_WFD_ATTRS_TYPE_STRING, /**< UTF-8 String type */ + MM_WFD_ATTRS_TYPE_DATA, /**< Pointer type */ + MM_WFD_ATTRS_TYPE_ARRAY, /**< Array type */ + MM_WFD_ATTRS_TYPE_RANGE, /**< Range type */ + MM_WFD_ATTRS_TYPE_NUM, /**< Number of attribute type */ +} MMWfdAttrsType; + +/** + * Enumeration for attribute validation type. + */ +typedef enum { + MM_WFD_ATTRS_VALID_TYPE_INVALID = -1, /**< Invalid validation type */ + MM_WFD_ATTRS_VALID_TYPE_NONE, /**< Do not check validity */ + MM_WFD_ATTRS_VALID_TYPE_INT_ARRAY, /**< validity checking type of integer array */ + MM_WFD_ATTRS_VALID_TYPE_INT_RANGE, /**< validity checking type of integer range */ + MM_WFD_ATTRS_VALID_TYPE_DOUBLE_ARRAY, /**< validity checking type of double array */ + MM_WFD_ATTRS_VALID_TYPE_DOUBLE_RANGE, /**< validity checking type of double range */ +} MMWfdAttrsValidType; + +/** + * Enumeration for attribute access flag. + */ +typedef enum { + MM_WFD_ATTRS_FLAG_NONE = 0, /**< None flag is set */ + MM_WFD_ATTRS_FLAG_READABLE = 1 << 0, /**< Readable */ + MM_WFD_ATTRS_FLAG_WRITABLE = 1 << 1, /**< Writable */ + MM_WFD_ATTRS_FLAG_MODIFIED = 1 << 2, /**< Modified */ + + MM_WFD_ATTRS_FLAG_RW = MM_WFD_ATTRS_FLAG_READABLE | MM_WFD_ATTRS_FLAG_WRITABLE, /**< Readable and Writable */ +} MMWfdAttrsFlag; + +/** + * Attribute validity structure + */ +typedef struct { + MMWfdAttrsType type; + MMWfdAttrsValidType validity_type; + MMWfdAttrsFlag flag; + /** + * a union that describes validity of the attribute. + * Only when type is 'MM_ATTRS_TYPE_INT' or 'MM_ATTRS_TYPE_DOUBLE', + * the attribute can have validity. + */ + union { + /** + * Validity structure for integer array. + */ + struct { + int *array; /**< a pointer of array */ + int count; /**< size of array */ + int d_val; + } int_array; + /** + * Validity structure for integer range. + */ + struct { + int min; /**< minimum range */ + int max; /**< maximum range */ + int d_val; + } int_range; + /** + * Validity structure for double array. + */ + struct { + double *array; /**< a pointer of array */ + int count; /**< size of array */ + double d_val; + } double_array; + /** + * Validity structure for double range. + */ + struct { + double min; /**< minimum range */ + double max; /**< maximum range */ + double d_val; + } double_range; + }; +} MMWfdAttrsInfo; + +MMHandleType _mmwfd_construct_attribute(MMHandleType hwfd); +void _mmwfd_deconstruct_attribute(MMHandleType hwfd); +int _mmwfd_set_attribute(MMHandleType hwfd, char **err_atr_name, const char *attribute_name, va_list args_list); +int _mmwfd_get_attributes_info(MMHandleType handle, const char *attribute_name, MMWfdAttrsInfo *dst_info); +int _mmwfd_get_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list); +#endif /* __MM_WFD_ATTRS_H__ */ \ No newline at end of file diff --git a/src/include/mm_wfd_sink_dlog.h b/src/include/mm_wfd_sink_dlog.h new file mode 100755 index 0000000..58082e8 --- /dev/null +++ b/src/include/mm_wfd_sink_dlog.h @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __MM_WFD_SINK_DLOG_H__ +#define __MM_WFD_SINK_DLOG_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MM_WFD_SINK" + +#define FONT_COLOR_RESET "\033[0m" +#define FONT_COLOR_RED "\033[31m" +#define FONT_COLOR_GREEN "\033[32m" +#define FONT_COLOR_YELLOW "\033[33m" +#define FONT_COLOR_BLUE "\033[34m" +#define FONT_COLOR_PURPLE "\033[35m" +#define FONT_COLOR_CYAN "\033[36m" +#define FONT_COLOR_GRAY "\033[37m" + +#define wfd_sink_debug(fmt, arg...) do { \ + LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ + } while (0) + +#define wfd_sink_info(fmt, arg...) do { \ + LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ + } while (0) + +#define wfd_sink_error(fmt, arg...) do { \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ + } while (0) + +#define wfd_sink_warning(fmt, arg...) do { \ + LOGW(FONT_COLOR_YELLOW""fmt""FONT_COLOR_RESET, ##arg); \ + } while (0) + +#define wfd_sink_debug_fenter() do { \ + LOGD(FONT_COLOR_RESET""); \ + } while (0) + +#define wfd_sink_debug_fleave() do { \ + LOGD(FONT_COLOR_RESET""); \ + } while (0) + +#define wfd_sink_error_fenter() do { \ + LOGE(FONT_COLOR_RED"NO-ERROR : "FONT_COLOR_RESET); \ + } while (0) + +#define wfd_sink_error_fleave() do { \ + LOGE(FONT_COLOR_RED"NO-ERROR : "FONT_COLOR_RESET); \ + } while (0) + +#define wfd_sink_sucure_info(fmt, arg...) do { \ + SECURE_LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ + } while (0) + +#define wfd_sink_return_if_fail(expr) \ + if(!(expr)) { \ + wfd_sink_error(FONT_COLOR_RED"failed [%s]\n"FONT_COLOR_RESET, #expr); \ + return; \ + } + +#define wfd_sink_return_val_if_fail(expr, val) \ + if (!(expr)) { \ + wfd_sink_error(FONT_COLOR_RED"failed [%s]\n"FONT_COLOR_RESET, #expr); \ + return val; \ + } + +#define wfd_sink_assert_not_reached() \ + { \ + wfd_sink_error(FONT_COLOR_RED"assert_not_reached()"FONT_COLOR_RESET); \ + assert(0); \ + } + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MM_WFD_SINK_DLOG_H__ */ + diff --git a/src/include/mm_wfd_sink_enum.h b/src/include/mm_wfd_sink_enum.h new file mode 100755 index 0000000..c88cc8b --- /dev/null +++ b/src/include/mm_wfd_sink_enum.h @@ -0,0 +1,145 @@ +/* + * Enumeration for WFD + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MM_WFD_SINK_WFD_ENUM_H_ +#define _MM_WFD_SINK_WFD_ENUM_H_ + +typedef enum { + WFD_AUDIO_UNKNOWN = 0, + WFD_AUDIO_LPCM = (1 << 0), + WFD_AUDIO_AAC = (1 << 1), + WFD_AUDIO_AC3 = (1 << 2) +} WFDAudioFormats; + +typedef enum { + WFD_FREQ_UNKNOWN = 0, + WFD_FREQ_44100 = (1 << 0), + WFD_FREQ_48000 = (1 << 1) +} WFDAudioFreq; + +typedef enum { + WFD_CHANNEL_UNKNOWN = 0, + WFD_CHANNEL_2 = (1 << 0), + WFD_CHANNEL_4 = (1 << 1), + WFD_CHANNEL_6 = (1 << 2), + WFD_CHANNEL_8 = (1 << 3) +} WFDAudioChannels; + + +typedef enum { + WFD_VIDEO_UNKNOWN = 0, + WFD_VIDEO_H264 = (1 << 0) +} WFDVideoCodecs; + +typedef enum { + WFD_VIDEO_CEA_RESOLUTION = 0, + WFD_VIDEO_VESA_RESOLUTION, + WFD_VIDEO_HH_RESOLUTION +} WFDVideoNativeResolution; + +typedef enum { + WFD_CEA_UNKNOWN = 0, + WFD_CEA_640x480P60 = (1 << 0), + WFD_CEA_720x480P60 = (1 << 1), + WFD_CEA_720x480I60 = (1 << 2), + WFD_CEA_720x576P50 = (1 << 3), + WFD_CEA_720x576I50 = (1 << 4), + WFD_CEA_1280x720P30 = (1 << 5), + WFD_CEA_1280x720P60 = (1 << 6), + WFD_CEA_1920x1080P30 = (1 << 7), + WFD_CEA_1920x1080P60 = (1 << 8), + WFD_CEA_1920x1080I60 = (1 << 9), + WFD_CEA_1280x720P25 = (1 << 10), + WFD_CEA_1280x720P50 = (1 << 11), + WFD_CEA_1920x1080P25 = (1 << 12), + WFD_CEA_1920x1080P50 = (1 << 13), + WFD_CEA_1920x1080I50 = (1 << 14), + WFD_CEA_1280x720P24 = (1 << 15), + WFD_CEA_1920x1080P24 = (1 << 16) +} WFDVideoCEAResolution; + +typedef enum { + WFD_VESA_UNKNOWN = 0, + WFD_VESA_800x600P30 = (1 << 0), + WFD_VESA_800x600P60 = (1 << 1), + WFD_VESA_1024x768P30 = (1 << 2), + WFD_VESA_1024x768P60 = (1 << 3), + WFD_VESA_1152x864P30 = (1 << 4), + WFD_VESA_1152x864P60 = (1 << 5), + WFD_VESA_1280x768P30 = (1 << 6), + WFD_VESA_1280x768P60 = (1 << 7), + WFD_VESA_1280x800P30 = (1 << 8), + WFD_VESA_1280x800P60 = (1 << 9), + WFD_VESA_1360x768P30 = (1 << 10), + WFD_VESA_1360x768P60 = (1 << 11), + WFD_VESA_1366x768P30 = (1 << 12), + WFD_VESA_1366x768P60 = (1 << 13), + WFD_VESA_1280x1024P30 = (1 << 14), + WFD_VESA_1280x1024P60 = (1 << 15), + WFD_VESA_1400x1050P30 = (1 << 16), + WFD_VESA_1400x1050P60 = (1 << 17), + WFD_VESA_1440x900P30 = (1 << 18), + WFD_VESA_1440x900P60 = (1 << 19), + WFD_VESA_1600x900P30 = (1 << 20), + WFD_VESA_1600x900P60 = (1 << 21), + WFD_VESA_1600x1200P30 = (1 << 22), + WFD_VESA_1600x1200P60 = (1 << 23), + WFD_VESA_1680x1024P30 = (1 << 24), + WFD_VESA_1680x1024P60 = (1 << 25), + WFD_VESA_1680x1050P30 = (1 << 26), + WFD_VESA_1680x1050P60 = (1 << 27), + WFD_VESA_1920x1200P30 = (1 << 28), + WFD_VESA_1920x1200P60 = (1 << 29) +} WFDVideoVESAResolution; + +typedef enum { + WFD_HH_UNKNOWN = 0, + WFD_HH_800x480P30 = (1 << 0), + WFD_HH_800x480P60 = (1 << 1), + WFD_HH_854x480P30 = (1 << 2), + WFD_HH_854x480P60 = (1 << 3), + WFD_HH_864x480P30 = (1 << 4), + WFD_HH_864x480P60 = (1 << 5), + WFD_HH_640x360P30 = (1 << 6), + WFD_HH_640x360P60 = (1 << 7), + WFD_HH_960x540P30 = (1 << 8), + WFD_HH_960x540P60 = (1 << 9), + WFD_HH_848x480P30 = (1 << 10), + WFD_HH_848x480P60 = (1 << 11) +} WFDVideoHHResolution; + +typedef enum { + WFD_H264_UNKNOWN_PROFILE = 0, + WFD_H264_BASE_PROFILE = (1 << 0), + WFD_H264_HIGH_PROFILE = (1 << 1) +} WFDVideoH264Profile; + +typedef enum { + WFD_H264_LEVEL_UNKNOWN = 0, + WFD_H264_LEVEL_3_1 = (1 << 0), + WFD_H264_LEVEL_3_2 = (1 << 1), + WFD_H264_LEVEL_4 = (1 << 2), + WFD_H264_LEVEL_4_1 = (1 << 3), + WFD_H264_LEVEL_4_2 = (1 << 4) +} WFDVideoH264Level; + +#endif /*_MM_WFD_SINK_WFD_ENUM_H_*/ diff --git a/src/include/mm_wfd_sink_ini.h b/src/include/mm_wfd_sink_ini.h new file mode 100755 index 0000000..f1122ce --- /dev/null +++ b/src/include/mm_wfd_sink_ini.h @@ -0,0 +1,353 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Manoj Kumar K , Hyunil Park + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_WFD_SINK_INI_H__ +#define __MM_WFD_SINK_INI_H__ + +#include +#include +#include "mm_wfd_sink_enum.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +enum WFDSinkINIProbeFlags +{ + WFD_SINK_INI_PROBE_DEFAULT = 0, + WFD_SINK_INI_PROBE_TIMESTAMP = (1 << 0), + WFD_SINK_INI_PROBE_BUFFERSIZE = (1 << 1), + WFD_SINK_INI_PROBE_CAPS = (1 << 2), + WFD_SINK_INI_PROBE_BUFFER_DURATION = (1 << 3), +}; + +#define MM_WFD_SINK_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_wfd_sink.ini" + +#define WFD_SINK_INI_MAX_STRLEN 256 +#define WFD_SINK_INI_MAX_ELEMENT 10 + +/* NOTE : MMPlayer has no initalizing API for library itself + * so we cannot decide when those ini values to be released. + * this is the reason of all string items are static array. + * make it do with malloc when MMPlayerInitialize() API created + * before that time, we should be careful with size limitation + * of each string item. + */ +typedef struct __mm_wfd_sink_ini { + /* general */ + gchar gst_param[5][WFD_SINK_INI_MAX_STRLEN]; + gboolean generate_dot; + gboolean enable_pad_probe; + gint state_change_timeout; + gboolean set_debug_property; + gboolean enable_asm; + gint jitter_buffer_latency; + gint video_sink_max_lateness; + gint sink_ts_offset; + gboolean audio_sink_async; + gboolean video_sink_async; + gboolean enable_retransmission; + gboolean enable_reset_basetime; + gboolean enable_ts_data_dump; + gboolean enable_wfdsrc_pad_probe; + + /* pipeline */ + gchar name_of_source[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_tsdemux[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_audio_hdcp[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_aac_parser[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_aac_decoder[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_ac3_parser[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_ac3_decoder[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_lpcm_converter[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_lpcm_filter[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_audio_resampler[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_audio_volume[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_audio_sink[WFD_SINK_INI_MAX_STRLEN]; + + gchar name_of_video_hdcp[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_parser[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_capssetter[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_decoder[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_converter[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_filter[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_sink[WFD_SINK_INI_MAX_STRLEN]; + gchar name_of_video_evas_sink[WFD_SINK_INI_MAX_STRLEN]; + + /* audio parameter for reponse of M3 request */ + guint audio_codec; + guint audio_latency; + guint audio_channel; + guint audio_sampling_frequency; + + /* video parameter for reponse of M3 request */ + guint video_codec; + guint video_native_resolution; + guint video_cea_support; + guint video_vesa_support; + guint video_hh_support; + guint video_profile; + guint video_level; + guint video_latency; + gint video_vertical_resolution; + gint video_horizontal_resolution; + gint video_minimum_slicing; + gint video_slice_enc_param; + gint video_framerate_control_support; + + /* hdcp parameter for reponse of M3 request */ + gint hdcp_content_protection; + gint hdcp_port_no; +} mm_wfd_sink_ini_t; + + +/*Default sink ini values*/ +/* General*/ +#define DEFAULT_GST_PARAM "" +#define DEFAULT_GENERATE_DOT FALSE +#define DEFAULT_ENABLE_PAD_PROBE FALSE +#define DEFAULT_STATE_CHANGE_TIMEOUT 5 /* sec */ +#define DEFAULT_SET_DEBUG_PROPERTY TRUE +#define DEFAULT_ENABLE_ASM FALSE +#define DEFAULT_JITTER_BUFFER_LATENCY 10 /* msec */ +#define DEFAULT_ENABLE_RETRANSMISSION FALSE +#define DEFAULT_ENABLE_RESET_BASETIME TRUE +#define DEFAULT_VIDEO_SINK_MAX_LATENESS 20000000 /* nsec */ +#define DEFAULT_SINK_TS_OFFSET 150000000 /* nsec */ +#define DEFAULT_AUDIO_SINK_ASYNC FALSE +#define DEFAULT_VIDEO_SINK_ASYNC FALSE +#define DEFAULT_ENABLE_TS_DATA_DUMP FALSE +#define DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE FALSE + +/* Pipeline */ +#define DEFAULT_NAME_OF_SOURCE "wfdsrc" +#define DEFAULT_NAME_OF_TSDEMUX "" +#define DEFAULT_NAME_OF_AUDIO_HDCP "" +#define DEFAULT_NAME_OF_AAC_PARSER "" +#define DEFAULT_NAME_OF_AAC_DECODER "" +#define DEFAULT_NAME_OF_AC3_PARSER "" +#define DEFAULT_NAME_OF_AC3_DECODER "" +#define DEFAULT_NAME_OF_LPCM_CONVERTER "" +#define DEFAULT_NAME_OF_LPCM_FILTER "" +#define DEFAULT_NAME_OF_AUDIO_RESAMPLER "" +#define DEFAULT_NAME_OF_AUDIO_VOLUME "" +#define DEFAULT_NAME_OF_AUDIO_SPLITTER "" +#define DEFAULT_NAME_OF_AUDIO_SINK "" +#define DEFAULT_NAME_OF_VIDEO_HDCP "" +#define DEFAULT_NAME_OF_VIDEO_PARSER "" +#define DEFAULT_NAME_OF_VIDEO_CAPSSETTER "" +#define DEFAULT_NAME_OF_VIDEO_DECODER "" +#define DEFAULT_NAME_OF_VIDEO_CONVERTER "" +#define DEFAULT_NAME_OF_VIDEO_FILTER "" +#define DEFAULT_NAME_OF_VIDEO_SINK "" +#define DEFAULT_NAME_OF_EVAS_VIDEO_SINK "" + +/* Audio */ +#define DEFAULT_AUDIO_CODEC WFD_AUDIO_LPCM | WFD_AUDIO_AAC +#define DEFAULT_AUDIO_LATENCY 0x0 +#define DEFAULT_AUDIO_CHANNELS WFD_CHANNEL_2 +#define DEFAULT_AUDIO_SAMP_FREQUENCY WFD_FREQ_44100 | WFD_FREQ_48000 + +/* Video */ +#define DEFAULT_VIDEO_CODEC WFD_VIDEO_H264 +#define DEFAULT_VIDEO_NATIVE_RESOLUTION 0x20 +/* CEA : WFD_CEA_640x480P60 | WFD_CEA_720x480P60 |WFD_CEA_720x576P50 |WFD_CEA_1280x720P30 | + WFD_CEA_1280x720P25 | WFD_CEA_1280x720P24 */ +#define DEFAULT_VIDEO_CEA_SUPPORT 0x84ab +/* VESA : WFD_VESA_800x600P30 */ +#define DEFAULT_VIDEO_VESA_SUPPORT 0x1 +/* HH : WFD_HH_800x480P30 | WFD_HH_854x480P30 | WFD_HH_864x480P30 | WFD_HH_640x360P30 | WFD_HH_960x540P30 | WFD_HH_848x480P30 */ +#define DEFAULT_VIDEO_HH_SUPPORT 0x555 +#define DEFAULT_VIDEO_PROFILE WFD_H264_BASE_PROFILE +#define DEFAULT_VIDEO_LEVEL WFD_H264_LEVEL_3_2 +#define DEFAULT_VIDEO_LATENCY 0x0 +#define DEFAULT_VIDEO_VERTICAL_RESOLUTION 720 +#define DEFAULT_VIDEO_HORIZONTAL_RESOLUTION 1280 +#define DEFAULT_VIDEO_MIN_SLICESIZE 0 +#define DEFAULT_VIDEO_SLICE_ENC_PARAM 200 +#define DEFAULT_VIDEO_FRAMERATE_CONTROL 11 + +/* HDCP */ +#define DEFAULT_HDCP_CONTENT_PROTECTION 0x0 +#define DEFAULT_HDCP_PORT_NO 0 + + +#define MM_WFD_SINK_DEFAULT_INI \ +" \ +[general]\n\ +; parameters for initializing gstreamer\n\ +; DEFAULT SET(--gst-debug=2, *wfd*:5)\n\ +gstparam1 = --gst-debug=2, *wfd*:5, *wfdtsdemux:1, *wfdrtpbuffer:1\n\ +gstparam2 =\n\ +gstparam3 =\n\ +gstparam4 =\n\ +gstparam5 =\n\ +\n\ +; generating dot file representing pipeline state\n\ +; do export GST_DEBUG_DUMP_DOT_DIR=[dot file path] in the shell\n\ +generate dot = no\n\ +\n\ +; enable pad probe\n\ +enable pad probe = no\n\ +\n\ +; enable wfdsrc inner pad probe\n\ +enable wfdsrc pad probe = no\n\ +\n\ +; enable ts data dump(eg. /var/tmp/*.ts)\n\ +enable ts data dump = no\n\ +\n\ +; allowed timeout for changing pipeline state\n\ +state change timeout = 5 ; sec\n\ +\n\ +; set debug property to wfdsrc plugin for debugging rtsp message\n\ +set debug property = yes\n\ +\n\ +; for asm function enable = yes, disable = no\n\ +enable asm = no\n\ +\n\ +; 0: default value set by wfdsrc element, other: user define value.\n\ +jitter buffer latency=10\n\ +\n\ +; for retransmission request enable = yes, disable = no\n\ +enable retransmission = no\n\ +\n\ +; for reset basetime, enable = yes, disable = no\n\ +enable reset basetime = yes\n\ +\n\ +; Maximum number of nanoseconds that a buffer can be late before it is dropped by videosink(-1 unlimited)\n\ +video sink max lateness=20000000\n\ +\n\ +; nanoseconds to be added to buffertimestamp by sink elements\n\ +sink ts offset=150000000\n\ +\n\ +; if no, go asynchronously to PAUSED without preroll \n\ +audio sink async=no\n\ +\n\ +; if no, go asynchronously to PAUSED without preroll \n\ +video sink async=no\n\ +\n\ +\n\ +\n\ +[pipeline]\n\ +wfdsrc element = wfdsrc\n\ +\n\ +tsdemux element = wfdtsdemux\n\ +\n\ +aac parser element = aacparse\n\ +\n\ +aac decoder element = avdec_aac\n\ +\n\ +ac3 parser element = ac3parse\n\ +\n\ +ac3 decoder element =\n\ +\n\ +lpcm converter element =\n\ +\n\ +lpcm filter element = capsfilter\n\ +\n\ +audio resampler element = audioconvert\n\ +\n\ +audio volume element =\n\ +\n\ +audio sink element = pulsesink\n\ +\n\ +video parser element = h264parse\n\ +\n\ +video capssetter element = capssetter\n\ +\n\ +video decoder element = avdec_h264;sprddec_h264;omxh264dec\n\ +\n\ +video converter element =\n\ +\n\ +video filter element =\n\ +\n\ +video sink element = waylandsink;xvimagesink\n\ +\n\ +\n\ +\n\ +[audio param]\n\ +; 0x1: LPCM, 0x2: aac, 0x4: ac3\n\ +;default aac and LPCM\n\ +audio codec=0x3\n\ +\n\ +audio latency=0x0\n\ +\n\ +;0x1 : 48000khz, 0x2: 44100khz\n\ +audio sampling frequency=0x3\n\ +\n\ +; 0x1:2 channels, 0x2:4 channels, 0x4:6channels, 0x8:8channels\n\ +audio channels=0x1\n\ +\n\ +\n\ +\n\ +[video param]\n\ +; 0: H264CBP 1: H264CHP\n\ +video codec=0x1\n\ +\n\ +video native resolution = 0x20\n\ +\n\ +video cea support=0x842b\n\ +\n\ +video vesa support=0x1\n\ +\n\ +video hh support=0x555\n\ +\n\ +; 0x1:base, 0x2:high\n\ +video profile=0x1\n\ +\n\ +; 0x1:level_3_1, 0x2:level_3_2, 0x4:level_4, 0x8:level_4_1, 0x10:level_4_2\n\ +video level=0x2\n\ +\n\ +video latency=0x0\n\ +\n\ +video vertical resolution=720\n\ +\n\ +video horizontal resolution=1280\n\ +\n\ +video minimum slicesize=0\n\ +\n\ +video slice encoding params=200\n\ +\n\ +video framerate control support=11\n\ +\n\ +\n\ +\n\ +[hdcp param]\n\ +;0x0:none, 0x1:HDCP_2.0, 0x2:HDCP_2.1\n\ +hdcp content protection=0x0\n\ +\n\ +hdcp port no=0\n\ +\n\ +" + +int +mm_wfd_sink_ini_load(mm_wfd_sink_ini_t *ini); + +int +mm_wfd_sink_ini_unload(mm_wfd_sink_ini_t *ini); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/mm_wfd_sink_manager.h b/src/include/mm_wfd_sink_manager.h new file mode 100755 index 0000000..47309e3 --- /dev/null +++ b/src/include/mm_wfd_sink_manager.h @@ -0,0 +1,112 @@ +/* + * libmm-wfd + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_WFD_SINK_MANAGER_H__ +#define __MM_WFD_SINK_MANAGER_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include "mm_wfd_sink_priv.h" +#include "mm_wfd_sink_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WFD_SINK_MANAGER_LOCK(wfd_sink) \ + do {\ + if (wfd_sink) {\ + g_mutex_lock(&((wfd_sink)->manager_thread_mutex));\ + }\ + } while (0); + +#define WFD_SINK_MANAGER_UNLOCK(wfd_sink) \ + do {\ + if (wfd_sink) {\ + g_mutex_unlock(&((wfd_sink)->manager_thread_mutex));\ + }\ + } while (0); + +#define WFD_SINK_MANAGER_WAIT_CMD(wfd_sink) \ + do {\ + if (wfd_sink->manager_thread_exit == FALSE) {\ + wfd_sink_debug("manager thread is waiting for command signal");\ + wfd_sink->waiting_cmd = TRUE; \ + g_cond_wait(&((wfd_sink)->manager_thread_cond), &((wfd_sink)->manager_thread_mutex)); \ + wfd_sink->waiting_cmd = FALSE; \ + } else {\ + wfd_sink_debug("manager thread is stopped, don't need to wait for command signal");\ + }\ + } while (0); + +#define WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, cmd) \ + do {\ + WFD_SINK_MANAGER_LOCK(wfd_sink);\ + if (cmd == WFD_SINK_MANAGER_CMD_EXIT) {\ + g_list_free(wfd_sink->manager_thread_cmd);\ + wfd_sink->manager_thread_cmd = NULL;\ + wfd_sink->manager_thread_exit = TRUE;\ + }\ + wfd_sink->manager_thread_cmd = g_list_append(wfd_sink->manager_thread_cmd, GINT_TO_POINTER(cmd)); \ + WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ + } while (0); + +#define WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink) \ + do {\ + WFD_SINK_MANAGER_LOCK(wfd_sink);\ + if (wfd_sink->waiting_cmd) {\ + if (wfd_sink->manager_thread_cmd) {\ + wfd_sink_debug("send command signal to manager thread");\ + g_cond_signal(&((wfd_sink)->manager_thread_cond));\ + }\ + }\ + WFD_SINK_MANAGER_UNLOCK(wfd_sink);\ + } while (0); + +/** + * This function is to initialize manager + * + * @param[in] handle Handle of wfd_sink. + * @return This function returns zero on success, or negative value with errors. + * @remarks + * @see + * + */ +int _mm_wfd_sink_init_manager(mm_wfd_sink_t *wfd_sink); +/** + * This function is to release manager + * + * @param[in] handle Handle of wfd_sink. + * @return This function returns zero on success, or negative value with errors. + * @remarks + * @see + * + */ +int _mm_wfd_sink_release_manager(mm_wfd_sink_t *wfd_sink); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/mm_wfd_sink_priv.h b/src/include/mm_wfd_sink_priv.h new file mode 100755 index 0000000..2a0d20b --- /dev/null +++ b/src/include/mm_wfd_sink_priv.h @@ -0,0 +1,248 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MM_WFD_SINK_PRIV_H_ +#define _MM_WFD_SINK_PRIV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mm_wfd_sink_ini.h" +#include "mm_wfd_sink_attrs.h" +#include "mm_wfd_sink.h" + +/* main pipeline's element id */ +enum WFDSinkMainElementID { + WFD_SINK_M_PIPE = 0, /* NOTE : WFD_SINK_M_PIPE should be zero */ + WFD_SINK_M_SRC, + WFD_SINK_M_DEPAY, + WFD_SINK_M_DEMUX, + WFD_SINK_M_NUM +}; + +/* audio decodebin's element id */ +enum WFDSinkAudioDecodeBinElementID { + WFD_SINK_A_D_BIN = 0, /* NOTE : WFD_SINK_A_D_BIN should be zero */ + WFD_SINK_A_D_QUEUE, + WFD_SINK_A_D_HDCP, + WFD_SINK_A_D_AAC_PARSE, + WFD_SINK_A_D_AAC_DEC, + WFD_SINK_A_D_AC3_PARSE, + WFD_SINK_A_D_AC3_DEC, + WFD_SINK_A_D_LPCM_CONVERTER, + WFD_SINK_A_D_LPCM_FILTER, + WFD_SINK_A_D_NUM +}; + +/* audio sinkbin's element id */ +enum WFDSinkAudioSinkBinElementID { + WFD_SINK_A_S_BIN = 0, /* NOTE : WFD_SINK_A_S_BIN should be zero */ + WFD_SINK_A_S_RESAMPLER, + WFD_SINK_A_S_VOLUME, + WFD_SINK_A_S_SINK, + WFD_SINK_A_S_NUM +}; + +/* video decodebin's element id */ +enum WFDSinkVideoDecodeBinElementID { + WFD_SINK_V_D_BIN = 0, /* NOTE : WFD_SINK_V_D_BIN should be zero */ + WFD_SINK_V_D_QUEUE, + WFD_SINK_V_D_HDCP, + WFD_SINK_V_D_PARSE, + WFD_SINK_V_D_CAPSSETTER, + WFD_SINK_V_D_DEC, + WFD_SINK_V_D_NUM +}; + +/* video sinkbin's element id */ +enum WFDSinkVideoSinkBinElementID { + WFD_SINK_V_S_BIN = 0, /* NOTE : WFD_SINK_V_S_BIN should be zero */ + WFD_SINK_V_S_CONVERT, + WFD_SINK_V_S_FILTER, + WFD_SINK_V_S_SINK, + WFD_SINK_V_S_NUM +}; + +/** + * * Enumerations of wifi-display command. + * */ +typedef enum { + MM_WFD_SINK_COMMAND_NONE, /**< command for nothing */ + MM_WFD_SINK_COMMAND_CREATE, /**< command for creating wifi-display sink */ + MM_WFD_SINK_COMMAND_PREPARE, /**< command for preparing wifi-display sink */ + MM_WFD_SINK_COMMAND_CONNECT, /**< command for connecting wifi-display sink */ + MM_WFD_SINK_COMMAND_START, /**< command for starting wifi-display sink */ + MM_WFD_SINK_COMMAND_PAUSE, /**< command for pausing wifi-display sink */ + MM_WFD_SINK_COMMAND_RESUME, /**< command for resuming wifi-display sink */ + MM_WFD_SINK_COMMAND_DISCONNECT, /**< command for disconnecting wifi-display sink */ + MM_WFD_SINK_COMMAND_UNPREPARE, /**< command for unpreparing wifi-display sink */ + MM_WFD_SINK_COMMAND_DESTROY, /**< command for destroting wifi-display sink */ + MM_WFD_SINK_COMMAND_NUM, /**< Number of wifi-display commands */ +} MMWFDSinkCommandType; + +/** + * * Enumerations of thread command. + * */ +typedef enum { + WFD_SINK_MANAGER_CMD_NONE = 0, + WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN, + WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN, + WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE, + WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE, + WFD_SINK_MANAGER_CMD_EXIT, +} WFDSinkManagerCMDType; + +/** + * * Enumerations of resolution. + * */ +typedef enum { + MM_WFD_SINK_RESOLUTION_UNKNOWN = 0, + MM_WFD_SINK_RESOLUTION_1920x1080_P30 = (1 << 0), /**< W-1920, H-1080, 30 fps*/ + MM_WFD_SINK_RESOLUTION_1280x720_P30 = (1 << 1), /**< W-1280, H-720, 30 fps*/ + MM_WFD_SINK_RESOLUTION_960x540_P30 = (1 << 2), /**< W-960, H-540, 30 fps*/ + MM_WFD_SINK_RESOLUTION_864x480_P30 = (1 << 3), /**< W-864, H-480, 30 fps*/ + MM_WFD_SINK_RESOLUTION_720x480_P60 = (1 << 4), /**< W-720, H-480, 30 fps*/ + MM_WFD_SINK_RESOLUTION_640x480_P60 = (1 << 5), /**< W-640, H-480, 60 fps*/ + MM_WFD_SINK_RESOLUTION_640x360_P30 = (1 << 6), /**< W-640, H-360, 30 fps*/ + MM_WFD_SINK_RESOLUTION_MAX = 128, +} MMWFDSinkResolution; + +typedef struct { + gint codec; + gint width; + gint height; + gint frame_rate; +} MMWFDSinkVideoStreamInfo; + +typedef struct { + gint codec; + gint channels; + gint sample_rate; + gint bitwidth; +} MMWFDSinkAudioStreamInfo; + +typedef struct { + MMWFDSinkAudioStreamInfo audio_stream_info; + MMWFDSinkVideoStreamInfo video_stream_info; +} MMWFDSinkStreamInfo; + + +typedef struct { + gint id; + GstElement *gst; +} MMWFDSinkGstElement; + +typedef struct { + MMWFDSinkGstElement *mainbin; + MMWFDSinkGstElement *a_decodebin; + MMWFDSinkGstElement *v_decodebin; + MMWFDSinkGstElement *a_sinkbin; + MMWFDSinkGstElement *v_sinkbin; +} MMWFDSinkGstPipelineInfo; + +typedef struct { + MMWFDSinkStateType state; /* wfd current state */ + MMWFDSinkStateType prev_state; /* wfd previous state */ + MMWFDSinkStateType pending_state; /* wfd state which is going to now */ +} MMWFDSinkState; + +#define MMWFDSINK_GET_ATTRS(x_wfd) ((x_wfd)? ((mm_wfd_sink_t*)x_wfd)->attrs : (MMHandleType)NULL) + +typedef struct { + /* gstreamer pipeline */ + MMWFDSinkGstPipelineInfo *pipeline; + gboolean audio_decodebin_is_linked; + gboolean video_decodebin_is_linked; + + /* timestamp compensation */ + gboolean need_to_reset_basetime; + + GstClock *clock; + gint64 video_average_gap; + gint64 video_accumulated_gap; + gint64 video_buffer_count; + gint64 audio_average_gap; + gint64 audio_accumulated_gap; + gint64 audio_buffer_count; + GstClockTime last_buffer_timestamp; + + /* attributes */ + MMHandleType attrs; + + /* state */ + MMWFDSinkState state; + + /* initialize values */ + mm_wfd_sink_ini_t ini; + + /* command */ + MMWFDSinkCommandType cmd; + GMutex cmd_lock; + gboolean waiting_cmd; + + /* stream information */ + MMWFDSinkStreamInfo stream_info; + + /* Message handling */ + MMWFDMessageCallback msg_cb; + void *msg_user_data; + + /* video resolution for negotiation */ + MMWFDSinkResolution supportive_resolution; + + GThread *manager_thread; + GMutex manager_thread_mutex; + GCond manager_thread_cond; + GList *manager_thread_cmd; + gboolean manager_thread_exit; +} mm_wfd_sink_t; + + +int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink); +int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri); +int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data); +int _mm_wfd_sink_get_resource(mm_wfd_sink_t *wfd_sink); +int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution); + +int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink); +int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink); + +const gchar *_mm_wfds_sink_get_state_name(MMWFDSinkStateType state); + +#endif + diff --git a/src/include/mm_wfd_sink_util.h b/src/include/mm_wfd_sink_util.h new file mode 100755 index 0000000..870982a --- /dev/null +++ b/src/include/mm_wfd_sink_util.h @@ -0,0 +1,130 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MM_WFD_SINK_UTIL_H_ +#define _MM_WFD_SINK_UTIL_H_ + +#include +#include +#include +#include +#include +#include "mm_wfd_sink_dlog.h" + +#define MMWFDSINK_FREEIF(x) \ + do {\ + if ((x)) \ + g_free((gpointer)(x)); \ + (x) = NULL;\ + } while (0); + +/* lock for commnad */ +#define MMWFDSINK_CMD_LOCK(x_wfd) \ + if (x_wfd) \ + g_mutex_lock(&(((mm_wfd_sink_t *)x_wfd)->cmd_lock)); + +#define MMWFDSINK_CMD_UNLOCK(x_wfd) \ + if (x_wfd) \ + g_mutex_unlock(&(((mm_wfd_sink_t *)x_wfd)->cmd_lock)); + +/* create element */ +#define MMWFDSINK_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \ + do { \ + if (x_name && (strlen(x_factory) > 1)) {\ + x_bin[x_id].id = x_id;\ + x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ + if (! x_bin[x_id].gst) {\ + wfd_sink_error("failed to create %s \n", x_factory);\ + goto CREATE_ERROR;\ + }\ + wfd_sink_debug("%s is created \n", x_factory);\ + if (x_add_bucket)\ + element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\ + }\ + } while (0); + +/* generating dot */ +#define MMWFDSINK_GENERATE_DOT_IF_ENABLED(x_wfd_sink, x_name) \ + if (x_wfd_sink->ini.generate_dot) { \ + wfd_sink_debug("create dot file : %s.dot", x_name);\ + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(x_wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst), \ + GST_DEBUG_GRAPH_SHOW_ALL, x_name); \ + } + +/* postint message */ +#define MMWFDSINK_POST_MESSAGE(x_wfd_sink, x_error_type, x_state_type) \ + if (x_wfd_sink->msg_cb) { \ + wfd_sink_debug("Message(error : %d, state : %d) will be posted using user callback\n", x_error_type, x_state_type); \ + x_wfd_sink->msg_cb(x_error_type, x_state_type, x_wfd_sink->msg_user_data); \ + } + + +/* state */ +#define MMWFDSINK_CURRENT_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.state +#define MMWFDSINK_PREVIOUS_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.prev_state +#define MMWFDSINK_PENDING_STATE(x_wfd_sink) ((mm_wfd_sink_t *)x_wfd_sink)->state.pending_state +#define MMWFDSINK_STATE_GET_NAME(x_state) _mm_wfds_sink_get_state_name(x_state) + +#define MMWFDSINK_PRINT_STATE(x_wfd_sink) \ + wfd_sink_debug("--prev %s, current %s, pending %s--\n", \ + MMWFDSINK_STATE_GET_NAME(MMWFDSINK_PREVIOUS_STATE(x_wfd_sink)), \ + MMWFDSINK_STATE_GET_NAME(MMWFDSINK_CURRENT_STATE(x_wfd_sink)), \ + MMWFDSINK_STATE_GET_NAME(MMWFDSINK_PENDING_STATE(x_wfd_sink))); + +#define MMWFDSINK_CHECK_STATE(x_wfd_sink, x_cmd) \ + switch (__mm_wfd_sink_check_state((mm_wfd_sink_t *)x_wfd_sink, x_cmd)) \ + { \ + case MM_ERROR_NONE: \ + break;\ + case MM_ERROR_WFD_NO_OP: \ + return MM_ERROR_NONE; \ + break; \ + default: \ + return MM_ERROR_WFD_INVALID_STATE; \ + break; \ + } + + +/* pad probe */ +void +mm_wfd_sink_util_add_pad_probe(GstPad *pad, GstElement *element, const gchar *pad_name); +void +mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer(GstPad *pad, GstElement *element, const gchar *pad_name); + +#define MMWFDSINK_PAD_PROBE(x_wfd_sink, x_pad, x_element, x_pad_name) \ + if (x_wfd_sink) { \ + if (x_wfd_sink->ini.enable_pad_probe) { \ + mm_wfd_sink_util_add_pad_probe(x_pad, x_element, (const gchar*)x_pad_name); \ + } else {\ + mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer (x_pad, x_element, (const gchar*)x_pad_name); \ + }\ + } + +void +mm_wfd_sink_util_add_pad_probe_for_data_dump(GstElement *element, const gchar *pad_name); + +#define MMWFDSINK_TS_DATA_DUMP(x_wfd_sink, x_element, x_pad_name) \ + if (x_wfd_sink && x_wfd_sink->ini.enable_ts_data_dump) { \ + mm_wfd_sink_util_add_pad_probe_for_data_dump (x_element, (const gchar*)x_pad_name); \ + } + +#endif diff --git a/src/include/mm_wfd_sink_wayland.h b/src/include/mm_wfd_sink_wayland.h new file mode 100755 index 0000000..d3e6da6 --- /dev/null +++ b/src/include/mm_wfd_sink_wayland.h @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef __MM_WFD_SINK_WLCLIENT_H__ +#define __MM_WFD_SINK_WLCLIENT_H__ +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct +{ + struct wl_display *display; + struct wl_registry *registry; + struct tizen_surface *tz_surface; + struct tizen_resource *tz_resource; +} wl_client; + +int mm_wfd_sink_wlclient_create (wl_client ** wlclient); +int mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wl_client * wlclient, struct wl_surface *surface, struct wl_display *display); +void mm_wfd_sink_wlclient_finalize (wl_client * wlclient); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_WFD_SINK_WLCLIENT_H__ */ diff --git a/src/mm_wfd_sink.c b/src/mm_wfd_sink.c new file mode 100755 index 0000000..fd0d335 --- /dev/null +++ b/src/mm_wfd_sink.c @@ -0,0 +1,450 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include "mm_wfd_sink_util.h" +#include "mm_wfd_sink.h" +#include "mm_wfd_sink_priv.h" +#include "mm_wfd_sink_dlog.h" + +int mm_wfd_sink_create(MMHandleType *wfd_sink) +{ + mm_wfd_sink_t *new_wfd_sink = NULL; + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + result = _mm_wfd_sink_create(&new_wfd_sink); + if (result != MM_ERROR_NONE) { + wfd_sink_error("fail to create wi-fi display sink handle. ret[%d]", result); + *wfd_sink = (MMHandleType)NULL; + return result; + } + + /* init wfd lock */ + g_mutex_init(&new_wfd_sink->cmd_lock); + + *wfd_sink = (MMHandleType)new_wfd_sink; + + wfd_sink_debug_fleave(); + + return result; + +} + +int mm_wfd_sink_prepare(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_prepare((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_connect(MMHandleType wfd_sink, const char *uri) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(uri, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_connect((mm_wfd_sink_t *)wfd_sink, uri); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_start(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_start((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_pause(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_pause((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_resume(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_resume((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_disconnect(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_disconnect((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_unprepare(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_unprepare((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_destroy(MMHandleType wfd_sink) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *sink_handle = NULL; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_destroy((mm_wfd_sink_t *)wfd_sink); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + g_mutex_clear(&(((mm_wfd_sink_t *)wfd_sink)->cmd_lock)); + + sink_handle = (mm_wfd_sink_t *)wfd_sink; + MMWFDSINK_FREEIF(sink_handle); + + return result; +} + +int mm_wfd_sink_set_message_callback(MMHandleType wfd_sink, MMWFDMessageCallback callback, void *user_data) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_set_message_callback((mm_wfd_sink_t *)wfd_sink, callback, user_data); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_set_attribute(MMHandleType wfd_sink, char **err_attr_name, const char *first_attribute_name, ...) +{ + int result = MM_ERROR_NONE; + va_list var_args; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(first_attribute_name, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd_sink); + va_start(var_args, first_attribute_name); + result = _mmwfd_set_attribute(MMWFDSINK_GET_ATTRS(wfd_sink), err_attr_name, first_attribute_name, var_args); + va_end(var_args); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_get_video_resolution(MMHandleType wfd_sink, gint *width, gint *height) +{ + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(width, MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(height, MM_ERROR_WFD_INVALID_ARGUMENT); + + *width = wfd->stream_info.video_stream_info.width; + *height = wfd->stream_info.video_stream_info.height; + + return MM_ERROR_NONE; +} + +int mm_wfd_sink_get_video_framerate(MMHandleType wfd_sink, gint *frame_rate) +{ + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(frame_rate, MM_ERROR_WFD_INVALID_ARGUMENT); + + *frame_rate = wfd->stream_info.video_stream_info.frame_rate; + + return MM_ERROR_NONE; +} + +int mm_wfd_sink_set_resolution(MMHandleType wfd_sink, gint resolution) +{ + int result = MM_ERROR_NONE; + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + MMWFDSINK_CMD_LOCK(wfd_sink); + result = _mm_wfd_sink_set_resolution((mm_wfd_sink_t *)wfd_sink, resolution); + MMWFDSINK_CMD_UNLOCK(wfd_sink); + + return result; +} + +int mm_wfd_sink_get_negotiated_video_codec(MMHandleType wfd_sink, gint *codec) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(codec, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *codec = wfd->stream_info.video_stream_info.codec; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_video_resolution(MMHandleType wfd_sink, gint *width, gint *height) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(width, MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(height, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *width = wfd->stream_info.video_stream_info.width; + *height = wfd->stream_info.video_stream_info.height; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_video_frame_rate(MMHandleType wfd_sink, gint *frame_rate) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(frame_rate, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *frame_rate = wfd->stream_info.video_stream_info.frame_rate; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_audio_codec(MMHandleType wfd_sink, gint *codec) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(codec, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *codec = wfd->stream_info.audio_stream_info.codec; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_audio_channel(MMHandleType wfd_sink, gint *channel) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(channel, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *channel = wfd->stream_info.audio_stream_info.channels; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_audio_sample_rate(MMHandleType wfd_sink, gint *sample_rate) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(sample_rate, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *sample_rate = wfd->stream_info.audio_stream_info.sample_rate; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} + +int mm_wfd_sink_get_negotiated_audio_bitwidth(MMHandleType wfd_sink, gint *bitwidth) +{ + int result = MM_ERROR_NONE; + mm_wfd_sink_t *wfd = (mm_wfd_sink_t *)wfd_sink; + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(bitwidth, MM_ERROR_WFD_INVALID_ARGUMENT); + + MMWFDSINK_CMD_LOCK(wfd); + + MMWFDSINK_PRINT_STATE(wfd); + cur_state = MMWFDSINK_CURRENT_STATE(wfd); + if (cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_PAUSED) { + + wfd_sink_error("This function must be called after MM_WFD_SINK_STATE_CONNECTED"); + result = MM_ERROR_WFD_INVALID_STATE; + } else { + *bitwidth = wfd->stream_info.audio_stream_info.bitwidth; + } + + MMWFDSINK_CMD_UNLOCK(wfd); + + wfd_sink_debug_fleave(); + + return result; +} diff --git a/src/mm_wfd_sink_attrs.c b/src/mm_wfd_sink_attrs.c new file mode 100755 index 0000000..e328d6a --- /dev/null +++ b/src/mm_wfd_sink_attrs.c @@ -0,0 +1,552 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Manoj Kumar K , Hyunil Park + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mm_wfd_sink_attrs.h" + +typedef struct { + char *name; + int value_type; + int flags; /* r, w */ + void *default_value; + int valid_type; + int value_min; + int value_max; +} MMWfdAttrsSpec; + +/*static gboolean __mmwfd_apply_attribute(MMHandleType handle, const char *attribute_name); */ + +MMHandleType +_mmwfd_construct_attribute(MMHandleType handle) +{ + int idx = 0; + MMHandleType attrs = 0; + int num_of_attrs = 0; + mmf_attrs_construct_info_t *base = NULL; + + debug_fenter(); + + return_val_if_fail(handle, (MMHandleType) NULL); + + MMWfdAttrsSpec wfd_attrs[] = { + { + (char *)"server_ip", + MM_ATTRS_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void *)"127.0.0.1", + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, + + { + (char *)"server_port", + MM_ATTRS_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void *)"8554", + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, + + { + (char *)"max_client_count", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *)1, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 10 + }, + /* Initialized with invalid native type, if a valid value is set then only this atribute will be considered */ + { + (char *)"native_resolution", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 3 + }, + /* Initialized with invalid resolution, if a valid value is set then only this atribute will be considered */ + { + (char *)"prefered_resolutions", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *)2147483647, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 2147483647 + }, + /* Initialized with invalid uibc option, if a valid value is set then only this atribute will be considered */ + { + (char *)"set_hdcp", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *)2, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 2 + }, + { + (char *)"display_rotate", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 3 + }, + { + (char *)"display_src_crop_x", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_src_crop_y", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_src_crop_width", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_src_crop_height", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_roi_x", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_roi_y", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_roi_width", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 480, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_roi_height", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 800, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_roi_mode", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) MM_DISPLAY_METHOD_CUSTOM_ROI_FULL_SCREEN, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_METHOD_CUSTOM_ROI_FULL_SCREEN, + MM_DISPLAY_METHOD_CUSTOM_ROI_LETER_BOX + }, + { + (char *)"display_rotation", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) MM_DISPLAY_ROTATION_NONE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_ROTATION_NONE, + MM_DISPLAY_ROTATION_270 + }, + { + (char *)"display_visible", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) TRUE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1 + }, + { + (char *)"display_method", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) MM_DISPLAY_METHOD_LETTER_BOX, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_METHOD_LETTER_BOX, + MM_DISPLAY_METHOD_CUSTOM_ROI + }, + { + (char *)"display_overlay", + MM_ATTRS_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void *) NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, + { + (char *)"display_overlay_user_data", + MM_ATTRS_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void *) NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, + { + (char *)"display_zoom", + MM_ATTRS_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void *) 1, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + 1.0, + 9.0 + }, + { + (char *)"display_surface_type", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) MM_DISPLAY_SURFACE_OVERLAY, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_SURFACE_OVERLAY, + MM_DISPLAY_SURFACE_REMOTE + }, + { + (char *)"display_width", /* dest width of fimcconvert ouput */ + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_height", /* dest height of fimcconvert ouput */ + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_evas_do_scaling", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) TRUE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + FALSE, + TRUE + }, + { + (char *)"display_x", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"display_y", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 4096 + }, + { + (char *)"hdcp_version", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 2 + }, + { + (char *)"hdcp_port", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 2147483647 + }, + }; + + num_of_attrs = ARRAY_SIZE(wfd_attrs); + + base = (mmf_attrs_construct_info_t *)malloc(num_of_attrs * sizeof(mmf_attrs_construct_info_t)); + + if (!base) { + debug_error("Cannot create mmwfd attribute\n"); + goto ERROR; + } + + /* initialize values of attributes */ + for (idx = 0; idx < num_of_attrs; idx++) { + base[idx].name = wfd_attrs[idx].name; + base[idx].value_type = wfd_attrs[idx].value_type; + base[idx].flags = wfd_attrs[idx].flags; + base[idx].default_value = wfd_attrs[idx].default_value; + } + + attrs = mmf_attrs_new_from_data( + "mmwfd_attrs", + base, + num_of_attrs, + NULL, + NULL); + + if (base) { + g_free(base); + base = NULL; + } + + if (!attrs) { + debug_error("Cannot create mmwfd attribute\n"); + goto ERROR; + } + + /* set validity type and range */ + for (idx = 0; idx < num_of_attrs; idx++) { + switch (wfd_attrs[idx].valid_type) { + case MM_ATTRS_VALID_TYPE_INT_RANGE: { + mmf_attrs_set_valid_type(attrs, idx, MM_ATTRS_VALID_TYPE_INT_RANGE); + mmf_attrs_set_valid_range(attrs, idx, + wfd_attrs[idx].value_min, + wfd_attrs[idx].value_max, + (int)wfd_attrs[idx].default_value); + } + break; + + case MM_ATTRS_VALID_TYPE_INT_ARRAY: + case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: + case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: + default: + break; + } + } + + debug_fleave(); + + return attrs; + +ERROR: + _mmwfd_deconstruct_attribute(attrs); + + return (MMHandleType)NULL; +} + +void +_mmwfd_deconstruct_attribute(MMHandleType handle) +{ + debug_fenter(); + + return_if_fail(handle); + + if (handle) + mmf_attrs_free(handle); + + debug_fleave(); +} + +int +_mmwfd_get_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list) +{ + int result = MM_ERROR_NONE; + MMHandleType attrs = 0; + + debug_fenter(); + + /* NOTE : Don't need to check err_attr_name because it can be set NULL */ + /* if it's not want to know it. */ + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); + + attrs = handle; + + return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); + + result = mm_attrs_get_valist(attrs, err_attr_name, attribute_name, args_list); + + if (result != MM_ERROR_NONE) + debug_error("failed to get %s attribute\n", attribute_name); + + debug_fleave(); + + return result; +} + +int +_mmwfd_set_attribute(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list args_list) +{ + int result = MM_ERROR_NONE; + MMHandleType attrs = 0; + + debug_fenter(); + + /* NOTE : Don't need to check err_attr_name because it can be set NULL */ + /* if it's not want to know it. */ + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); + + attrs = handle; + + return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); + + /* set attributes and commit them */ + result = mm_attrs_set_valist(attrs, err_attr_name, attribute_name, args_list); + + if (result != MM_ERROR_NONE) { + debug_error("failed to set %s attribute\n", attribute_name); + return result; + } + + /*__mmwfd_apply_attribute(handle, attribute_name); */ + + debug_fleave(); + + return result; +} + +/* Currently not used. */ +/*static gboolean +__mmwfd_apply_attribute(MMHandleType handle, const char *attribute_name) +{ + MMHandleType attrs = 0; + mm_wfd_t* wfd = 0; + + debug_fenter(); + + return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + attrs = handle; + + return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); + + wfd = (mm_wfd_t*)handle; + + // TODO: This function is not useful at this moment + + debug_fleave(); + + return TRUE; +}*/ + +int +_mmwfd_get_attributes_info(MMHandleType handle, const char *attribute_name, MMWfdAttrsInfo *dst_info) +{ + int result = MM_ERROR_NONE; + MMHandleType attrs = 0; + MMAttrsInfo src_info = {0, }; + + debug_fenter(); + + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(dst_info, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); + + attrs = handle; + + return_val_if_fail(attrs, MM_ERROR_COMMON_INVALID_ARGUMENT); + + result = mm_attrs_get_info_by_name(attrs, attribute_name, &src_info); + + if (result != MM_ERROR_NONE) { + debug_error("failed to get attribute info\n"); + return result; + } + + memset(dst_info, 0x00, sizeof(MMWfdAttrsInfo)); + + dst_info->type = src_info.type; + dst_info->flag = src_info.flag; + dst_info->validity_type = src_info.validity_type; + + switch (src_info.validity_type) { + case MM_ATTRS_VALID_TYPE_INT_ARRAY: + dst_info->int_array.array = src_info.int_array.array; + dst_info->int_array.count = src_info.int_array.count; + dst_info->int_array.d_val = src_info.int_array.dval; + break; + + case MM_ATTRS_VALID_TYPE_INT_RANGE: + dst_info->int_range.min = src_info.int_range.min; + dst_info->int_range.max = src_info.int_range.max; + dst_info->int_range.d_val = src_info.int_range.dval; + break; + + case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: + dst_info->double_array.array = src_info.double_array.array; + dst_info->double_array.count = src_info.double_array.count; + dst_info->double_array.d_val = src_info.double_array.dval; + break; + + case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: + dst_info->double_range.min = src_info.double_range.min; + dst_info->double_range.max = src_info.double_range.max; + dst_info->double_range.d_val = src_info.double_range.dval; + break; + + default: + break; + } + + debug_fleave(); + + return result; +} + + diff --git a/src/mm_wfd_sink_ini.c b/src/mm_wfd_sink_ini.c new file mode 100755 index 0000000..24b7de4 --- /dev/null +++ b/src/mm_wfd_sink_ini.c @@ -0,0 +1,374 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Manoj Kumar K , Hyunil Park + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include "mm_wfd_sink_ini.h" +#include "mm_wfd_sink_dlog.h" + +static gboolean loaded = FALSE; + +/* global variables here */ +#ifdef MM_WFD_SINK_DEFAULT_INI +static gboolean __generate_sink_default_ini(void); +#endif + +static void __mm_wfd_sink_ini_check_status(void); + +/* macro */ +#define MM_WFD_SINK_INI_GET_STRING(x_dict, x_item, x_ini, x_default) \ + do { \ + gchar *str = NULL; \ + gint length = 0; \ + \ + str = iniparser_getstring(x_dict, x_ini, (char *)x_default); \ + if (str) { \ + length = strlen(str); \ + if ((length > 1) && (length < WFD_SINK_INI_MAX_STRLEN)) \ + strncpy(x_item, str, WFD_SINK_INI_MAX_STRLEN-1); \ + else \ + strncpy(x_item, x_default, WFD_SINK_INI_MAX_STRLEN-1); \ + } else { \ + strncpy(x_item, x_default, WFD_SINK_INI_MAX_STRLEN-1); \ + } \ + } while (0); + +#ifdef MM_WFD_SINK_DEFAULT_INI +static +gboolean __generate_sink_default_ini(void) +{ + FILE *fp = NULL; + const gchar *default_ini = MM_WFD_SINK_DEFAULT_INI; + + + /* create new file */ + fp = fopen(MM_WFD_SINK_INI_DEFAULT_PATH, "wt"); + + if (!fp) { + return FALSE; + } + + /* writing default ini file */ + if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) { + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} +#endif + +int +mm_wfd_sink_ini_load(mm_wfd_sink_ini_t *ini) +{ + dictionary *dict = NULL; + + wfd_sink_debug_fenter(); + + + __mm_wfd_sink_ini_check_status(); + + /* first, try to load existing ini file */ + dict = iniparser_load(MM_WFD_SINK_INI_DEFAULT_PATH); + + /* if no file exists. create one with set of default values */ + if (!dict) { +#ifdef MM_WFD_SINK_DEFAULT_INI + wfd_sink_debug("No inifile found. create default ini file.\n"); + if (FALSE == __generate_sink_default_ini()) { + wfd_sink_error("Creating default ini file failed. Use default values.\n"); + } else { + /* load default ini */ + dict = iniparser_load(MM_WFD_SINK_INI_DEFAULT_PATH); + } +#else + wfd_sink_error("No ini file found. \n"); + + return MM_ERROR_FILE_NOT_FOUND; +#endif + } + + /* get ini values */ + memset(ini, 0, sizeof(mm_wfd_sink_ini_t)); + + if (dict) { /* if dict is available */ + /* general */ + MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[0], "general:gstparam1", DEFAULT_GST_PARAM); + MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[1], "general:gstparam2", DEFAULT_GST_PARAM); + MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[2], "general:gstparam3", DEFAULT_GST_PARAM); + MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[3], "general:gstparam4", DEFAULT_GST_PARAM); + MM_WFD_SINK_INI_GET_STRING(dict, ini->gst_param[4], "general:gstparam5", DEFAULT_GST_PARAM); + ini->generate_dot = iniparser_getboolean(dict, "general:generate dot", DEFAULT_GENERATE_DOT); + ini->enable_pad_probe = iniparser_getboolean(dict, "general:enable pad probe", DEFAULT_ENABLE_PAD_PROBE); + ini->state_change_timeout = iniparser_getint(dict, "general:state change timeout", DEFAULT_STATE_CHANGE_TIMEOUT); + ini->set_debug_property = iniparser_getboolean(dict, "general:set debug property", DEFAULT_SET_DEBUG_PROPERTY); + ini->enable_asm = iniparser_getboolean(dict, "general:enable asm", DEFAULT_ENABLE_ASM); + ini->jitter_buffer_latency = iniparser_getint(dict, "general:jitter buffer latency", DEFAULT_JITTER_BUFFER_LATENCY); + ini->enable_retransmission = iniparser_getboolean(dict, "general:enable retransmission", DEFAULT_ENABLE_RETRANSMISSION); + ini->enable_reset_basetime = iniparser_getboolean(dict, "general:enable reset basetime", DEFAULT_ENABLE_RESET_BASETIME); + ini->video_sink_max_lateness = iniparser_getint(dict, "general:video sink max lateness", DEFAULT_VIDEO_SINK_MAX_LATENESS); + ini->sink_ts_offset = iniparser_getint(dict, "general:sink ts offset", DEFAULT_SINK_TS_OFFSET); + ini->audio_sink_async = iniparser_getboolean(dict, "general:audio sink async", DEFAULT_AUDIO_SINK_ASYNC); + ini->video_sink_async = iniparser_getboolean(dict, "general:video sink async", DEFAULT_VIDEO_SINK_ASYNC); + ini->enable_ts_data_dump = iniparser_getboolean(dict, "general:enable ts data dump", DEFAULT_ENABLE_TS_DATA_DUMP); + ini->enable_wfdsrc_pad_probe = iniparser_getboolean(dict, "general:enable wfdsrc pad probe", DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE); + + + /* pipeline */ + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_source, "pipeline:wfdsrc element", DEFAULT_NAME_OF_SOURCE); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_tsdemux, "pipeline:tsdemux element", DEFAULT_NAME_OF_TSDEMUX); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_hdcp, "pipeline:audio hdcp element", DEFAULT_NAME_OF_AUDIO_HDCP); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_aac_parser, "pipeline:aac parser element", DEFAULT_NAME_OF_AAC_PARSER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_aac_decoder, "pipeline:aac decoder element", DEFAULT_NAME_OF_AAC_DECODER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_ac3_parser, "pipeline:ac3 parser element", DEFAULT_NAME_OF_AC3_PARSER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_ac3_decoder, "pipeline:ac3 decoder element", DEFAULT_NAME_OF_AC3_DECODER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_lpcm_converter, "pipeline:lpcm converter element", DEFAULT_NAME_OF_LPCM_CONVERTER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_lpcm_filter, "pipeline:lpcm filter element", DEFAULT_NAME_OF_LPCM_FILTER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_resampler, "pipeline:audio resampler element", DEFAULT_NAME_OF_AUDIO_RESAMPLER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_volume, "pipeline:audio volume element", DEFAULT_NAME_OF_AUDIO_VOLUME); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_audio_sink, "pipeline:audio sink element", DEFAULT_NAME_OF_AUDIO_SINK); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_hdcp, "pipeline:video hdcp element", DEFAULT_NAME_OF_VIDEO_HDCP); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_parser, "pipeline:video parser element", DEFAULT_NAME_OF_VIDEO_PARSER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_capssetter, "pipeline:video capssetter element", DEFAULT_NAME_OF_VIDEO_CAPSSETTER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_decoder, "pipeline:video decoder element", DEFAULT_NAME_OF_VIDEO_DECODER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_converter, "pipeline:video converter element", DEFAULT_NAME_OF_VIDEO_CONVERTER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_filter, "pipeline:video filter element", DEFAULT_NAME_OF_VIDEO_FILTER); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_sink, "pipeline:video sink element", DEFAULT_NAME_OF_VIDEO_SINK); + MM_WFD_SINK_INI_GET_STRING(dict, ini->name_of_video_evas_sink, "pipeline:video evas sink element", DEFAULT_NAME_OF_EVAS_VIDEO_SINK); + + /* audio parameter*/ + ini->audio_codec = iniparser_getint(dict, "audio param:audio codec", DEFAULT_AUDIO_CODEC); + ini->audio_latency = iniparser_getint(dict, "audio param:audio latency", DEFAULT_AUDIO_LATENCY); + ini->audio_channel = iniparser_getint(dict, "audio param:audio channels", DEFAULT_AUDIO_CHANNELS); + ini->audio_sampling_frequency = iniparser_getint(dict, "audio param:audio sampling frequency", DEFAULT_AUDIO_SAMP_FREQUENCY); + + /* video parameter*/ + ini->video_codec = iniparser_getint(dict, "video param:video codec", DEFAULT_VIDEO_CODEC); + ini->video_native_resolution = iniparser_getint(dict, "video param:video native resolution", DEFAULT_VIDEO_NATIVE_RESOLUTION); + ini->video_cea_support = iniparser_getint(dict, "video param:video cea support", DEFAULT_VIDEO_CEA_SUPPORT); + ini->video_vesa_support = iniparser_getint(dict, "video param:video vesa support", DEFAULT_VIDEO_VESA_SUPPORT); + ini->video_hh_support = iniparser_getint(dict, "video param:video hh support", DEFAULT_VIDEO_HH_SUPPORT); + ini->video_profile = iniparser_getint(dict, "video param:video profile", DEFAULT_VIDEO_PROFILE); + ini->video_level = iniparser_getint(dict, "video param:video level", DEFAULT_VIDEO_LEVEL); + ini->video_latency = iniparser_getint(dict, "video param:video latency", DEFAULT_VIDEO_LATENCY); + ini->video_vertical_resolution = iniparser_getint(dict, "video param:video vertical resolution", DEFAULT_VIDEO_VERTICAL_RESOLUTION); + ini->video_horizontal_resolution = iniparser_getint(dict, "video param:video horizontal resolution", DEFAULT_VIDEO_HORIZONTAL_RESOLUTION); + ini->video_minimum_slicing = iniparser_getint(dict, "video param:video minimum slicesize", DEFAULT_VIDEO_MIN_SLICESIZE); + ini->video_slice_enc_param = iniparser_getint(dict, "video param:video slice encoding params", DEFAULT_VIDEO_SLICE_ENC_PARAM); + ini->video_framerate_control_support = iniparser_getint(dict, "video param:video framerate control support", DEFAULT_VIDEO_FRAMERATE_CONTROL); + + /* hdcp parameter*/ + ini->hdcp_content_protection = iniparser_getint(dict, "hdcp param:hdcp content protection", DEFAULT_HDCP_CONTENT_PROTECTION); + ini->hdcp_port_no = iniparser_getint(dict, "hdcp param:hdcp port no", DEFAULT_HDCP_PORT_NO); + } else { /* if dict is not available just fill the structure with default value */ + wfd_sink_error("failed to load ini. using hardcoded default\n"); + + /* general */ + strncpy(ini->gst_param[0], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->gst_param[1], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->gst_param[2], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->gst_param[3], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->gst_param[4], DEFAULT_GST_PARAM, WFD_SINK_INI_MAX_STRLEN - 1); + ini->generate_dot = DEFAULT_GENERATE_DOT; + ini->enable_pad_probe = DEFAULT_ENABLE_PAD_PROBE; + ini->state_change_timeout = DEFAULT_STATE_CHANGE_TIMEOUT; + ini->set_debug_property = DEFAULT_SET_DEBUG_PROPERTY; + ini->enable_asm = DEFAULT_ENABLE_ASM; + ini->jitter_buffer_latency = DEFAULT_JITTER_BUFFER_LATENCY; + ini->enable_retransmission = DEFAULT_ENABLE_RETRANSMISSION; + ini->enable_reset_basetime = DEFAULT_ENABLE_RESET_BASETIME; + ini->video_sink_max_lateness = DEFAULT_VIDEO_SINK_MAX_LATENESS; + ini->sink_ts_offset = DEFAULT_SINK_TS_OFFSET; + ini->enable_ts_data_dump = DEFAULT_ENABLE_TS_DATA_DUMP; + ini->enable_wfdsrc_pad_probe = DEFAULT_ENABLE_WFDRTSPSRC_PAD_PROBE; + + /* pipeline */ + strncpy(ini->name_of_source, DEFAULT_NAME_OF_TSDEMUX, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_tsdemux, DEFAULT_NAME_OF_TSDEMUX, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_audio_hdcp, DEFAULT_NAME_OF_AUDIO_HDCP, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_aac_parser, DEFAULT_NAME_OF_AAC_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_aac_decoder, DEFAULT_NAME_OF_AAC_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_ac3_parser, DEFAULT_NAME_OF_AC3_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_ac3_decoder, DEFAULT_NAME_OF_AC3_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_lpcm_converter, DEFAULT_NAME_OF_LPCM_CONVERTER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_lpcm_filter, DEFAULT_NAME_OF_LPCM_FILTER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_audio_resampler, DEFAULT_NAME_OF_AUDIO_RESAMPLER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_audio_volume, DEFAULT_NAME_OF_AUDIO_VOLUME, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_audio_sink, DEFAULT_NAME_OF_AUDIO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_hdcp, DEFAULT_NAME_OF_VIDEO_HDCP, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_parser, DEFAULT_NAME_OF_VIDEO_PARSER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_capssetter, DEFAULT_NAME_OF_VIDEO_CAPSSETTER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_decoder, DEFAULT_NAME_OF_VIDEO_DECODER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_converter, DEFAULT_NAME_OF_VIDEO_CONVERTER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_filter, DEFAULT_NAME_OF_VIDEO_FILTER, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_sink, DEFAULT_NAME_OF_VIDEO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); + strncpy(ini->name_of_video_evas_sink, DEFAULT_NAME_OF_EVAS_VIDEO_SINK, WFD_SINK_INI_MAX_STRLEN - 1); + + /* audio parameter*/ + ini->audio_codec = DEFAULT_AUDIO_CODEC; + ini->audio_latency = DEFAULT_AUDIO_LATENCY; + ini->audio_channel = DEFAULT_AUDIO_CHANNELS; + ini->audio_sampling_frequency = DEFAULT_AUDIO_SAMP_FREQUENCY; + + /* video parameter*/ + ini->video_codec = DEFAULT_VIDEO_CODEC; + ini->video_native_resolution = DEFAULT_VIDEO_NATIVE_RESOLUTION; + ini->video_cea_support = DEFAULT_VIDEO_CEA_SUPPORT; + ini->video_vesa_support = DEFAULT_VIDEO_VESA_SUPPORT; + ini->video_hh_support = DEFAULT_VIDEO_HH_SUPPORT; + ini->video_profile = DEFAULT_VIDEO_PROFILE; + ini->video_level = DEFAULT_VIDEO_LEVEL; + ini->video_latency = DEFAULT_VIDEO_LATENCY; + ini->video_vertical_resolution = DEFAULT_VIDEO_VERTICAL_RESOLUTION; + ini->video_horizontal_resolution = DEFAULT_VIDEO_HORIZONTAL_RESOLUTION; + ini->video_minimum_slicing = DEFAULT_VIDEO_MIN_SLICESIZE; + ini->video_slice_enc_param = DEFAULT_VIDEO_SLICE_ENC_PARAM; + ini->video_framerate_control_support = DEFAULT_VIDEO_FRAMERATE_CONTROL; + + /* hdcp parameter*/ + ini->hdcp_content_protection = DEFAULT_HDCP_CONTENT_PROTECTION; + ini->hdcp_port_no = DEFAULT_HDCP_PORT_NO; + } + + /* free dict as we got our own structure */ + iniparser_freedict(dict); + + + /* dump structure */ + wfd_sink_debug("W-Fi Display Sink Initial Settings-----------------------------------\n"); + + /* general */ + wfd_sink_debug("gst_param1 : %s\n", ini->gst_param[0]); + wfd_sink_debug("gst_param2 : %s\n", ini->gst_param[1]); + wfd_sink_debug("gst_param3 : %s\n", ini->gst_param[2]); + wfd_sink_debug("gst_param4 : %s\n", ini->gst_param[3]); + wfd_sink_debug("gst_param5 : %s\n", ini->gst_param[4]); + wfd_sink_debug("generate_dot : %d\n", ini->generate_dot); + if (ini->generate_dot == TRUE) { + wfd_sink_debug("generate_dot is TRUE, dot file will be stored into /tmp/\n"); + g_setenv("GST_DEBUG_DUMP_DOT_DIR", "/tmp/", FALSE); + } + wfd_sink_debug("enable_pad_probe : %d\n", ini->enable_pad_probe); + wfd_sink_debug("state_change_timeout(sec) : %d\n", ini->state_change_timeout); + wfd_sink_debug("set_debug_property : %d\n", ini->set_debug_property); + wfd_sink_debug("enable_asm : %d\n", ini->enable_asm); + wfd_sink_debug("jitter_buffer_latency(msec) : %d\n", ini->jitter_buffer_latency); + wfd_sink_debug("enable_retransmission : %d\n", ini->enable_retransmission); + wfd_sink_debug("enable_reset_basetime : %d\n", ini->enable_reset_basetime); + wfd_sink_debug("video_sink_max_lateness(nsec) : %d\n", ini->video_sink_max_lateness); + wfd_sink_debug("sink_ts_offset(nsec) : %d\n", ini->sink_ts_offset); + wfd_sink_debug("audio_sink_async : %d\n", ini->audio_sink_async); + wfd_sink_debug("video_sink_async : %d\n", ini->video_sink_async); + wfd_sink_debug("enable_ts_data_dump : %d\n", ini->enable_ts_data_dump); + wfd_sink_debug("enable_wfdsrc_pad_probe : %d\n", ini->enable_wfdsrc_pad_probe); + + /* pipeline */ + wfd_sink_debug("name_of_source : %s\n", ini->name_of_source); + wfd_sink_debug("name_of_tsdemux : %s\n", ini->name_of_tsdemux); + wfd_sink_debug("name_of_audio_hdcp : %s\n", ini->name_of_audio_hdcp); + wfd_sink_debug("name_of_aac_parser : %s\n", ini->name_of_aac_parser); + wfd_sink_debug("name_of_aac_decoder : %s\n", ini->name_of_aac_decoder); + wfd_sink_debug("name_of_ac3_parser : %s\n", ini->name_of_ac3_parser); + wfd_sink_debug("name_of_ac3_decoder : %s\n", ini->name_of_ac3_decoder); + wfd_sink_debug("name_of_lpcm_converter : %s\n", ini->name_of_lpcm_converter); + wfd_sink_debug("name_of_lpcm_filter : %s\n", ini->name_of_lpcm_filter); + wfd_sink_debug("name_of_audio_resampler : %s\n", ini->name_of_audio_resampler); + wfd_sink_debug("name_of_audio_volume : %s\n", ini->name_of_audio_volume); + wfd_sink_debug("name_of_audio_sink : %s\n", ini->name_of_audio_sink); + wfd_sink_debug("name_of_video_hdcp : %s\n", ini->name_of_video_hdcp); + wfd_sink_debug("name_of_video_parser : %s\n", ini->name_of_video_parser); + wfd_sink_debug("name_of_video_capssetter : %s\n", ini->name_of_video_capssetter); + wfd_sink_debug("name_of_video_decoder : %s\n", ini->name_of_video_decoder); + wfd_sink_debug("name_of_video_converter : %s\n", ini->name_of_video_converter); + wfd_sink_debug("name_of_video_filter : %s\n", ini->name_of_video_filter); + wfd_sink_debug("name_of_video_sink : %s\n", ini->name_of_video_sink); + wfd_sink_debug("name_of_video_evas_sink : %s\n", ini->name_of_video_evas_sink); + + /* audio parameter*/ + wfd_sink_debug("audio_codec : %x\n", ini->audio_codec); + wfd_sink_debug("audio_latency : %d\n", ini->audio_latency); + wfd_sink_debug("audio_channel : %x\n", ini->audio_channel); + wfd_sink_debug("audio_sampling_frequency : %x\n", ini->audio_sampling_frequency); + + /* video parameter*/ + wfd_sink_debug("video_codec : %x\n", ini->video_codec); + wfd_sink_debug("video_native_resolution : %x\n", ini->video_native_resolution); + wfd_sink_debug("video_cea_support : %x\n", ini->video_cea_support); + wfd_sink_debug("video_vesa_support : %x\n", ini->video_vesa_support); + wfd_sink_debug("video_hh_support : %x\n", ini->video_hh_support); + wfd_sink_debug("video_profile : %x\n", ini->video_profile); + wfd_sink_debug("video_level : %x\n", ini->video_level); + wfd_sink_debug("video_latency : %d\n", ini->video_latency); + wfd_sink_debug("video_vertical_resolution : %d\n", ini->video_vertical_resolution); + wfd_sink_debug("video_horizontal_resolution : %d\n", ini->video_horizontal_resolution); + wfd_sink_debug("video_minimum_slicing : %d\n", ini->video_minimum_slicing); + wfd_sink_debug("video_slice_enc_param : %d\n", ini->video_slice_enc_param); + wfd_sink_debug("video_framerate_control_support : %d\n", ini->video_framerate_control_support); + + /* hdcp parameter*/ + wfd_sink_debug("hdcp_content_protection : %x\n", ini->hdcp_content_protection); + wfd_sink_debug("hdcp_port_no : %d\n", ini->hdcp_port_no); + + wfd_sink_debug("---------------------------------------------------\n"); + + loaded = TRUE; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + + +static +void __mm_wfd_sink_ini_check_status(void) +{ + struct stat ini_buff; + + wfd_sink_debug_fenter(); + + if (g_stat(MM_WFD_SINK_INI_DEFAULT_PATH, &ini_buff) < 0) { + wfd_sink_error("failed to get mmfw_wfd_sink ini status\n"); + } else { + if (ini_buff.st_size < 5) { + wfd_sink_error("mmfw_wfd_sink.ini file size=%d, Corrupted! So, Removed\n", (int)ini_buff.st_size); + g_remove(MM_WFD_SINK_INI_DEFAULT_PATH); + } + } + + wfd_sink_debug_fleave(); +} + +int +mm_wfd_sink_ini_unload(mm_wfd_sink_ini_t *ini) +{ + wfd_sink_debug_fenter(); + + loaded = FALSE; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} diff --git a/src/mm_wfd_sink_manager.c b/src/mm_wfd_sink_manager.c new file mode 100755 index 0000000..3eb86f9 --- /dev/null +++ b/src/mm_wfd_sink_manager.c @@ -0,0 +1,169 @@ +/* + * libmm-wfd + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "mm_wfd_sink_manager.h" + + +static gpointer __mm_wfd_sink_manager_thread(gpointer data); + +int _mm_wfd_sink_init_manager(mm_wfd_sink_t *wfd_sink) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* create manager mutex */ + g_mutex_init(&(wfd_sink->manager_thread_mutex)); + + /* create capture cond */ + g_cond_init(&(wfd_sink->manager_thread_cond)); + + wfd_sink->manager_thread_cmd = NULL; + wfd_sink->manager_thread_exit = FALSE; + + /* create manager thread */ + wfd_sink->manager_thread = + g_thread_new("__mm_wfd_sink_manager_thread", __mm_wfd_sink_manager_thread, (gpointer)wfd_sink); + if (wfd_sink->manager_thread == NULL) { + wfd_sink_error("failed to create manager thread\n"); + goto failed_to_init; + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + +failed_to_init: + g_mutex_clear(&(wfd_sink->manager_thread_mutex)); + g_cond_clear(&(wfd_sink->manager_thread_cond)); + + return MM_ERROR_WFD_INTERNAL; +} + +int _mm_wfd_sink_release_manager(mm_wfd_sink_t *wfd_sink) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* release manager thread */ + if (wfd_sink->manager_thread) { + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); + + wfd_sink_debug("waitting for manager thread exit"); + g_thread_join(wfd_sink->manager_thread); + g_mutex_clear(&(wfd_sink->manager_thread_mutex)); + g_cond_clear(&(wfd_sink->manager_thread_cond)); + wfd_sink_debug("manager thread released"); + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static gpointer +__mm_wfd_sink_manager_thread(gpointer data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data; + WFDSinkManagerCMDType cmd = WFD_SINK_MANAGER_CMD_NONE; + GList *walk = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, NULL); + + if (wfd_sink->manager_thread_exit) { + wfd_sink_debug("exit manager thread..."); + return NULL; + } + + wfd_sink_debug("manager thread started. waiting for signal"); + + while (TRUE) { + WFD_SINK_MANAGER_LOCK(wfd_sink); + WFD_SINK_MANAGER_WAIT_CMD(wfd_sink); + + for (walk = wfd_sink->manager_thread_cmd; walk; walk = g_list_next(walk)) { + cmd = GPOINTER_TO_INT(walk->data); + + wfd_sink_debug("got command %d", cmd); + + switch (cmd) { + case WFD_SINK_MANAGER_CMD_LINK_A_DECODEBIN: + wfd_sink_debug("try to link audio decodebin."); + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_LINK_V_DECODEBIN: + wfd_sink_debug("try to link video decodebin."); + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE: + wfd_sink_debug("try to prepare audio pipeline."); + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare audio pipeline.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE: + wfd_sink_debug("try to prepare video pipeline."); + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare video pipeline.....\n"); + goto EXIT; + } + break; + case WFD_SINK_MANAGER_CMD_EXIT: + wfd_sink_debug("exiting manager thread"); + goto EXIT; + break; + default: + break; + } + } + + g_list_free(wfd_sink->manager_thread_cmd); + wfd_sink->manager_thread_cmd = NULL; + + WFD_SINK_MANAGER_UNLOCK(wfd_sink); + } + + wfd_sink_debug_fleave(); + + return NULL; + +EXIT: + wfd_sink->manager_thread_exit = TRUE; + g_list_free(wfd_sink->manager_thread_cmd); + wfd_sink->manager_thread_cmd = NULL; + WFD_SINK_MANAGER_UNLOCK(wfd_sink); + + return NULL; +} + diff --git a/src/mm_wfd_sink_priv.c b/src/mm_wfd_sink_priv.c new file mode 100755 index 0000000..dc17608 --- /dev/null +++ b/src/mm_wfd_sink_priv.c @@ -0,0 +1,3689 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "mm_wfd_sink_util.h" +#include "mm_wfd_sink_priv.h" +#include "mm_wfd_sink_manager.h" +#include "mm_wfd_sink_dlog.h" +#include "mm_wfd_sink_enum.h" +#include "mm_wfd_sink_wayland.h" + +/* gstreamer */ +static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink); +static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async); + +/* state */ +static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd); +static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state); + +/* util */ +static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink); +static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution); + +int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + mm_wfd_sink_t *new_wfd_sink = NULL; + + /* create handle */ + new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t)); + if (!new_wfd_sink) { + wfd_sink_error("failed to allocate memory for wi-fi display sink"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + /* Initialize gstreamer related */ + new_wfd_sink->attrs = 0; + + new_wfd_sink->pipeline = NULL; + new_wfd_sink->audio_decodebin_is_linked = FALSE; + new_wfd_sink->video_decodebin_is_linked = FALSE; + + /* Initialize timestamp compensation related */ + new_wfd_sink->need_to_reset_basetime = FALSE; + new_wfd_sink->clock = NULL; + new_wfd_sink->video_buffer_count = 0LL; + new_wfd_sink->video_average_gap = 0LL; + new_wfd_sink->video_accumulated_gap = 0LL; + new_wfd_sink->audio_buffer_count = 0LL; + new_wfd_sink->audio_average_gap = 0LL; + new_wfd_sink->audio_accumulated_gap = 0LL; + new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE; + + /* Initialize all states */ + MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; + MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; + MMWFDSINK_PENDING_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE; + + /* initialize audio/video information */ + new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE; + new_wfd_sink->stream_info.audio_stream_info.channels = 0; + new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0; + new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0; + new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE; + new_wfd_sink->stream_info.video_stream_info.width = 0; + new_wfd_sink->stream_info.video_stream_info.height = 0; + new_wfd_sink->stream_info.video_stream_info.frame_rate = 0; + + /* Initialize command */ + new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE; + new_wfd_sink->waiting_cmd = FALSE; + + /* Initialize manager related */ + new_wfd_sink->manager_thread = NULL; + new_wfd_sink->manager_thread_cmd = NULL; + new_wfd_sink->manager_thread_exit = FALSE; + + /* Initialize video resolution */ + new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN; + + /* construct attributes */ + new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink); + if (!new_wfd_sink->attrs) { + MMWFDSINK_FREEIF(new_wfd_sink); + wfd_sink_error("failed to set attribute"); + return MM_ERROR_WFD_INTERNAL; + } + + /* load ini for initialize */ + result = mm_wfd_sink_ini_load(&new_wfd_sink->ini); + if (result != MM_ERROR_NONE) { + wfd_sink_error("failed to load ini file"); + goto fail_to_load_ini; + } + new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime; + + /* initialize manager */ + result = _mm_wfd_sink_init_manager(new_wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to init manager : %d", result); + goto fail_to_init; + } + + /* initialize gstreamer */ + result = __mm_wfd_sink_init_gstreamer(new_wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to init gstreamer : %d", result); + goto fail_to_init; + } + + /* set state */ + __mm_wfd_sink_set_state(new_wfd_sink, MM_WFD_SINK_STATE_NULL); + + /* now take handle */ + *wfd_sink = new_wfd_sink; + + wfd_sink_debug_fleave(); + + return result; + + /* ERRORS */ +fail_to_init: + mm_wfd_sink_ini_unload(&new_wfd_sink->ini); +fail_to_load_ini: + _mmwfd_deconstruct_attribute(new_wfd_sink->attrs); + MMWFDSINK_FREEIF(new_wfd_sink); + + *wfd_sink = NULL; + + return result; +} + +int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE); + + /* construct pipeline */ + /* create main pipeline */ + result = __mm_wfd_sink_create_pipeline(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to create pipeline : %d", result); + goto fail_to_create; + } + + /* create video decodebin */ + result = __mm_wfd_sink_create_video_decodebin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to create video decodebin %d", result); + goto fail_to_create; + } + + /* create video sinkbin */ + result = __mm_wfd_sink_create_video_sinkbin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to create video sinkbin %d", result); + goto fail_to_create; + } + + /* create audio decodebin */ + result = __mm_wfd_sink_create_audio_decodebin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("fail to create audio decodebin : %d", result); + goto fail_to_create; + } + + /* create audio sinkbin */ + result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink); + if (result < MM_ERROR_NONE) { + wfd_sink_error("fail to create audio sinkbin : %d", result); + goto fail_to_create; + } + + /* set pipeline READY state */ + result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to set state : %d", result); + goto fail_to_create; + } + + /* set state */ + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PREPARED); + + wfd_sink_debug_fleave(); + + return result; + + /* ERRORS */ +fail_to_create: + /* need to destroy pipeline already created */ + __mm_wfd_sink_destroy_pipeline(wfd_sink); + return result; +} + +int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"), MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT); + + wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri)); + + /* set uri to wfdsrc */ + g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL); + + /* set pipeline PAUSED state */ + result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to set state : %d", result); + return result; + } + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START); + + WFD_SINK_MANAGER_LOCK(wfd_sink) ; + wfd_sink_debug("check pipeline is ready to start"); + WFD_SINK_MANAGER_UNLOCK(wfd_sink); + + result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE); + if (result < MM_ERROR_NONE) { + wfd_sink_error("failed to set state : %d", result); + return result; + } + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE); + + g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL); + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME); + + g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL); + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst && + wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT); + + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); + + g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL); + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE); + + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT); + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); + + /* release pipeline */ + result = __mm_wfd_sink_destroy_pipeline(wfd_sink); + if (result != MM_ERROR_NONE) { + wfd_sink_error("failed to destory pipeline"); + return MM_ERROR_WFD_INTERNAL; + } else { + wfd_sink_debug("success to destory pipeline"); + } + + /* set state */ + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL); + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* check current wi-fi display sink state */ + MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY); + + /* unload ini */ + mm_wfd_sink_ini_unload(&wfd_sink->ini); + + /* release attributes */ + _mmwfd_deconstruct_attribute(wfd_sink->attrs); + + if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) { + wfd_sink_error("failed to release manager"); + return MM_ERROR_WFD_INTERNAL; + } + + + /* set state */ + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE); + + wfd_sink_debug_fleave(); + + return result; +} + +int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data) +{ + int result = MM_ERROR_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + wfd_sink->msg_cb = callback; + wfd_sink->msg_user_data = user_data; + + wfd_sink_debug_fleave(); + + return result; +} + +static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink) +{ + int result = MM_ERROR_NONE; + gint *argc = NULL; + gchar **argv = NULL; + static const int max_argc = 50; + GError *err = NULL; + gint i = 0; + + wfd_sink_debug_fenter(); + + /* alloc */ + argc = calloc(1, sizeof(gint)); + argv = calloc(max_argc, sizeof(gchar *)); + if (!argc || !argv) { + wfd_sink_error("failed to allocate memory for wfdsink"); + + MMWFDSINK_FREEIF(argv); + MMWFDSINK_FREEIF(argc); + + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + /* we would not do fork for scanning plugins */ + argv[*argc] = g_strdup("--gst-disable-registry-fork"); + (*argc)++; + + /* check disable registry scan */ + argv[*argc] = g_strdup("--gst-disable-registry-update"); + (*argc)++; + + /* check disable segtrap */ + argv[*argc] = g_strdup("--gst-disable-segtrap"); + (*argc)++; + + /* check ini */ + for (i = 0; i < 5; i++) { + if (strlen(wfd_sink->ini.gst_param[i]) > 2) { + wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]); + argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]); + (*argc)++; + } + } + + wfd_sink_debug("initializing gstreamer with following parameter"); + wfd_sink_debug("argc : %d", *argc); + + for (i = 0; i < *argc; i++) { + wfd_sink_debug("argv[%d] : %s", i, argv[i]); + } + + /* initializing gstreamer */ + if (!gst_init_check(argc, &argv, &err)) { + wfd_sink_error("failed to initialize gstreamer: %s", err ? err->message : "unknown error occurred"); + if (err) + g_error_free(err); + + result = MM_ERROR_WFD_INTERNAL; + } + + /* release */ + for (i = 0; i < *argc; i++) { + MMWFDSINK_FREEIF(argv[i]); + } + MMWFDSINK_FREEIF(argv); + MMWFDSINK_FREEIF(argc); + + wfd_sink_debug_fleave(); + + return result; +} + +static GstBusSyncReply +_mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data) +{ + GstBusSyncReply ret = GST_BUS_PASS; + + wfd_sink_return_val_if_fail(message && + GST_IS_MESSAGE(message) && + GST_MESSAGE_SRC(message), + GST_BUS_DROP); + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_TAG: + break; + case GST_MESSAGE_DURATION: + break; + case GST_MESSAGE_STATE_CHANGED: { + /* we only handle state change messages from pipeline */ + if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message))) + ret = GST_BUS_DROP; + } + break; + case GST_MESSAGE_ASYNC_DONE: { + if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message))) + ret = GST_BUS_DROP; + } + break; + default: + break; + } + + return ret; +} + +static gboolean +_mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data; + const GstStructure *message_structure = gst_message_get_structure(msg); + gboolean ret = TRUE; + + wfd_sink_return_val_if_fail(wfd_sink, FALSE); + wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE); + + wfd_sink_debug("got %s from %s", + GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)), + GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)))); + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: { + GError *error = NULL; + gchar *debug = NULL; + + /* get error code */ + gst_message_parse_error(msg, &error, &debug); + + wfd_sink_error("error : %s", error->message); + wfd_sink_error("debug : %s", debug); + + MMWFDSINK_FREEIF(debug); + g_error_free(error); + } + break; + + case GST_MESSAGE_WARNING: { + char *debug = NULL; + GError *error = NULL; + + gst_message_parse_warning(msg, &error, &debug); + + wfd_sink_warning("warning : %s", error->message); + wfd_sink_warning("debug : %s", debug); + + MMWFDSINK_FREEIF(debug); + g_error_free(error); + } + break; + + case GST_MESSAGE_STATE_CHANGED: { + const GValue *voldstate, *vnewstate, *vpending; + GstState oldstate, newstate, pending; + const GstStructure *structure; + + /* we only handle messages from pipeline */ + if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst) + break; + + /* get state info from msg */ + structure = gst_message_get_structure(msg); + if (structure == NULL) + break; + + voldstate = gst_structure_get_value(structure, "old-state"); + vnewstate = gst_structure_get_value(structure, "new-state"); + vpending = gst_structure_get_value(structure, "pending-state"); + if (voldstate == NULL || vnewstate == NULL || vpending == NULL) + break; + + oldstate = (GstState)voldstate->data[0].v_int; + newstate = (GstState)vnewstate->data[0].v_int; + pending = (GstState)vpending->data[0].v_int; + + wfd_sink_debug("state changed [%s] : %s--->%s final : %s", + GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), + gst_element_state_get_name((GstState)oldstate), + gst_element_state_get_name((GstState)newstate), + gst_element_state_get_name((GstState)pending)); + + if (oldstate == newstate) { + wfd_sink_debug("pipeline reports state transition to old state"); + break; + } + + switch (newstate) { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + case GST_STATE_READY: + case GST_STATE_PAUSED: + case GST_STATE_PLAYING: + default: + break; + } + } + break; + + case GST_MESSAGE_CLOCK_LOST: { + GstClock *clock = NULL; + gst_message_parse_clock_lost(msg, &clock); + wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.", (clock ? GST_OBJECT_NAME(clock) : "NULL")); + } + break; + + case GST_MESSAGE_NEW_CLOCK: { + GstClock *clock = NULL; + gst_message_parse_new_clock(msg, &clock); + if (!clock) + break; + + if (wfd_sink->clock) { + if (wfd_sink->clock != clock) + wfd_sink_debug("clock is changed! [%s] -->[%s]", + GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)), + GST_STR_NULL(GST_OBJECT_NAME(clock))); + else + wfd_sink_debug("same clock is selected again! [%s]", + GST_STR_NULL(GST_OBJECT_NAME(clock))); + } else { + wfd_sink_debug("new clock [%s] was selected in the pipeline", + (GST_STR_NULL(GST_OBJECT_NAME(clock)))); + } + + wfd_sink->clock = clock; + } + break; + + case GST_MESSAGE_APPLICATION: { + const gchar *message_structure_name; + + message_structure_name = gst_structure_get_name(message_structure); + if (!message_structure_name) + break; + + wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name)); + } + break; + + case GST_MESSAGE_ELEMENT: { + const gchar *structure_name = NULL; + + structure_name = gst_structure_get_name(message_structure); + if (structure_name) { + wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name)); + if (g_strrstr(structure_name, "GstUDPSrcTimeout")) { + wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name)); + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } else if (g_strrstr(structure_name, "GstWFDSrcSessionTimeout")) { + wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name)); + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } + } + } + break; + + case GST_MESSAGE_PROGRESS: { + GstProgressType type = GST_PROGRESS_TYPE_ERROR; + gchar *category = NULL, *text = NULL; + + gst_message_parse_progress(msg, &type, &category, &text); + wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text)); + + switch (type) { + case GST_PROGRESS_TYPE_START: + break; + case GST_PROGRESS_TYPE_COMPLETE: + if (category && !strcmp(category, "open")) + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED); + else if (category && !strcmp(category, "play")) { + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING); + /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */ + } else if (category && !strcmp(category, "pause")) + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED); + else if (category && !strcmp(category, "close")) + __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED); + break; + case GST_PROGRESS_TYPE_CANCELED: + break; + case GST_PROGRESS_TYPE_ERROR: + if (category && !strcmp(category, "open")) { + wfd_sink_error("got error : %s", GST_STR_NULL(text)); + /*_mm_wfd_sink_disconnect (wfd_sink); */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } else if (category && !strcmp(category, "play")) { + wfd_sink_error("got error : %s", GST_STR_NULL(text)); + /*_mm_wfd_sink_disconnect (wfd_sink); */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } else if (category && !strcmp(category, "pause")) { + wfd_sink_error("got error : %s", GST_STR_NULL(text)); + /*_mm_wfd_sink_disconnect (wfd_sink); */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } else if (category && !strcmp(category, "close")) { + wfd_sink_error("got error : %s", GST_STR_NULL(text)); + /*_mm_wfd_sink_disconnect (wfd_sink); */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + } else { + wfd_sink_error("got error : %s", GST_STR_NULL(text)); + } + break; + default: + wfd_sink_error("progress message has no type"); + return ret; + } + + MMWFDSINK_FREEIF(category); + MMWFDSINK_FREEIF(text); + } + break; + case GST_MESSAGE_ASYNC_START: + wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); + break; + case GST_MESSAGE_ASYNC_DONE: + wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg))); + break; + case GST_MESSAGE_UNKNOWN: + case GST_MESSAGE_INFO: + case GST_MESSAGE_TAG: + case GST_MESSAGE_BUFFERING: + case GST_MESSAGE_EOS: + case GST_MESSAGE_STATE_DIRTY: + case GST_MESSAGE_STEP_DONE: + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_STRUCTURE_CHANGE: + case GST_MESSAGE_STREAM_STATUS: + case GST_MESSAGE_SEGMENT_START: + case GST_MESSAGE_SEGMENT_DONE: + case GST_MESSAGE_DURATION: + case GST_MESSAGE_LATENCY: + case GST_MESSAGE_REQUEST_STATE: + case GST_MESSAGE_STEP_START: + case GST_MESSAGE_QOS: + case GST_MESSAGE_ANY: + break; + default: + wfd_sink_debug("unhandled message"); + break; + } + + return ret; +} + +static int +__mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare) +{ + GList *bucket = element_bucket; + MMWFDSinkGstElement *element = NULL; + int successful_add_count = 0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(element_bucket, 0); + wfd_sink_return_val_if_fail(bin, 0); + + for (; bucket; bucket = bucket->next) { + element = (MMWFDSinkGstElement *)bucket->data; + + if (element && element->gst) { + if (need_prepare) + gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY); + + if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) { + wfd_sink_error("failed to add element [%s] to bin [%s]", + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); + return 0; + } + + wfd_sink_debug("add element [%s] to bin [%s]", + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))), + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin)))); + + successful_add_count++; + } + } + + wfd_sink_debug_fleave(); + + return successful_add_count; +} + +static int +__mm_wfd_sink_gst_element_link_bucket(GList *element_bucket) +{ + GList *bucket = element_bucket; + MMWFDSinkGstElement *element = NULL; + MMWFDSinkGstElement *prv_element = NULL; + gint successful_link_count = 0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(element_bucket, -1); + + prv_element = (MMWFDSinkGstElement *)bucket->data; + bucket = bucket->next; + + for (; bucket; bucket = bucket->next) { + element = (MMWFDSinkGstElement *)bucket->data; + + if (element && element->gst) { + if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) { + wfd_sink_debug("linking [%s] to [%s] success", + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); + successful_link_count++; + } else { + wfd_sink_error("linking [%s] to [%s] failed", + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))), + GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)))); + return -1; + } + } + + prv_element = element; + } + + wfd_sink_debug_fleave(); + + return successful_link_count; +} + +static int +__mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd) +{ + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_PRINT_STATE(wfd_sink); + + cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink); + + switch (cmd) { + case MM_WFD_SINK_COMMAND_CREATE: { + if (cur_state != MM_WFD_SINK_STATE_NONE) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL; + } + break; + + case MM_WFD_SINK_COMMAND_PREPARE: { + if (cur_state == MM_WFD_SINK_STATE_PREPARED) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_NULL) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED; + } + break; + + case MM_WFD_SINK_COMMAND_CONNECT: { + if (cur_state == MM_WFD_SINK_STATE_CONNECTED) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_PREPARED) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED; + } + break; + + case MM_WFD_SINK_COMMAND_START: { + if (cur_state == MM_WFD_SINK_STATE_PLAYING) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_CONNECTED) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING; + } + break; + + case MM_WFD_SINK_COMMAND_PAUSE: { + if (cur_state == MM_WFD_SINK_STATE_PAUSED) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_PLAYING) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED; + } + break; + + case MM_WFD_SINK_COMMAND_RESUME: { + if (cur_state == MM_WFD_SINK_STATE_PLAYING) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_PAUSED) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING; + } + break; + + case MM_WFD_SINK_COMMAND_DISCONNECT: { + if (cur_state == MM_WFD_SINK_STATE_NONE || + cur_state == MM_WFD_SINK_STATE_NULL || + cur_state == MM_WFD_SINK_STATE_PREPARED || + cur_state == MM_WFD_SINK_STATE_DISCONNECTED) + goto no_operation; + else if (cur_state != MM_WFD_SINK_STATE_PLAYING && + cur_state != MM_WFD_SINK_STATE_CONNECTED && + cur_state != MM_WFD_SINK_STATE_PAUSED) + goto invalid_state; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED; + } + break; + + case MM_WFD_SINK_COMMAND_UNPREPARE: { + if (cur_state == MM_WFD_SINK_STATE_NONE || + cur_state == MM_WFD_SINK_STATE_NULL) + goto no_operation; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL; + } + break; + + case MM_WFD_SINK_COMMAND_DESTROY: { + if (cur_state == MM_WFD_SINK_STATE_NONE) + goto no_operation; + + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; + } + break; + + default: + break; + } + + wfd_sink->cmd = cmd; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + +no_operation: + wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state)); + return MM_ERROR_WFD_NO_OP; + + /* ERRORS */ +invalid_state: + wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state)); + return MM_ERROR_WFD_INVALID_STATE; +} + +static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) { + wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state)); + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; + return MM_ERROR_NONE; + } + + /* update wi-fi display state */ + MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink); + MMWFDSINK_CURRENT_STATE(wfd_sink) = state; + + if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink)) + MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE; + + /* poset state message to application */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_NONE, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + + /* print state */ + MMWFDSINK_PRINT_STATE(wfd_sink); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int +__mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async) +{ + GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; + GstState cur_state = GST_STATE_VOID_PENDING; + GstState pending_state = GST_STATE_VOID_PENDING; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING, MM_ERROR_WFD_INVALID_ARGUMENT); + + wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state)); + + result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state); + if (result == GST_STATE_CHANGE_FAILURE) { + wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state)); + return MM_ERROR_WFD_INTERNAL; + } + + if (!async) { + wfd_sink_debug("wait for changing state is completed "); + + result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND); + if (result == GST_STATE_CHANGE_FAILURE) { + wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout); + + __mm_wfd_sink_dump_pipeline_state(wfd_sink); + + return MM_ERROR_WFD_INTERNAL; + } else if (result == GST_STATE_CHANGE_NO_PREROLL) { + wfd_sink_debug("successfully changed state but is not able to provide data yet"); + } + + wfd_sink_debug("cur state is %s, pending state is %s", + gst_element_state_get_name(cur_state), + gst_element_state_get_name(pending_state)); + } + + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static void +_mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink) +{ + GstClockTime base_time = GST_CLOCK_TIME_NONE; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime); + + + if (wfd_sink->clock) + base_time = gst_clock_get_time(wfd_sink->clock); + + if (GST_CLOCK_TIME_IS_VALID(base_time)) { + + wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time)); + + for (i = 0; i < WFD_SINK_M_NUM; i++) { + if (wfd_sink->pipeline->mainbin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time); + } + + if (wfd_sink->pipeline->v_decodebin) { + for (i = 0; i < WFD_SINK_V_D_NUM; i++) { + if (wfd_sink->pipeline->v_decodebin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time); + } + } + + if (wfd_sink->pipeline->v_sinkbin) { + for (i = 0; i < WFD_SINK_V_S_NUM; i++) { + if (wfd_sink->pipeline->v_sinkbin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time); + } + } + + if (wfd_sink->pipeline->a_decodebin) { + for (i = 0; i < WFD_SINK_A_D_NUM; i++) { + if (wfd_sink->pipeline->a_decodebin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time); + } + } + + if (wfd_sink->pipeline->a_sinkbin) { + for (i = 0; i < WFD_SINK_A_S_NUM; i++) { + if (wfd_sink->pipeline->a_sinkbin[i].gst) + gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time); + } + } + + wfd_sink->need_to_reset_basetime = FALSE; + } + + wfd_sink_debug_fleave(); + + return; +} + +int +__mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink) +{ + GstElement *bin = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check video decodebin is linked */ + if (!wfd_sink->video_decodebin_is_linked) { + /* check video decodebin is created */ + if (wfd_sink->pipeline->v_decodebin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to create video decodebin...."); + goto ERROR; + } + } + + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin....."); + goto ERROR; + } + } + + /* check video sinkbin is created */ + if (wfd_sink->pipeline->v_sinkbin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) { + wfd_sink_error("failed to create video sinkbin...."); + goto ERROR; + } + } + + /* set video decodebin state as READY */ + if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { + bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to video decodebin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without video decodebin...."); + } + + /* set video sinkbin state as READY */ + if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { + bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to video sinkbin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without video sinkbin...."); + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +ERROR: + /* need to notify to app */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + + return MM_ERROR_WFD_INTERNAL; +} + +int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink) +{ + GstElement *bin = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check audio decodebin is linked */ + if (!wfd_sink->audio_decodebin_is_linked) { + /* check audio decodebin is created */ + if (wfd_sink->pipeline->a_decodebin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to create audio decodebin...."); + goto ERROR; + } + } + + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin....."); + goto ERROR; + } + } + + /* check audio sinkbin is created */ + if (wfd_sink->pipeline->a_sinkbin == NULL) { + if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) { + wfd_sink_error("failed to create audio sinkbin...."); + goto ERROR; + } + } + + /* set audio decodebin state as READY */ + if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { + bin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to audio decodebin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without audio decodebin...."); + } + + /* set audio sinkbin state as READY */ + if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { + bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; + if (GST_STATE(bin) <= GST_STATE_NULL) { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) { + wfd_sink_error("failed to set state(READY) to audio sinkbin"); + goto ERROR; + } + } + } else { + wfd_sink_warning("going on without audio sinkbin...."); + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +ERROR: + /* need to notify to app */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + + return MM_ERROR_WFD_INTERNAL; +} + +#define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */ +#define COMPENSATION_CHECK_PERIOD (30*GST_SECOND) /* 30 sec */ + +static GstPadProbeReturn +_mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data; + GstClockTime current_time = GST_CLOCK_TIME_NONE; + GstClockTime start_time = GST_CLOCK_TIME_NONE; + GstClockTime running_time = GST_CLOCK_TIME_NONE; + GstClockTime base_time = GST_CLOCK_TIME_NONE; + GstClockTime render_time = GST_CLOCK_TIME_NONE; + GstClockTimeDiff diff = GST_CLOCK_TIME_NONE; + GstBuffer *buffer = NULL; + gint64 ts_offset = 0LL; + + wfd_sink_return_val_if_fail(info, FALSE); + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, + GST_PAD_PROBE_DROP); + + if (!wfd_sink->clock) { + wfd_sink_warning("pipeline did not select clock, yet"); + return GST_PAD_PROBE_OK; + } + + if (wfd_sink->need_to_reset_basetime) + _mm_wfd_sink_reset_basetime(wfd_sink); + + /* calculate current runninig time */ + current_time = gst_clock_get_time(wfd_sink->clock); + if (g_strrstr(GST_OBJECT_NAME(pad), "video")) + base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst); + else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) + base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst); + start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + if (GST_CLOCK_TIME_IS_VALID(current_time) && + GST_CLOCK_TIME_IS_VALID(start_time) && + GST_CLOCK_TIME_IS_VALID(base_time)) { + running_time = current_time - (start_time + base_time); + } else { + wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT + " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time), + GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time)); + return GST_PAD_PROBE_OK; + } + + /* calculate this buffer rendering time */ + buffer = gst_pad_probe_info_get_buffer(info); + if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) { + wfd_sink_warning("buffer timestamp is invalid."); + return GST_PAD_PROBE_OK; + } + + if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) { + if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) + g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL); + } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) { + if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) + g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL); + } + + render_time = GST_BUFFER_TIMESTAMP(buffer); + render_time += ts_offset; + + /* chekc this buffer could be rendered or not */ + if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) { + diff = GST_CLOCK_DIFF(running_time, render_time); + if (diff < 0) { + /* this buffer could be NOT rendered */ + wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "", + GST_STR_NULL((GST_OBJECT_NAME(pad))), + GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time))); + } else { + /* this buffer could be rendered */ + /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */ + /* GST_STR_NULL((GST_OBJECT_NAME(pad))), */ + /* GST_TIME_ARGS(diff)); */ + } + } + + /* update buffer count and gap */ + if (g_strrstr(GST_OBJECT_NAME(pad), "video")) { + wfd_sink->video_buffer_count++; + wfd_sink->video_accumulated_gap += diff; + } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) { + wfd_sink->audio_buffer_count++; + wfd_sink->audio_accumulated_gap += diff; + } else { + wfd_sink_warning("invalid buffer type.. "); + return GST_PAD_PROBE_DROP; + } + + if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) { + /* fisrt 60sec, just calculate the gap between source device and sink device */ + if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND) + return GST_PAD_PROBE_OK; + + /* every 10sec, calculate the gap between source device and sink device */ + if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer)) + > COMPENSATION_CHECK_PERIOD) { + gint64 audio_avgrage_gap = 0LL; + gint64 video_avgrage_gap = 0LL; + gint64 audio_avgrage_gap_diff = 0LL; + gint64 video_avgrage_gap_diff = 0LL; + gboolean video_minus_compensation = FALSE; + gboolean audio_minus_compensation = FALSE; + gint64 avgrage_gap_diff = 0LL; + gboolean minus_compensation = FALSE; + + /* check video */ + if (wfd_sink->video_buffer_count > 0) { + video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count; + + if (wfd_sink->video_average_gap != 0) { + if (video_avgrage_gap > wfd_sink->video_average_gap) { + video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap; + video_minus_compensation = TRUE; + } else { + video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap; + video_minus_compensation = FALSE; + } + } else { + wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap); + wfd_sink->video_average_gap = video_avgrage_gap; + } + } else { + wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT + " ~ %" GST_TIME_FORMAT"", + GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + } + + /* check audio */ + if (wfd_sink->audio_buffer_count > 0) { + audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count; + + if (wfd_sink->audio_average_gap != 0) { + if (audio_avgrage_gap > wfd_sink->audio_average_gap) { + audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap; + audio_minus_compensation = TRUE; + } else { + audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap; + audio_minus_compensation = FALSE; + } + } else { + wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap); + wfd_sink->audio_average_gap = audio_avgrage_gap; + } + } else { + wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT + " ~ %" GST_TIME_FORMAT"", + GST_TIME_ARGS(wfd_sink->last_buffer_timestamp), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + } + + /* selecet average_gap_diff between video and audio */ + /* which makes no buffer drop in the sink elements */ + if (video_avgrage_gap_diff && audio_avgrage_gap_diff) { + if (!video_minus_compensation && !audio_minus_compensation) { + minus_compensation = FALSE; + if (video_avgrage_gap_diff > audio_avgrage_gap_diff) + avgrage_gap_diff = video_avgrage_gap_diff; + else + avgrage_gap_diff = audio_avgrage_gap_diff; + } else if (video_minus_compensation && audio_minus_compensation) { + minus_compensation = TRUE; + if (video_avgrage_gap_diff > audio_avgrage_gap_diff) + avgrage_gap_diff = audio_avgrage_gap_diff; + else + avgrage_gap_diff = video_avgrage_gap_diff; + } else { + minus_compensation = FALSE; + if (!video_minus_compensation) + avgrage_gap_diff = video_avgrage_gap_diff; + else + avgrage_gap_diff = audio_avgrage_gap_diff; + } + } else if (video_avgrage_gap_diff) { + minus_compensation = video_minus_compensation; + avgrage_gap_diff = video_avgrage_gap_diff; + } else if (audio_avgrage_gap_diff) { + minus_compensation = audio_minus_compensation; + avgrage_gap_diff = audio_avgrage_gap_diff; + } + + wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ", + audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff, + video_minus_compensation ? "-" : "", video_avgrage_gap_diff); + + + /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */ + if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) { + if (minus_compensation) + ts_offset -= avgrage_gap_diff; + else + ts_offset += avgrage_gap_diff; + + wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %" + GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")", + minus_compensation ? "-" : "", avgrage_gap_diff, + GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time)); + + if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst) + g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); + if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst) + g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL); + } else { + wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")", + minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset)); + } + + /* reset values*/ + wfd_sink->video_buffer_count = 0; + wfd_sink->video_accumulated_gap = 0LL; + wfd_sink->audio_buffer_count = 0; + wfd_sink->audio_accumulated_gap = 0LL; + wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); + } + } else { + wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT, + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer); + } + + return GST_PAD_PROBE_OK; +} + + +static void +__mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; + gchar *name = gst_pad_get_name(pad); + GstElement *pipeline = NULL; + GstElement *decodebin = NULL; + GstElement *sinkbin = NULL; + GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + + pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst; + + /* take decodebin/sinkbin */ + if (name[0] == 'v') { + wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad..."); + + MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); + + gst_pad_add_probe(pad, + GST_PAD_PROBE_TYPE_BUFFER, + _mm_wfd_sink_check_running_time, + (gpointer)wfd_sink, + NULL); + + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare video pipeline...."); + goto ERROR; + } + + if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) + decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst; + if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) + sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst; + } else if (name[0] == 'a') { + wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad..."); + + MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL); + + gst_pad_add_probe(pad, + GST_PAD_PROBE_TYPE_BUFFER, + _mm_wfd_sink_check_running_time, + (gpointer)wfd_sink, + NULL); + + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) { + wfd_sink_error("failed to prepare audio pipeline...."); + goto ERROR; + } + + if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) + decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst; + if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) + sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst; + } else { + wfd_sink_error("unexceptable pad is added!!!"); + return; + } + + srcpad = gst_object_ref(pad); + + /* add decodebin and link */ + if (decodebin) { + if (!gst_bin_add(GST_BIN(pipeline), decodebin)) { + wfd_sink_error("failed to add %s to pipeline", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); + goto ERROR; + } + + sinkpad = gst_element_get_static_pad(decodebin, "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); + goto ERROR; + } + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { + wfd_sink_error("failed to link %s and %s", + GST_STR_NULL(GST_PAD_NAME(srcpad)), + GST_STR_NULL(GST_PAD_NAME(sinkpad))); + goto ERROR; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + srcpad = gst_element_get_static_pad(decodebin, "src"); + if (!srcpad) { + wfd_sink_error("failed to get src pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(decodebin))); + goto ERROR; + } + } else { + wfd_sink_warning("going on without decodebin..."); + } + + /* add sinkbin and link */ + if (sinkbin) { + if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) { + wfd_sink_error("failed to add %s to pipeline", + GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); + goto ERROR; + } + + sinkpad = gst_element_get_static_pad(sinkbin, "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from %s", + GST_STR_NULL(GST_ELEMENT_NAME(sinkbin))); + goto ERROR; + } + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { + wfd_sink_error("failed to link %s and %s", + GST_STR_NULL(GST_PAD_NAME(srcpad)), + GST_STR_NULL(GST_PAD_NAME(sinkpad))); + goto ERROR; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + } else { + wfd_sink_error("there is no sinkbin..."); + goto ERROR; + } + + + /* run */ + if (decodebin) { + if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) { + wfd_sink_error("failed to sync %s state with parent", + GST_STR_NULL(GST_PAD_NAME(decodebin))); + goto ERROR; + } + } + + if (sinkbin) { + if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) { + wfd_sink_error("failed to sync %s state with parent", + GST_STR_NULL(GST_PAD_NAME(sinkbin))); + goto ERROR; + } + } + + if (name[0] == 'v') { + MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline"); + } else if (name[0] == 'a') { + MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline"); + } + + MMWFDSINK_FREEIF(name); + + wfd_sink_debug_fleave(); + + return; + + /* ERRORS */ +ERROR: + MMWFDSINK_FREEIF(name); + + if (srcpad) + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + /* need to notify to app */ + MMWFDSINK_POST_MESSAGE(wfd_sink, + MM_ERROR_WFD_INTERNAL, + MMWFDSINK_CURRENT_STATE(wfd_sink)); + + return; +} + +static void +__mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; + + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink); + wfd_sink_return_if_fail(need_to_flush); + + if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) { + wfd_sink_debug("need to flush pipeline"); + *need_to_flush = (gpointer) TRUE; + } else { + wfd_sink_debug("don't need to flush pipeline"); + *need_to_flush = (gpointer) FALSE; + } + + + wfd_sink_debug_fleave(); +} + + +static void +__mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data) +{ + mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data; + MMWFDSinkStreamInfo *stream_info = NULL; + gint is_valid_audio_format = FALSE; + gint is_valid_video_format = FALSE; + gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; + gint video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE; + gchar *audio_format; + gchar *video_format; + + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str)); + wfd_sink_return_if_fail(wfd_sink); + + stream_info = &wfd_sink->stream_info; + + audio_codec = wfd_sink->stream_info.audio_stream_info.codec; + video_codec = wfd_sink->stream_info.video_stream_info.codec; + + if (gst_structure_has_field(str, "audio_format")) { + is_valid_audio_format = TRUE; + audio_format = g_strdup(gst_structure_get_string(str, "audio_format")); + if (g_strrstr(audio_format, "AAC")) + stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC; + else if (g_strrstr(audio_format, "AC3")) + stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3; + else if (g_strrstr(audio_format, "LPCM")) + stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM; + else { + wfd_sink_error("invalid audio format(%s)...", audio_format); + is_valid_audio_format = FALSE; + } + + if (is_valid_audio_format == TRUE) { + if (gst_structure_has_field(str, "audio_rate")) + gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate); + if (gst_structure_has_field(str, "audio_channels")) + gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels); + if (gst_structure_has_field(str, "audio_bitwidth")) + gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth); + + if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { + if (audio_codec != stream_info->audio_stream_info.codec) { + wfd_sink_debug("audio codec is changed...need to change audio decodebin"); + } + } else { + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE); + } + + wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t", + audio_format, + stream_info->audio_stream_info.sample_rate, + stream_info->audio_stream_info.channels, + stream_info->audio_stream_info.bitwidth); + } + } + + if (gst_structure_has_field(str, "video_format")) { + is_valid_video_format = TRUE; + video_format = g_strdup(gst_structure_get_string(str, "video_format")); + if (!g_strrstr(video_format, "H264")) { + wfd_sink_error("invalid video format(%s)...", video_format); + is_valid_video_format = FALSE; + } + + if (is_valid_video_format == TRUE) { + stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264; + + if (gst_structure_has_field(str, "video_width")) + gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width); + if (gst_structure_has_field(str, "video_height")) + gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height); + if (gst_structure_has_field(str, "video_framerate")) + gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate); + + if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) { + if (video_codec != stream_info->video_stream_info.codec) { + wfd_sink_debug("video codec is changed...need to change video decodebin"); + } + } else { + WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE); + } + + wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t", + video_format, + stream_info->video_stream_info.width, + stream_info->video_stream_info.height, + stream_info->video_stream_info.frame_rate); + } + } + + WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink); + + wfd_sink_debug_fleave(); +} + +static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc) +{ + GstStructure *audio_param = NULL; + GstStructure *video_param = NULL; + GstStructure *hdcp_param = NULL; + gint hdcp_version = 0; + gint hdcp_port = 0; + guint CEA_resolution = 0; + guint VESA_resolution = 0; + guint HH_resolution = 0; + GObjectClass *klass; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED); + + klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc)); + + g_object_set(G_OBJECT(wfdsrc), "debug", wfd_sink->ini.set_debug_property, NULL); + g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdsrc_pad_probe, NULL); + if (g_object_class_find_property(klass, "udp-buffer-size")) + g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL); + if (g_object_class_find_property(klass, "do-request")) + g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL); + if (g_object_class_find_property(klass, "latency")) + g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL); + + audio_param = gst_structure_new("audio_param", + "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec, + "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency, + "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel, + "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency, + NULL); + + CEA_resolution = wfd_sink->ini.video_cea_support; + VESA_resolution = wfd_sink->ini.video_vesa_support; + HH_resolution = wfd_sink->ini.video_hh_support; + + __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution, &CEA_resolution, &VESA_resolution, &HH_resolution); + + wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution); + + video_param = gst_structure_new("video_param", + "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec, + "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution, + "video_cea_support", G_TYPE_UINT, CEA_resolution, + "video_vesa_support", G_TYPE_UINT, VESA_resolution, + "video_hh_support", G_TYPE_UINT, HH_resolution, + "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile, + "video_level", G_TYPE_UINT, wfd_sink->ini.video_level, + "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency, + "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution, + "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution, + "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing, + "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param, + "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support, + NULL); + + mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version); + mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port); + wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port); + + hdcp_param = gst_structure_new("hdcp_param", + "hdcp_version", G_TYPE_INT, hdcp_version, + "hdcp_port_no", G_TYPE_INT, hdcp_port, + NULL); + + g_object_set(G_OBJECT(wfdsrc), "audio-param", audio_param, NULL); + g_object_set(G_OBJECT(wfdsrc), "video-param", video_param, NULL); + g_object_set(G_OBJECT(wfdsrc), "hdcp-param", hdcp_param, NULL); + + g_signal_connect(wfdsrc, "update-media-info", G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink); + + g_signal_connect(wfdsrc, "change-av-format", G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED); + + g_signal_connect(demux, "pad-added", G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data) +{ + wfd_sink_debug_fenter(); + + return_if_fail(element); + + wfd_sink_warning("%s is overrun", + GST_STR_NULL(GST_ELEMENT_NAME(element))); + + wfd_sink_debug_fleave(); + + return; +} + +static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue) +{ + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink); + wfd_sink_return_if_fail(queue); + + /* set maximum buffer size of queue as 3sec */ + g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL); + g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL); + g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL); + g_signal_connect(queue, "overrun", G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink); + + wfd_sink_debug_fleave(); + + return; +} + + +static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *mainbin = NULL; + GList *element_bucket = NULL; + GstBus *bus = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); + + /* Create pipeline */ + wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo)); + if (wfd_sink->pipeline == NULL) + goto CREATE_ERROR; + + memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo)); + + /* create mainbin */ + mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM); + if (mainbin == NULL) + goto CREATE_ERROR; + + memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM); + + /* create pipeline */ + mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE; + mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink"); + if (!mainbin[WFD_SINK_M_PIPE].gst) { + wfd_sink_error("failed to create pipeline"); + goto CREATE_ERROR; + } + + /* create wfdsrc */ + MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src"); + if (mainbin[WFD_SINK_M_SRC].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) { + wfd_sink_error("failed to prepare wfdsrc..."); + goto CREATE_ERROR; + } + } + + /* create rtpmp2tdepay */ + MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink"); + + MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src"); + + /* create tsdemuxer*/ + MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink"); + if (mainbin[WFD_SINK_M_DEMUX].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) { + wfd_sink_error("failed to prepare demux..."); + goto CREATE_ERROR; + } + } + + /* adding created elements to pipeline */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements"); + goto CREATE_ERROR; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements"); + goto CREATE_ERROR; + } + + /* connect bus callback */ + bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst)); + if (!bus) { + wfd_sink_error("cannot get bus from pipeline."); + goto CREATE_ERROR; + } + + /* add bus message callback*/ + gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink); + + /* set sync handler to get tag synchronously */ + gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL); + + g_list_free(element_bucket); + gst_object_unref(GST_OBJECT(bus)); + + /* now we have completed mainbin. take it */ + wfd_sink->pipeline->mainbin = mainbin; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +CREATE_ERROR: + wfd_sink_error("ERROR : releasing pipeline"); + + if (element_bucket) + g_list_free(element_bucket); + element_bucket = NULL; + + /* finished */ + if (bus) + gst_object_unref(GST_OBJECT(bus)); + bus = NULL; + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_M_NUM; i++) { /* NOTE : skip pipeline */ + if (mainbin != NULL && mainbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(mainbin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(mainbin[i].gst)); + mainbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release mainbin with it's childs */ + if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst) + gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); + + MMWFDSINK_FREEIF(mainbin); + + MMWFDSINK_FREEIF(wfd_sink->pipeline); + + return MM_ERROR_WFD_INTERNAL; +} + +int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *a_decodebin = NULL; + MMWFDSinkGstElement *first_element = NULL; + MMWFDSinkGstElement *last_element = NULL; + GList *element_bucket = NULL; + GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; + GstPad *ghostpad = NULL; + GList *first_list = NULL; + GList *last_list = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->a_decodebin && + wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->audio_decodebin_is_linked) { + wfd_sink_debug("audio decodebin is already linked... nothing to do"); + return MM_ERROR_NONE; + } + + /* take audio decodebin */ + a_decodebin = wfd_sink->pipeline->a_decodebin; + + /* check audio queue */ + if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]); + + /* check audio hdcp */ + if (a_decodebin[WFD_SINK_A_D_HDCP].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]); + + /* check audio codec */ + switch (wfd_sink->stream_info.audio_stream_info.codec) { + case MM_WFD_SINK_AUDIO_CODEC_LPCM: + if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]); + if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) { + GstCaps *caps = NULL; + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]); + caps = gst_caps_new_simple("audio/x-raw", + "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate, + "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels, + "format", G_TYPE_STRING, "S16BE", NULL); + + g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL); + gst_object_unref(GST_OBJECT(caps)); + } + break; + + case MM_WFD_SINK_AUDIO_CODEC_AAC: + if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]); + if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]); + break; + + case MM_WFD_SINK_AUDIO_CODEC_AC3: + if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]); + if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst) + element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]); + break; + + default: + wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin..."); + return MM_ERROR_WFD_INTERNAL; + break; + } + + if (element_bucket == NULL) { + wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy audio decodebin"); + goto fail_to_link; + } + goto done; + } + + /* adding elements to audio decodebin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to audio decodebin"); + goto fail_to_link; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements of the audio decodebin"); + goto fail_to_link; + } + + /* get first element's sinkpad for creating ghostpad */ + first_list = g_list_first(element_bucket); + if (first_list == NULL) { + wfd_sink_error("failed to get first list of the element_bucket"); + goto fail_to_link; + } + + first_element = (MMWFDSinkGstElement *)first_list->data; + if (!first_element) { + wfd_sink_error("failed to get first element of the audio decodebin"); + goto fail_to_link; + } + + sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("sink", sinkpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + + /* get last element's src for creating ghostpad */ + last_list = g_list_last(element_bucket); + if (last_list == NULL) { + wfd_sink_error("failed to get last list of the element_bucket"); + goto fail_to_link; + } + + last_element = (MMWFDSinkGstElement *)last_list->data; + if (!last_element) { + wfd_sink_error("failed to get last element of the audio decodebin"); + goto fail_to_link; + } + + srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); + if (!srcpad) { + wfd_sink_error("failed to get src pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("src", srcpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + g_list_free(element_bucket); + +done: + wfd_sink->audio_decodebin_is_linked = TRUE; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS*/ +fail_to_link: + if (srcpad) + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + g_list_free(element_bucket); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink) +{ + wfd_sink_debug_fenter(); + + /* check audiosink is created */ + wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE, NULL); + g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL); + g_object_set(G_OBJECT(audio_sink), "slave-method", 2, NULL); + g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL); + g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *a_decodebin = NULL; + GstObject *parent = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline && + wfd_sink->pipeline->a_decodebin && + wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) { + a_decodebin = wfd_sink->pipeline->a_decodebin; + } else { + wfd_sink_debug("audio decodebin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } + + parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst); + if (!parent) { + wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); + + if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of audio decodebin to NULL"); + ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of audio decodebin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ + if (a_decodebin[i].gst) { + parent = gst_element_get_parent(a_decodebin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), + ((GObject *) a_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); + a_decodebin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)), + ((GObject *) a_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audio decodebin with it's childs */ + if (a_decodebin[WFD_SINK_A_D_BIN].gst) + gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); + + } else { + wfd_sink_debug("audio decodebin has parent(%s), unref it ", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + wfd_sink->audio_decodebin_is_linked = FALSE; + + MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *a_decodebin = NULL; + gint audio_codec = WFD_AUDIO_UNKNOWN; + GList *element_bucket = NULL; + gboolean link = TRUE; + gint i = 0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* check audio decodebin could be linked now */ + switch (wfd_sink->stream_info.audio_stream_info.codec) { + case MM_WFD_SINK_AUDIO_CODEC_AAC: + audio_codec = WFD_AUDIO_AAC; + link = TRUE; + break; + case MM_WFD_SINK_AUDIO_CODEC_AC3: + audio_codec = WFD_AUDIO_AC3; + link = TRUE; + break; + case MM_WFD_SINK_AUDIO_CODEC_LPCM: + audio_codec = WFD_AUDIO_LPCM; + link = TRUE; + break; + case MM_WFD_SINK_AUDIO_CODEC_NONE: + default: + wfd_sink_debug("audio decodebin could NOT be linked now, just create"); + audio_codec = wfd_sink->ini.audio_codec; + link = FALSE; + break; + } + + /* alloc handles */ + a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); + if (!a_decodebin) { + wfd_sink_error("failed to allocate memory for audio decodebin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM); + + /* create audio decodebin */ + a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN; + a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin"); + if (!a_decodebin[WFD_SINK_A_D_BIN].gst) { + wfd_sink_error("failed to create audio decodebin"); + goto CREATE_ERROR; + } + + /* create queue */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink"); + if (a_decodebin[WFD_SINK_A_D_QUEUE].gst) + __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst); + + /* create hdcp */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink"); + + /* create codec */ + audio_codec = wfd_sink->ini.audio_codec; + if (audio_codec & WFD_AUDIO_LPCM) { + /* create LPCM converter */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src"); + + /* create LPCM filter */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src"); + } + + if (audio_codec & WFD_AUDIO_AAC) { + /* create AAC parse */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src"); + + /* create AAC decoder */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src"); + } + + if (audio_codec & WFD_AUDIO_AC3) { + /* create AC3 parser */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src"); + + /* create AC3 decoder */ + MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src"); + } + + g_list_free(element_bucket); + + /* take it */ + wfd_sink->pipeline->a_decodebin = a_decodebin; + + /* link audio decodebin if audio codec is fixed */ + if (link) { + if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to link audio decodebin, destroy audio decodebin"); + __mm_wfd_sink_destroy_audio_decodebin(wfd_sink); + return MM_ERROR_WFD_INTERNAL; + } + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + +CREATE_ERROR: + wfd_sink_error("failed to create audio decodebin, release all"); + + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */ + if (a_decodebin != NULL && a_decodebin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(a_decodebin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(a_decodebin[i].gst)); + a_decodebin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audioo decodebin with it's childs */ + if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst) + gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst)); + + MMWFDSINK_FREEIF(a_decodebin); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *a_sinkbin = NULL; + GstObject *parent = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline && + wfd_sink->pipeline->a_sinkbin && + wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) { + a_sinkbin = wfd_sink->pipeline->a_sinkbin; + } else { + wfd_sink_debug("audio sinkbin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } + + parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst); + if (!parent) { + wfd_sink_debug("audio decodebin has no parent.. need to relase by itself"); + + if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of audio decodebin to NULL"); + ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of audio decodebin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ + if (a_sinkbin[i].gst) { + parent = gst_element_get_parent(a_sinkbin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), + ((GObject *) a_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); + a_sinkbin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)), + ((GObject *) a_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audio decodebin with it's childs */ + if (a_sinkbin[WFD_SINK_A_S_BIN].gst) + gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); + + } else { + wfd_sink_debug("audio sinkbin has parent(%s), unref it ", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *a_sinkbin = NULL; + MMWFDSinkGstElement *first_element = NULL; + GList *element_bucket = NULL; + GstPad *ghostpad = NULL; + GstPad *pad = NULL; + gint i = 0; + GList *first_list = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* alloc handles */ + a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); + if (!a_sinkbin) { + wfd_sink_error("failed to allocate memory for audio sinkbin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM); + + /* create audio sinkbin */ + a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN; + a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin"); + if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) { + wfd_sink_error("failed to create audio sinkbin"); + goto CREATE_ERROR; + } + + /* create resampler */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src"); + + /* create volume */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src"); + + /* create sink */ + MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink"); + if (a_sinkbin[WFD_SINK_A_S_SINK].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) { + wfd_sink_error("failed to set audio sink property...."); + goto CREATE_ERROR; + } + } + + /* adding created elements to audio sinkbin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to audio sinkbin"); + goto CREATE_ERROR; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements fo the audio sinkbin"); + goto CREATE_ERROR; + } + + /* get first element's of the audio sinkbin */ + first_list = g_list_first(element_bucket); + if (first_list == NULL) { + wfd_sink_error("failed to get first list of the element_bucket"); + goto CREATE_ERROR; + } + + first_element = (MMWFDSinkGstElement *)first_list->data; + if (!first_element) { + wfd_sink_error("failed to get first element of the audio sinkbin"); + goto CREATE_ERROR; + } + + /* get first element's sinkpad for creating ghostpad */ + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!pad) { + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto CREATE_ERROR; + } + + ghostpad = gst_ghost_pad_new("sink", pad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of audio sinkbin"); + goto CREATE_ERROR; + } + + if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to audio sinkbin"); + goto CREATE_ERROR; + } + gst_object_unref(GST_OBJECT(pad)); + + g_list_free(element_bucket); + + /* take it */ + wfd_sink->pipeline->a_sinkbin = a_sinkbin; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + +CREATE_ERROR: + wfd_sink_error("failed to create audio sinkbin, releasing all"); + + if (pad) + gst_object_unref(GST_OBJECT(pad)); + pad = NULL; + + if (ghostpad) + gst_object_unref(GST_OBJECT(ghostpad)); + ghostpad = NULL; + + if (element_bucket) + g_list_free(element_bucket); + element_bucket = NULL; + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */ + if (a_sinkbin != NULL && a_sinkbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(a_sinkbin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(a_sinkbin[i].gst)); + a_sinkbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audio sinkbin with it's childs */ + if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst) + gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst)); + + MMWFDSINK_FREEIF(a_sinkbin); + + return MM_ERROR_WFD_INTERNAL; +} + +int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *v_decodebin = NULL; + MMWFDSinkGstElement *first_element = NULL; + MMWFDSinkGstElement *last_element = NULL; + GList *element_bucket = NULL; + GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; + GstPad *ghostpad = NULL; + GList *first_list = NULL; + GList *last_list = NULL; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->v_decodebin && + wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst, + MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->video_decodebin_is_linked) { + wfd_sink_debug("video decodebin is already linked... nothing to do"); + return MM_ERROR_NONE; + } + + /* take video decodebin */ + v_decodebin = wfd_sink->pipeline->v_decodebin; + + /* check video queue */ + if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]); + + /* check video hdcp */ + if (v_decodebin[WFD_SINK_V_D_HDCP].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]); + + /* check video codec */ + switch (wfd_sink->stream_info.video_stream_info.codec) { + case MM_WFD_SINK_VIDEO_CODEC_H264: + if (v_decodebin[WFD_SINK_V_D_PARSE].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]); + if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) { + GstCaps *caps = NULL; + + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]); + caps = gst_caps_new_simple("video/x-h264", + "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width, + "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height, + "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL); + g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL); + gst_object_unref(GST_OBJECT(caps)); + } + if (v_decodebin[WFD_SINK_V_D_DEC].gst) + element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]); + break; + + default: + wfd_sink_error("video codec is not decied yet. cannot link video decpdebin..."); + return MM_ERROR_WFD_INTERNAL; + break; + } + + if (element_bucket == NULL) { + wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it"); + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy video decodebin"); + goto fail_to_link; + } + goto done; + } + + /* adding elements to video decodebin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to video decodebin"); + goto fail_to_link; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements of the video decodebin"); + goto fail_to_link; + } + + /* get first element's sinkpad for creating ghostpad */ + first_list = g_list_first(element_bucket); + if (first_list == NULL) { + wfd_sink_error("failed to get first list of the element_bucket"); + goto fail_to_link; + } + + first_element = (MMWFDSinkGstElement *)first_list->data; + if (!first_element) { + wfd_sink_error("failed to get first element of the video decodebin"); + goto fail_to_link; + } + + sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!sinkpad) { + wfd_sink_error("failed to get sink pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("sink", sinkpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of video decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + + /* get last element's src for creating ghostpad */ + last_list = g_list_last(element_bucket); + if (last_list == NULL) { + wfd_sink_error("failed to get last list of the element_bucket"); + goto fail_to_link; + } + + last_element = (MMWFDSinkGstElement *)last_list->data; + if (!last_element) { + wfd_sink_error("failed to get last element of the video decodebin"); + goto fail_to_link; + } + + srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src"); + if (!srcpad) { + wfd_sink_error("failed to get src pad from element(%s)", + GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst))); + goto fail_to_link; + } + + ghostpad = gst_ghost_pad_new("src", srcpad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of video decodebin"); + goto fail_to_link; + } + + if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video decodebin"); + goto fail_to_link; + } + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + g_list_free(element_bucket); + +done: + wfd_sink->video_decodebin_is_linked = TRUE; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS*/ +fail_to_link: + if (srcpad != NULL) + gst_object_unref(GST_OBJECT(srcpad)); + srcpad = NULL; + + if (sinkpad != NULL) + gst_object_unref(GST_OBJECT(sinkpad)); + sinkpad = NULL; + + g_list_free(element_bucket); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec) +{ + wfd_sink_debug_fenter(); + + /* check video decoder is created */ + wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink) +{ + gboolean visible = TRUE; + gint surface_type = MM_DISPLAY_SURFACE_OVERLAY; + + wfd_sink_debug_fenter(); + + /* check videosink is created */ + wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT); + wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED); + + /* update display surface */ + mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); + wfd_sink_debug("check display surface type attribute: %d", surface_type); + mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible); + wfd_sink_debug("check display visible attribute: %d", visible); + + /* configuring display */ + switch (surface_type) { + case MM_DISPLAY_SURFACE_EVAS: { + void *object = NULL; + gint scaling = 0; + + /* common case if using evas surface */ + mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object); + mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling); + if (object) { + wfd_sink_debug("set video param : evas-object %x", object); + g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL); + } else { + wfd_sink_error("no evas object"); + return MM_ERROR_WFD_INTERNAL; + } + } + break; + + case MM_DISPLAY_SURFACE_OVERLAY: { + int wl_window_x = 0; + int wl_window_y = 0; + int wl_window_width = 0; + int wl_window_height = 0; + unsigned int wl_surface_id = 0; + struct wl_surface *wl_surface = NULL; + struct wl_display *wl_display = NULL; + Ecore_Wl_Window *wl_window = NULL; + wl_client *wlclient = NULL; + Evas_Object *obj = NULL; + void *object = NULL; + const char *object_type = NULL; + int ret = 0; + + mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object); + + if (object != NULL) { + obj = (Evas_Object *)object; + object_type = evas_object_type_get(obj); + wfd_sink_debug("window object type : %s", object_type); + + /* wayland overlay surface */ + LOGI("Wayland overlay surface type"); + evas_object_geometry_get(obj, &wl_window_x, &wl_window_y, &wl_window_width, &wl_window_height); + + wfd_sink_debug ("x[%d] y[%d] width[%d] height[%d]", wl_window_x, wl_window_y, + wl_window_width, wl_window_height); + + wl_window = elm_win_wl_window_get(obj); + wl_surface = (struct wl_surface *) ecore_wl_window_surface_get(wl_window); + + /* get wl_display */ + wl_display = (struct wl_display *) ecore_wl_display_get(); + + ret = mm_wfd_sink_wlclient_create(&wlclient); + if ( ret != MM_ERROR_NONE) { + wfd_sink_error("Wayland client create failure"); + return ret; + } + + if (wl_surface && wl_display){ + wfd_sink_debug ("surface = %p, wl_display = %p", wl_surface, wl_display); + wl_surface_id = mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wlclient, wl_surface, wl_display); + wfd_sink_debug ("wl_surface_id = %d", wl_surface_id); + } + if (wlclient) { + g_free(wlclient); + wlclient = NULL; + } + + wfd_sink_debug("set video param : surface_id %d", wl_surface_id); + gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), + wl_surface_id); + /* After setting window handle, set render rectangle */ + gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(video_sink), + wl_window_x, wl_window_y, wl_window_width, wl_window_height); + } else { + wfd_sink_debug ("display object is NULL!"); + return MM_ERROR_WFD_INTERNAL; + } + } + break; + + case MM_DISPLAY_SURFACE_NULL: { + /* do nothing */ + wfd_sink_error("Not Supported Surface."); + return MM_ERROR_WFD_INTERNAL; + } + break; + default: { + wfd_sink_error("Not Supported Surface.(default case)"); + return MM_ERROR_WFD_INTERNAL; + } + break; + } + + g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL); + g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL); + g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL); + g_object_set(G_OBJECT(video_sink), "visible", visible, NULL); + g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *v_decodebin = NULL; + GstObject *parent = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline && + wfd_sink->pipeline->v_decodebin && + wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) { + v_decodebin = wfd_sink->pipeline->v_decodebin; + } else { + wfd_sink_debug("video decodebin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } + + + parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst); + if (!parent) { + wfd_sink_debug("video decodebin has no parent.. need to relase by itself"); + + if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of video decodebin to NULL"); + ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of video decodebin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ + if (v_decodebin[i].gst) { + parent = gst_element_get_parent(v_decodebin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), + ((GObject *) v_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); + v_decodebin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)), + ((GObject *) v_decodebin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + /* release video decodebin with it's childs */ + if (v_decodebin[WFD_SINK_V_D_BIN].gst) { + gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)), + ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count); + } + } else { + wfd_sink_debug("video decodebin has parent(%s), unref it", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + wfd_sink->video_decodebin_is_linked = FALSE; + + MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *v_decodebin = NULL; + guint video_codec = WFD_VIDEO_UNKNOWN; + GList *element_bucket = NULL; + gboolean link = TRUE; + gint i = 0; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline->v_decodebin) { + wfd_sink_debug("video decodebin is already created... nothing to do"); + return MM_ERROR_NONE; + } + + /* check audio decodebin could be linked now */ + switch (wfd_sink->stream_info.video_stream_info.codec) { + case MM_WFD_SINK_VIDEO_CODEC_H264: + video_codec = WFD_VIDEO_H264; + link = TRUE; + break; + case MM_WFD_SINK_VIDEO_CODEC_NONE: + default: + wfd_sink_debug("video decodebin could NOT be linked now, just create"); + video_codec = wfd_sink->ini.video_codec; + link = FALSE; + break; + } + + /* alloc handles */ + v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); + if (!v_decodebin) { + wfd_sink_error("failed to allocate memory for video decodebin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM); + + /* create video decodebin */ + v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN; + v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin"); + if (!v_decodebin[WFD_SINK_V_D_BIN].gst) { + wfd_sink_error("failed to create video decodebin"); + goto CREATE_ERROR; + } + + /* create queue */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink"); + if (v_decodebin[WFD_SINK_V_D_QUEUE].gst) + __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst); + + /* create hdcp */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src"); + + if (video_codec & WFD_VIDEO_H264) { + /* create parser */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "src"); + + /* create capssetter */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "src"); + + /* create dec */ + MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "src"); + if (v_decodebin[WFD_SINK_V_D_DEC].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) { + wfd_sink_error("failed to set video decoder property..."); + goto CREATE_ERROR; + } + } + } + + g_list_free(element_bucket); + + /* take it */ + wfd_sink->pipeline->v_decodebin = v_decodebin; + + /* link video decodebin if video codec is fixed */ + if (link) { + if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to link video decodebin, destroy video decodebin"); + __mm_wfd_sink_destroy_video_decodebin(wfd_sink); + return MM_ERROR_WFD_INTERNAL; + } + } + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +CREATE_ERROR: + wfd_sink_error("failed to create video decodebin, releasing all"); + + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */ + if (v_decodebin != NULL && v_decodebin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(v_decodebin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(v_decodebin[i].gst)); + v_decodebin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release video decodebin with it's childs */ + if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst) + gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst)); + + MMWFDSINK_FREEIF(v_decodebin); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + MMWFDSinkGstElement *v_sinkbin = NULL; + GstObject *parent = NULL; + int i; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + if (wfd_sink->pipeline && + wfd_sink->pipeline->v_sinkbin && + wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) { + v_sinkbin = wfd_sink->pipeline->v_sinkbin; + } else { + wfd_sink_debug("video sinkbin is not created, nothing to destroy"); + return MM_ERROR_NONE; + } + + + parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst); + if (!parent) { + wfd_sink_debug("video sinkbin has no parent.. need to relase by itself"); + + if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) { + wfd_sink_debug("try to change state of video sinkbin to NULL"); + ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of video sinkbin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + } + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ + if (v_sinkbin[i].gst) { + parent = gst_element_get_parent(v_sinkbin[i].gst); + if (!parent) { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), + ((GObject *) v_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); + v_sinkbin[i].gst = NULL; + } else { + wfd_sink_debug("unref %s(current ref %d)", + GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)), + ((GObject *) v_sinkbin[i].gst)->ref_count); + gst_object_unref(GST_OBJECT(parent)); + } + } + } + /* release video sinkbin with it's childs */ + if (v_sinkbin[WFD_SINK_V_S_BIN].gst) { + gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); + } + } else { + wfd_sink_debug("video sinkbin has parent(%s), unref it ", + GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent)))); + + gst_object_unref(GST_OBJECT(parent)); + } + + MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin); + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink) +{ + MMWFDSinkGstElement *first_element = NULL; + MMWFDSinkGstElement *v_sinkbin = NULL; + GList *element_bucket = NULL; + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + gint i = 0; + gint surface_type = MM_DISPLAY_SURFACE_OVERLAY; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink && + wfd_sink->pipeline, + MM_ERROR_WFD_NOT_INITIALIZED); + + /* alloc handles */ + v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); + if (!v_sinkbin) { + wfd_sink_error("failed to allocate memory for video sinkbin"); + return MM_ERROR_WFD_NO_FREE_SPACE; + } + + memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM); + + /* create video sinkbin */ + v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN; + v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin"); + if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) { + wfd_sink_error("failed to create video sinkbin"); + goto CREATE_ERROR; + } + + /* create convert */ + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src"); + + /* create filter */ + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink"); + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src"); + if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) { + GstCaps *caps = NULL; + caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL); + g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL); + gst_object_unref(GST_OBJECT(caps)); + } + + /* create sink */ + mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); + + if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) { + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE); + } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) { + MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE); + } else { + wfd_sink_error("failed to set video sink...."); + goto CREATE_ERROR; + } + + MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink"); + if (v_sinkbin[WFD_SINK_V_S_SINK].gst) { + if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) { + wfd_sink_error("failed to set video sink property...."); + goto CREATE_ERROR; + } + } + + /* adding created elements to video sinkbin */ + if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) { + wfd_sink_error("failed to add elements to video sinkbin"); + goto CREATE_ERROR; + } + + /* linking elements in the bucket by added order. */ + if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) { + wfd_sink_error("failed to link elements of the video sinkbin"); + goto CREATE_ERROR; + } + + /* get first element's sinkpad for creating ghostpad */ + first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0); + if (!first_element) { + wfd_sink_error("failed to get first element of the video sinkbin"); + goto CREATE_ERROR; + } + + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if (!pad) { + wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin", + GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst))); + goto CREATE_ERROR; + } + + ghostpad = gst_ghost_pad_new("sink", pad); + if (!ghostpad) { + wfd_sink_error("failed to create ghostpad of the video sinkbin"); + goto CREATE_ERROR; + } + + if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) { + wfd_sink_error("failed to add ghostpad to video sinkbin"); + goto CREATE_ERROR; + } + + gst_object_unref(GST_OBJECT(pad)); + + g_list_free(element_bucket); + + + /* take it */ + wfd_sink->pipeline->v_sinkbin = v_sinkbin; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; + + /* ERRORS */ +CREATE_ERROR: + wfd_sink_error("failed to create video sinkbin, releasing all"); + + if (pad) + gst_object_unref(GST_OBJECT(pad)); + pad = NULL; + + if (ghostpad) + gst_object_unref(GST_OBJECT(ghostpad)); + ghostpad = NULL; + + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */ + if (v_sinkbin != NULL && v_sinkbin[i].gst) { + GstObject *parent = NULL; + parent = gst_element_get_parent(v_sinkbin[i].gst); + + if (!parent) { + gst_object_unref(GST_OBJECT(v_sinkbin[i].gst)); + v_sinkbin[i].gst = NULL; + } else { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release video sinkbin with it's childs */ + if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst) + gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst)); + + MMWFDSINK_FREEIF(v_sinkbin); + + return MM_ERROR_WFD_INTERNAL; +} + +static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + /* cleanup gst stuffs */ + if (wfd_sink->pipeline) { + MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin; + + if (mainbin) { + ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) { + wfd_sink_error("failed to change state of mainbin to NULL"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy video decodebin"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) { + wfd_sink_error("failed to destroy audio decodebin"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) { + wfd_sink_error("failed to destroy video sinkbin"); + return MM_ERROR_WFD_INTERNAL; + } + + if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) { + wfd_sink_error("failed to destroy audio sinkbin"); + return MM_ERROR_WFD_INTERNAL; + } + + gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst)); + + MMWFDSINK_FREEIF(mainbin); + } + + MMWFDSINK_FREEIF(wfd_sink->pipeline); + } + + wfd_sink->audio_decodebin_is_linked = FALSE; + wfd_sink->video_decodebin_is_linked = FALSE; + wfd_sink->need_to_reset_basetime = FALSE; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} + +static void +__mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink) +{ + GstIterator *iter = NULL; + gboolean done = FALSE; + + GstElement *item = NULL; + GstElementFactory *factory = NULL; + + GstState state = GST_STATE_VOID_PENDING; + GstState pending = GST_STATE_VOID_PENDING; + GstClockTime time = 200 * GST_MSECOND; + + wfd_sink_debug_fenter(); + + wfd_sink_return_if_fail(wfd_sink && + wfd_sink->pipeline && + wfd_sink->pipeline->mainbin && + wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + + iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)); + + if (iter != NULL) { + while (!done) { + switch (gst_iterator_next(iter, (gpointer)&item)) { + case GST_ITERATOR_OK: + gst_element_get_state(GST_ELEMENT(item), &state, &pending, time); + + factory = gst_element_get_factory(item) ; + if (factory) { + wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", + GST_STR_NULL(GST_OBJECT_NAME(factory)), + GST_STR_NULL(GST_ELEMENT_NAME(item)), + gst_element_state_get_name(state), + gst_element_state_get_name(pending), + GST_OBJECT_REFCOUNT_VALUE(item)); + } + gst_object_unref(item); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync(iter); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + default: + done = TRUE; + break; + } + } + } + + item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst); + + gst_element_get_state(GST_ELEMENT(item), &state, &pending, time); + + factory = gst_element_get_factory(item) ; + if (factory) { + wfd_sink_error("%s:%s : From:%s To:%s refcount : %d", + GST_OBJECT_NAME(factory), + GST_ELEMENT_NAME(item), + gst_element_state_get_name(state), + gst_element_state_get_name(pending), + GST_OBJECT_REFCOUNT_VALUE(item)); + } + + if (iter) + gst_iterator_free(iter); + + wfd_sink_debug_fleave(); + + return; +} + +const gchar * _mm_wfds_sink_get_state_name(MMWFDSinkStateType state) +{ + switch (state) { + case MM_WFD_SINK_STATE_NONE: + return "NONE"; + case MM_WFD_SINK_STATE_NULL: + return "NULL"; + case MM_WFD_SINK_STATE_PREPARED: + return "PREPARED"; + case MM_WFD_SINK_STATE_CONNECTED: + return "CONNECTED"; + case MM_WFD_SINK_STATE_PLAYING: + return "PLAYING"; + case MM_WFD_SINK_STATE_PAUSED: + return "PAUSED"; + case MM_WFD_SINK_STATE_DISCONNECTED: + return "DISCONNECTED"; + default: + return "INVAID"; + } +} + +static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution) +{ + if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return; + + *CEA_resolution = 0; + *VESA_resolution = 0; + *HH_resolution = 0; + + if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30) + *CEA_resolution |= WFD_CEA_1920x1080P30; + + if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30) + *CEA_resolution |= WFD_CEA_1280x720P30; + + if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30) + *HH_resolution |= WFD_HH_960x540P30; + + if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30) + *HH_resolution |= WFD_HH_864x480P30; + + if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60) + *CEA_resolution |= WFD_CEA_720x480P60; + + if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60) + *CEA_resolution |= WFD_CEA_640x480P60; + + if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30) + *HH_resolution |= WFD_HH_640x360P30; +} + +int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution) +{ + MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE; + + wfd_sink_debug_fenter(); + + wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED); + + MMWFDSINK_PRINT_STATE(wfd_sink); + cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink); + if (cur_state != MM_WFD_SINK_STATE_NULL) { + wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL"); + return MM_ERROR_WFD_INVALID_STATE; + } + + wfd_sink->supportive_resolution = resolution; + + wfd_sink_debug_fleave(); + + return MM_ERROR_NONE; +} diff --git a/src/mm_wfd_sink_util.c b/src/mm_wfd_sink_util.c new file mode 100755 index 0000000..405a818 --- /dev/null +++ b/src/mm_wfd_sink_util.c @@ -0,0 +1,224 @@ +/* + * libmm-wfd + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * Maksym Ukhanov , Hyunjun Ko + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mm_wfd_sink_util.h" +#include +#include + +#define DUMP_TS_DATA_PATH tzplatform_mkpath(TZ_SYS_VAR, "tmp/") + +static GstPadProbeReturn +_mm_wfd_sink_util_dump(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + gint8 *data = NULL; + gint size = 0; + FILE *f = NULL; + char buf[256] = {0, }; + char path[256] = {0, }; + GstElement * parent = NULL; + + parent = gst_pad_get_parent_element(pad); + if (parent == NULL) { + wfd_sink_error("The parent of pad is NULL."); + return GST_PAD_PROBE_OK; + } + + snprintf(path, sizeof(path), "%s%s_%s.ts", DUMP_TS_DATA_PATH, gst_element_get_name(parent), gst_pad_get_name(pad)); + gst_object_unref(parent); + + if (info && info->type & GST_PAD_PROBE_TYPE_BUFFER) { + GstMapInfo buf_info; + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + + gst_buffer_map(buffer, &buf_info, GST_MAP_READ); + + wfd_sink_debug("got buffer %p with size %d", buffer, buf_info.size); + data = (gint8 *)(buf_info.data); + size = buf_info.size; + f = fopen(path, "a"); + if (f == NULL) { + strerror_r(errno, buf, sizeof(buf)); + wfd_sink_error("failed to fopen! : %s", buf); + return GST_PAD_PROBE_OK; + } + fwrite(data, size, 1, f); + fclose(f); + gst_buffer_unmap(buffer, &buf_info); + } + + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +_mm_wfd_sink_util_pad_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + GstElement *parent = NULL; + + wfd_sink_return_val_if_fail(info && + info->type != GST_PAD_PROBE_TYPE_INVALID, + GST_PAD_PROBE_DROP); + wfd_sink_return_val_if_fail(pad, GST_PAD_PROBE_DROP); + + parent = (GstElement *)gst_object_get_parent(GST_OBJECT(pad)); + if (!parent) { + wfd_sink_error("failed to get parent of pad"); + return GST_PAD_PROBE_DROP; + } + + if (info->type & GST_PAD_PROBE_TYPE_BUFFER) { + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + /* show name and timestamp */ + wfd_sink_debug("BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%"G_GSSIZE_FORMAT" bytes)\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), + GST_STR_NULL(GST_PAD_NAME(pad)), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), + gst_buffer_get_size(buffer)); + } else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM || + info->type & GST_PAD_PROBE_TYPE_EVENT_UPSTREAM || + info->type & GST_PAD_PROBE_TYPE_EVENT_FLUSH || + info->type & GST_PAD_PROBE_TYPE_EVENT_BOTH) { + GstEvent *event = gst_pad_probe_info_get_event(info); + + /* show name and event type */ + wfd_sink_debug("EVENT PROBE : %s:%s : %s\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), + GST_STR_NULL(GST_PAD_NAME(pad)), + GST_EVENT_TYPE_NAME(event)); + + if (GST_EVENT_TYPE(event) == GST_EVENT_SEGMENT) { + const GstSegment *segment = NULL; + gst_event_parse_segment(event, &segment); + if (segment) + wfd_sink_debug("NEWSEGMENT : %" GST_TIME_FORMAT + " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT " \n", + GST_TIME_ARGS(segment->start), GST_TIME_ARGS(segment->stop), + GST_TIME_ARGS(segment->time)); + } + } + + if (parent) + gst_object_unref(parent); + + return GST_PAD_PROBE_OK; +} + +void +mm_wfd_sink_util_add_pad_probe(GstPad *pad, GstElement *element, const gchar *pad_name) +{ + GstPad *probe_pad = NULL; + + if (!pad) { + if (element && pad_name) + probe_pad = gst_element_get_static_pad(element, pad_name); + } else { + probe_pad = pad; + gst_object_ref(probe_pad); + } + + if (probe_pad) { + wfd_sink_debug("add pad(%s) probe", GST_STR_NULL(GST_PAD_NAME(probe_pad))); + gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_DATA_BOTH, _mm_wfd_sink_util_pad_probe_cb, (gpointer)NULL, NULL); + gst_object_unref(probe_pad); + } +} + +void +mm_wfd_sink_util_add_pad_probe_for_data_dump(GstElement *element, const gchar *pad_name) +{ + GstPad *probe_pad = NULL; + + if (element && pad_name) + probe_pad = gst_element_get_static_pad(element, pad_name); + + if (probe_pad) { + wfd_sink_debug("add pad(%s) probe", GST_STR_NULL(GST_PAD_NAME(probe_pad))); + gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_BUFFER, _mm_wfd_sink_util_dump, (gpointer)NULL, NULL); + gst_object_unref(probe_pad); + } +} + +static GstPadProbeReturn +_mm_wfd_sink_util_check_first_buffer_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) +{ + GstElement *parent = NULL; + GstBuffer *buffer = NULL; + guint *probe_id = (guint *)user_data; + + wfd_sink_return_val_if_fail(pad, GST_PAD_PROBE_DROP); + wfd_sink_return_val_if_fail(info, GST_PAD_PROBE_DROP); + + parent = GST_ELEMENT_CAST(gst_object_get_parent(GST_OBJECT(pad))); + if (parent == NULL) { + wfd_sink_error("The parent of pad is NULL."); + return GST_PAD_PROBE_DROP; + } + + buffer = gst_pad_probe_info_get_buffer(info); + + wfd_sink_debug("FIRST BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%"G_GSSIZE_FORMAT" bytes)\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), gst_buffer_get_size(buffer)); + + if (probe_id && *probe_id > 0) { + wfd_sink_debug("remove buffer probe[%d]\n", *probe_id); + gst_pad_remove_probe(pad, *probe_id); + + MMWFDSINK_FREEIF(probe_id); + } + + if (parent) + gst_object_unref(parent); + + return GST_PAD_PROBE_REMOVE; +} + +void +mm_wfd_sink_util_add_pad_probe_for_checking_first_buffer(GstPad *pad, GstElement *element, const gchar *pad_name) +{ + GstPad *probe_pad = NULL; + guint *probe_id = NULL; + + if (!pad) { + if (element && pad_name) + probe_pad = gst_element_get_static_pad(element, pad_name); + } else { + probe_pad = pad; + gst_object_ref(probe_pad); + } + + if (probe_pad) { + probe_id = g_malloc0(sizeof(guint)); + if (!probe_id) { + wfd_sink_error("failed to allocate memory for probe id\n"); + gst_object_unref(probe_pad); + return; + } + + *probe_id = gst_pad_add_probe(probe_pad, GST_PAD_PROBE_TYPE_BUFFER, _mm_wfd_sink_util_check_first_buffer_cb, (gpointer)probe_id, NULL); + wfd_sink_debug("add pad(%s) probe, %d", GST_STR_NULL(GST_PAD_NAME(probe_pad)), *probe_id); + + gst_object_unref(probe_pad); + } + + return; +} + diff --git a/src/mm_wfd_sink_wayland.c b/src/mm_wfd_sink_wayland.c new file mode 100755 index 0000000..787dea8 --- /dev/null +++ b/src/mm_wfd_sink_wayland.c @@ -0,0 +1,148 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include + +#include "mm_wfd_sink_dlog.h" +#include "mm_wfd_sink_wayland.h" + +#define goto_if_fail(expr,label) \ +{ \ + if (!(expr)) { \ + wfd_sink_error(" failed [%s]\n", #expr); \ + goto label; \ + } \ +} + +void mm_wfd_sink_handle_resource_id(void *data, struct tizen_resource *tizen_resource, uint32_t id) +{ + unsigned int *wl_surface_id = data; + + *wl_surface_id = id; + + wfd_sink_debug("[CLIENT] got wl_surface_id(%d) from server\n", id); +} + +static const struct tizen_resource_listener tz_resource_listener = +{ + mm_wfd_sink_handle_resource_id, +}; + +static void +mm_wfd_sink_handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + return_if_fail (data != NULL); + wl_client *wlclient = data; + + if (strcmp(interface, "tizen_surface") == 0) + { + wfd_sink_debug("binding tizen_surface"); + wlclient->tz_surface = wl_registry_bind(registry, name, &tizen_surface_interface, version); + return_if_fail (wlclient->tz_surface != NULL); + } +} + +static void mm_wfd_sink_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name) +{ + wfd_sink_debug("wl_registry_handle_global_remove"); +} + +static const struct wl_registry_listener registry_listener = +{ + mm_wfd_sink_handle_global, + mm_wfd_sink_handle_global_remove +}; + +int mm_wfd_sink_wlclient_create (wl_client ** wlclient) +{ + wl_client *ptr = NULL; + + ptr = g_malloc0 (sizeof (wl_client)); + if (!ptr) { + wfd_sink_error ("Cannot allocate memory for wlclient\n"); + goto ERROR; + } else { + *wlclient = ptr; + wfd_sink_debug ("Success create wlclient(%p)", *wlclient); + } + return MM_ERROR_NONE; + +ERROR: + *wlclient = NULL; + return MM_ERROR_WFD_NO_FREE_SPACE; +} + + +int mm_wfd_sink_wlclient_get_wl_window_wl_surface_id (wl_client * wlclient, struct wl_surface *surface, struct wl_display *display) +{ + goto_if_fail (wlclient != NULL, failed); + goto_if_fail (surface != NULL, failed); + goto_if_fail (display != NULL, failed); + + unsigned int wl_surface_id = 0; + + wlclient->display = display; + goto_if_fail (wlclient->display != NULL, failed); + + wlclient->registry = wl_display_get_registry(wlclient->display); + goto_if_fail (wlclient->registry != NULL, failed); + + wl_registry_add_listener(wlclient->registry, ®istry_listener, wlclient); + wl_display_dispatch(wlclient->display); + wl_display_roundtrip(wlclient->display); + + /* check global objects */ + goto_if_fail (wlclient->tz_surface != NULL, failed); + + /* Get wl_surface_id which is unique in a entire systemw. */ + wlclient->tz_resource = tizen_surface_get_tizen_resource(wlclient->tz_surface, surface); + goto_if_fail (wlclient->tz_resource != NULL, failed); + + tizen_resource_add_listener(wlclient->tz_resource, &tz_resource_listener, &wl_surface_id); + wl_display_roundtrip(wlclient->display); + goto_if_fail (wl_surface_id > 0, failed); + + mm_wfd_sink_wlclient_finalize(wlclient); + + return wl_surface_id; + +failed: + wfd_sink_error ("Failed to get wl_surface_id"); + + return 0; +} + +void mm_wfd_sink_wlclient_finalize (wl_client * wlclient) +{ + wfd_sink_debug ("start finalize wlclient"); + return_if_fail (wlclient != NULL) + + if (wlclient->tz_surface) + tizen_surface_destroy(wlclient->tz_surface); + + if (wlclient->tz_resource) + tizen_resource_destroy(wlclient->tz_resource); + + /* destroy registry */ + if (wlclient->registry) + wl_registry_destroy(wlclient->registry); + return; +}