summaryrefslogtreecommitdiffstats
path: root/gst/rtsp
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2006-02-16 10:42:25 +0000
committerWim Taymans <wim.taymans@gmail.com>2006-02-16 10:42:25 +0000
commitd465618d5b76c800939cd01c1dc0991447212362 (patch)
tree25183b0b7dd6807f5857cda58cb51e09cc3d71b4 /gst/rtsp
parent2d150478bbe3df6ad4abff0ff9681a352fda1108 (diff)
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.
Diffstat (limited to 'gst/rtsp')
-rw-r--r--gst/rtsp/README16
-rw-r--r--gst/rtsp/gstrtspsrc.c155
-rw-r--r--gst/rtsp/gstrtspsrc.h1
3 files changed, 139 insertions, 33 deletions
diff --git a/gst/rtsp/README b/gst/rtsp/README
index 820c17d3..02458915 100644
--- a/gst/rtsp/README
+++ b/gst/rtsp/README
@@ -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
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
- will create an udp source element. We get the port number by getting the "port"
- property of the element after setting the element to PAUSED.
+ 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 with a random port number. We get the port
+ 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
<<
- 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.
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
- is send to the client yet.
+ is sent to the client yet.
optionally udpsrc elements can be configured to receive client RTP and
RTSP messages.
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
index bc039281..1bf57efc 100644
--- a/gst/rtsp/gstrtspsrc.c
+++ b/gst/rtsp/gstrtspsrc.c
@@ -27,11 +27,14 @@
#include "gstrtspsrc.h"
#include "sdp.h"
+GST_DEBUG_CATEGORY (rtspsrc_debug);
+#define GST_CAT_DEFAULT (rtspsrc_debug)
+
/* elementfactory information */
static GstElementDetails gst_rtspsrc_details =
GST_ELEMENT_DETAILS ("RTSP packet receiver",
"Source/Network",
- "Receive data over the network via RTSP",
+ "Receive data over the network via RTSP (RFC 2326)",
"Wim Taymans <wim@fluendo.com>");
static GstStaticPadTemplate rtptemplate =
@@ -55,6 +58,7 @@ enum
#define DEFAULT_LOCATION NULL
#define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP
#define DEFAULT_DEBUG FALSE
+#define DEFAULT_RETRY 20
enum
{
@@ -62,6 +66,7 @@ enum
PROP_LOCATION,
PROP_PROTOCOLS,
PROP_DEBUG,
+ PROP_RETRY,
/* FILL ME */
};
@@ -129,6 +134,8 @@ gst_rtspsrc_get_type (void)
NULL
};
+ GST_DEBUG_CATEGORY_INIT (rtspsrc_debug, "rtspsrc", 0, "RTSP src");
+
rtspsrc_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstRTSPSrc", &rtspsrc_info,
0);
@@ -166,21 +173,27 @@ gst_rtspsrc_class_init (GstRTSPSrc * klass)
gobject_class->set_property = gst_rtspsrc_set_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",
"Location of the RTSP url to read",
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",
GST_TYPE_RTSP_PROTO, DEFAULT_PROTOCOLS,
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",
"Dump request and response messages to stdout",
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;
}
@@ -208,6 +221,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
case PROP_DEBUG:
rtspsrc->debug = g_value_get_boolean (value);
break;
+ case PROP_RETRY:
+ rtspsrc->retry = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -232,6 +248,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_DEBUG:
g_value_set_boolean (value, rtspsrc->debug);
break;
+ case PROP_RETRY:
+ g_value_set_uint (value, rtspsrc->retry);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -476,59 +495,139 @@ gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream, SDPMedia * media,
GstStateChangeReturn ret;
GstRTSPSrc *src;
GstCaps *caps;
+ GstElement *tmp, *rtp, *rtcp;
+ gint tmp_rtp, tmp_rtcp;
+ guint count;
src = stream->parent;
- if (!(stream->rtpsrc =
- gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL)))
- goto no_udp_rtp_protocol;
+ tmp = NULL;
+ rtp = NULL;
+ rtcp = NULL;
+ count = 0;
- /* we manage this element */
- gst_rtspsrc_add_element (src, stream->rtpsrc);
+ /* 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;
- ret = gst_element_set_state (stream->rtpsrc, GST_STATE_PAUSED);
+ ret = gst_element_set_state (rtp, GST_STATE_PAUSED);
if (ret == GST_STATE_CHANGE_FAILURE)
goto start_rtp_failure;
- if (!(stream->rtcpsrc =
- gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL)))
+ g_object_get (G_OBJECT (rtp), "port", &tmp_rtp, 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;
- /* we manage this element */
- gst_rtspsrc_add_element (src, stream->rtcpsrc);
+ /* set port */
+ 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)
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);
+ /* set caps */
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;
- /* ERRORS, FIXME, cleanup */
+ /* ERRORS */
no_udp_rtp_protocol:
{
- GST_DEBUG ("could not get UDP source for rtp");
- return FALSE;
+ GST_DEBUG ("could not get UDP source for RTP");
+ goto cleanup;
}
-no_udp_rtcp_protocol:
+start_rtp_failure:
{
- GST_DEBUG ("could not get UDP source for rtcp");
- return FALSE;
+ GST_DEBUG ("could not start UDP source for RTP");
+ goto cleanup;
}
-start_rtp_failure:
+no_ports:
{
- GST_DEBUG ("could not start UDP source for rtp");
- return FALSE;
+ 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:
{
- 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;
}
}
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
index 2cab470a..faf8e2a3 100644
--- a/gst/rtsp/gstrtspsrc.h
+++ b/gst/rtsp/gstrtspsrc.h
@@ -86,6 +86,7 @@ struct _GstRTSPSrc {
gchar *location;
gboolean debug;
+ guint retry;
GstRTSPProto protocols;
/* supported options */