From e6b9d94ba0002775c7e1c6e7956e80ffd307f07b Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Wed, 23 Nov 2016 13:48:18 +0900 Subject: [PATCH] Add 'TCP/UDP Switching' feature Using this feature, User can choose transport layer protocol between TCP and UDP. [Version] 1.6.1-4 [Profile] Common [Issue Type] Add feature [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161111.1] Change-Id: Ief6aec65e3058c32760fc5490631c3bff635c254 Signed-off-by: Hyunsoo, Park --- gst/rtsp-server/gstwfdmessage.c | 240 +++++++++++++ gst/rtsp-server/gstwfdmessage.h | 55 +++ gst/rtsp-server/rtsp-client-wfd.c | 701 +++++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-client-wfd.h | 2 + gst/rtsp-server/rtsp-server-wfd.c | 58 ++++ gst/rtsp-server/rtsp-server-wfd.h | 2 + packaging/gst-rtsp-server.spec | 2 +- 7 files changed, 1057 insertions(+), 3 deletions(-) mode change 100644 => 100755 gst/rtsp-server/gstwfdmessage.c mode change 100644 => 100755 gst/rtsp-server/gstwfdmessage.h mode change 100755 => 100644 gst/rtsp-server/rtsp-client-wfd.c mode change 100644 => 100755 gst/rtsp-server/rtsp-client-wfd.h mode change 100644 => 100755 gst/rtsp-server/rtsp-server-wfd.h diff --git a/gst/rtsp-server/gstwfdmessage.c b/gst/rtsp-server/gstwfdmessage.c old mode 100644 new mode 100755 index 0e1f7dd..8d75982 --- a/gst/rtsp-server/gstwfdmessage.c +++ b/gst/rtsp-server/gstwfdmessage.c @@ -334,6 +334,21 @@ gst_wfd_message_uninit (GstWFDMessage * msg) if (msg->idr_request) { FREE_STRING (msg->idr_request); } + if (msg->tcp_ports) { + FREE_STRING(msg->tcp_ports); + } + + if (msg->buf_len) { + FREE_STRING(msg->buf_len); + } + + if (msg->audio_status) { + FREE_STRING(msg->audio_status); + } + + if (msg->video_status) { + FREE_STRING(msg->video_status); + } return GST_WFD_OK; } @@ -444,6 +459,7 @@ gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg) #define WFD_READ_STRING(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); REPLACE_STRING (field, temp) #define WFD_READ_UINT32(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 16) #define WFD_READ_UINT32_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 10) +#define WFD_READ_UINT64_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoull (temp, NULL, 10) _read_string_attr_and_value (attr, value, sizeof (attr), sizeof (value), ':', p); @@ -743,6 +759,40 @@ gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg) } else if (!g_strcmp0 (attr, GST_STRING_WFD_IDR_REQUEST)) { msg->idr_request = g_new0 (GstWFDIdrRequest, 1); msg->idr_request->idr_request = TRUE; + } else if (!g_strcmp0 (attr, GST_STRING_WFD2_TCP_PORTS)) { + msg->tcp_ports = g_new0 (GstWFDTCPPorts, 1); + if (strlen (v)) { + WFD_SKIP_SPACE (v); + WFD_READ_STRING (msg->tcp_ports->profile); + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tcp_ports->rtp_port0); + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tcp_ports->rtp_port1); + WFD_SKIP_SPACE (v); + WFD_READ_STRING (msg->tcp_ports->mode); + } + } else if (!g_strcmp0 (attr, GST_STRING_WFD2_BUFFER_LEN)) { + msg->buf_len = g_new0 (GstWFDBufferLen, 1); + if (strlen (v)) { + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->buf_len->buf_len); + } + } else if (!g_strcmp0 (attr, GST_STRING_WFD2_AUDIO_STATUS)) { + msg->audio_status = g_new0 (GstWFDAudioReport, 1); + if (strlen (v)) { + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->audio_status->aud_bufsize); + WFD_SKIP_SPACE (v); + WFD_READ_UINT64_DIGIT (msg->audio_status->aud_pts); + } + } else if (!g_strcmp0 (attr, GST_STRING_WFD2_VIDEO_STATUS)) { + msg->video_status = g_new0 (GstWFDVideoReport, 1); + if (strlen (v)) { + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->video_status->vid_bufsize); + WFD_SKIP_SPACE (v); + WFD_READ_UINT64_DIGIT (msg->video_status->vid_pts); + } } return; } @@ -1106,6 +1156,24 @@ gst_wfd_message_as_text (const GstWFDMessage * msg) g_string_append_printf (lines, "\r\n"); } + if (msg->tcp_ports) { + g_string_append_printf (lines, GST_STRING_WFD2_TCP_PORTS); + if (msg->tcp_ports->profile) { + g_string_append_printf (lines, ":"); + g_string_append_printf (lines, " %s", msg->tcp_ports->profile); + g_string_append_printf (lines, " %d", msg->tcp_ports->rtp_port0); + g_string_append_printf (lines, " %d", msg->tcp_ports->rtp_port1); + g_string_append_printf (lines, " %s", msg->tcp_ports->mode); + } + g_string_append_printf (lines, "\r\n"); + } + + if (msg->buf_len) { + g_string_append_printf (lines, GST_STRING_WFD2_BUFFER_LEN); + g_string_append_printf (lines, ":"); + g_string_append_printf (lines, " %d", msg->buf_len->buf_len); + g_string_append_printf (lines, "\r\n"); + } return g_string_free (lines, FALSE); } @@ -1189,6 +1257,22 @@ gst_wfd_message_param_names_as_text (const GstWFDMessage * msg) g_string_append_printf (lines, GST_STRING_WFD_IDR_REQUEST); g_string_append_printf (lines, "\r\n"); } + if (msg->tcp_ports) { + g_string_append_printf (lines, GST_STRING_WFD2_TCP_PORTS); + g_string_append_printf (lines, "\r\n"); + } + if (msg->buf_len) { + g_string_append_printf (lines, GST_STRING_WFD2_BUFFER_LEN); + g_string_append_printf (lines, "\r\n"); + } + if (msg->audio_status) { + g_string_append_printf (lines, GST_STRING_WFD2_AUDIO_STATUS); + g_string_append_printf (lines, "\r\n"); + } + if (msg->video_status) { + g_string_append_printf (lines, GST_STRING_WFD2_VIDEO_STATUS); + g_string_append_printf (lines, "\r\n"); + } return g_string_free (lines, FALSE); } @@ -1383,6 +1467,35 @@ gst_wfd_message_dump (const GstWFDMessage * msg) g_print (GST_STRING_WFD_IDR_REQUEST); g_print ("\r\n"); } + if (msg->tcp_ports) { + g_print (" TCP Ports : \n"); + if (msg->tcp_ports->profile) { + g_print ("%s\n", msg->tcp_ports->profile); + g_print (" %d\n", msg->tcp_ports->rtp_port0); + g_print (" %d\n", msg->tcp_ports->rtp_port1); + g_print (" %s\n", msg->tcp_ports->mode); + } + g_print ("\r\n"); + } + + if (msg->buf_len) { + g_print (" Buffer Length : %d\n", msg->buf_len->buf_len); + g_print ("\r\n"); + } + + if (msg->audio_status) { + g_print ("Audio Playback Status : \n"); + g_print (" Current audio buffer size : %d\n", msg->audio_status->aud_bufsize); + g_print (" Current audio decoded PTS : %lld\n", msg->audio_status->aud_pts); + g_print ("\r\n"); + } + + if (msg->video_status) { + g_print ("Video Playback Status : \n"); + g_print (" Current video buffer size : %d\n", msg->video_status->vid_bufsize); + g_print (" Current video decoded PTS : %lld\n", msg->video_status->vid_pts); + g_print ("\r\n"); + } return GST_WFD_OK; } @@ -1982,3 +2095,130 @@ gst_wfd_message_get_av_format_change_timing (GstWFDMessage * msg, guint64 * PTS, return GST_WFD_OK; } +GstWFDResult +gst_wfd_messge_set_prefered_tcp_ports (GstWFDMessage *msg, + GstWFDRTSPTransMode trans, + GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, + guint32 rtp_port0, + guint32 rtp_port1) +{ + GString *lines; + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->tcp_ports) + msg->tcp_ports = g_new0 (GstWFDTCPPorts, 1); + + if (trans != GST_WFD_RTSP_TRANS_UNKNOWN) { + lines = g_string_new (""); + if (trans == GST_WFD_RTSP_TRANS_RTP) + g_string_append_printf (lines, "RTP"); + else if (trans == GST_WFD_RTSP_TRANS_RDT) + g_string_append_printf (lines, "RDT"); + + if (profile == GST_WFD_RTSP_PROFILE_AVP) + g_string_append_printf (lines, "/AVP"); + else if (profile == GST_WFD_RTSP_PROFILE_SAVP) + g_string_append_printf (lines, "/SAVP"); + + if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP) + g_string_append_printf (lines, "/UDP;unicast"); + else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST) + g_string_append_printf (lines, "/UDP;multicast"); + else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_TCP) + g_string_append_printf (lines, "/TCP;unicast"); + else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_HTTP) + g_string_append_printf (lines, "/HTTP"); + + msg->tcp_ports->profile = g_string_free (lines, FALSE); + msg->tcp_ports->rtp_port0 = rtp_port0; + msg->tcp_ports->rtp_port1 = rtp_port1; + msg->tcp_ports->mode = g_strdup ("mode=play"); + } + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_message_get_prefered_tcp_ports (GstWFDMessage *msg, + GstWFDRTSPTransMode *trans, + GstWFDRTSPProfile *profile, + GstWFDRTSPLowerTrans *lowertrans, + guint32 *rtp_port0, + guint32 *rtp_port1) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->tcp_ports != NULL, GST_WFD_EINVAL); + + if (g_strrstr (msg->tcp_ports->profile, "RTP")) + *trans = GST_WFD_RTSP_TRANS_RTP; + if (g_strrstr (msg->tcp_ports->profile, "RDT")) + *trans = GST_WFD_RTSP_TRANS_RDT; + if (g_strrstr (msg->tcp_ports->profile, "AVP")) + *profile = GST_WFD_RTSP_PROFILE_AVP; + if (g_strrstr (msg->tcp_ports->profile, "SAVP")) + *profile = GST_WFD_RTSP_PROFILE_SAVP; + if (g_strrstr (msg->tcp_ports->profile, "UDP;unicast")) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP; + if (g_strrstr (msg->tcp_ports->profile, "UDP;multicast")) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST; + if (g_strrstr (msg->tcp_ports->profile, "TCP;unicast")) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP; + if (g_strrstr (msg->tcp_ports->profile, "HTTP")) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP; + + *rtp_port0 = msg->tcp_ports->rtp_port0; + *rtp_port1 = msg->tcp_ports->rtp_port1; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_message_set_buffer_length (GstWFDMessage *msg, guint buf_len) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->buf_len) + msg->buf_len = g_new0 (GstWFDBufferLen, 1); + msg->buf_len->buf_len = buf_len; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_message_get_buffer_length (GstWFDMessage *msg, guint *buf_len) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->buf_len != NULL, GST_WFD_EINVAL); + + *buf_len = msg->buf_len->buf_len; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_message_get_audio_playback_status (GstWFDMessage *msg, + guint *bufsize, + guint64 *pts) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->audio_status != NULL, GST_WFD_EINVAL); + + *bufsize = msg->audio_status->aud_bufsize; + *pts = msg->audio_status->aud_pts; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_message_get_video_playback_status (GstWFDMessage *msg, + guint *bufsize, + guint64 *pts) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->video_status != NULL, GST_WFD_EINVAL); + + *bufsize = msg->video_status->vid_bufsize; + *pts = msg->video_status->vid_pts; + + return GST_WFD_OK; +} diff --git a/gst/rtsp-server/gstwfdmessage.h b/gst/rtsp-server/gstwfdmessage.h old mode 100644 new mode 100755 index b390ef3..5a64696 --- a/gst/rtsp-server/gstwfdmessage.h +++ b/gst/rtsp-server/gstwfdmessage.h @@ -66,6 +66,10 @@ G_BEGIN_DECLS #define GST_STRING_WFD_CONNECTOR_TYPE "wfd_connector_type" #define GST_STRING_WFD_IDR_REQUEST "wfd_idr_request" +#define GST_STRING_WFD2_TCP_PORTS "wfd2_tcp_ports" +#define GST_STRING_WFD2_BUFFER_LEN "wfd2_buffer_len" +#define GST_STRING_WFD2_AUDIO_STATUS "wfd2_audio_playback_status" +#define GST_STRING_WFD2_VIDEO_STATUS "wfd2_video_playback_status" /** * GstWFDResult: * @GST_WFD_OK: A successful return value @@ -422,6 +426,26 @@ typedef struct { gboolean idr_request; } GstWFDIdrRequest; +typedef struct { + gchar *profile; + guint32 rtp_port0; + guint32 rtp_port1; + gchar *mode; +} GstWFDTCPPorts; + +typedef struct { + guint buf_len; +} GstWFDBufferLen; + +typedef struct { + guint aud_bufsize; + guint64 aud_pts; +} GstWFDAudioReport; + +typedef struct { + guint vid_bufsize; + guint64 vid_pts; +} GstWFDVideoReport; /** * GstWFDMessage: * @version: the protocol version @@ -459,6 +483,10 @@ typedef struct { GstWFDStandby *standby; GstWFDConnectorType *connector_type; GstWFDIdrRequest *idr_request; + GstWFDTCPPorts *tcp_ports; + GstWFDBufferLen *buf_len; + GstWFDAudioReport *audio_status; + GstWFDVideoReport *video_status; } GstWFDMessage; GType gst_wfd_message_get_type (void); @@ -613,6 +641,33 @@ GstWFDResult gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg, GstWFDResult gst_wfd_message_get_av_format_change_timing(GstWFDMessage *msg, guint64 *PTS, guint64 *DTS); +GstWFDResult gst_wfd_messge_set_prefered_tcp_ports (GstWFDMessage *msg, + GstWFDRTSPTransMode trans, + GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, + guint32 rtp_port0, + guint32 rtp_port1); + +GstWFDResult gst_wfd_message_get_prefered_tcp_ports (GstWFDMessage *msg, + GstWFDRTSPTransMode *trans, + GstWFDRTSPProfile *profile, + GstWFDRTSPLowerTrans *lowertrans, + guint32 *rtp_port0, + guint32 *rtp_port1); + +GstWFDResult gst_wfd_message_set_buffer_length (GstWFDMessage *msg, + guint buf_len); + +GstWFDResult gst_wfd_message_get_buffer_length (GstWFDMessage *msg, + guint *buf_len); + +GstWFDResult gst_wfd_message_get_audio_playback_status (GstWFDMessage *msg, + guint *bufsize, + guint64 *pts); + +GstWFDResult gst_wfd_message_get_video_playback_status (GstWFDMessage *msg, + guint *bufsize, + guint64 *pts); G_END_DECLS #endif /* __GST_WFD_MESSAGE_H__ */ diff --git a/gst/rtsp-server/rtsp-client-wfd.c b/gst/rtsp-server/rtsp-client-wfd.c old mode 100755 new mode 100644 index 6e5729a..55c32d7 --- a/gst/rtsp-server/rtsp-client-wfd.c +++ b/gst/rtsp-server/rtsp-client-wfd.c @@ -41,6 +41,11 @@ #include #include +#include +#include +#include +#include +#include #include "rtsp-client-wfd.h" #include "rtsp-media-factory-wfd.h" @@ -71,6 +76,16 @@ struct _GstRTSPClientRTPStats guint resent_packets; }; +typedef enum { + WFD_TS_UDP, + WFD_TS_TCP +} WFDTSMode; + +typedef enum { + WFD_TS_REP_AUDIO, + WFD_TS_REP_VIDEO +} WFDTSReportType; + struct _GstRTSPWFDClientPrivate { GstRTSPWFDClientSendFunc send_func; /* protected by send_lock */ @@ -141,6 +156,19 @@ struct _GstRTSPWFDClientPrivate gboolean rtcp_stats_enabled; gchar *sink_user_agent; + guint ctrans_tcp; + guint cprofile_tcp; + guint clowertrans_tcp; + guint32 crtp_port0_tcp; + guint32 crtp_port1_tcp; + guint buf_len; + WFDTSMode ts_mode; + WFDTSReportType report_type; + GstRTSPWatch *datawatch; + guint datawatchid; + GstRTSPConnection *data_conn; + gchar *uristr; + GMutex tcp_send_lock; }; #define DEFAULT_WFD_TIMEOUT 60 @@ -323,6 +351,9 @@ gst_rtsp_wfd_client_init (GstRTSPWFDClient * client) memset (&priv->stats, 0x00, sizeof (GstRTSPClientRTPStats)); priv->sink_user_agent = NULL; + priv->ts_mode = WFD_TS_UDP; + priv->report_type = WFD_TS_REP_AUDIO; + g_mutex_init (&priv->tcp_send_lock); GST_INFO_OBJECT (client, "Client is initialized"); } @@ -351,6 +382,7 @@ gst_rtsp_wfd_client_finalize (GObject * obj) g_mutex_clear (&priv->keep_alive_lock); g_mutex_clear (&priv->stats_lock); + g_mutex_clear (&priv->tcp_send_lock); G_OBJECT_CLASS (gst_rtsp_wfd_client_parent_class)->finalize (obj); } @@ -499,6 +531,10 @@ static gboolean wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx) { + if (media) { + GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client); + priv->media = media; + } if (stream) { GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client); if (priv) @@ -1008,6 +1044,378 @@ handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_client_wfd_signals[SIGNAL_WFD_PLAYING_DONE], 0, NULL); } +static gboolean +do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) +{ + GstRTSPMessage message = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + GstMapInfo map_info; + guint8 *data; + guint usize; + + gst_rtsp_message_init_data (&message, channel); + + /* FIXME, need some sort of iovec RTSPMessage here */ + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) + return FALSE; + + gst_rtsp_message_take_body (&message, map_info.data, map_info.size); + + g_mutex_lock (&(GST_RTSP_WFD_CLIENT (client)->priv->tcp_send_lock)); + + gst_rtsp_watch_send_message (GST_RTSP_WFD_CLIENT (client)->priv->datawatch, &message, NULL); + + g_mutex_unlock (&(GST_RTSP_WFD_CLIENT (client)->priv->tcp_send_lock)); + + gst_rtsp_message_steal_body (&message, &data, &usize); + gst_buffer_unmap (buffer, &map_info); + + gst_rtsp_message_unset (&message); + + return res == GST_RTSP_OK; +} +static GstRTSPResult +message_received (GstRTSPWatch * watch, GstRTSPMessage * message, + gpointer user_data) +{ + return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message); +} + +static GstRTSPResult +message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) +{ + GstRTSPClient *client; + + client = GST_RTSP_CLIENT (user_data); + if(client == NULL) + return GST_RTSP_ERROR; + return GST_RTSP_OK; +} + +static GstRTSPResult +error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + gchar *str; + + str = gst_rtsp_strresult (result); + GST_INFO ("client %p: received an error %s", client, str); + g_free (str); + + return GST_RTSP_OK; +} +static GstRTSPResult +closed_tcp (GstRTSPWatch * watch, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + GST_INFO ("client %p: connection closed", client); + + return GST_RTSP_OK; +} + +static GstRTSPResult +error_full_tcp (GstRTSPWatch * watch, GstRTSPResult result, + GstRTSPMessage * message, guint id, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + gchar *str; + + str = gst_rtsp_strresult (result); + GST_INFO + ("client %p: received an error %s when handling message %p with id %d", + client, str, message, id); + g_free (str); + + return GST_RTSP_OK; +} + +static GstRTSPWatchFuncs watch_funcs_tcp = { + message_received, + message_sent, + closed_tcp, + error, + NULL, + NULL, + error_full_tcp, + NULL +}; +static void +client_watch_notify_tcp (GstRTSPClient * client) +{ + GST_INFO ("client %p: watch destroyed", client); + GST_RTSP_WFD_CLIENT (client)->priv->datawatch = NULL; + GST_RTSP_WFD_CLIENT (client)->priv->data_conn = NULL; +} + +static GstRTSPResult +new_tcp (GstRTSPWFDClient * client) +{ + int fd; + GstRTSPResult res = GST_RTSP_OK; + GstRTSPConnection *conn = NULL; + GstRTSPConnection *parent_conn = NULL; + GstRTSPUrl *url; + guint64 timeout = 20000000; + struct sockaddr_in server_addr; + socklen_t sin_len; + GSource *source; + GMainContext *context; + int retry = 0; + int bsize = 1024000; + int rn = sizeof(int); + int state = 1; + GSocket *tcp = NULL; + + struct sockaddr_in my_addr; + /* client's address */ + gint sockoptval = 1; + int ret; + GSocketAddress *local; + + /* Get the client connection details */ + parent_conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client)); + url = gst_rtsp_connection_get_url (parent_conn); + if(!url) + return GST_RTSP_ERROR; + + gst_rtsp_url_set_port (url, client->priv->crtp_port0_tcp); + + GST_INFO ("create new connection %p ip %s:%d", client, url->host, url->port); + + /* create a TCP/IP socket */ + if ((tcp = g_socket_new (AF_INET, SOCK_STREAM, 0, NULL)) == NULL) { + GST_ERROR ("cannot create socket"); + return GST_RTSP_ERROR; + } + /* allow immediate reuse of the port */ + ret = g_socket_set_option (tcp, SOL_SOCKET, SO_REUSEADDR, sockoptval, NULL); + if(ret == 0) + { + GST_ERROR ("cannot change socket options"); + return GST_RTSP_ERROR; + } + /* bind the socket to our source address */ + memset ((char*)&my_addr, 0, sizeof(my_addr)); + /* 0 out the structure */ + my_addr.sin_family = AF_INET; + /* address family */ + my_addr.sin_port = htons (url->port); + my_addr.sin_addr.s_addr = inet_addr(url->host); + + local = g_socket_address_new_from_native (&my_addr, sizeof(my_addr)); + + g_socket_set_blocking (tcp, FALSE); + +tcp_retry: + if ((g_socket_connect (tcp, local, NULL, NULL))) { + g_print( "Error connecting socket : %s\n", strerror( errno ) ); + if (retry < 50) { + GST_ERROR("Connection failed... Try again..."); + usleep(100000); + retry++; + goto tcp_retry; + } + + return GST_RTSP_ERROR; + } + + if ((res = gst_rtsp_connection_create_from_socket (tcp, url->host, url->port, NULL, &conn)) < 0) + return GST_RTSP_ERROR; + + GST_DEBUG_OBJECT (client, "Able to connect to new port"); + + sin_len = sizeof(struct sockaddr); + fd = g_socket_get_fd (gst_rtsp_connection_get_read_socket (conn)); + if (fd == -1) { + return GST_RTSP_EINVAL; + } + + if (getsockname (fd, (struct sockaddr *)&server_addr, &sin_len) < 0) { + GST_ERROR_OBJECT (client, "Getsockname fail"); + close(fd); + return GST_RTSP_ERROR; + } + + GST_DEBUG_OBJECT (client, "New port created : %d", ntohs(server_addr.sin_port)); + + /* Set send buffer size to 5242880 */ + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, (socklen_t)rn) < 0) { + GST_ERROR_OBJECT(client, "setsockopt failed"); + } else { + getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, (socklen_t *)&rn); + GST_WARNING_OBJECT(client, "New Send buf size : %d\n", bsize); + } + + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state)) < 0) { + GST_ERROR_OBJECT(client, "setsockopt failed"); + } else { + GST_WARNING_OBJECT(client, "TCP NO DELAY"); + } + + client->priv->data_conn = conn; + + /* create watch for the connection and attach */ + client->priv->datawatch = gst_rtsp_watch_new (client->priv->data_conn, &watch_funcs_tcp, client, (GDestroyNotify) client_watch_notify_tcp); + GST_DEBUG_OBJECT (client, "data watch : %p", client->priv->datawatch); + /* find the context to add the watch */ + if ((source = g_main_current_source ())) + context = g_source_get_context (source); + else + context = NULL; + + GST_DEBUG (" source = %p", source); + GST_INFO ("attaching to context %p", context); + client->priv->datawatchid = gst_rtsp_watch_attach (client->priv->datawatch, context); + gst_rtsp_watch_unref (client->priv->datawatch); + return res; +} + +static void +do_keepalive (GstRTSPSession * session) +{ + GST_INFO ("keep session %p alive", session); + gst_rtsp_session_touch (session); +} +static void +map_transport (GstRTSPWFDClient * client, GstRTSPTransport * ct) +{ + switch(client->priv->ctrans) { + case GST_WFD_RTSP_TRANS_RTP: + ct->trans = GST_RTSP_TRANS_RTP; + break; + case GST_WFD_RTSP_TRANS_RDT: + ct->trans = GST_RTSP_TRANS_RDT; + break; + default: + ct->trans = GST_RTSP_TRANS_UNKNOWN; + break; + } + switch(client->priv->cprofile) { + case GST_WFD_RTSP_PROFILE_AVP: + ct->profile = GST_RTSP_PROFILE_AVP; + break; + case GST_WFD_RTSP_PROFILE_SAVP: + ct->profile = GST_RTSP_PROFILE_SAVP; + break; + default: + ct->profile = GST_RTSP_PROFILE_UNKNOWN; + break; + } + switch(client->priv->clowertrans) { + case GST_WFD_RTSP_LOWER_TRANS_UDP: + ct->lower_transport = GST_RTSP_LOWER_TRANS_UDP; + break; + case GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST: + ct->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + break; + case GST_WFD_RTSP_LOWER_TRANS_TCP: + ct->lower_transport = GST_RTSP_LOWER_TRANS_TCP; + break; + case GST_WFD_RTSP_LOWER_TRANS_HTTP: + ct->lower_transport = GST_RTSP_LOWER_TRANS_HTTP; + break; + default: + ct->lower_transport = GST_RTSP_LOWER_TRANS_UNKNOWN; + break; + } + + if (client->priv->ts_mode == WFD_TS_TCP) + ct->lower_transport = GST_RTSP_LOWER_TRANS_TCP; +} + +static GstRTSPResult +handle_ts_response (GstRTSPWFDClient * client, GstRTSPContext * ctx) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPTransport *ct; + GstRTSPConnection *conn; + GstRTSPUrl *url = NULL; + GList *t = NULL; + GstRTSPStreamTransport *tr = NULL; + GPtrArray *ta = NULL; + + ta = g_ptr_array_new(); + + t = client->priv->transports; + tr = GST_RTSP_STREAM_TRANSPORT (t->data); + g_ptr_array_add (ta, t->data); + + gst_rtsp_stream_transport_set_callbacks (tr, NULL, NULL, NULL, NULL); + gst_rtsp_stream_transport_set_keepalive (tr, NULL, ctx->session, NULL); + + gst_rtsp_transport_new (&ct); + gst_rtsp_transport_init (ct); + + map_transport (client, ct); + + if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) { + GST_WARNING_OBJECT (client, "Trans or profile is wrong"); + goto error; + } + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_HTTP || + ct->lower_transport == GST_RTSP_LOWER_TRANS_UNKNOWN) { + GST_WARNING_OBJECT (client, "Lowertrans is wrong"); + goto error; + } + g_free (ct->destination); + if (client->priv->ts_mode == WFD_TS_UDP) { + g_print ("\nSwitched to UDP !!!\n"); + /* Free any previous TCP connection */ + if(client->priv->data_conn) + { + gst_rtsp_connection_close (client->priv->data_conn); + gst_rtsp_connection_free(client->priv->data_conn); + if (client->priv->datawatch) { + g_source_destroy ((GSource *)client->priv->datawatch); + } + } + conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client)); + url = gst_rtsp_connection_get_url (conn); + gst_rtsp_url_set_port (url, client->priv->crtp_port0); + ct->destination = g_strdup (url->host); + ct->client_port.min = client->priv->crtp_port0; + if(client->priv->crtp_port1 == 0) + ct->client_port.max = client->priv->crtp_port0 + 1; + else ct->client_port.max = client->priv->crtp_port1; + } else if (client->priv->ts_mode == WFD_TS_TCP) { + res = new_tcp(client); + if(res != GST_RTSP_OK) + goto error; + + conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client)); + url = gst_rtsp_connection_get_url (conn); + ct->destination = g_strdup (url->host); + ct->client_port.min = client->priv->crtp_port0_tcp; + if(client->priv->crtp_port1_tcp == 0) + ct->client_port.max = client->priv->crtp_port0_tcp + 1; + else ct->client_port.max = client->priv->crtp_port1_tcp; + } + + gst_rtsp_stream_transport_set_transport (tr, ct); + + GST_DEBUG ("client %p: linking transport", client); + if (client->priv->ts_mode == WFD_TS_TCP) { + g_print ("\nSwitched to TCP !!!\n"); + gst_rtsp_stream_transport_set_callbacks (tr, (GstRTSPSendFunc) do_send_data, + (GstRTSPSendFunc) do_send_data, client, NULL); + } + else if(client->priv->ts_mode == WFD_TS_UDP ) { + g_print ("\nSwitched to UDP !!!\n"); + /* configure keepalive for this transport */ + gst_rtsp_stream_transport_set_keepalive (tr, (GstRTSPKeepAliveFunc) do_keepalive, ctx->session, NULL); + gst_rtsp_stream_transport_set_callbacks (tr, NULL, NULL, client, NULL); + } + + gst_rtsp_media_set_state (client->priv->media, GST_STATE_PLAYING, ta); + + g_ptr_array_free (ta, FALSE); + + return res; + +error: + return GST_RTSP_ERROR; +} static void handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -1111,6 +1519,28 @@ handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx) goto error; } } + if (msg->tcp_ports) { + /* Get the TCP ports preferred by WFDSink */ + wfd_res = + gst_wfd_message_get_prefered_tcp_ports (msg, &priv->ctrans_tcp, + &priv->cprofile_tcp, &priv->clowertrans_tcp, &priv->crtp_port0_tcp, + &priv->crtp_port1_tcp); + if (wfd_res != GST_WFD_OK) { + GST_WARNING_OBJECT (client, + "Failed to get wfd prefered RTP ports..."); + goto error; + } + } + + if (msg->buf_len) { + wfd_res = + gst_wfd_message_get_buffer_length (msg, &priv->buf_len); + if (wfd_res != GST_WFD_OK) { + GST_WARNING_OBJECT (client, + "Failed to get wfd prefered RTP ports..."); + goto error; + } + } if (msg->display_edid) { guint32 edid_block_count = 0; @@ -1176,6 +1606,41 @@ handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST], 0, ctx); } else { + if (g_strrstr((char *)data, "wfd2_buffer_len")) { + GstWFDResult wfd_res; + GstWFDMessage *msg = NULL; + GST_DEBUG_OBJECT (_client, "Get TS message responce"); + + /* Parse TS response from sink */ + wfd_res = gst_wfd_message_new (&msg); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to create wfd message..."); + goto error; + } + + wfd_res = gst_wfd_message_init (msg); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to init wfd message..."); + goto error; + } + + wfd_res = gst_wfd_message_parse_buffer (data, size, msg); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to parse wfd message..."); + goto error; + } + + wfd_res = gst_wfd_message_get_buffer_length (msg, &_client->priv->buf_len); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to parse wfd message..."); + goto error; + } + + if (GST_RTSP_OK != handle_ts_response (_client, ctx)) { + GST_ERROR_OBJECT (client, "Failed to handle transport switch response"); + goto error; + } + } /* TODO-WFD: Handle another GET_PARAMETER response with body */ } } else if (size == 0) { @@ -1431,6 +1896,8 @@ typedef enum TEARDOWN_TRIGGER, PLAY_TRIGGER, PAUSE_TRIGGER, + TS_REQ_MSG, + TS_REP_REQ_MSG, } GstWFDMessageType; static gboolean @@ -1605,6 +2072,24 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type, goto error; } + /* set the preffered TCP ports for the WFD server */ + wfd_res = + gst_wfd_messge_set_prefered_tcp_ports (msg, GST_WFD_RTSP_TRANS_RTP, + GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->crtp_port0, priv->crtp_port1); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, + "Failed to set tcp ports parameter on wfd message..."); + goto error; + } + + /* set the buffer length for the WFD server */ + wfd_res = + gst_wfd_message_set_buffer_length (msg, 0); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, + "Failed to set tcp ports parameter on wfd message..."); + goto error; + } *data = gst_wfd_message_param_names_as_text (msg); if (*data == NULL) { GST_ERROR_OBJECT (client, "Failed to get wfd message as text..."); @@ -1794,6 +2279,69 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type, GST_ERROR_OBJECT (client, "Failed to get wfd message as text..."); goto error; } else { + *len = strlen (*data); + } + + } else if (msg_type == TS_REQ_MSG) { + /* create transport switch request to be sent */ + wfd_res = gst_wfd_message_new (&msg); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to create wfd message..."); + goto error; + } + + wfd_res = gst_wfd_message_init (msg); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, "Failed to init wfd message..."); + goto error; + } + + g_string_append_printf (buf, "rtsp://"); + + if (priv->host_address) { + g_string_append (buf, priv->host_address); + } else { + GST_ERROR_OBJECT (client, "Failed to get host address"); + if (buf) g_string_free (buf, TRUE); + goto error; + } + + g_string_append_printf (buf, "/wfd1.0/streamid=0"); + + /* set the preffered TCP ports for the WFD server */ + if (priv->ts_mode == WFD_TS_UDP) { + wfd_res = + gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_RTP, + GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->crtp_port0, priv->crtp_port1); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, + "Failed to set prefered RTP ports on wfd message..."); + goto error; + } + } else { + wfd_res = + gst_wfd_messge_set_prefered_tcp_ports (msg, GST_WFD_RTSP_TRANS_RTP, + GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_TCP, priv->crtp_port0_tcp, priv->crtp_port1_tcp); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, + "Failed to set prefered TCP ports on wfd message..."); + goto error; + } + } + + wfd_res = + gst_wfd_message_set_buffer_length (msg, 200); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (client, + "Failed to set prefered buffer length on wfd message..."); + goto error; + } + + *data = gst_wfd_message_as_text (msg); + if (*data == NULL) { + GST_ERROR_OBJECT (client, "Failed to get wfd message as text..."); + goto error; + } else { gchar *append_data = NULL; g_signal_emit (client, @@ -3102,8 +3650,157 @@ gst_rtsp_wfd_client_set_rtp_port1 (GstRTSPWFDClient * client, guint32 port) priv->crtp_port1 = port; } -gchar * -gst_rtsp_wfd_client_get_sink_user_agent (GstRTSPWFDClient * client) + +/** +* prepare_transport_switch_request: +* @client: client object +* @request : requst message to be prepared +* @url : url need to be in the request +* +* Prepares request based on @method & @message_type +* +* Returns: a #GstRTSPResult. +*/ +static GstRTSPResult +prepare_transport_switch_request (GstRTSPWFDClient * client, GstRTSPMessage * request) +{ + GstRTSPResult res = GST_RTSP_OK; + gchar *url = NULL; + gchar *msg = NULL; + guint msglen = 0; + GString *msglength; + + GstRTSPMethod method = GST_RTSP_SET_PARAMETER; + + url = g_strdup ("rtsp://localhost/wfd1.0"); + + GST_DEBUG_OBJECT (client, "Preparing request for transport switch"); + + /* initialize the request */ + res = gst_rtsp_message_init_request (request, method, url); + if (res < 0) { + GST_ERROR ("init request failed"); + return res; + } + + /* add content type */ + res = + gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, + "text/parameters"); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (client, "Failed to add header to rtsp request..."); + goto error; + } + + _set_wfd_message_body (client, TS_REQ_MSG, &msg, &msglen); + msglength = g_string_new (""); + g_string_append_printf (msglength, "%d", msglen); + GST_DEBUG ("Transport switch server side message body: %s", msg); + + /* add content-length type */ + res = + gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, + g_string_free (msglength, FALSE)); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (client, "Failed to add header to rtsp message..."); + goto error; + } + + res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (client, "Failed to add header to rtsp message..."); + goto error; + } + + g_free (msg); + + return res; + +error: + return GST_RTSP_ERROR; +} + +GstRTSPResult +gst_rtsp_wfd_client_switch_to_udp (GstRTSPWFDClient * client) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GList *tl = NULL; + GPtrArray *ta = NULL; + + ta = g_ptr_array_new(); + + tl = gst_rtsp_stream_transport_filter (client->priv->stats.stream, NULL, NULL); + client->priv->transports = tl; + g_ptr_array_add (ta, tl->data); + + if (client->priv->ts_mode == WFD_TS_UDP) { + GST_ERROR_OBJECT (client, "Transport already UDP"); + return res; + } + + client->priv->ts_mode = WFD_TS_UDP; + res = prepare_transport_switch_request (client, &request); + if (GST_RTSP_OK != res) { + GST_ERROR_OBJECT (client, "Failed to prepare transport switch request....\n"); + goto error; + } + + GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message for transport switch..."); + + gst_send_request (client, NULL, &request); + + gst_rtsp_media_set_state (client->priv->media, GST_STATE_PAUSED, ta); + + g_ptr_array_free (ta, FALSE); + + return res; + +error: + return res; + +} + +GstRTSPResult +gst_rtsp_wfd_client_switch_to_tcp (GstRTSPWFDClient * client) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GList *tl = NULL; + GPtrArray *ta = NULL; + + ta = g_ptr_array_new(); + + tl = gst_rtsp_stream_transport_filter (client->priv->stats.stream, NULL, NULL); + client->priv->transports = tl; + g_ptr_array_add (ta, tl->data); + + if (client->priv->ts_mode == WFD_TS_TCP) { + GST_ERROR_OBJECT (client, "Transport already TCP"); + return res; + } + + client->priv->ts_mode = WFD_TS_TCP; + res = prepare_transport_switch_request (client, &request); + if (GST_RTSP_OK != res) { + GST_ERROR_OBJECT (client, "Failed to prepare transport switch request....\n"); + goto error; + } + + GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message for transport switch..."); + + gst_send_request (client, NULL, &request); + + gst_rtsp_media_set_state (client->priv->media, GST_STATE_PAUSED, ta); + + g_ptr_array_free (ta, FALSE); + + return res; + +error: + return res; +} +gchar * gst_rtsp_wfd_client_get_sink_user_agent (GstRTSPWFDClient * client) { char *str = NULL; GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client); diff --git a/gst/rtsp-server/rtsp-client-wfd.h b/gst/rtsp-server/rtsp-client-wfd.h old mode 100644 new mode 100755 index f59835b..4d78382 --- a/gst/rtsp-server/rtsp-client-wfd.h +++ b/gst/rtsp-server/rtsp-client-wfd.h @@ -149,6 +149,8 @@ GstRTSPResult gst_prepare_request (GstRTSPWFDClient * client, GstRTSPMessage * request, GstRTSPMethod method, gchar * url); void gst_send_request (GstRTSPWFDClient * client, GstRTSPSession * session, GstRTSPMessage * request); +GstRTSPResult gst_rtsp_wfd_client_switch_to_udp (GstRTSPWFDClient * client); +GstRTSPResult gst_rtsp_wfd_client_switch_to_tcp (GstRTSPWFDClient * client); guint gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client); guint gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client); diff --git a/gst/rtsp-server/rtsp-server-wfd.c b/gst/rtsp-server/rtsp-server-wfd.c index 0fa2cd5..042ec3b 100644 --- a/gst/rtsp-server/rtsp-server-wfd.c +++ b/gst/rtsp-server/rtsp-server-wfd.c @@ -334,3 +334,61 @@ gst_rtsp_wfd_server_set_audio_codec (GstRTSPWFDServer * server, GST_RTSP_WFD_SERVER_UNLOCK (server); return res; } + +GstRTSPResult +gst_rtsp_wfd_server_switch_to_udp (GstRTSPWFDServer *server) +{ + GstRTSPResult res = GST_RTSP_OK; + GList *clients, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), GST_RTSP_ERROR); + + clients = gst_rtsp_server_client_filter (GST_RTSP_SERVER(server), NULL, NULL); + if (clients == NULL) { + GST_ERROR_OBJECT (server, "There is no client in this server"); + } + + for (walk = clients; walk; walk = next) { + GstRTSPClient *client = walk->data; + + next = g_list_next (walk); + + res = + gst_rtsp_wfd_client_switch_to_udp (GST_RTSP_WFD_CLIENT (client)); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (server, "Failed to switch transport to UDP"); + } + g_object_unref (client); + } + + return res; +} + +GstRTSPResult +gst_rtsp_wfd_server_switch_to_tcp (GstRTSPWFDServer *server) +{ + GstRTSPResult res = GST_RTSP_OK; + GList *clients, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), GST_RTSP_ERROR); + + clients = gst_rtsp_server_client_filter (GST_RTSP_SERVER(server), NULL, NULL); + if (clients == NULL) { + GST_ERROR_OBJECT (server, "There is no client in this server"); + } + + for (walk = clients; walk; walk = next) { + GstRTSPClient *client = walk->data; + + next = g_list_next (walk); + + res = + gst_rtsp_wfd_client_switch_to_tcp (GST_RTSP_WFD_CLIENT (client)); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (server, "Failed to switch transport to TCP"); + } + g_object_unref (client); + } + + return res; +} diff --git a/gst/rtsp-server/rtsp-server-wfd.h b/gst/rtsp-server/rtsp-server-wfd.h old mode 100644 new mode 100755 index e718e62..1666f18 --- a/gst/rtsp-server/rtsp-server-wfd.h +++ b/gst/rtsp-server/rtsp-server-wfd.h @@ -81,6 +81,8 @@ GstRTSPResult gst_rtsp_wfd_server_trigger_request (GstRTSPServer *s GstRTSPResult gst_rtsp_wfd_server_set_supported_reso (GstRTSPWFDServer *server, guint64 supported_reso); GstRTSPResult gst_rtsp_wfd_server_set_video_native_reso (GstRTSPWFDServer *server, guint64 native_reso); GstRTSPResult gst_rtsp_wfd_server_set_audio_codec (GstRTSPWFDServer *server, guint8 audio_codec); +GstRTSPResult gst_rtsp_wfd_server_switch_to_udp (GstRTSPWFDServer *server); +GstRTSPResult gst_rtsp_wfd_server_switch_to_tcp (GstRTSPWFDServer *server); #if 0 void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); diff --git a/packaging/gst-rtsp-server.spec b/packaging/gst-rtsp-server.spec index f73387c..d6ae977 100644 --- a/packaging/gst-rtsp-server.spec +++ b/packaging/gst-rtsp-server.spec @@ -1,7 +1,7 @@ Name: gst-rtsp-server Summary: Multimedia Framework Library Version: 1.6.1 -Release: 3 +Release: 4 Url: http://gstreamer.freedesktop.org/ Group: System/Libraries License: LGPL-2.0+ -- 2.7.4