gst/rtsp/gstrtspsrc.c: Send RTCP messages back to the server over the TCP connection.

Original commit message from CVS:
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_event),
(gst_rtspsrc_handle_src_query), (gst_rtspsrc_sink_chain),
(gst_rtspsrc_stream_configure_manager),
(gst_rtspsrc_stream_free_udp), (gst_rtspsrc_stream_configure_tcp),
(gst_rtspsrc_stream_configure_mcast),
(gst_rtspsrc_stream_configure_udp),
(gst_rtspsrc_stream_configure_udp_sink),
(gst_rtspsrc_stream_configure_transport):
Send RTCP messages back to the server over the TCP connection.
* gst/rtsp/rtspconnection.c: (rtsp_connection_write),
(rtsp_connection_send), (rtsp_connection_read), (read_body),
(rtsp_connection_receive):
* gst/rtsp/rtspconnection.h:
Factor out and expose lowlevel _write and _read methods.
Implement sending data messages to the server.
This commit is contained in:
Wim Taymans 2007-05-04 12:31:32 +00:00
parent 4d42c097a6
commit fb80e57990
4 changed files with 183 additions and 56 deletions

View file

@ -1,3 +1,22 @@
2007-05-04 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_event),
(gst_rtspsrc_handle_src_query), (gst_rtspsrc_sink_chain),
(gst_rtspsrc_stream_configure_manager),
(gst_rtspsrc_stream_free_udp), (gst_rtspsrc_stream_configure_tcp),
(gst_rtspsrc_stream_configure_mcast),
(gst_rtspsrc_stream_configure_udp),
(gst_rtspsrc_stream_configure_udp_sink),
(gst_rtspsrc_stream_configure_transport):
Send RTCP messages back to the server over the TCP connection.
* gst/rtsp/rtspconnection.c: (rtsp_connection_write),
(rtsp_connection_send), (rtsp_connection_read), (read_body),
(rtsp_connection_receive):
* gst/rtsp/rtspconnection.h:
Factor out and expose lowlevel _write and _read methods.
Implement sending data messages to the server.
2007-05-03 Wim Taymans <wim@fluendo.com> 2007-05-03 Wim Taymans <wim@fluendo.com>
* gst/multipart/multipartmux.c: (gst_multipart_mux_queue_pads), * gst/multipart/multipartmux.c: (gst_multipart_mux_queue_pads),

View file

@ -120,12 +120,19 @@ static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("stream%d",
GST_PAD_SOMETIMES, GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtp; application/x-rdt")); GST_STATIC_CAPS ("application/x-rtp; application/x-rdt"));
/* template used internally */ /* templates used internally */
static GstStaticPadTemplate anytemplate = GST_STATIC_PAD_TEMPLATE ("internal%d", static GstStaticPadTemplate anysrctemplate =
GST_STATIC_PAD_TEMPLATE ("internalsrc%d",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_SOMETIMES, GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY); GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate anysinktemplate =
GST_STATIC_PAD_TEMPLATE ("internalsink%d",
GST_PAD_SINK,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
enum enum
{ {
/* FILL ME */ /* FILL ME */
@ -1081,6 +1088,40 @@ gst_rtspsrc_handle_src_query (GstPad * pad, GstQuery * query)
return res; return res;
} }
/* callback for RTCP messages to be sent to the server when operating in TCP
* mode. */
static GstFlowReturn
gst_rtspsrc_sink_chain (GstPad * pad, GstBuffer * buffer)
{
GstRTSPSrc *src;
GstRTSPStream *stream;
GstFlowReturn res = GST_FLOW_OK;
guint8 *data;
guint size;
RTSPResult ret;
RTSPMessage message = { 0 };
stream = (GstRTSPStream *) gst_pad_get_element_private (pad);
src = stream->parent;
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
rtsp_message_init_data (&message, stream->channel[1]);
rtsp_message_take_body (&message, data, size);
GST_DEBUG_OBJECT (src, "sending %u bytes RTCP", size);
ret = rtsp_connection_send (src->connection, &message, NULL);
GST_DEBUG_OBJECT (src, "sent RTCP, %d", ret);
rtsp_message_steal_body (&message, &data, &size);
gst_buffer_unref (buffer);
return res;
}
static void static void
pad_unblocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src) pad_unblocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src)
{ {
@ -1350,14 +1391,12 @@ gst_rtspsrc_stream_configure_tcp (GstRTSPSrc * src, GstRTSPStream * stream,
*outpad = gst_object_ref (stream->channelpad[0]); *outpad = gst_object_ref (stream->channelpad[0]);
} else { } else {
GstPadTemplate *template;
GST_DEBUG_OBJECT (src, "using manager source pad"); GST_DEBUG_OBJECT (src, "using manager source pad");
template = gst_static_pad_template_get (&anytemplate); template = gst_static_pad_template_get (&anysrctemplate);
/* allocate pads for sending the channel data into the manager */ /* allocate pads for sending the channel data into the manager */
pad0 = gst_pad_new_from_template (template, "internal0"); pad0 = gst_pad_new_from_template (template, "internalsrc0");
gst_pad_set_event_function (pad0, gst_rtspsrc_handle_src_event); gst_pad_set_event_function (pad0, gst_rtspsrc_handle_src_event);
gst_pad_set_query_function (pad0, gst_rtspsrc_handle_src_query); gst_pad_set_query_function (pad0, gst_rtspsrc_handle_src_query);
gst_pad_link (pad0, stream->channelpad[0]); gst_pad_link (pad0, stream->channelpad[0]);
@ -1367,12 +1406,31 @@ gst_rtspsrc_stream_configure_tcp (GstRTSPSrc * src, GstRTSPStream * stream,
if (stream->channelpad[1]) { if (stream->channelpad[1]) {
/* if we have a sinkpad for the other channel, create a pad and link to the /* if we have a sinkpad for the other channel, create a pad and link to the
* manager. */ * manager. */
pad1 = gst_pad_new_from_template (template, "internal1"); pad1 = gst_pad_new_from_template (template, "internalsrc1");
gst_pad_link (pad1, stream->channelpad[1]); gst_pad_link (pad1, stream->channelpad[1]);
stream->channelpad[1] = pad1; stream->channelpad[1] = pad1;
} }
gst_object_unref (template); gst_object_unref (template);
} }
/* setup RTCP transport back to the server */
if (src->session) {
GstPad *pad;
template = gst_static_pad_template_get (&anysinktemplate);
stream->rtcppad = gst_pad_new_from_template (template, "internalsink0");
gst_pad_set_chain_function (stream->rtcppad, gst_rtspsrc_sink_chain);
gst_pad_set_element_private (stream->rtcppad, stream);
gst_pad_set_active (stream->rtcppad, TRUE);
/* get session RTCP pad */
name = g_strdup_printf ("send_rtcp_src_%d", stream->id);
pad = gst_element_get_request_pad (src->session, name);
g_free (name);
/* and link */
gst_pad_link (pad, stream->rtcppad);
}
return TRUE; return TRUE;
} }
@ -1500,6 +1558,10 @@ gst_rtspsrc_stream_configure_udp_sink (GstRTSPSrc * src, GstRTSPStream * stream,
gint port; gint port;
gchar *destination, *uri, *name; gchar *destination, *uri, *name;
/* no session, we're done */
if (src->session == NULL)
return TRUE;
/* get host and port */ /* get host and port */
if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST) if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST)
port = transport->port.max; port = transport->port.max;

View file

@ -264,13 +264,44 @@ append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str)
} }
} }
RTSPResult
rtsp_connection_write (RTSPConnection * conn, const guint8 * data, guint size,
GTimeVal * timeout)
{
guint towrite;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
g_return_val_if_fail (data != NULL || size == 0, RTSP_EINVAL);
towrite = size;
while (towrite > 0) {
gint written;
written = write (conn->fd, data, towrite);
if (written < 0) {
if (errno != EAGAIN && errno != EINTR)
goto write_error;
} else {
towrite -= written;
data += written;
}
}
return RTSP_OK;
/* ERRORS */
write_error:
{
return RTSP_ESYS;
}
}
RTSPResult RTSPResult
rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message, rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message,
GTimeVal * timeout) GTimeVal * timeout)
{ {
GString *str; GString *str = NULL;
gint towrite; RTSPResult res;
gchar *data;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
WSADATA w; WSADATA w;
@ -305,57 +336,69 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message,
g_string_append_printf (str, "RTSP/1.0 %d %s\r\n", g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
message->type_data.response.code, message->type_data.response.reason); message->type_data.response.code, message->type_data.response.reason);
break; break;
case RTSP_MESSAGE_DATA:
{
guint8 data_header[4];
/* prepare data header */
data_header[0] = '$';
data_header[1] = message->type_data.data.channel;
data_header[2] = (message->body_size >> 8) & 0xff;
data_header[3] = message->body_size & 0xff;
/* create string with header and data */
str = g_string_append_len (str, (gchar *) data_header, 4);
str =
g_string_append_len (str, (gchar *) message->body,
message->body_size);
break;
}
default: default:
g_assert_not_reached (); g_assert_not_reached ();
break; break;
} }
/* append session id if we have one */ /* append specific headers and body */
if (conn->session_id[0] != '\0') { switch (message->type) {
append_header (RTSP_HDR_SESSION, conn->session_id, str); case RTSP_MESSAGE_REQUEST:
} case RTSP_MESSAGE_RESPONSE:
/* append session id if we have one */
if (conn->session_id[0] != '\0') {
append_header (RTSP_HDR_SESSION, conn->session_id, str);
}
/* append headers */
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
/* append headers */ /* Append any authentication headers */
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str); append_auth_header (conn, message, str);
/* Append any authentication headers */ /* append Content-Length and body if needed */
append_auth_header (conn, message, str); if (message->body != NULL && message->body_size > 0) {
gchar *len;
/* append Content-Length and body if needed */ len = g_strdup_printf ("%d", message->body_size);
if (message->body != NULL && message->body_size > 0) { append_header (RTSP_HDR_CONTENT_LENGTH, len, str);
gchar *len; g_free (len);
/* header ends here */
len = g_strdup_printf ("%d", message->body_size); g_string_append (str, "\r\n");
append_header (RTSP_HDR_CONTENT_LENGTH, len, str); str =
g_free (len); g_string_append_len (str, (gchar *) message->body,
/* header ends here */ message->body_size);
g_string_append (str, "\r\n"); } else {
str = /* just end headers */
g_string_append_len (str, (gchar *) message->body, message->body_size); g_string_append (str, "\r\n");
} else { }
/* just end headers */ break;
g_string_append (str, "\r\n"); default:
break;
} }
/* write request */ /* write request */
towrite = str->len; res = rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
data = str->str;
while (towrite > 0) {
gint written;
written = write (conn->fd, data, towrite);
if (written < 0) {
if (errno != EAGAIN && errno != EINTR)
goto write_error;
} else {
towrite -= written;
data += written;
}
}
g_string_free (str, TRUE); g_string_free (str, TRUE);
return RTSP_OK; return res;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
startup_error: startup_error:
@ -371,11 +414,6 @@ version_error:
return RTSP_EWSAVERSION; return RTSP_EWSAVERSION;
} }
#endif #endif
write_error:
{
g_string_free (str, TRUE);
return RTSP_ESYS;
}
} }
static RTSPResult static RTSPResult
@ -550,7 +588,7 @@ no_column:
} }
RTSPResult RTSPResult
rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size, rtsp_connection_read (RTSPConnection * conn, guint8 * data, guint size,
GTimeVal * timeout) GTimeVal * timeout)
{ {
fd_set readfds; fd_set readfds;
@ -631,7 +669,7 @@ rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size,
goto read_error; goto read_error;
} else { } else {
toread -= bytes; toread -= bytes;
data = (char *) data + bytes; data += bytes;
} }
} }
return RTSP_OK; return RTSP_OK;
@ -663,7 +701,7 @@ static RTSPResult
read_body (RTSPConnection * conn, glong content_length, RTSPMessage * msg, read_body (RTSPConnection * conn, glong content_length, RTSPMessage * msg,
GTimeVal * timeout) GTimeVal * timeout)
{ {
gchar *body; guint8 *body;
RTSPResult res; RTSPResult res;
if (content_length <= 0) { if (content_length <= 0) {
@ -732,7 +770,8 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg,
rtsp_message_init_data (msg, (gint) c); rtsp_message_init_data (msg, (gint) c);
/* next two bytes are the length of the data */ /* next two bytes are the length of the data */
RTSP_CHECK (rtsp_connection_read (conn, &size, 2, timeout), read_error); RTSP_CHECK (rtsp_connection_read (conn, (guint8 *) & size, 2, timeout),
read_error);
size = GUINT16_FROM_BE (size); size = GUINT16_FROM_BE (size);

View file

@ -78,10 +78,17 @@ RTSPResult rtsp_connection_connect (RTSPConnection *conn, GTimeVal *timeou
RTSPResult rtsp_connection_close (RTSPConnection *conn); RTSPResult rtsp_connection_close (RTSPConnection *conn);
RTSPResult rtsp_connection_free (RTSPConnection *conn); RTSPResult rtsp_connection_free (RTSPConnection *conn);
/* sending/receiving raw bytes */
RTSPResult rtsp_connection_read (RTSPConnection * conn, guint8 * data,
guint size, GTimeVal * timeout);
RTSPResult rtsp_connection_write (RTSPConnection * conn, const guint8 * data,
guint size, GTimeVal * timeout);
/* sending/receiving messages */ /* sending/receiving messages */
RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout);
RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout);
/* flushing state */
RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush); RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush);
/* Configure Authentication data */ /* Configure Authentication data */