[farsight2/master] Add new gather_local_candidates method to the FsStreamTransmitter

Olivier Crête olivier.crete at collabora.co.uk
Tue Dec 23 15:22:07 PST 2008


---
 docs/libs/farsight2-libs-sections.txt              |    1 +
 gst-libs/gst/farsight/fs-stream-transmitter.c      |   26 +
 gst-libs/gst/farsight/fs-stream-transmitter.h      |    8 +
 transmitters/rawudp/Makefile.am                    |   21 +-
 transmitters/rawudp/fs-rawudp-component.c          |  683 ++++++++++++++++++-
 transmitters/rawudp/fs-rawudp-component.h          |   10 +-
 transmitters/rawudp/fs-rawudp-marshal.c            |   88 +++
 transmitters/rawudp/fs-rawudp-marshal.h            |   20 +
 transmitters/rawudp/fs-rawudp-marshal.list         |    1 +
 transmitters/rawudp/fs-rawudp-stream-transmitter.c |  708 +++-----------------
 10 files changed, 916 insertions(+), 650 deletions(-)
 create mode 100644 transmitters/rawudp/fs-rawudp-marshal.c
 create mode 100644 transmitters/rawudp/fs-rawudp-marshal.h
 create mode 100644 transmitters/rawudp/fs-rawudp-marshal.list

diff --git a/docs/libs/farsight2-libs-sections.txt b/docs/libs/farsight2-libs-sections.txt
index ce69c41..e7730fe 100644
--- a/docs/libs/farsight2-libs-sections.txt
+++ b/docs/libs/farsight2-libs-sections.txt
@@ -173,6 +173,7 @@ FsStreamTransmitterClass
 fs_stream_transmitter_add_remote_candidate
 fs_stream_transmitter_remote_candidates_added
 fs_stream_transmitter_select_candidate_pair
+fs_stream_transmitter_gather_local_candidates
 fs_stream_transmitter_emit_error
 <SUBSECTION Standard>
 FS_IS_STREAM_TRANSMITTER
diff --git a/gst-libs/gst/farsight/fs-stream-transmitter.c b/gst-libs/gst/farsight/fs-stream-transmitter.c
index 887f3db..7495d85 100644
--- a/gst-libs/gst/farsight/fs-stream-transmitter.c
+++ b/gst-libs/gst/farsight/fs-stream-transmitter.c
@@ -355,6 +355,32 @@ fs_stream_transmitter_select_candidate_pair (
   return FALSE;
 }
 
+/**
+ * fs_stream_transmitter_gather_local_candidates:
+ * @streamtransmitter: a #FsStreamTransmitter
+ * @error: location of a #GErrorh, or NULL if no error occured
+ *
+ * This function tells the transmitter to start gathering local candidates,
+ * signals for new candidates and newly active candidates can be emitted
+ * during the call to this function.
+ *
+ * Returns: %TRUE if it succeeds (or is not implemented), %FALSE otherwise
+ */
+
+gboolean
+fs_stream_transmitter_gather_local_candidates (
+    FsStreamTransmitter *streamtransmitter,
+    GError **error)
+{
+  FsStreamTransmitterClass *klass =
+    FS_STREAM_TRANSMITTER_GET_CLASS (streamtransmitter);
+
+  if (klass->gather_local_candidates)
+    return klass->gather_local_candidates (streamtransmitter, error);
+  else
+    return TRUE;
+}
+
 
 /**
  * fs_stream_transmitter_emit_error:
diff --git a/gst-libs/gst/farsight/fs-stream-transmitter.h b/gst-libs/gst/farsight/fs-stream-transmitter.h
index c4586f3..f8aed8c 100644
--- a/gst-libs/gst/farsight/fs-stream-transmitter.h
+++ b/gst-libs/gst/farsight/fs-stream-transmitter.h
@@ -60,6 +60,7 @@ typedef struct _FsStreamTransmitterPrivate FsStreamTransmitterPrivate;
  * @add_remote_candidate: Sets the remote candidate
  * @remote_candidates_added: Tell the stream to start the connectivity checks
  * @select_candidate_pair: Select the candidate pair
+ * @gather_local_candidates: Starts the gathering of local candidates
  *
  * You must override the add_remote_candidate in a subclass
  */
@@ -77,6 +78,8 @@ struct _FsStreamTransmitterClass
   gboolean (*select_candidate_pair) (FsStreamTransmitter *streamtransmitter,
                                      gchar *lfoundation, gchar *rfoundation,
                                      GError **error);
+  gboolean (*gather_local_candidates) (FsStreamTransmitter *streamtransmitter,
+                                       GError **error);
 
   /*< private >*/
   gpointer _padding[8];
@@ -109,6 +112,11 @@ gboolean fs_stream_transmitter_select_candidate_pair (
     FsStreamTransmitter *streamtransmitter, gchar *lfoundation,
     gchar *rfoundation, GError **error);
 
+gboolean
+fs_stream_transmitter_gather_local_candidates (
+    FsStreamTransmitter *streamtransmitter,
+    GError **error);
+
 void fs_stream_transmitter_emit_error (FsStreamTransmitter *streamtransmitter,
   gint error_no, gchar *error_msg, gchar *debug_msg);
 
diff --git a/transmitters/rawudp/Makefile.am b/transmitters/rawudp/Makefile.am
index 1bc6442..b22fdde 100644
--- a/transmitters/rawudp/Makefile.am
+++ b/transmitters/rawudp/Makefile.am
@@ -9,6 +9,7 @@ librawudp_transmitter_la_SOURCES = \
 	fs-rawudp-stream-transmitter.c \
 	fs-rawudp-component.c \
 	fs-interfaces.c \
+	fs-rawudp-marshal.c \
 	stun.c
 
 # flags used to compile this plugin
@@ -23,5 +24,23 @@ noinst_HEADERS = \
 	fs-rawudp-transmitter.h \
 	fs-rawudp-stream-transmitter.h \
 	fs-rawudp-component.h \
-	fs-interfaces.h \
+	fs-interfaces.h \	
+	fs-rawudp-marshal.h \
 	stun.h
+
+BUILT_SOURCES = \
+		fs-rawudp-marshal.c \
+		fs-rawudp-marshal.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+
+fs-rawudp-marshal.h: fs-rawudp-marshal.list Makefile
+		glib-genmarshal --header --prefix=_fs_rawudp_marshal $(srcdir)/$< > $@.tmp
+		mv $@.tmp $@
+
+fs-rawudp-marshal.c: fs-rawudp-marshal.list Makefile
+		echo "#include \"glib-object.h\"" >> $@.tmp
+		echo "#include \"fs-rawudp-marshal.h\"" >> $@.tmp
+		glib-genmarshal --body --prefix=_fs_rawudp_marshal $(srcdir)/$< >> $@.tmp
+		mv $@.tmp $@
diff --git a/transmitters/rawudp/fs-rawudp-component.c b/transmitters/rawudp/fs-rawudp-component.c
index 54b9852..01bf054 100644
--- a/transmitters/rawudp/fs-rawudp-component.c
+++ b/transmitters/rawudp/fs-rawudp-component.c
@@ -29,14 +29,30 @@
 
 #include "fs-rawudp-component.h"
 
+#include "fs-rawudp-marshal.h"
+
+#include "stun.h"
+#include "fs-interfaces.h"
+
 #include <gst/farsight/fs-conference-iface.h>
 
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
 
 #define GST_CAT_DEFAULT fs_rawudp_transmitter_debug
 
 /* Signals */
 enum
 {
+  NEW_LOCAL_CANDIDATE,
+  LOCAL_CANDIDATES_PREPARED,
+  NEW_ACTIVE_CANDIDATE_PAIR,
+  ERROR,
   LAST_SIGNAL
 };
 
@@ -45,12 +61,14 @@ enum
 {
   PROP_0,
   PROP_COMPONENT,
+  PROP_IP,
+  PROP_PORT,
   PROP_STUN_IP,
   PROP_STUN_PORT,
   PROP_STUN_TIMEOUT,
   PROP_SENDING,
-  PROP_UDPPORT,
-  PROP_TRANSMITTER
+  PROP_TRANSMITTER,
+  PROP_FORCED_CANDIDATE
 };
 
 
@@ -60,26 +78,44 @@ struct _FsRawUdpComponentPrivate
 
   guint component;
 
+  GError *construction_error;
+
   UdpPort *udpport;
   FsRawUdpTransmitter *transmitter;
 
+  gchar *ip;
+  guint port;
+
   gchar *stun_ip;
   guint stun_port;
   guint stun_timeout;
 
   GMutex *mutex;
 
+  gchar stun_cookie[16];
+
   /* Above this line, its all set at construction time */
   /* This is protected by the mutex */
 
   FsCandidate *remote_candidate;
 
+  FsCandidate *local_active_candidate;
+  FsCandidate *local_forced_candidate;
+  FsCandidate *local_stun_candidate;
+
+
+  gulong stun_recv_id;
+
+  GstClockID stun_timeout_id;
+  GstClockTime next_stun_timeout;
+  GThread *stun_timeout_thread;
+
   gboolean sending;
 };
 
 
 static GObjectClass *parent_class = NULL;
-// static guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = { 0 };
 
 static GType type = 0;
 
@@ -93,6 +129,8 @@ fs_rawudp_component_class_init (FsRawUdpComponentClass *klass);
 static void
 fs_rawudp_component_init (FsRawUdpComponent *self);
 static void
+fs_rawudp_constructed (GObject *object);
+static void
 fs_rawudp_component_dispose (GObject *object);
 static void
 fs_rawudp_component_finalize (GObject *object);
@@ -108,6 +146,26 @@ fs_rawudp_component_set_property (GObject *object,
     GParamSpec *pspec);
 
 
+static gboolean
+fs_rawudp_component_no_stun (FsRawUdpComponent *self, GError **error);
+static gboolean
+fs_rawudp_component_emit_local_candidates (FsRawUdpComponent *self,
+    GError **eror);
+static void
+fs_rawudp_component_emit_error (FsRawUdpComponent *self,
+    gint error_no,
+    gchar *error_msg,
+    gchar *debug_msg);
+static void
+fs_rawudp_component_maybe_new_active_candidate_pair (FsRawUdpComponent *self);
+
+static gboolean
+stun_recv_cb (GstPad *pad, GstBuffer *buffer,
+    gpointer user_data);
+static gpointer
+stun_timeout_func (gpointer user_data);
+
+
 GType
 fs_rawudp_component_get_type (void)
 {
@@ -135,8 +193,6 @@ fs_rawudp_component_register_type (FsPlugin *module)
   return type;
 }
 
-
-
 static void
 fs_rawudp_component_class_init (FsRawUdpComponentClass *klass)
 {
@@ -146,15 +202,17 @@ fs_rawudp_component_class_init (FsRawUdpComponentClass *klass)
 
   gobject_class->set_property = fs_rawudp_component_set_property;
   gobject_class->get_property = fs_rawudp_component_get_property;
+  gobject_class->constructed = fs_rawudp_constructed;
+  gobject_class->dispose = fs_rawudp_component_dispose;
+  gobject_class->finalize = fs_rawudp_component_finalize;
 
-
- g_object_class_install_property (gobject_class,
+  g_object_class_install_property (gobject_class,
       PROP_COMPONENT,
       g_param_spec_uint ("component",
           "The component id",
           "The id of this component",
           1, G_MAXUINT, 1,
-          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
 
   g_object_class_install_property (gobject_class,
@@ -166,6 +224,23 @@ fs_rawudp_component_class_init (FsRawUdpComponentClass *klass)
           G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class,
+      PROP_IP,
+      g_param_spec_string ("ip",
+          "The local IP of this component",
+          "The IPv4 address as a x.x.x.x string",
+          NULL,
+          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_PORT,
+      g_param_spec_uint ("port",
+          "The local port requested for this component",
+          "The IPv4 UDP port",
+          1, 65535, 7078,
+          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+
+
+  g_object_class_install_property (gobject_class,
       PROP_STUN_IP,
       g_param_spec_string ("stun-ip",
           "The IP address of the STUN server",
@@ -200,14 +275,68 @@ fs_rawudp_component_class_init (FsRawUdpComponentClass *klass)
 
 
   g_object_class_install_property (gobject_class,
-      PROP_UDPPORT,
-      g_param_spec_pointer ("udpport",
-          "The UdpPort for this component",
-          "a gpointer to the udpport",
-          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+      PROP_FORCED_CANDIDATE,
+      g_param_spec_boxed ("forced-candidate",
+          "A Forced candidate",
+          "This candidate is built from a user preference",
+          FS_TYPE_CANDIDATE,
+          G_PARAM_WRITABLE));
+
+   /**
+   * FsComponent::new-local-candidate:
+   * @self: #FsStream that emitted the signal
+   * @local_candidate: #FsCandidate of the local candidate
+   *
+   * This signal is emitted when a new local candidate is discovered.
+   */
+  signals[NEW_LOCAL_CANDIDATE] = g_signal_new
+    ("new-local-candidate",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL,
+      NULL,
+      g_cclosure_marshal_VOID__BOXED,
+      G_TYPE_NONE, 1, FS_TYPE_CANDIDATE);
+
+ /**
+   * FsComponent::local-candidates-prepared:
+   * @self: #FsStream that emitted the signal
+   *
+   * This signal is emitted when all local candidates have been
+   * prepared for this component.
+   */
+  signals[LOCAL_CANDIDATES_PREPARED] = g_signal_new
+    ("local-candidates-prepared",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL,
+      NULL,
+      g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+
+  /**
+   * FsComponent::new-active-candidate-pair:
+   * @self: #FsStream that emitted the signal
+   * @local_candidate: #FsCandidate of the local candidate being used
+   * @remote_candidate: #FsCandidate of the remote candidate being used
+   *
+   * This signal is emitted when there is a new active chandidate pair that has
+   * been established.
+   *
+   */
+  signals[NEW_ACTIVE_CANDIDATE_PAIR] = g_signal_new
+    ("new-active-candidate-pair",
+        G_TYPE_FROM_CLASS (klass),
+        G_SIGNAL_RUN_LAST,
+        0,
+        NULL,
+        NULL,
+        _fs_rawudp_marshal_VOID__BOXED_BOXED,
+        G_TYPE_NONE, 2, FS_TYPE_CANDIDATE, FS_TYPE_CANDIDATE);
+
 
-  gobject_class->dispose = fs_rawudp_component_dispose;
-  gobject_class->finalize = fs_rawudp_component_finalize;
 
   g_type_class_add_private (klass, sizeof (FsRawUdpComponentPrivate));
 }
@@ -222,24 +351,75 @@ fs_rawudp_component_init (FsRawUdpComponent *self)
       FS_TYPE_RAWUDP_COMPONENT,
       FsRawUdpComponentPrivate);
 
+  self->priv->disposed = FALSE;
+
   self->priv->sending = TRUE;
+  self->priv->port = 7078;
 
-  self->priv->disposed = FALSE;
+  ((guint32*)self->priv->stun_cookie)[0] = g_random_int ();
+  ((guint32*)self->priv->stun_cookie)[1] = g_random_int ();
+  ((guint32*)self->priv->stun_cookie)[2] = g_random_int ();
+  ((guint32*)self->priv->stun_cookie)[3] = g_random_int ();
 
   self->priv->mutex = g_mutex_new ();
 }
 
+static void
+fs_rawudp_constructed (GObject *object)
+{
+  FsRawUdpComponent *self = FS_RAWUDP_COMPONENT (object);
+
+  if (!self->priv->transmitter)
+  {
+    self->priv->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_INVALID_ARGUMENTS,
+        "You need a transmitter to build this object");
+    return;
+  }
 
+  self->priv->udpport =
+    fs_rawudp_transmitter_get_udpport (self->priv->transmitter,
+        self->priv->component,
+        self->priv->ip,
+        self->priv->port,
+        &self->priv->construction_error);
+  if (!self->priv->udpport)
+  {
+    if (!self->priv->construction_error)
+      self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_INTERNAL,
+          "Unkown error when trying to open udp port");
+    return;
+  }
+
+  GST_CALL_PARENT (G_OBJECT_CLASS, constructed, (object));
+}
 
 static void
 fs_rawudp_component_dispose (GObject *object)
 {
   FsRawUdpComponent *self = FS_RAWUDP_COMPONENT (object);
+  FsRawUdpTransmitter *ts = NULL;
 
   if (self->priv->disposed)
     /* If dispose did already run, return. */
     return;
 
+  FS_RAWUDP_COMPONENT_LOCK (self);
+
+  /* Make sure dispose does not run twice. */
+  self->priv->disposed = TRUE;
+
+  if (self->priv->stun_timeout_thread != NULL)
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+    g_thread_join (self->priv->stun_timeout_thread);
+    FS_RAWUDP_COMPONENT_LOCK (self);
+
+    self->priv->stun_timeout_thread = NULL;
+  }
+
+  FS_RAWUDP_COMPONENT_UNLOCK (self);
+
   if (self->priv->remote_candidate &&
       self->priv->udpport &&
       self->priv->sending)
@@ -247,18 +427,18 @@ fs_rawudp_component_dispose (GObject *object)
           self->priv->remote_candidate->ip,
           self->priv->remote_candidate->port);
 
-  FS_RAWUDP_COMPONENT_LOCK (self);
+  if (self->priv->udpport)
+    fs_rawudp_transmitter_put_udpport (self->priv->transmitter,
+        self->priv->udpport);
 
+  FS_RAWUDP_COMPONENT_LOCK (self);
   self->priv->udpport = NULL;
-
-  g_object_unref (self->priv->transmitter);
+  ts = self->priv->transmitter;
   self->priv->transmitter = NULL;
-
-  /* Make sure dispose does not run twice. */
-  self->priv->disposed = TRUE;
-
   FS_RAWUDP_COMPONENT_UNLOCK (self);
 
+  g_object_unref (ts);
+
   parent_class->dispose (object);
 }
 
@@ -270,7 +450,14 @@ fs_rawudp_component_finalize (GObject *object)
 
   if (self->priv->remote_candidate)
     fs_candidate_destroy (self->priv->remote_candidate);
-
+  if (self->priv->local_active_candidate)
+    fs_candidate_destroy (self->priv->local_active_candidate);
+  if (self->priv->local_stun_candidate)
+    fs_candidate_destroy (self->priv->local_stun_candidate);
+  if (self->priv->local_forced_candidate)
+    fs_candidate_destroy (self->priv->local_forced_candidate);
+
+  g_free (self->priv->ip);
   g_free (self->priv->stun_ip);
 
   g_mutex_free (self->priv->mutex);
@@ -294,6 +481,14 @@ fs_rawudp_component_get_property (GObject *object,
       g_value_set_boolean (value, self->priv->sending);
       FS_RAWUDP_COMPONENT_UNLOCK (self);
       break;
+    case PROP_FORCED_CANDIDATE:
+      FS_RAWUDP_COMPONENT_LOCK (self);
+      g_value_set_boxed (value, self->priv->local_forced_candidate);
+      FS_RAWUDP_COMPONENT_UNLOCK (self);
+      break;
+    case PROP_COMPONENT:
+      g_value_set_uint (value, self->priv->component);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -336,6 +531,13 @@ fs_rawudp_component_set_property (GObject *object,
         }
       }
       break;
+    case PROP_IP:
+      g_free (self->priv->ip);
+      self->priv->ip = g_value_dup_string (value);
+      break;
+    case PROP_PORT:
+      self->priv->port = g_value_get_uint (value);
+      break;
     case PROP_STUN_IP:
       g_free (self->priv->stun_ip);
       self->priv->stun_ip = g_value_dup_string (value);
@@ -346,12 +548,17 @@ fs_rawudp_component_set_property (GObject *object,
     case PROP_STUN_TIMEOUT:
       self->priv->stun_timeout = g_value_get_uint (value);
       break;
-    case PROP_UDPPORT:
-      self->priv->udpport = g_value_get_pointer (value);
-      break;
     case PROP_TRANSMITTER:
       self->priv->transmitter = g_value_dup_object (value);
       break;
+    case PROP_FORCED_CANDIDATE:
+      FS_RAWUDP_COMPONENT_LOCK (self);
+      if (self->priv->local_forced_candidate)
+        GST_WARNING ("Tried to reset a forced candidate");
+      else
+        self->priv->local_forced_candidate = g_value_dup_boxed (value);
+      FS_RAWUDP_COMPONENT_UNLOCK (self);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -363,10 +570,12 @@ FsRawUdpComponent *
 fs_rawudp_component_new (
     guint component,
     FsRawUdpTransmitter *trans,
+    const gchar *ip,
+    guint port,
     const gchar *stun_ip,
     guint stun_port,
     guint stun_timeout,
-    UdpPort *udpport,
+    guint *used_port,
     GError **error)
 {
   FsRawUdpComponent *self = NULL;
@@ -374,10 +583,11 @@ fs_rawudp_component_new (
   self = g_object_new (FS_TYPE_RAWUDP_COMPONENT,
       "component", component,
       "transmitter", trans,
+      "ip", ip,
+      "port", port,
       "stun-ip", stun_ip,
       "stun-port", stun_port,
       "stun-timeout", stun_timeout,
-      "udpport", udpport,
       NULL);
 
   if (!self)
@@ -387,6 +597,16 @@ fs_rawudp_component_new (
     return NULL;
   }
 
+  if (self->priv->construction_error)
+  {
+    g_propagate_error (error, self->priv->construction_error);
+    g_object_unref (self);
+    return NULL;
+  }
+
+  if (used_port)
+    *used_port = fs_rawudp_transmitter_udpport_get_port (self->priv->udpport);
+
   return self;
 }
 
@@ -427,5 +647,410 @@ fs_rawudp_component_add_remote_candidate (FsRawUdpComponent *self,
     fs_candidate_destroy (old_candidate);
   }
 
+  fs_rawudp_component_maybe_new_active_candidate_pair (self);
+
+  return TRUE;
+}
+
+gboolean
+fs_rawudp_component_gather_local_candidates (FsRawUdpComponent *self,
+    GError **error)
+{
+  if (self->priv->stun_ip && self->priv->stun_port)
+  {
+    if (!fs_rawudp_component_start_stun (self, error))
+      return FALSE;
+  }
+  else
+  {
+    if (!fs_rawudp_component_no_stun (self, error))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+gboolean
+fs_rawudp_component_start_stun (FsRawUdpComponent *self, GError **error)
+{
+  struct addrinfo hints;
+  struct addrinfo *result = NULL;
+  struct sockaddr_in address;
+  gchar *packed;
+  guint length;
+  int retval;
+  StunMessage *msg;
+  gboolean res = TRUE;
+  GstClock *sysclock = NULL;
+
+  sysclock = gst_system_clock_obtain ();
+  if (sysclock == NULL)
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
+        "Could not obtain gst system clock");
+    return FALSE;
+  }
+
+  memset (&hints, 0, sizeof (struct addrinfo));
+  hints.ai_family = AF_INET;
+  hints.ai_flags = AI_NUMERICHOST;
+  retval = getaddrinfo (self->priv->stun_ip, NULL, &hints, &result);
+  if (retval != 0)
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+        "Invalid IP address %s passed for STUN: %s",
+        self->priv->stun_ip, gai_strerror (retval));
+    return FALSE;
+  }
+  memcpy (&address, result->ai_addr, sizeof (struct sockaddr_in));
+  freeaddrinfo (result);
+
+  address.sin_family = AF_INET;
+  address.sin_port = htons (self->priv->stun_port);
+
+  FS_RAWUDP_COMPONENT_LOCK (self);
+  self->priv->stun_recv_id =
+    fs_rawudp_transmitter_udpport_connect_recv (
+        self->priv->udpport,
+        G_CALLBACK (stun_recv_cb), self);
+  FS_RAWUDP_COMPONENT_UNLOCK (self);
+
+  msg = stun_message_new (STUN_MESSAGE_BINDING_REQUEST,
+      self->priv->stun_cookie, 0);
+  if (!msg)
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+        "Could not create a new STUN binding request");
+    return FALSE;
+  }
+
+  length = stun_message_pack (msg, &packed);
+
+  if (!fs_rawudp_transmitter_udpport_sendto (self->priv->udpport,
+          packed, length, (const struct sockaddr *)&address, sizeof (address),
+          error))
+  {
+    g_free (packed);
+    stun_message_free (msg);
+    return FALSE;
+  }
+  g_free (packed);
+  stun_message_free (msg);
+
+  FS_RAWUDP_COMPONENT_LOCK (self);
+
+  self->priv->next_stun_timeout = gst_clock_get_time (sysclock) +
+    (self->priv->stun_timeout * GST_SECOND);
+
+  gst_object_unref (sysclock);
+
+  if (self->priv->stun_timeout_thread == NULL) {
+    /* only create a new thread if the old one was stopped. Otherwise we can
+     * just reuse the currently running one. */
+    self->priv->stun_timeout_thread =
+      g_thread_create (stun_timeout_func, self, TRUE, error);
+  }
+
+  res = (self->priv->stun_timeout_thread != NULL);
+
+  g_assert (error == NULL || res || *error);
+
+  FS_RAWUDP_COMPONENT_UNLOCK (self);
+
+  return res;
+}
+
+/*
+ * This function MUST always be called wiuth the Component lock held
+ */
+
+static void
+fs_rawudp_component_stop_stun_locked (FsRawUdpComponent *self)
+{
+  if (self->priv->stun_recv_id)
+  {
+    fs_rawudp_transmitter_udpport_disconnect_recv (
+        self->priv->udpport,
+        self->priv->stun_recv_id);
+    self->priv->stun_recv_id = 0;
+  }
+
+  self->priv->next_stun_timeout = 0;
+  if (self->priv->stun_timeout_id)
+    gst_clock_id_unschedule (self->priv->stun_timeout_id);
+}
+
+
+
+static gboolean
+stun_recv_cb (GstPad *pad, GstBuffer *buffer,
+    gpointer user_data)
+{
+  FsRawUdpComponent *self = FS_RAWUDP_COMPONENT (user_data);
+  FsCandidate *candidate = NULL;
+  StunMessage *msg;
+  StunAttribute **attr;
+
+  if (GST_BUFFER_SIZE (buffer) < 4)
+    /* Packet is too small to be STUN */
+    return TRUE;
+
+  if (GST_BUFFER_DATA (buffer)[0] >> 6)
+    /* Non stun packet */
+    return TRUE;
+
+
+  g_assert (fs_rawudp_transmitter_udpport_is_pad (self->priv->udpport, pad));
+
+  msg = stun_message_unpack (GST_BUFFER_SIZE (buffer),
+      (const gchar *) GST_BUFFER_DATA (buffer));
+  if (!msg)
+    /* invalid message */
+    return TRUE;
+
+  if (memcmp (msg->transaction_id, self->priv->stun_cookie, 16) != 0)
+  {
+    /* not ours */
+    stun_message_free (msg);
+    return TRUE;
+  }
+
+  if (msg->type == STUN_MESSAGE_BINDING_ERROR_RESPONSE)
+  {
+    fs_rawudp_component_emit_error (FS_RAWUDP_COMPONENT (self),
+        FS_ERROR_NETWORK, "Got an error message from the STUN server",
+        "The STUN process produced an error");
+    stun_message_free (msg);
+    // fs_rawudp_component_stop_stun (self, component_id);
+    /* Lets not stop the STUN now and wait for the timeout
+     * in case the server answers with the right reply
+     */
+    return FALSE;
+  }
+
+  if (msg->type != STUN_MESSAGE_BINDING_RESPONSE)
+  {
+    stun_message_free (msg);
+    return TRUE;
+  }
+
+
+  for (attr = msg->attributes; *attr; attr++)
+  {
+    if ((*attr)->type == STUN_ATTRIBUTE_MAPPED_ADDRESS)
+    {
+      // TODO
+      gchar *id = g_strdup_printf ("L1");
+      gchar *ip = g_strdup_printf ("%u.%u.%u.%u",
+          ((*attr)->address.ip & 0xff000000) >> 24,
+          ((*attr)->address.ip & 0x00ff0000) >> 16,
+          ((*attr)->address.ip & 0x0000ff00) >>  8,
+          ((*attr)->address.ip & 0x000000ff));
+
+      candidate = fs_candidate_new (id,
+          self->priv->component,
+          FS_CANDIDATE_TYPE_SRFLX,
+          FS_NETWORK_PROTOCOL_UDP,
+          ip,
+          (*attr)->address.port);
+      g_free (id);
+      g_free (ip);
+
+      GST_DEBUG ("Stun server says we are %u.%u.%u.%u %u\n",
+          ((*attr)->address.ip & 0xff000000) >> 24,
+          ((*attr)->address.ip & 0x00ff0000) >> 16,
+          ((*attr)->address.ip & 0x0000ff00) >>  8,
+          ((*attr)->address.ip & 0x000000ff),(*attr)->address.port);
+      break;
+    }
+  }
+
+  FS_RAWUDP_COMPONENT_LOCK(self);
+  fs_rawudp_component_stop_stun_locked (self);
+  FS_RAWUDP_COMPONENT_UNLOCK(self);
+
+  g_signal_emit (self, signals[NEW_LOCAL_CANDIDATE], 0, candidate);
+  g_signal_emit (self, signals[LOCAL_CANDIDATES_PREPARED], 0);
+
+  fs_candidate_destroy (candidate);
+
+  /* It was a stun packet, lets drop it */
+  stun_message_free (msg);
+  return FALSE;
+}
+
+static gpointer
+stun_timeout_func (gpointer user_data)
+{
+  FsRawUdpComponent *self = FS_RAWUDP_COMPONENT (user_data);
+  GstClock *sysclock = NULL;
+  GstClockID id;
+  gboolean emit = TRUE;
+
+  sysclock = gst_system_clock_obtain ();
+  if (sysclock == NULL)
+  {
+    fs_rawudp_component_emit_error (self, FS_ERROR_INTERNAL,
+        "Could not obtain gst system clock", NULL);
+    emit = FALSE;
+    FS_RAWUDP_COMPONENT_LOCK(self);
+    goto error;
+  }
+
+  FS_RAWUDP_COMPONENT_LOCK(self);
+  id = self->priv->stun_timeout_id = gst_clock_new_single_shot_id (sysclock,
+      self->priv->next_stun_timeout);
+
+  FS_RAWUDP_COMPONENT_UNLOCK(self);
+  gst_clock_id_wait (id, NULL);
+  FS_RAWUDP_COMPONENT_LOCK(self);
+
+  gst_clock_id_unref (id);
+  self->priv->stun_timeout_id = NULL;
+
+  if (self->priv->next_stun_timeout == 0)
+    emit = FALSE;
+
+ error:
+  fs_rawudp_component_stop_stun_locked (self);
+
+  FS_RAWUDP_COMPONENT_UNLOCK(self);
+
+  gst_object_unref (sysclock);
+
+  if (emit)
+  {
+    if (!fs_rawudp_component_emit_local_candidates (self, NULL))
+    {
+      return NULL;
+    }
+
+    g_signal_emit (self, signals[LOCAL_CANDIDATES_PREPARED], 0);
+  }
+
+  return NULL;
+}
+
+
+static void
+fs_rawudp_component_emit_error (FsRawUdpComponent *self,
+    gint error_no,
+    gchar *error_msg,
+    gchar *debug_msg)
+{
+  g_signal_emit (self, signals[ERROR], 0, error_no, error_msg, debug_msg);
+}
+
+
+static gboolean
+fs_rawudp_component_no_stun (FsRawUdpComponent *self, GError **error)
+{
+  /* If we have a STUN'd candidate, dont send the locally generated
+   * ones */
+
+  FS_RAWUDP_COMPONENT_LOCK (self);
+  if (!self->priv->local_active_candidate)
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+    if (!fs_rawudp_component_emit_local_candidates (self, error))
+      return FALSE;
+  }
+  else
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+  }
+
+  g_signal_emit (self, signals[LOCAL_CANDIDATES_PREPARED], 0);
+
   return TRUE;
 }
+
+
+static void
+fs_rawudp_component_maybe_new_active_candidate_pair (FsRawUdpComponent *self)
+{
+
+  FS_RAWUDP_COMPONENT_LOCK (self);
+
+  if (self->priv->local_active_candidate && self->priv->remote_candidate)
+  {
+    FsCandidate *remote = fs_candidate_copy (self->priv->remote_candidate);
+
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+
+    g_signal_emit (self, signals[NEW_ACTIVE_CANDIDATE_PAIR], 0,
+        self->priv->local_active_candidate, remote);
+
+    fs_candidate_destroy (remote);
+  }
+  else
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+  }
+}
+
+
+
+static gboolean
+fs_rawudp_component_emit_local_candidates (FsRawUdpComponent *self,
+    GError **error)
+{
+  GList *ips = NULL;
+  GList *current;
+  guint port;
+
+  FS_RAWUDP_COMPONENT_LOCK (self);
+  if (self->priv->local_forced_candidate)
+  {
+    self->priv->local_active_candidate = fs_candidate_copy (
+        self->priv->local_forced_candidate);
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+
+    g_signal_emit (self, signals[NEW_LOCAL_CANDIDATE], 0,
+        self->priv->local_active_candidate);
+    fs_rawudp_component_maybe_new_active_candidate_pair (self);
+
+    return TRUE;
+  }
+
+  port = fs_rawudp_transmitter_udpport_get_port (self->priv->udpport);
+
+  ips = farsight_get_local_ips (TRUE);
+
+  for (current = g_list_first (ips);
+       current;
+       current = g_list_next (current))
+  {
+    self->priv->local_active_candidate = fs_candidate_new ("L1",
+        self->priv->component,
+        FS_CANDIDATE_TYPE_HOST,
+        FS_NETWORK_PROTOCOL_UDP,
+        current->data,
+        port);    /* FIXME: Emit only the first candidate ?? */
+    break;
+  }
+
+  /* free list of ips */
+  g_list_foreach (ips, (GFunc) g_free, NULL);
+  g_list_free (ips);
+
+  if (self->priv->local_active_candidate)
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+    g_signal_emit (self, signals[NEW_LOCAL_CANDIDATE], 0,
+        self->priv->local_active_candidate);
+  }
+  else
+  {
+    FS_RAWUDP_COMPONENT_UNLOCK (self);
+    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+        "We have no local candidate for component %d",
+        self->priv->component);
+    return FALSE;
+  }
+
+  fs_rawudp_component_maybe_new_active_candidate_pair (self);
+
+  return TRUE;
+}
+
diff --git a/transmitters/rawudp/fs-rawudp-component.h b/transmitters/rawudp/fs-rawudp-component.h
index 0ea8ba2..aa85e66 100644
--- a/transmitters/rawudp/fs-rawudp-component.h
+++ b/transmitters/rawudp/fs-rawudp-component.h
@@ -93,10 +93,12 @@ FsRawUdpComponent *
 fs_rawudp_component_new (
     guint component,
     FsRawUdpTransmitter *trans,
+    const gchar *ip,
+    guint port,
     const gchar *stun_ip,
     guint stun_port,
     guint stun_timeout,
-    UdpPort *udpport,
+    guint *used_port,
     GError **error);
 
 gboolean
@@ -104,6 +106,12 @@ fs_rawudp_component_add_remote_candidate (FsRawUdpComponent *self,
     FsCandidate *candidate,
     GError **error);
 
+gboolean
+fs_rawudp_component_gather_local_candidates (FsRawUdpComponent *self,
+    GError **error);
+
+gboolean
+fs_rawudp_component_start_stun (FsRawUdpComponent *self, GError **error);
 
 G_END_DECLS
 
diff --git a/transmitters/rawudp/fs-rawudp-marshal.c b/transmitters/rawudp/fs-rawudp-marshal.c
new file mode 100644
index 0000000..95f33b0
--- /dev/null
+++ b/transmitters/rawudp/fs-rawudp-marshal.c
@@ -0,0 +1,88 @@
+#include "glib-object.h"
+#include "fs-rawudp-marshal.h"
+
+#include	<glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:BOXED,BOXED (./fs-rawudp-marshal.list:1) */
+void
+_fs_rawudp_marshal_VOID__BOXED_BOXED (GClosure     *closure,
+                                      GValue       *return_value G_GNUC_UNUSED,
+                                      guint         n_param_values,
+                                      const GValue *param_values,
+                                      gpointer      invocation_hint G_GNUC_UNUSED,
+                                      gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__BOXED_BOXED) (gpointer     data1,
+                                                  gpointer     arg_1,
+                                                  gpointer     arg_2,
+                                                  gpointer     data2);
+  register GMarshalFunc_VOID__BOXED_BOXED callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__BOXED_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_boxed (param_values + 1),
+            g_marshal_value_peek_boxed (param_values + 2),
+            data2);
+}
+
diff --git a/transmitters/rawudp/fs-rawudp-marshal.h b/transmitters/rawudp/fs-rawudp-marshal.h
new file mode 100644
index 0000000..8532627
--- /dev/null
+++ b/transmitters/rawudp/fs-rawudp-marshal.h
@@ -0,0 +1,20 @@
+
+#ifndef ___fs_rawudp_marshal_MARSHAL_H__
+#define ___fs_rawudp_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:BOXED,BOXED (./fs-rawudp-marshal.list:1) */
+extern void _fs_rawudp_marshal_VOID__BOXED_BOXED (GClosure     *closure,
+                                                  GValue       *return_value,
+                                                  guint         n_param_values,
+                                                  const GValue *param_values,
+                                                  gpointer      invocation_hint,
+                                                  gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* ___fs_rawudp_marshal_MARSHAL_H__ */
+
diff --git a/transmitters/rawudp/fs-rawudp-marshal.list b/transmitters/rawudp/fs-rawudp-marshal.list
new file mode 100644
index 0000000..73ccad0
--- /dev/null
+++ b/transmitters/rawudp/fs-rawudp-marshal.list
@@ -0,0 +1 @@
+VOID:BOXED,BOXED
diff --git a/transmitters/rawudp/fs-rawudp-stream-transmitter.c b/transmitters/rawudp/fs-rawudp-stream-transmitter.c
index 2342122..90afb86 100644
--- a/transmitters/rawudp/fs-rawudp-stream-transmitter.c
+++ b/transmitters/rawudp/fs-rawudp-stream-transmitter.c
@@ -74,7 +74,6 @@
 
 #include "fs-rawudp-component.h"
 
-#include "stun.h"
 #include "fs-interfaces.h"
 
 #include <gst/farsight/fs-candidate.h>
@@ -83,12 +82,7 @@
 #include <gst/gst.h>
 
 #include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
+
 
 #define GST_CAT_DEFAULT fs_rawudp_transmitter_debug
 
@@ -121,37 +115,19 @@ struct _FsRawUdpStreamTransmitterPrivate
 
   gboolean sending;
 
-  /*
-   * We have at most of those per component (index 0 is unused)
-   */
-  FsCandidate **remote_candidate;
-
-  FsCandidate **local_forced_candidate;
-  FsCandidate **local_stun_candidate;
-  FsCandidate **local_active_candidate;
-
-  UdpPort **udpports;
-
+  /* This is an array of size n_components+1 */
   FsRawUdpComponent **component;
 
   gchar *stun_ip;
   guint stun_port;
   guint stun_timeout;
 
-  /* These are protected by the sources_mutex too
-   * And there is one per component (+1)
-   */
-  gulong *stun_recv_id;
-  guint  *stun_timeout_id;
-
-  gchar stun_cookie[16];
-
   GList *preferred_local_candidates;
-
   guint next_candidate_id;
 
-  GMutex *sources_mutex;
-  GList *sources;
+  /* Everything below this line is protected by the mutex */
+  GMutex *mutex;
+  gboolean *candidates_prepared;
 };
 
 #define FS_RAWUDP_STREAM_TRANSMITTER_GET_PRIVATE(o)                     \
@@ -177,28 +153,26 @@ static gboolean fs_rawudp_stream_transmitter_add_remote_candidate (
     FsStreamTransmitter *streamtransmitter,
     FsCandidate *candidate,
     GError **error);
-
-static gboolean fs_rawudp_stream_transmitter_start_stun (
-    FsRawUdpStreamTransmitter *self,
-    guint component_id,
+static gboolean fs_rawudp_stream_transmitter_gather_local_candidates (
+    FsStreamTransmitter *streamtransmitter,
     GError **error);
-static void fs_rawudp_stream_transmitter_stop_stun (
-    FsRawUdpStreamTransmitter *self,
-    guint component_id);
 
 static FsCandidate* fs_rawudp_stream_transmitter_build_forced_candidate (
     FsRawUdpStreamTransmitter *self,
     const char *ip,
     gint port,
     guint component_id);
-static gboolean fs_rawudp_stream_transmitter_no_stun (
+
+static void
+_component_new_local_candidate (FsRawUdpComponent *component,
+    FsCandidate *candidate, gpointer user_data);
+static void
+_component_local_candidates_prepared (FsRawUdpComponent *component,
     gpointer user_data);
-static void fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (
-    FsRawUdpStreamTransmitter *self,
-    guint component_id);
-static gboolean fs_rawudp_stream_transmitter_emit_local_candidates (
-    FsRawUdpStreamTransmitter *self,
-    guint component_id);
+static void
+_component_new_active_candidate_pair (FsRawUdpComponent *component,
+    FsCandidate *local, FsCandidate *remote, gpointer user_data);
+
 
 
 static GObjectClass *parent_class = NULL;
@@ -249,6 +223,8 @@ fs_rawudp_stream_transmitter_class_init (FsRawUdpStreamTransmitterClass *klass)
 
   streamtransmitterclass->add_remote_candidate =
     fs_rawudp_stream_transmitter_add_remote_candidate;
+  streamtransmitterclass->gather_local_candidates =
+    fs_rawudp_stream_transmitter_gather_local_candidates;
 
   g_object_class_override_property (gobject_class, PROP_SENDING, "sending");
   g_object_class_override_property (gobject_class,
@@ -293,13 +269,7 @@ fs_rawudp_stream_transmitter_init (FsRawUdpStreamTransmitter *self)
 
   self->priv->sending = TRUE;
 
-  /* Use a pseudo-random number for the STUN cookie */
-  ((guint32*)self->priv->stun_cookie)[0] = g_random_int ();
-  ((guint32*)self->priv->stun_cookie)[1] = g_random_int ();
-  ((guint32*)self->priv->stun_cookie)[2] = g_random_int ();
-  ((guint32*)self->priv->stun_cookie)[3] = g_random_int ();
-
-  self->priv->sources_mutex = g_mutex_new ();
+  self->priv->mutex = g_mutex_new ();
 }
 
 static void
@@ -324,26 +294,6 @@ fs_rawudp_stream_transmitter_dispose (GObject *object)
     }
   }
 
-  g_mutex_lock (self->priv->sources_mutex);
-
-  if (self->priv->stun_recv_id)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->stun_recv_id[c])
-        fs_rawudp_stream_transmitter_stop_stun (self, c);
-    }
-  }
-
-  if (self->priv->sources)
-  {
-    g_list_foreach (self->priv->sources, (GFunc) g_source_remove, NULL);
-    g_list_free (self->priv->sources);
-    self->priv->sources = NULL;
-  }
-  g_mutex_unlock (self->priv->sources_mutex);
-
-
   /* Make sure dispose does not run twice. */
   self->priv->disposed = TRUE;
 
@@ -354,7 +304,6 @@ static void
 fs_rawudp_stream_transmitter_finalize (GObject *object)
 {
   FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (object);
-  gint c; /* component_id */
 
   g_free (self->priv->stun_ip);
 
@@ -367,67 +316,9 @@ fs_rawudp_stream_transmitter_finalize (GObject *object)
     self->priv->component = NULL;
   }
 
-  if (self->priv->remote_candidate)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->remote_candidate[c])
-      {
-        if (self->priv->udpports && self->priv->udpports[c])
-          fs_candidate_destroy (self->priv->remote_candidate[c]);
-      }
-    }
-
-    g_free (self->priv->remote_candidate);
-  }
-
-  if (self->priv->udpports)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->udpports[c])
-        fs_rawudp_transmitter_put_udpport (self->priv->transmitter,
-            self->priv->udpports[c]);
-    }
-
-    g_free (self->priv->udpports);
-  }
-
-  if (self->priv->local_forced_candidate)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->local_forced_candidate[c])
-        fs_candidate_destroy (self->priv->local_forced_candidate[c]);
-    }
-    g_free (self->priv->local_forced_candidate);
-  }
+  g_mutex_free (self->priv->mutex);
 
-  if (self->priv->local_stun_candidate)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->local_stun_candidate[c])
-        fs_candidate_destroy (self->priv->local_stun_candidate[c]);
-    }
-    g_free (self->priv->local_stun_candidate);
-  }
-
-  if (self->priv->local_active_candidate)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-    {
-      if (self->priv->local_active_candidate[c])
-        fs_candidate_destroy (self->priv->local_active_candidate[c]);
-        self->priv->local_active_candidate[c] = NULL;
-    }
-    g_free (self->priv->local_active_candidate);
-  }
-
-  g_mutex_free (self->priv->sources_mutex);
-
-  g_free (self->priv->stun_recv_id);
-  g_free (self->priv->stun_timeout_id);
+  g_free (self->priv->candidates_prepared);
 
   parent_class->finalize (object);
 }
@@ -481,7 +372,7 @@ fs_rawudp_stream_transmitter_set_property (GObject *object,
 
         for (c = 1; c <= self->priv->transmitter->components; c++)
           if (self->priv->component[c])
-            g_object_set_property (self->priv->component[c],
+            g_object_set_property (G_OBJECT (self->priv->component[c]),
                 "sending", value);
       }
       break;
@@ -518,19 +409,7 @@ fs_rawudp_stream_transmitter_build (FsRawUdpStreamTransmitter *self,
 
   self->priv->component = g_new0 (FsRawUdpComponent *,
       self->priv->transmitter->components + 1);
-  self->priv->udpports = g_new0 (UdpPort *,
-      self->priv->transmitter->components + 1);
-  self->priv->remote_candidate = g_new0 (FsCandidate *,
-      self->priv->transmitter->components + 1);
-  self->priv->local_forced_candidate = g_new0 (FsCandidate *,
-      self->priv->transmitter->components + 1);
-  self->priv->local_stun_candidate = g_new0 (FsCandidate *,
-      self->priv->transmitter->components + 1);
-  self->priv->local_active_candidate = g_new0 (FsCandidate *,
-      self->priv->transmitter->components + 1);
-  self->priv->stun_recv_id = g_new0 (gulong,
-      self->priv->transmitter->components + 1);
-  self->priv->stun_timeout_id = g_new0 (guint,
+  self->priv->candidates_prepared = g_new0 (gboolean,
       self->priv->transmitter->components + 1);
 
   for (item = g_list_first (self->priv->preferred_local_candidates);
@@ -589,18 +468,30 @@ fs_rawudp_stream_transmitter_build (FsRawUdpStreamTransmitter *self,
   for (c = 1; c <= self->priv->transmitter->components; c++)
   {
     gint requested_port = ports[c];
-    gint used_port;
+    guint used_port;
 
     if (!requested_port)
       requested_port = next_port;
 
-    self->priv->udpports[c] =
-      fs_rawudp_transmitter_get_udpport (self->priv->transmitter, c, ips[c],
-          requested_port, error);
-    if (!self->priv->udpports[c])
+
+    self->priv->component[c] = fs_rawudp_component_new (c,
+        self->priv->transmitter,
+        ips[c],
+        requested_port,
+        self->priv->stun_ip,
+        self->priv->stun_port,
+        self->priv->stun_timeout,
+        &used_port,
+        error);
+    if (self->priv->component[c] == NULL)
       goto error;
 
-    used_port = fs_rawudp_transmitter_udpport_get_port (self->priv->udpports[c]);
+    g_signal_connect (self->priv->component[c], "new-local-candidate",
+        G_CALLBACK (_component_new_local_candidate), self);
+    g_signal_connect (self->priv->component[c], "local-candidates-prepared",
+        G_CALLBACK (_component_local_candidates_prepared), self);
+    g_signal_connect (self->priv->component[c], "new-active-candidate-pair",
+        G_CALLBACK (_component_new_active_candidate_pair), self);
 
     /* If we dont get the requested port and it wasnt a forced port,
      * then we rewind up to the last forced port and jump to the next
@@ -610,15 +501,8 @@ fs_rawudp_stream_transmitter_build (FsRawUdpStreamTransmitter *self,
     if (used_port != requested_port  &&  !ports[c])
     {
       do {
-        fs_rawudp_transmitter_put_udpport (self->priv->transmitter,
-            self->priv->udpports[c]);
-        self->priv->udpports[c] = NULL;
-
-        if (self->priv->local_forced_candidate[c])
-        {
-          fs_candidate_destroy (self->priv->local_forced_candidate[c]);
-          self->priv->local_forced_candidate[c] = NULL;
-        }
+        g_object_unref (self->priv->component[c]);
+        self->priv->component[c] = NULL;
 
         c--;
       } while (!ports[c]);  /* Will always stop because ports[1] != 0 */
@@ -628,42 +512,15 @@ fs_rawudp_stream_transmitter_build (FsRawUdpStreamTransmitter *self,
     }
 
     if (ips[c])
-      self->priv->local_forced_candidate[c] =
+    {
+      FsCandidate *forced =
         fs_rawudp_stream_transmitter_build_forced_candidate (self, ips[c],
             used_port, c);
-
-    next_port = used_port+1;
-  }
-
-  for (c = 1; c <= self->priv->transmitter->components; c++)
-    if (self->priv->udpports[c])
-    {
-      self->priv->component[c] = fs_rawudp_component_new (c,
-          self->priv->transmitter,
-          self->priv->stun_ip,
-          self->priv->stun_port,
-          self->priv->stun_timeout,
-          self->priv->udpports[c],
-          error);
-      if (self->priv->component[c] == NULL)
-        goto error;
+      g_object_set (self->priv->component[c], "forced-candidate", forced, NULL);
+      fs_candidate_destroy (forced);
     }
 
-  if (self->priv->stun_ip && self->priv->stun_port)
-  {
-    for (c = 1; c <= self->priv->transmitter->components; c++)
-      if (!fs_rawudp_stream_transmitter_start_stun (self, c, error))
-        goto error;
-  }
-  else
-  {
-    guint id;
-    id = g_idle_add (fs_rawudp_stream_transmitter_no_stun, self);
-    g_assert (id);
-    g_mutex_lock (self->priv->sources_mutex);
-    self->priv->sources = g_list_prepend (self->priv->sources,
-        GUINT_TO_POINTER(id));
-    g_mutex_unlock (self->priv->sources_mutex);
+    next_port = used_port+1;
   }
 
   g_free (ips);
@@ -733,15 +590,6 @@ fs_rawudp_stream_transmitter_add_remote_candidate (
           candidate, error))
     return FALSE;
 
-  if (self->priv->remote_candidate[candidate->component_id])
-    fs_candidate_destroy (
-        self->priv->remote_candidate[candidate->component_id]);
-  self->priv->remote_candidate[candidate->component_id] =
-    fs_candidate_copy (candidate);
-
-  fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (self,
-      candidate->component_id);
-
   return TRUE;
 }
 
@@ -779,315 +627,6 @@ struct CandidateTransit {
   guint component_id;
 };
 
-static gboolean
-fs_rawudp_stream_transmitter_emit_stun_candidate (gpointer user_data)
-{
-  struct CandidateTransit *data = user_data;
-  gboolean all_active = TRUE;
-  gint c;
-  GSource *source;
-
-  data->self->priv->local_stun_candidate[data->component_id] =
-    data->candidate;
-  data->self->priv->local_active_candidate[data->component_id] =
-    fs_candidate_copy (data->candidate);
-
-  g_signal_emit_by_name (data->self, "new-local-candidate", data->candidate);
-
-  for (c = 1; c <= data->self->priv->transmitter->components; c++)
-  {
-    if (!data->self->priv->local_active_candidate[c])
-    {
-      all_active = FALSE;
-      break;
-    }
-  }
-
-  if (all_active)
-    g_signal_emit_by_name (data->self, "local-candidates-prepared");
-
-
-  /* Lets remove this source from the list of sources to destroy */
-  source = g_main_current_source ();
-
-  if (source)
-  {
-    guint id = g_source_get_id (source);
-
-    g_mutex_lock (data->self->priv->sources_mutex);
-    data->self->priv->sources =
-      g_list_remove (data->self->priv->sources, GUINT_TO_POINTER (id));
-    g_mutex_unlock (data->self->priv->sources_mutex);
-  }
-
-  fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (data->self,
-      data->component_id);
-
-  g_free (data);
-
-  /* We only pass one candidate at a time */
-  return FALSE;
-}
-
-/*
- * We have to be extremely careful in this callback, it is executed
- * on the streaming thread, so all data must either be object-constant
- * (ie doesnt change for the life of the object) or locked by a mutex
- *
- */
-
-static gboolean
-fs_rawudp_stream_transmitter_stun_recv_cb (GstPad *pad, GstBuffer *buffer,
-    gpointer user_data)
-{
-  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (user_data);
-  gint component_id = -1;
-  FsCandidate *candidate = NULL;
-  StunMessage *msg;
-  StunAttribute **attr;
-  gint c;
-
-
-  if (GST_BUFFER_SIZE (buffer) < 4)
-    /* Packet is too small to be STUN */
-    return TRUE;
-
-  if (GST_BUFFER_DATA (buffer)[0] >> 6)
-    /* Non stun packet */
-    return TRUE;
-
-  for (c = 1; c <= self->priv->transmitter->components; c++)
-  {
-    if (fs_rawudp_transmitter_udpport_is_pad (self->priv->udpports[c], pad))
-    {
-      component_id = c;
-      break;
-    }
-  }
-
-  if (component_id < 0)
-  {
-    g_error ("We've been called from a pad we shouldn't be listening to");
-    return FALSE;
-  }
-
-  msg = stun_message_unpack (GST_BUFFER_SIZE (buffer),
-      (const gchar *) GST_BUFFER_DATA (buffer));
-  if (!msg)
-    /* invalid message */
-    return TRUE;
-
-  if (memcmp (msg->transaction_id, self->priv->stun_cookie, 16) != 0)
-  {
-    /* not ours */
-    stun_message_free (msg);
-    return TRUE;
-  }
-
-  if (msg->type == STUN_MESSAGE_BINDING_ERROR_RESPONSE)
-  {
-    fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
-        FS_ERROR_NETWORK, "Got an error message from the STUN server",
-        "The STUN process produced an error");
-    stun_message_free (msg);
-    // fs_rawudp_stream_transmitter_stop_stun (self, component_id);
-    /* Lets not stop the STUN now and wait for the timeout
-     * in case the server answers with the right reply
-     */
-    return FALSE;
-  }
-
-  if (msg->type != STUN_MESSAGE_BINDING_RESPONSE)
-  {
-    stun_message_free (msg);
-    return TRUE;
-  }
-
-
-  for (attr = msg->attributes; *attr; attr++)
-  {
-    if ((*attr)->type == STUN_ATTRIBUTE_MAPPED_ADDRESS)
-    {
-
-      candidate = g_new0 (FsCandidate,1);
-      candidate->candidate_id = g_strdup_printf ("L%u",
-          self->priv->next_candidate_id);
-      candidate->component_id = component_id;
-      candidate->ip = g_strdup_printf ("%u.%u.%u.%u",
-          ((*attr)->address.ip & 0xff000000) >> 24,
-          ((*attr)->address.ip & 0x00ff0000) >> 16,
-          ((*attr)->address.ip & 0x0000ff00) >>  8,
-          ((*attr)->address.ip & 0x000000ff));
-      candidate->port = (*attr)->address.port;
-      candidate->proto = FS_NETWORK_PROTOCOL_UDP;
-      candidate->type = FS_CANDIDATE_TYPE_SRFLX;
-
-      GST_DEBUG ("Stun server says we are %u.%u.%u.%u %u\n",
-          ((*attr)->address.ip & 0xff000000) >> 24,
-          ((*attr)->address.ip & 0x00ff0000) >> 16,
-          ((*attr)->address.ip & 0x0000ff00) >>  8,
-          ((*attr)->address.ip & 0x000000ff),(*attr)->address.port);
-      break;
-    }
-  }
-
-  g_mutex_lock (self->priv->sources_mutex);
-  fs_rawudp_stream_transmitter_stop_stun (self, component_id);
-  g_mutex_unlock (self->priv->sources_mutex);
-
-  if (candidate)
-  {
-    guint id;
-    struct CandidateTransit *data = g_new0 (struct CandidateTransit, 1);
-    data->self = self;
-    data->candidate = candidate;
-    data->component_id = component_id;
-    id = g_idle_add (fs_rawudp_stream_transmitter_emit_stun_candidate, data);
-    g_assert (id);
-    g_mutex_lock (self->priv->sources_mutex);
-    self->priv->sources = g_list_prepend (self->priv->sources,
-        GUINT_TO_POINTER(id));
-    g_mutex_unlock (self->priv->sources_mutex);
-  }
-
-  /* It was a stun packet, lets drop it */
-  stun_message_free (msg);
-  return FALSE;
-}
-
-static gboolean
-fs_rawudp_stream_transmitter_stun_timeout_cb (gpointer user_data)
-{
-  struct CandidateTransit *data = user_data;
-  gint c;
-  gboolean all_active = TRUE;
-
-  g_mutex_lock (data->self->priv->sources_mutex);
-  fs_rawudp_stream_transmitter_stop_stun (data->self, data->component_id);
-  g_mutex_unlock (data->self->priv->sources_mutex);
-
-  if (!fs_rawudp_stream_transmitter_emit_local_candidates (data->self,
-          data->component_id))
-    return FALSE;
-
-  for (c = 1; c <= data->self->priv->transmitter->components; c++)
-  {
-    if (!data->self->priv->local_active_candidate[c])
-    {
-      all_active = FALSE;
-      break;
-    }
-  }
-
-  if (all_active)
-    g_signal_emit_by_name (data->self, "local-candidates-prepared");
-
-  return FALSE;
-}
-
-static gboolean
-fs_rawudp_stream_transmitter_start_stun (FsRawUdpStreamTransmitter *self,
-    guint component_id, GError **error)
-{
-  struct addrinfo hints;
-  struct addrinfo *result = NULL;
-  struct sockaddr_in address;
-  gchar *packed;
-  guint length;
-  int retval;
-  StunMessage *msg;
-  gboolean ret = TRUE;
-  struct CandidateTransit *data;
-
-  memset (&hints, 0, sizeof (struct addrinfo));
-  hints.ai_family = AF_INET;
-  hints.ai_flags = AI_NUMERICHOST;
-  retval = getaddrinfo (self->priv->stun_ip, NULL, &hints, &result);
-  if (retval != 0)
-  {
-    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
-        "Invalid IP address %s passed for STUN: %s",
-        self->priv->stun_ip, gai_strerror (retval));
-    return FALSE;
-  }
-  memcpy (&address, result->ai_addr, sizeof (struct sockaddr_in));
-  freeaddrinfo (result);
-
-  address.sin_family = AF_INET;
-  address.sin_port = htons (self->priv->stun_port);
-
-  g_mutex_lock (self->priv->sources_mutex);
-  self->priv->stun_recv_id[component_id] =
-    fs_rawudp_transmitter_udpport_connect_recv (
-        self->priv->udpports[component_id],
-        G_CALLBACK (fs_rawudp_stream_transmitter_stun_recv_cb), self);
-  g_mutex_unlock (self->priv->sources_mutex);
-
-  msg = stun_message_new (STUN_MESSAGE_BINDING_REQUEST,
-      self->priv->stun_cookie, 0);
-  if (!msg)
-  {
-    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
-        "Could not create a new STUN binding request");
-    return FALSE;
-  }
-
-  length = stun_message_pack (msg, &packed);
-
-  if (!fs_rawudp_transmitter_udpport_sendto (self->priv->udpports[component_id],
-          packed, length, (const struct sockaddr *)&address, sizeof (address),
-          error))
-    ret = FALSE;
-
-  g_free (packed);
-  stun_message_free (msg);
-
-  data = g_new0 (struct CandidateTransit, 1);
-  data->self = self;
-  data->component_id = component_id;
-
-  g_mutex_lock (data->self->priv->sources_mutex);
-#if 0
-  /* This IS broken in GLib 2.14.6
-   * See http://bugzilla.gnome.org/show_bug.cgi?id=448943
-   */
-  self->priv->stun_timeout_id[component_id] = g_timeout_add_seconds_full (
-      G_PRIORITY_DEFAULT, self->priv->stun_timeout,
-      fs_rawudp_stream_transmitter_stun_timeout_cb, data, g_free);
-#else
-  self->priv->stun_timeout_id[component_id] = g_timeout_add_full (
-      G_PRIORITY_DEFAULT, self->priv->stun_timeout * 1000,
-      fs_rawudp_stream_transmitter_stun_timeout_cb, data, g_free);
-#endif
-  g_assert (self->priv->stun_timeout_id[component_id]);
-  g_mutex_unlock (data->self->priv->sources_mutex);
-
-  return ret;
-}
-
-/*
- * This function MUST be called with the sources_mutex held
- */
-
-static void
-fs_rawudp_stream_transmitter_stop_stun (FsRawUdpStreamTransmitter *self,
-    guint component_id)
-{
-  if (self->priv->stun_recv_id[component_id])
-  {
-    fs_rawudp_transmitter_udpport_disconnect_recv (
-        self->priv->udpports[component_id],
-        self->priv->stun_recv_id[component_id]);
-    self->priv->stun_recv_id[component_id] = 0;
-  }
-
-  if (self->priv->stun_timeout_id[component_id])
-  {
-    g_source_remove (self->priv->stun_timeout_id[component_id]);
-    self->priv->stun_timeout_id[component_id] = 0;
-  }
-}
-
 static FsCandidate *
 fs_rawudp_stream_transmitter_build_forced_candidate (
     FsRawUdpStreamTransmitter *self, const char *ip, gint port,
@@ -1105,135 +644,66 @@ fs_rawudp_stream_transmitter_build_forced_candidate (
   return candidate;
 }
 
+
 static gboolean
-fs_rawudp_stream_transmitter_emit_local_candidates (
-    FsRawUdpStreamTransmitter *self, guint component_id)
+fs_rawudp_stream_transmitter_gather_local_candidates (
+    FsStreamTransmitter *streamtransmitter,
+    GError **error)
 {
-  GList *ips = NULL;
-  GList *current;
-  guint port;
-
-  if (component_id > self->priv->transmitter->components)
-  {
-    gchar *text = g_strdup_printf ("Internal error: invalid component %d",
-        component_id);
-    fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
-        FS_ERROR_INVALID_ARGUMENTS, text, text);
-    g_free (text);
-    return FALSE;
-  }
-
-  if (self->priv->local_forced_candidate[component_id])
-  {
-    self->priv->local_active_candidate[component_id] = fs_candidate_copy (
-        self->priv->local_forced_candidate[component_id]);
-    g_signal_emit_by_name (self, "new-local-candidate",
-        self->priv->local_forced_candidate[component_id]);
-    fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (self,
-        component_id);
-    return TRUE;
-  }
-
-  port = fs_rawudp_transmitter_udpport_get_port (
-      self->priv->udpports[component_id]);
-
-  ips = farsight_get_local_ips (TRUE);
-
-  for (current = g_list_first (ips);
-       current;
-       current = g_list_next (current))
-  {
-    FsCandidate *candidate = g_new0 (FsCandidate, 1);
-
-    candidate->candidate_id = g_strdup_printf ("L%u",
-        self->priv->next_candidate_id++);
-    candidate->component_id = component_id;
-    candidate->ip = g_strdup (current->data);
-    candidate->port = port;
-    candidate->proto = FS_NETWORK_PROTOCOL_UDP;
-    candidate->type = FS_CANDIDATE_TYPE_HOST;
-
-    g_signal_emit_by_name (self, "new-local-candidate", candidate);
-
-    self->priv->local_active_candidate[component_id] = candidate;
-
-    /* FIXME: Emit only the first candidate ?? */
-    break;
-  }
-
-  /* free list of ips */
-  g_list_foreach (ips, (GFunc) g_free, NULL);
-  g_list_free (ips);
-
-  if (!self->priv->local_active_candidate[component_id])
-  {
-    gchar *text = g_strdup_printf (
-        "We have no local candidate for component %d", component_id);
-    fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
-        FS_ERROR_NETWORK, "Could not generate local candidate", text);
-    g_free (text);
-    return FALSE;
-  }
+  FsRawUdpStreamTransmitter *self =
+    FS_RAWUDP_STREAM_TRANSMITTER (streamtransmitter);
+  int c;
 
-  fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (self,
-      component_id);
+  for (c = 1; c <= self->priv->transmitter->components; c++)
+    if (!fs_rawudp_component_gather_local_candidates (self->priv->component[c],
+            error))
+      return FALSE;
 
   return TRUE;
 }
 
-/*
- * This is called when there is no stun
- */
+static void
+_component_new_local_candidate (FsRawUdpComponent *component,
+    FsCandidate *candidate, gpointer user_data)
+{
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (user_data);
 
-static gboolean
-fs_rawudp_stream_transmitter_no_stun (gpointer user_data)
+  g_signal_emit_by_name (self, "new-local-candidate", candidate);
+}
+
+static void
+_component_local_candidates_prepared (FsRawUdpComponent *component,
+    gpointer user_data)
 {
-  FsRawUdpStreamTransmitter *self = user_data;
-  GSource *source;
-  gint c;
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (user_data);
+  guint component_id;
+  guint c;
+  gboolean emit = TRUE;
 
-  /* If we have a STUN'd candidate, dont send the locally generated
-   * ones */
+  g_object_get (component, "component", &component_id, NULL);
+
+  g_mutex_lock (self->priv->mutex);
+  self->priv->candidates_prepared[component_id] = TRUE;
 
   for (c = 1; c <= self->priv->transmitter->components; c++)
   {
-    if (!self->priv->local_active_candidate[c])
+    if (self->priv->candidates_prepared[c] == FALSE)
     {
-      if (!fs_rawudp_stream_transmitter_emit_local_candidates (self, c))
-        return FALSE;
+      emit = FALSE;
+      break;
     }
-    g_assert (self->priv->local_active_candidate[c]);
-  }
-
-  g_signal_emit_by_name (self, "local-candidates-prepared");
-
-  /* Lets remove this source from the list of sources to destroy
-   * For the case when its called from an idle source
-   */
-  source = g_main_current_source ();
-  if (source)
-  {
-    guint id = g_source_get_id (source);
-
-    g_mutex_lock (self->priv->sources_mutex);
-    self->priv->sources = g_list_remove (self->priv->sources,
-        GUINT_TO_POINTER (id));
-    g_mutex_unlock (self->priv->sources_mutex);
   }
+  g_mutex_unlock (self->priv->mutex);
 
-  return FALSE;
+  if (emit)
+    g_signal_emit_by_name (self, "local-candidates-prepared");
 }
 
 static void
-fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (
-    FsRawUdpStreamTransmitter *self, guint component_id)
+_component_new_active_candidate_pair (FsRawUdpComponent *component,
+    FsCandidate *local, FsCandidate *remote, gpointer user_data)
 {
-  if (self->priv->local_active_candidate[component_id] &&
-      self->priv->remote_candidate[component_id])
-  {
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (user_data);
 
-    g_signal_emit_by_name (self, "new-active-candidate-pair",
-        self->priv->local_active_candidate[component_id],
-        self->priv->remote_candidate[component_id]);
-  }
+  g_signal_emit_by_name (self, "new-active-candidate-pair", local, remote);
 }
-- 
1.5.6.5




More information about the farsight-commits mailing list