[gst-devel] PATCH: sockfd property to udpsrc/dynudpsink elements

Kai Vehmanen kvehmanen at eca.cx
Wed Nov 30 10:33:02 CET 2005


Hello all,

here's a patch that adds a 'sockfd' property to the udpsrc/dynudpsink 
elements in gst-plugins-good.

I'd like to get these into 0.10 if possible (sorry for the bad/late 
timing). If 0.10 is out of the question, when would be an appropriate 
time? I assume adding new properties to elements is possible in 0.10.x 
releases). Comments on the patch are of course also very much welcome.

Anyways, this patch is needed for two+ reasons:

* To be able to send&receive RTP+RTCP when connected to network
   via a NAT/FW device, the same local port must be used for sending and
   receiving (-> symmetric RTP). This is an essential feature for any VoIP
   style client using RTP.

* The current udpsrc/dynudpsink interface is clumsy if the
   requested port is reserved at NULL->READY state change. And especially
   if you need to reserve paired ports on a busy system (X for RTP, and
   X+1 for RTCP) without race-conditions. It would be much easier to have
   the app reserve and bind to the ports, and then pass the bound sockfds to
   udpsrc/dynudpsink for use.

* Longer term: to integrate NAT traversal mechanisms such as STUN
   <http://www.faqs.org/rfcs/rfc3489.html> and UPnP-IGD to gstreamer, the
   STUN client API has to create and bind the socket (you cannot do
   this inside udpsrc/dynudpsink).

For testing, I've committed patches to the Farsight darcs repository, and 
modified the gsmsendrecv.c test program to utilize the patched dynudpsink 
and udpsrc (see the below message). This allows to symmetric use of both 
RTP and RTCP (verified to work with current gstreamer CVS). You can get 
the needed elements with:

   darcs get http://projects.collabora.co.uk/darcs/farsight/gst-plugins-farsight


---------- Forwarded message ----------
Date: Wed, 30 Nov 2005 20:12:04 +0200 (EET)
From: Kai Vehmanen <kvehmanen at eca.cx>
To: farsight-devel at lists.sourceforge.net
Subject: [Farsight-devel] darcs-commits; symmetric-rtp, accepting own packets

Hello,

I just committed some changes to enable symmetric RTP support:

* Added 'rtp_sockfd' and 'rtcp_sockfd' properties to rtpbin.
   - If not specified, rtpbin will behave as before.
   - Requires the patches to udpsrc and dynudpsink (will
     send to gstreamer-devel).

* Configure jrtplib to accept own packets by default.
   - This allows to use the test apps in gst-plugins-farsight
     without patching jrtplib, and without getenv() hacks.
   - If someone really wants to use multicast with rtpbin,
     please go ahead and add a nice way to select this
     at rtpbin creation time.

* Modified gst-plugins-farsight/tests/gsmsendrecv.c
   - Creates and binds sockets for RTP and RTCP, passes
     these to rtpbin, and runs a RTP/GSM test over
     local loopback.
   - Tested to work with a snapshot of today's (2005-11-30)
     gstreamer/gst-plugins-* CVS.
   - Thanks to the accept-own-packets change above,
     you can actually run the test without hacking'n'patching
     jrtplib as you had to do before.

--
  under work: Sofia-SIP at http://sofia-sip.sf.net
-------------- next part --------------
Index: gst/udp/gstdynudpsink.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/udp/gstdynudpsink.c,v
retrieving revision 1.4
diff -u -r1.4 gstdynudpsink.c
--- gst/udp/gstdynudpsink.c	29 Nov 2005 17:46:04 -0000	1.4
+++ gst/udp/gstdynudpsink.c	30 Nov 2005 18:10:42 -0000
@@ -1,5 +1,6 @@
 /* GStreamer
  * Copyright (C) <2005> Philippe Khalaf <burger at speedy.org>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen at nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -54,6 +55,7 @@
 enum
 {
   PROP_0,
+  PROP_SOCKFD
   /* FILL ME */
 };
 
@@ -139,6 +141,11 @@
       NULL, NULL, gst_udp_marshal_BOXED__STRING_INT, G_TYPE_VALUE_ARRAY, 2,
       G_TYPE_STRING, G_TYPE_INT);
 
+  g_object_class_install_property (gobject_class, PROP_SOCKFD,
+				   g_param_spec_int ("sockfd", "socket handle", 
+						     "Socket to use for UDP reception.",
+						     0, G_MAXINT16, 0, G_PARAM_READWRITE));
+
   gstelement_class->change_state = gst_dynudpsink_change_state;
 
   gstbasesink_class->get_times = gst_dynudpsink_get_times;
@@ -151,6 +158,10 @@
 static void
 gst_dynudpsink_init (GstDynUDPSink * sink)
 {
+  GstDynUDPSink *udpsink;
+  udpsink = GST_DYNUDPSINK (sink);
+  
+  sink->sock = -1;
 }
 
 static void
@@ -231,6 +242,11 @@
   udpsink = GST_DYNUDPSINK (object);
 
   switch (prop_id) {
+    case PROP_SOCKFD:
+      udpsink->sock = g_value_get_int (value);
+      GST_DEBUG ("setting SOCKFD to %d", udpsink->sock);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -246,6 +262,10 @@
   udpsink = GST_DYNUDPSINK (object);
 
   switch (prop_id) {
+    case PROP_SOCKFD:
+      g_value_set_int (value, udpsink->sock);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -260,15 +280,18 @@
   guint bc_val;
   gint ret;
 
-  /* create sender socket */
-  if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
-    goto no_socket;
-
-  bc_val = 1;
-  if ((ret =
-          setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val,
-              sizeof (bc_val))) < 0)
-    goto no_broadcast;
+  if (sink->sock == -1) {
+    /* create sender socket if none available */
+
+    if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
+      goto no_socket;
+
+    bc_val = 1;
+    if ((ret =
+	 setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val,
+		     sizeof (bc_val))) < 0)
+      goto no_broadcast;
+  }
 
   return TRUE;
 
Index: gst/udp/gstudpsrc.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/udp/gstudpsrc.c,v
retrieving revision 1.48
diff -u -r1.48 gstudpsrc.c
--- gst/udp/gstudpsrc.c	29 Nov 2005 17:46:04 -0000	1.48
+++ gst/udp/gstudpsrc.c	30 Nov 2005 18:10:42 -0000
@@ -1,5 +1,6 @@
 /* GStreamer
  * Copyright (C) <2005> Wim Taymans <wim at fluendo.com>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen at nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -76,6 +77,7 @@
   PROP_MULTICAST_GROUP,
   PROP_URI,
   PROP_CAPS,
+  PROP_SOCKFD
   /* FILL ME */
 };
 
@@ -149,6 +151,10 @@
   g_object_class_install_property (gobject_class, PROP_CAPS,
       g_param_spec_boxed ("caps", "Caps",
           "The caps of the source pad", GST_TYPE_CAPS, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_SOCKFD,
+      g_param_spec_int ("sockfd", "socket handle", 
+          "Socket to use for UDP reception.",
+          0, G_MAXINT16, 0, G_PARAM_READWRITE));
 
   gstbasesrc_class->start = gst_udpsrc_start;
   gstbasesrc_class->stop = gst_udpsrc_stop;
@@ -403,6 +409,10 @@
       gst_pad_set_caps (GST_BASE_SRC (udpsrc)->srcpad, new_caps);
       break;
     }
+    case PROP_SOCKFD:
+      udpsrc->sock = g_value_get_int (value);
+      GST_DEBUG ("setting SOCKFD to %d", udpsrc->sock);
+      break;
     default:
       break;
   }
@@ -427,6 +437,9 @@
     case PROP_CAPS:
       gst_value_set_caps (value, udpsrc->caps);
       break;
+    case PROP_SOCKFD:
+      g_value_set_int (value, udpsrc->sock);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -454,27 +467,30 @@
   fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
   fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
 
-  if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
-    goto no_socket;
-
-  src->sock = ret;
-
-  reuse = 1;
-  if ((ret =
-          setsockopt (src->sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
-              sizeof (reuse))) < 0)
-    goto setsockopt_error;
-
-  memset (&src->myaddr, 0, sizeof (src->myaddr));
-  src->myaddr.sin_family = AF_INET;     /* host byte order */
-  src->myaddr.sin_port = htons (src->port);     /* short, network byte order */
-  src->myaddr.sin_addr.s_addr = INADDR_ANY;
-
-  GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
-  if ((ret =
-          bind (src->sock, (struct sockaddr *) &src->myaddr,
-              sizeof (src->myaddr))) < 0)
-    goto bind_error;
+  if (src->sock == -1) {
+    if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+      goto no_socket;
+
+    src->sock = ret;
+
+    reuse = 1;
+    if ((ret =
+	 setsockopt (src->sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
+		     sizeof (reuse))) < 0)
+      goto setsockopt_error;
+
+    /* XXX-kvehmanen: add ability to select a random, free port */
+    memset (&src->myaddr, 0, sizeof (src->myaddr));
+    src->myaddr.sin_family = AF_INET;     /* host byte order */
+    src->myaddr.sin_port = htons (src->port);     /* short, network byte order */
+    src->myaddr.sin_addr.s_addr = INADDR_ANY;
+
+    GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
+    if ((ret =
+	 bind (src->sock, (struct sockaddr *) &src->myaddr,
+	       sizeof (src->myaddr))) < 0)
+      goto bind_error;
+  }
 
   if (inet_aton (src->multi_group, &(src->multi_addr.imr_multiaddr))) {
     if (src->multi_addr.imr_multiaddr.s_addr) {


More information about the gstreamer-devel mailing list