gst/rtsp/README: Updated README.

Original commit message from CVS:
* gst/rtsp/README:
Updated README.

* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_get_type),
(gst_rtspsrc_class_init), (gst_rtspsrc_set_property),
(gst_rtspsrc_get_property), (gst_rtspsrc_stream_setup_rtp):
* gst/rtsp/gstrtspsrc.h:
Make sure the RTP port is an even port an try to allocate
another if not.
Added retry property to control max retries for port allocation.
Make sure RTCP port is RTP port+1.
Cleanup when port allocation fails.
Fixes #319183.
This commit is contained in:
Wim Taymans 2006-02-16 10:42:25 +00:00
parent 2d150478bb
commit d465618d5b
4 changed files with 156 additions and 34 deletions

View file

@ -1,3 +1,19 @@
2006-02-16 Wim Taymans <wim@fluendo.com>
* gst/rtsp/README:
Updated README.
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_get_type),
(gst_rtspsrc_class_init), (gst_rtspsrc_set_property),
(gst_rtspsrc_get_property), (gst_rtspsrc_stream_setup_rtp):
* gst/rtsp/gstrtspsrc.h:
Make sure the RTP port is an even port an try to allocate
another if not.
Added retry property to control max retries for port allocation.
Make sure RTCP port is RTP port+1.
Cleanup when port allocation fails.
Fixes #319183.
2006-02-16 Tim-Philipp Müller <tim at centricular dot net> 2006-02-16 Tim-Philipp Müller <tim at centricular dot net>
* gst/alpha/gstalpha.c: (gst_alpha_change_state): * gst/alpha/gstalpha.c: (gst_alpha_change_state):

View file

@ -40,9 +40,15 @@ An RTSP session is created as follows:
to allocate two local UDP ports for receiving the RTP and RTCP data because we to allocate two local UDP ports for receiving the RTP and RTCP data because we
need to send the port numbers to the server in the next request. need to send the port numbers to the server in the next request.
In RTSPSrc we create two elements that can handle the udp://0.0.0.0:0 uri. This In RTSPSrc we first create an element that can handle the udp://0.0.0.0:0 uri. This
will create an udp source element. We get the port number by getting the "port" will create an udp source element with a random port number. We get the port
property of the element after setting the element to PAUSED. number by getting the "port" property of the element after setting the element to
PAUSED. This element is used for the RTP packets and has to be an even number. If
the random port number is not an even number we retry to allocate a new udp source.
We then create another UDP source element with the next (uneven) port number to
receive the RTCP packet on. After this step we have two udp ports we can use to
accept RTP packets.
+-----------------+ +-----------------+
| +------------+ | | +------------+ |
@ -129,7 +135,7 @@ An RTSP session is created as follows:
<< Session: 5d5cb94413288ccd << Session: 5d5cb94413288ccd
<< <<
This means that RTP/RTCP messages will be send on channel 0/1 respectively and that This means that RTP/RTCP messages will be sent on channel 0/1 respectively and that
the data will be received on the same connection as the RTSP connection. the data will be received on the same connection as the RTSP connection.
At this point, we remove the UDP source elements as we don't need them anymore. We At this point, we remove the UDP source elements as we don't need them anymore. We
@ -303,7 +309,7 @@ Minimal server requirements:
+------------+ +-------------+ +------------+ +-------------+
The server would set the above pipeline to PAUSE to make sure no data The server would set the above pipeline to PAUSE to make sure no data
is send to the client yet. is sent to the client yet.
optionally udpsrc elements can be configured to receive client RTP and optionally udpsrc elements can be configured to receive client RTP and
RTSP messages. RTSP messages.

View file

@ -27,11 +27,14 @@
#include "gstrtspsrc.h" #include "gstrtspsrc.h"
#include "sdp.h" #include "sdp.h"
GST_DEBUG_CATEGORY (rtspsrc_debug);
#define GST_CAT_DEFAULT (rtspsrc_debug)
/* elementfactory information */ /* elementfactory information */
static GstElementDetails gst_rtspsrc_details = static GstElementDetails gst_rtspsrc_details =
GST_ELEMENT_DETAILS ("RTSP packet receiver", GST_ELEMENT_DETAILS ("RTSP packet receiver",
"Source/Network", "Source/Network",
"Receive data over the network via RTSP", "Receive data over the network via RTSP (RFC 2326)",
"Wim Taymans <wim@fluendo.com>"); "Wim Taymans <wim@fluendo.com>");
static GstStaticPadTemplate rtptemplate = static GstStaticPadTemplate rtptemplate =
@ -55,6 +58,7 @@ enum
#define DEFAULT_LOCATION NULL #define DEFAULT_LOCATION NULL
#define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP #define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP
#define DEFAULT_DEBUG FALSE #define DEFAULT_DEBUG FALSE
#define DEFAULT_RETRY 20
enum enum
{ {
@ -62,6 +66,7 @@ enum
PROP_LOCATION, PROP_LOCATION,
PROP_PROTOCOLS, PROP_PROTOCOLS,
PROP_DEBUG, PROP_DEBUG,
PROP_RETRY,
/* FILL ME */ /* FILL ME */
}; };
@ -129,6 +134,8 @@ gst_rtspsrc_get_type (void)
NULL NULL
}; };
GST_DEBUG_CATEGORY_INIT (rtspsrc_debug, "rtspsrc", 0, "RTSP src");
rtspsrc_type = rtspsrc_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstRTSPSrc", &rtspsrc_info, g_type_register_static (GST_TYPE_ELEMENT, "GstRTSPSrc", &rtspsrc_info,
0); 0);
@ -166,21 +173,27 @@ gst_rtspsrc_class_init (GstRTSPSrc * klass)
gobject_class->set_property = gst_rtspsrc_set_property; gobject_class->set_property = gst_rtspsrc_set_property;
gobject_class->get_property = gst_rtspsrc_get_property; gobject_class->get_property = gst_rtspsrc_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LOCATION, g_object_class_install_property (gobject_class, PROP_LOCATION,
g_param_spec_string ("location", "RTSP Location", g_param_spec_string ("location", "RTSP Location",
"Location of the RTSP url to read", "Location of the RTSP url to read",
DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROTOCOLS, g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
g_param_spec_flags ("protocols", "Protocols", "Allowed protocols", g_param_spec_flags ("protocols", "Protocols", "Allowed protocols",
GST_TYPE_RTSP_PROTO, DEFAULT_PROTOCOLS, GST_TYPE_RTSP_PROTO, DEFAULT_PROTOCOLS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEBUG, g_object_class_install_property (gobject_class, PROP_DEBUG,
g_param_spec_boolean ("debug", "Debug", g_param_spec_boolean ("debug", "Debug",
"Dump request and response messages to stdout", "Dump request and response messages to stdout",
DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_RETRY,
g_param_spec_uint ("retry", "Retry",
"Max number of retries when allocating RTP ports.",
0, G_MAXUINT16, DEFAULT_RETRY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
gstelement_class->change_state = gst_rtspsrc_change_state; gstelement_class->change_state = gst_rtspsrc_change_state;
} }
@ -208,6 +221,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
case PROP_DEBUG: case PROP_DEBUG:
rtspsrc->debug = g_value_get_boolean (value); rtspsrc->debug = g_value_get_boolean (value);
break; break;
case PROP_RETRY:
rtspsrc->retry = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -232,6 +248,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_DEBUG: case PROP_DEBUG:
g_value_set_boolean (value, rtspsrc->debug); g_value_set_boolean (value, rtspsrc->debug);
break; break;
case PROP_RETRY:
g_value_set_uint (value, rtspsrc->retry);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -476,59 +495,139 @@ gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream, SDPMedia * media,
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstRTSPSrc *src; GstRTSPSrc *src;
GstCaps *caps; GstCaps *caps;
GstElement *tmp, *rtp, *rtcp;
gint tmp_rtp, tmp_rtcp;
guint count;
src = stream->parent; src = stream->parent;
if (!(stream->rtpsrc = tmp = NULL;
gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL))) rtp = NULL;
rtcp = NULL;
count = 0;
/* try to allocate 2 udp ports, the RTP port should be an even
* number and the RTCP port should be the next (uneven) port */
again:
rtp = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL);
if (rtp == NULL)
goto no_udp_rtp_protocol; goto no_udp_rtp_protocol;
/* we manage this element */ ret = gst_element_set_state (rtp, GST_STATE_PAUSED);
gst_rtspsrc_add_element (src, stream->rtpsrc);
ret = gst_element_set_state (stream->rtpsrc, GST_STATE_PAUSED);
if (ret == GST_STATE_CHANGE_FAILURE) if (ret == GST_STATE_CHANGE_FAILURE)
goto start_rtp_failure; goto start_rtp_failure;
if (!(stream->rtcpsrc = g_object_get (G_OBJECT (rtp), "port", &tmp_rtp, NULL);
gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL))) GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp);
/* check if port is even */
if ((tmp_rtp & 0x01) != 0) {
/* port not even, close and allocate another */
count++;
if (count > src->retry)
goto no_ports;
GST_DEBUG_OBJECT (src, "RTP port not even, retry %d", count);
/* have to keep port allocated so we can get a new one */
if (tmp != NULL) {
GST_DEBUG_OBJECT (src, "free temp");
gst_element_set_state (tmp, GST_STATE_NULL);
gst_object_unref (tmp);
}
tmp = rtp;
GST_DEBUG_OBJECT (src, "retry %d", count);
goto again;
}
/* free leftover temp element/port */
if (tmp) {
gst_element_set_state (tmp, GST_STATE_NULL);
gst_object_unref (tmp);
tmp = NULL;
}
/* allocate port+1 for RTCP now */
rtcp = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
if (rtcp == NULL)
goto no_udp_rtcp_protocol; goto no_udp_rtcp_protocol;
/* we manage this element */ /* set port */
gst_rtspsrc_add_element (src, stream->rtcpsrc); tmp_rtcp = tmp_rtp + 1;
g_object_set (G_OBJECT (rtcp), "port", tmp_rtcp, NULL);
ret = gst_element_set_state (stream->rtcpsrc, GST_STATE_PAUSED); GST_DEBUG_OBJECT (src, "starting RTCP on port %d", tmp_rtcp);
ret = gst_element_set_state (rtcp, GST_STATE_PAUSED);
/* FIXME, this could fail if the next port is not free, we
* should retry with another port then */
if (ret == GST_STATE_CHANGE_FAILURE) if (ret == GST_STATE_CHANGE_FAILURE)
goto start_rtcp_failure; goto start_rtcp_failure;
/* all fine, do port check */
g_object_get (G_OBJECT (rtp), "port", rtpport, NULL);
g_object_get (G_OBJECT (rtcp), "port", rtcpport, NULL);
/* this should not happen */
if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp)
goto port_error;
/* we manage these elements */
stream->rtpsrc = rtp;
gst_rtspsrc_add_element (src, stream->rtpsrc);
stream->rtcpsrc = rtcp;
gst_rtspsrc_add_element (src, stream->rtcpsrc);
caps = gst_rtspsrc_media_to_caps (media); caps = gst_rtspsrc_media_to_caps (media);
/* set caps */
g_object_set (G_OBJECT (stream->rtpsrc), "caps", caps, NULL); g_object_set (G_OBJECT (stream->rtpsrc), "caps", caps, NULL);
g_object_get (G_OBJECT (stream->rtpsrc), "port", rtpport, NULL);
g_object_get (G_OBJECT (stream->rtcpsrc), "port", rtcpport, NULL);
return TRUE; return TRUE;
/* ERRORS, FIXME, cleanup */ /* ERRORS */
no_udp_rtp_protocol: no_udp_rtp_protocol:
{ {
GST_DEBUG ("could not get UDP source for rtp"); GST_DEBUG ("could not get UDP source for RTP");
return FALSE; goto cleanup;
}
no_udp_rtcp_protocol:
{
GST_DEBUG ("could not get UDP source for rtcp");
return FALSE;
} }
start_rtp_failure: start_rtp_failure:
{ {
GST_DEBUG ("could not start UDP source for rtp"); GST_DEBUG ("could not start UDP source for RTP");
return FALSE; goto cleanup;
}
no_ports:
{
GST_DEBUG ("could not allocate UDP port pair after %d retries", count);
goto cleanup;
}
no_udp_rtcp_protocol:
{
GST_DEBUG ("could not get UDP source for RTCP");
goto cleanup;
} }
start_rtcp_failure: start_rtcp_failure:
{ {
GST_DEBUG ("could not start UDP source for rtcp"); GST_DEBUG ("could not start UDP source for RTCP");
goto cleanup;
}
port_error:
{
GST_DEBUG ("ports don't match rtp: %d<->%d, rtcp: %d<->%d",
tmp_rtp, *rtpport, tmp_rtcp, *rtcpport);
goto cleanup;
}
cleanup:
{
if (tmp) {
gst_element_set_state (tmp, GST_STATE_NULL);
gst_object_unref (tmp);
}
if (rtp) {
gst_element_set_state (rtp, GST_STATE_NULL);
gst_object_unref (rtp);
}
if (rtcp) {
gst_element_set_state (rtcp, GST_STATE_NULL);
gst_object_unref (rtcp);
}
return FALSE; return FALSE;
} }
} }

View file

@ -86,6 +86,7 @@ struct _GstRTSPSrc {
gchar *location; gchar *location;
gboolean debug; gboolean debug;
guint retry;
GstRTSPProto protocols; GstRTSPProto protocols;
/* supported options */ /* supported options */