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;
}
#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);
} 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;
}
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);
}
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);
}
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;
}
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;
+}
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
#include "rtsp-client-wfd.h"
#include "rtsp-media-factory-wfd.h"
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 */
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
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");
}
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);
}
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)
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)
{
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;
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) {
TEARDOWN_TRIGGER,
PLAY_TRIGGER,
PAUSE_TRIGGER,
+ TS_REQ_MSG,
+ TS_REP_REQ_MSG,
} GstWFDMessageType;
static gboolean
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...");
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,
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);