gst/rtsp/gstrtspsrc.c: Refactor transport configuration code.

Original commit message from CVS:
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
(gst_rtspsrc_alloc_udp_ports), (gst_rtspsrc_handle_src_event),
(gst_rtspsrc_handle_src_query),
(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), (gst_rtspsrc_push_event),
(gst_rtspsrc_loop_udp), (gst_rtspsrc_open),
(gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play),
(gst_rtspsrc_pause):
Refactor transport configuration code.
Create internal pads for TCP transport so that we can implement events
and queries.
Handle events and queries.
Parse range from the SDP.
Fix race in pause handler where the connection could still be flushing.
This commit is contained in:
Wim Taymans 2007-05-03 13:48:54 +00:00
parent 24e51b3c73
commit 17011e9a41
2 changed files with 432 additions and 215 deletions

View file

@ -1,3 +1,24 @@
2007-05-03 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
(gst_rtspsrc_alloc_udp_ports), (gst_rtspsrc_handle_src_event),
(gst_rtspsrc_handle_src_query),
(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), (gst_rtspsrc_push_event),
(gst_rtspsrc_loop_udp), (gst_rtspsrc_open),
(gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play),
(gst_rtspsrc_pause):
Refactor transport configuration code.
Create internal pads for TCP transport so that we can implement events
and queries.
Handle events and queries.
Parse range from the SDP.
Fix race in pause handler where the connection could still be flushing.
2007-05-02 Wim Taymans <wim@fluendo.com> 2007-05-02 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),

View file

@ -120,6 +120,12 @@ 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 */
static GstStaticPadTemplate anytemplate = GST_STATIC_PAD_TEMPLATE ("internal%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
enum enum
{ {
/* FILL ME */ /* FILL ME */
@ -313,7 +319,6 @@ gst_rtspsrc_finalize (GObject * object)
g_free (rtspsrc->req_location); g_free (rtspsrc->req_location);
g_free (rtspsrc->content_base); g_free (rtspsrc->content_base);
rtsp_url_free (rtspsrc->url); rtsp_url_free (rtspsrc->url);
g_free (rtspsrc->addr);
g_static_rec_mutex_free (rtspsrc->state_rec_lock); g_static_rec_mutex_free (rtspsrc->state_rec_lock);
g_free (rtspsrc->state_rec_lock); g_free (rtspsrc->state_rec_lock);
@ -939,7 +944,7 @@ again:
g_object_get (G_OBJECT (udpsrc0), "port", rtpport, NULL); g_object_get (G_OBJECT (udpsrc0), "port", rtpport, NULL);
g_object_get (G_OBJECT (udpsrc1), "port", rtcpport, NULL); g_object_get (G_OBJECT (udpsrc1), "port", rtcpport, NULL);
/* this should not happen */ /* this should not happen... */
if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp) if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp)
goto port_error; goto port_error;
@ -1005,6 +1010,77 @@ cleanup:
} }
} }
static gboolean
gst_rtspsrc_handle_src_event (GstPad * pad, GstEvent * event)
{
GstRTSPSrc *src;
gboolean res = TRUE;
src = GST_RTSPSRC_CAST (gst_pad_get_element_private (pad));
GST_DEBUG_OBJECT (src, "pad %s:%s received event %s",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_QOS:
break;
case GST_EVENT_SEEK:
break;
case GST_EVENT_NAVIGATION:
break;
case GST_EVENT_LATENCY:
break;
default:
break;
}
return res;
}
static gboolean
gst_rtspsrc_handle_src_query (GstPad * pad, GstQuery * query)
{
GstRTSPSrc *src;
gboolean res = TRUE;
src = GST_RTSPSRC_CAST (gst_pad_get_element_private (pad));
GST_DEBUG_OBJECT (src, "pad %s:%s received query %s",
GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION:
{
break;
}
case GST_QUERY_DURATION:
{
GstFormat format;
gst_query_parse_duration (query, &format, NULL);
switch (format) {
case GST_FORMAT_TIME:
break;
default:
res = FALSE;
break;
}
break;
}
case GST_QUERY_LATENCY:
{
/* we are live with a min latency of 0 and unlimted max latency */
gst_query_set_latency (query, TRUE, 0, -1);
break;
}
default:
break;
}
return res;
}
static void static void
pad_unblocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src) pad_unblocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src)
{ {
@ -1135,39 +1211,15 @@ unknown_stream:
} }
} }
/* sets up all elements needed for streaming over the specified transport. /* try to get and configure a manager */
* Does not yet expose the element pads, this will be done when there is actuall
* dataflow detected, which might never happen when UDP is blocked in a
* firewall, for example.
*/
static gboolean static gboolean
gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream, gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
RTSPTransport * transport) RTSPTransport * transport)
{ {
GstRTSPSrc *src; const gchar *manager;
GstPad *outpad = NULL;
GstPadTemplate *template;
GstStateChangeReturn ret;
gchar *name; gchar *name;
GstStructure *s;
const gchar *mime, *manager;
RTSPResult res; RTSPResult res;
GstStateChangeReturn ret;
src = stream->parent;
GST_DEBUG_OBJECT (src, "configuring transport for stream %p", stream);
s = gst_caps_get_structure (stream->caps, 0);
/* get the proper mime type for this stream now */
if ((res = rtsp_transport_get_mime (transport->trans, &mime)) < 0)
goto no_mime;
if (!mime)
goto no_mime;
/* configure the final mime type */
GST_DEBUG_OBJECT (src, "setting mime to %s", mime);
gst_structure_set_name (s, mime);
/* find a manager */ /* find a manager */
if ((res = rtsp_transport_get_manager (transport->trans, &manager, 0)) < 0) if ((res = rtsp_transport_get_manager (transport->trans, &manager, 0)) < 0)
@ -1199,6 +1251,15 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
goto start_session_failure; goto start_session_failure;
g_object_set (src->session, "latency", src->latency, NULL); g_object_set (src->session, "latency", src->latency, NULL);
/* connect to signals if we did not already do so */
GST_DEBUG_OBJECT (src, "connect to signals on session manager");
src->session_sig_id =
g_signal_connect (src->session, "pad-added",
(GCallback) new_session_pad, src);
src->session_ptmap_id =
g_signal_connect (src->session, "request-pt-map",
(GCallback) request_pt_map, src);
} }
/* we stream directly to the manager, get some pads. Each RTSP stream goes /* we stream directly to the manager, get some pads. Each RTSP stream goes
@ -1210,197 +1271,341 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
stream->channelpad[1] = gst_element_get_request_pad (src->session, name); stream->channelpad[1] = gst_element_get_request_pad (src->session, name);
g_free (name); g_free (name);
} }
use_no_manager: use_no_manager:
return TRUE;
if (transport->lower_transport == RTSP_LOWER_TRANS_TCP) { /* ERRORS */
gint i; no_manager:
{
GST_DEBUG_OBJECT (src, "cannot get a session manager");
return FALSE;
}
manager_failed:
{
GST_DEBUG_OBJECT (src, "no session manager element %s found", manager);
return FALSE;
}
start_session_failure:
{
GST_DEBUG_OBJECT (src, "could not start session");
return FALSE;
}
}
/* configure for interleaved delivery, nothing needs to be done /* free the UDP sources allocated when negotiating a transport.
* here, the loop function will call the chain functions of the * This function is called when the server negotiated to a transport where the
* session manager. */ * UDP sources are not needed anymore, such as TCP or multicast. */
stream->channel[0] = transport->interleaved.min; static void
stream->channel[1] = transport->interleaved.max; gst_rtspsrc_stream_free_udp (GstRTSPStream * stream)
GST_DEBUG_OBJECT (src, "stream %p on channels %d-%d", stream, {
stream->channel[0], stream->channel[1]); gint i;
/* we can remove the allocated UDP ports now */ for (i = 0; i < 2; i++) {
for (i = 0; i < 2; i++) { if (stream->udpsrc[i]) {
if (stream->udpsrc[i]) { gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL); gst_object_unref (stream->udpsrc[i]);
gst_object_unref (stream->udpsrc[i]); stream->udpsrc[i] = NULL;
stream->udpsrc[i] = NULL;
}
} }
}
}
/* no session manager, send data to srcpad directly */ /* for TCP, create pads to send and receive data to and from the manager and to
if (!stream->channelpad[0]) { * intercept various events and queries
GST_DEBUG_OBJECT (src, "no manager, creating pad"); */
static gboolean
gst_rtspsrc_stream_configure_tcp (GstRTSPSrc * src, GstRTSPStream * stream,
RTSPTransport * transport, GstPad ** outpad)
{
gchar *name;
GstPadTemplate *template;
GstPad *pad0, *pad1;
/* create a new pad we will use to stream to */ /* configure for interleaved delivery, nothing needs to be done
name = g_strdup_printf ("stream%d", stream->id); * here, the loop function will call the chain functions of the
template = gst_static_pad_template_get (&rtptemplate); * session manager. */
stream->channelpad[0] = gst_pad_new_from_template (template, name); stream->channel[0] = transport->interleaved.min;
gst_object_unref (template); stream->channel[1] = transport->interleaved.max;
g_free (name); GST_DEBUG_OBJECT (src, "stream %p on channels %d-%d", stream,
stream->channel[0], stream->channel[1]);
/* set caps and activate */ /* we can remove the allocated UDP ports now */
gst_pad_use_fixed_caps (stream->channelpad[0]); gst_rtspsrc_stream_free_udp (stream);
gst_pad_set_active (stream->channelpad[0], TRUE);
outpad = gst_object_ref (stream->channelpad[0]); /* no session manager, send data to srcpad directly */
} else { if (!stream->channelpad[0]) {
GST_DEBUG_OBJECT (src, "using manager source pad"); GST_DEBUG_OBJECT (src, "no manager, creating pad");
/* we connected to pad-added signal to get pads from the manager */
} /* create a new pad we will use to stream to */
name = g_strdup_printf ("stream%d", stream->id);
template = gst_static_pad_template_get (&rtptemplate);
stream->channelpad[0] = gst_pad_new_from_template (template, name);
gst_object_unref (template);
g_free (name);
/* set caps and activate */
gst_pad_use_fixed_caps (stream->channelpad[0]);
gst_pad_set_active (stream->channelpad[0], TRUE);
*outpad = gst_object_ref (stream->channelpad[0]);
} else { } else {
/* multicast was selected, create UDP sources and join the multicast GstPadTemplate *template;
* group. */
if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST) {
gchar *uri;
GST_DEBUG_OBJECT (src, "creating UDP sources for multicast"); GST_DEBUG_OBJECT (src, "using manager source pad");
/* creating UDP source */ template = gst_static_pad_template_get (&anytemplate);
if (transport->port.min != -1) {
uri = g_strdup_printf ("udp://%s:%d", transport->destination,
transport->port.min);
stream->udpsrc[0] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
g_free (uri);
if (stream->udpsrc[0] == NULL)
goto no_element;
/* take ownership */ /* allocate pads for sending the channel data into the manager */
gst_object_ref (stream->udpsrc[0]); pad0 = gst_pad_new_from_template (template, "internal0");
gst_object_sink (stream->udpsrc[0]); gst_pad_set_event_function (pad0, gst_rtspsrc_handle_src_event);
gst_pad_set_query_function (pad0, gst_rtspsrc_handle_src_query);
gst_pad_link (pad0, stream->channelpad[0]);
stream->channelpad[0] = pad0;
gst_pad_set_element_private (pad0, src);
/* change state */ if (stream->channelpad[1]) {
gst_element_set_state (stream->udpsrc[0], GST_STATE_READY); /* if we have a sinkpad for the other channel, create a pad and link to the
} * manager. */
pad1 = gst_pad_new_from_template (template, "internal1");
/* creating another UDP source */ gst_pad_link (pad1, stream->channelpad[1]);
if (transport->port.max != -1) { stream->channelpad[1] = pad1;
uri = g_strdup_printf ("udp://%s:%d", transport->destination,
transport->port.max);
stream->udpsrc[1] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
g_free (uri);
if (stream->udpsrc[1] == NULL)
goto no_element;
/* take ownership */
gst_object_ref (stream->udpsrc[1]);
gst_object_sink (stream->udpsrc[1]);
gst_element_set_state (stream->udpsrc[1], GST_STATE_READY);
}
} }
gst_object_unref (template);
}
return TRUE;
}
/* we manage the UDP elements now. For unicast, the UDP sources where /* For multicast create UDP sources and join the multicast group. */
* allocated in the stream when we suggested a transport. */ static gboolean
if (stream->udpsrc[0]) { gst_rtspsrc_stream_configure_mcast (GstRTSPSrc * src, GstRTSPStream * stream,
gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]); RTSPTransport * transport, GstPad ** outpad)
{
gchar *uri;
GST_DEBUG_OBJECT (src, "setting up UDP source"); GST_DEBUG_OBJECT (src, "creating UDP sources for multicast");
/* configure a timeout on the UDP port. When the timeout message is /* we can remove the allocated UDP ports now */
* posted, we assume UDP transport is not possible. We reconnect using TCP gst_rtspsrc_stream_free_udp (stream);
* if we can. */
g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->timeout,
NULL);
/* get output pad of the UDP source. */ /* creating UDP source */
outpad = gst_element_get_pad (stream->udpsrc[0], "src"); if (transport->port.min != -1) {
uri = g_strdup_printf ("udp://%s:%d", transport->destination,
transport->port.min);
stream->udpsrc[0] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
g_free (uri);
if (stream->udpsrc[0] == NULL)
goto no_element;
/* save it so we can unblock */ /* take ownership */
stream->blockedpad = outpad; gst_object_ref (stream->udpsrc[0]);
gst_object_sink (stream->udpsrc[0]);
/* configure pad block on the pad. As soon as there is dataflow on the /* change state */
* UDP source, we know that UDP is not blocked by a firewall and we can gst_element_set_state (stream->udpsrc[0], GST_STATE_READY);
* configure all the streams to let the application autoplug decoders. */ }
gst_pad_set_blocked_async (outpad, TRUE,
(GstPadBlockCallback) pad_blocked, src);
if (stream->channelpad[0]) { /* creating another UDP source */
GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager"); if (transport->port.max != -1) {
/* configure for UDP delivery, we need to connect the UDP pads to uri = g_strdup_printf ("udp://%s:%d", transport->destination,
* the session plugin. */ transport->port.max);
gst_pad_link (outpad, stream->channelpad[0]); stream->udpsrc[1] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
gst_object_unref (outpad); g_free (uri);
outpad = NULL; if (stream->udpsrc[1] == NULL)
/* we connected to pad-added signal to get pads from the manager */ goto no_element;
} else {
GST_DEBUG_OBJECT (src, "using UDP src pad as output");
}
}
if (stream->udpsrc[1]) { /* take ownership */
gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[1]); gst_object_ref (stream->udpsrc[1]);
gst_object_sink (stream->udpsrc[1]);
if (stream->channelpad[1]) { gst_element_set_state (stream->udpsrc[1], GST_STATE_READY);
GstPad *pad; }
return TRUE;
GST_DEBUG_OBJECT (src, "connecting UDP source 1 to manager"); /* ERRORS */
no_element:
{
GST_DEBUG_OBJECT (src, "no UDP source element found");
return FALSE;
}
}
pad = gst_element_get_pad (stream->udpsrc[1], "src"); /* configure the remainder of the UDP ports */
gst_pad_link (pad, stream->channelpad[1]); static gboolean
gst_object_unref (pad); gst_rtspsrc_stream_configure_udp (GstRTSPSrc * src, GstRTSPStream * stream,
} RTSPTransport * transport, GstPad ** outpad)
} {
/* configure udpsink back to the server for RTCP messages. */ /* we manage the UDP elements now. For unicast, the UDP sources where
{ * allocated in the stream when we suggested a transport. */
GstPad *pad; if (stream->udpsrc[0]) {
gint port; gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]);
gchar *destination, *uri;
/* get host and port */ GST_DEBUG_OBJECT (src, "setting up UDP source");
if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST)
port = transport->port.max;
else
port = transport->server_port.max;
/* first take the source, then the endpoint to figure out where to send /* configure a timeout on the UDP port. When the timeout message is
* the RTCP. */ * posted, we assume UDP transport is not possible. We reconnect using TCP
destination = transport->source; * if we can. */
if (destination == NULL) g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->timeout, NULL);
destination = src->connection->ip;
GST_DEBUG_OBJECT (src, "configure UDP sink for %s:%d", destination, port); /* get output pad of the UDP source. */
*outpad = gst_element_get_pad (stream->udpsrc[0], "src");
uri = g_strdup_printf ("udp://%s:%d", destination, port); /* save it so we can unblock */
stream->udpsink = gst_element_make_from_uri (GST_URI_SINK, uri, NULL); stream->blockedpad = *outpad;
g_free (uri);
if (stream->udpsink == NULL)
goto no_sink_element;
/* we keep this playing always */ /* configure pad block on the pad. As soon as there is dataflow on the
gst_element_set_locked_state (stream->udpsink, TRUE); * UDP source, we know that UDP is not blocked by a firewall and we can
gst_element_set_state (stream->udpsink, GST_STATE_PLAYING); * configure all the streams to let the application autoplug decoders. */
gst_pad_set_blocked_async (stream->blockedpad, TRUE,
(GstPadBlockCallback) pad_blocked, src);
/* no sync needed */ if (stream->channelpad[0]) {
g_object_set (G_OBJECT (stream->udpsink), "sync", FALSE, NULL); GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager");
/* configure for UDP delivery, we need to connect the UDP pads to
gst_object_ref (stream->udpsink); * the session plugin. */
gst_bin_add (GST_BIN_CAST (src), stream->udpsink); gst_pad_link (*outpad, stream->channelpad[0]);
gst_object_unref (*outpad);
stream->rtcppad = gst_element_get_pad (stream->udpsink, "sink"); *outpad = NULL;
/* we connected to pad-added signal to get pads from the manager */
/* get session RTCP pad */ } else {
name = g_strdup_printf ("send_rtcp_src_%d", stream->id); GST_DEBUG_OBJECT (src, "using UDP src pad as output");
pad = gst_element_get_request_pad (src->session, name);
g_free (name);
/* and link */
gst_pad_link (pad, stream->rtcppad);
} }
} }
if (src->session && !src->session_sig_id) { /* RTCP port */
GST_DEBUG_OBJECT (src, "connect to signals on session manager"); if (stream->udpsrc[1]) {
src->session_sig_id = gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[1]);
g_signal_connect (src->session, "pad-added",
(GCallback) new_session_pad, src); if (stream->channelpad[1]) {
src->session_ptmap_id = GstPad *pad;
g_signal_connect (src->session, "request-pt-map",
(GCallback) request_pt_map, src); GST_DEBUG_OBJECT (src, "connecting UDP source 1 to manager");
pad = gst_element_get_pad (stream->udpsrc[1], "src");
gst_pad_link (pad, stream->channelpad[1]);
gst_object_unref (pad);
} else {
/* leave unlinked */
}
}
return TRUE;
}
/* configure the UDP sink back to the server for status reports */
static gboolean
gst_rtspsrc_stream_configure_udp_sink (GstRTSPSrc * src, GstRTSPStream * stream,
RTSPTransport * transport)
{
GstPad *pad;
gint port;
gchar *destination, *uri, *name;
/* get host and port */
if (transport->lower_transport == RTSP_LOWER_TRANS_UDP_MCAST)
port = transport->port.max;
else
port = transport->server_port.max;
/* first take the source, then the endpoint to figure out where to send
* the RTCP. */
destination = transport->source;
if (destination == NULL)
destination = src->connection->ip;
GST_DEBUG_OBJECT (src, "configure UDP sink for %s:%d", destination, port);
uri = g_strdup_printf ("udp://%s:%d", destination, port);
stream->udpsink = gst_element_make_from_uri (GST_URI_SINK, uri, NULL);
g_free (uri);
if (stream->udpsink == NULL)
goto no_sink_element;
/* we keep this playing always */
gst_element_set_locked_state (stream->udpsink, TRUE);
gst_element_set_state (stream->udpsink, GST_STATE_PLAYING);
/* no sync needed */
g_object_set (G_OBJECT (stream->udpsink), "sync", FALSE, NULL);
gst_object_ref (stream->udpsink);
gst_bin_add (GST_BIN_CAST (src), stream->udpsink);
stream->rtcppad = gst_element_get_pad (stream->udpsink, "sink");
/* 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;
/* ERRORS */
no_sink_element:
{
GST_DEBUG_OBJECT (src, "no UDP sink element found");
return FALSE;
}
}
/* sets up all elements needed for streaming over the specified transport.
* Does not yet expose the element pads, this will be done when there is actuall
* dataflow detected, which might never happen when UDP is blocked in a
* firewall, for example.
*/
static gboolean
gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
RTSPTransport * transport)
{
GstRTSPSrc *src;
GstPad *outpad = NULL;
GstPadTemplate *template;
gchar *name;
GstStructure *s;
const gchar *mime;
RTSPResult res;
src = stream->parent;
GST_DEBUG_OBJECT (src, "configuring transport for stream %p", stream);
s = gst_caps_get_structure (stream->caps, 0);
/* get the proper mime type for this stream now */
if ((res = rtsp_transport_get_mime (transport->trans, &mime)) < 0)
goto unknown_transport;
if (!mime)
goto unknown_transport;
/* configure the final mime type */
GST_DEBUG_OBJECT (src, "setting mime to %s", mime);
gst_structure_set_name (s, mime);
/* try to get and configure a manager, channelpad[0-1] will be configured with
* the pads for the manager, or NULL when no manager is needed. */
if (!gst_rtspsrc_stream_configure_manager (src, stream, transport))
goto no_manager;
switch (transport->lower_transport) {
case RTSP_LOWER_TRANS_TCP:
if (!gst_rtspsrc_stream_configure_tcp (src, stream, transport, &outpad))
goto transport_failed;
break;
case RTSP_LOWER_TRANS_UDP_MCAST:
if (!gst_rtspsrc_stream_configure_mcast (src, stream, transport, &outpad))
goto transport_failed;
/* fallthrough, the rest is the same for UDP and MCAST */
case RTSP_LOWER_TRANS_UDP:
if (!gst_rtspsrc_stream_configure_udp (src, stream, transport, &outpad))
goto transport_failed;
/* configure udpsink back to the server for RTCP messages. */
if (!gst_rtspsrc_stream_configure_udp_sink (src, stream, transport))
goto transport_failed;
break;
default:
goto unknown_transport;
} }
if (outpad) { if (outpad) {
@ -1424,7 +1629,12 @@ use_no_manager:
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
no_mime: transport_failed:
{
GST_DEBUG_OBJECT (src, "failed to configure transport");
return FALSE;
}
unknown_transport:
{ {
GST_DEBUG_OBJECT (src, "unknown transport"); GST_DEBUG_OBJECT (src, "unknown transport");
return FALSE; return FALSE;
@ -1434,26 +1644,6 @@ no_manager:
GST_DEBUG_OBJECT (src, "cannot get a session manager"); GST_DEBUG_OBJECT (src, "cannot get a session manager");
return FALSE; return FALSE;
} }
manager_failed:
{
GST_DEBUG_OBJECT (src, "no session manager element %s found", manager);
return FALSE;
}
no_element:
{
GST_DEBUG_OBJECT (src, "no UDP source element found");
return FALSE;
}
no_sink_element:
{
GST_DEBUG_OBJECT (src, "no UDP sink element found");
return FALSE;
}
start_session_failure:
{
GST_DEBUG_OBJECT (src, "could not start session");
return FALSE;
}
} }
/* Adds the source pads of all configured streams to the element. /* Adds the source pads of all configured streams to the element.
@ -1543,7 +1733,7 @@ gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event)
for (streams = src->streams; streams; streams = g_list_next (streams)) { for (streams = src->streams; streams; streams = g_list_next (streams)) {
GstRTSPStream *ostream = (GstRTSPStream *) streams->data; GstRTSPStream *ostream = (GstRTSPStream *) streams->data;
/* only pads that have a connection to the outside world */ /* only streams that have a connection to the outside world */
if (ostream->srcpad == NULL) if (ostream->srcpad == NULL)
continue; continue;
@ -1867,7 +2057,7 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
rtsp_connection_flush (src->connection, FALSE); rtsp_connection_flush (src->connection, FALSE);
goto interrupt; goto interrupt;
case RTSP_ETIMEOUT: case RTSP_ETIMEOUT:
/* ignore result, a warning was posted */ /* send keep-alive, ignore the result, a warning will be posted. */
GST_DEBUG_OBJECT (src, "timout, sending keep-alive"); GST_DEBUG_OBJECT (src, "timout, sending keep-alive");
res = gst_rtspsrc_send_keep_alive (src); res = gst_rtspsrc_send_keep_alive (src);
continue; continue;
@ -2814,14 +3004,13 @@ gst_rtspsrc_open (GstRTSPSrc * src)
if (src->extension && src->extension->parse_sdp) if (src->extension && src->extension->parse_sdp)
src->extension->parse_sdp (src->extension, &sdp); src->extension->parse_sdp (src->extension, &sdp);
/* parse address */ /* parse range */
{ {
SDPOrigin *origin; gchar *range;
origin = sdp_message_get_origin (&sdp); range = sdp_message_get_attribute_val (&sdp, "range");
g_free (src->addr); GST_DEBUG_OBJECT (src, "got range: %s", GST_STR_NULL (range));
src->addr = g_strdup (origin->addr);
} }
/* create streams */ /* create streams */
@ -3070,6 +3259,7 @@ gst_rtspsrc_parse_rtpinfo (GstRTSPSrc * src, gchar * rtpinfo)
timebase = atol (fields[j] + 8); timebase = atol (fields[j] + 8);
} }
} }
g_strfreev (fields);
/* now we need to store the values in the caps of the stream and make sure /* now we need to store the values in the caps of the stream and make sure
* that the UDP elements have the same caps property set before they receive * that the UDP elements have the same caps property set before they receive
* the first buffer. */ * the first buffer. */
@ -3132,7 +3322,7 @@ gst_rtspsrc_play (GstRTSPSrc * src)
/* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp /* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp
* for the RTP packets. If this is not present, we assume all starts from 0... * for the RTP packets. If this is not present, we assume all starts from 0...
* FIXME, this is info for the RTP session manager ideally. */ * This is info for the RTP session manager that we pass to it in caps. */
rtsp_message_get_header (&response, RTSP_HDR_RTP_INFO, &rtpinfo); rtsp_message_get_header (&response, RTSP_HDR_RTP_INFO, &rtpinfo);
if (rtpinfo) if (rtpinfo)
gst_rtspsrc_parse_rtpinfo (src, rtpinfo); gst_rtspsrc_parse_rtpinfo (src, rtpinfo);
@ -3201,6 +3391,12 @@ gst_rtspsrc_pause (GstRTSPSrc * src)
if (src->state == RTSP_STATE_READY) if (src->state == RTSP_STATE_READY)
goto was_paused; goto was_paused;
/* wait for streaming to finish */
GST_RTSP_STREAM_LOCK (src);
GST_RTSP_STREAM_UNLOCK (src);
rtsp_connection_flush (src->connection, FALSE);
/* do pause */ /* do pause */
res = rtsp_message_init_request (&request, RTSP_PAUSE, src->req_location); res = rtsp_message_init_request (&request, RTSP_PAUSE, src->req_location);
if (res < 0) if (res < 0)