[farsight2/master] Start multicast transmitter as a copy of the rawudp transmitter

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


---
 configure.ac                                       |    4 +-
 transmitters/multicast/Makefile.am                 |   23 +
 transmitters/multicast/fs-interfaces.c             |    1 +
 transmitters/multicast/fs-interfaces.h             |    1 +
 .../multicast/fs-multicast-stream-transmitter.c    | 1161 ++++++++++++++++++++
 .../multicast/fs-multicast-stream-transmitter.h    |   97 ++
 transmitters/multicast/fs-multicast-transmitter.c  |  854 ++++++++++++++
 transmitters/multicast/fs-multicast-transmitter.h  |  122 ++
 8 files changed, 2262 insertions(+), 1 deletions(-)
 create mode 100644 transmitters/multicast/Makefile.am
 create mode 120000 transmitters/multicast/fs-interfaces.c
 create mode 120000 transmitters/multicast/fs-interfaces.h
 create mode 100644 transmitters/multicast/fs-multicast-stream-transmitter.c
 create mode 100644 transmitters/multicast/fs-multicast-stream-transmitter.h
 create mode 100644 transmitters/multicast/fs-multicast-transmitter.c
 create mode 100644 transmitters/multicast/fs-multicast-transmitter.h

diff --git a/configure.ac b/configure.ac
index 56e2af9..ab75d72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,7 +139,8 @@ dnl *** path for our local plugins ***
 
 dnl these are all the transmitter plug-ins
 FS2_TRANSMITTER_PLUGINS_ALL=" \
-	rawudp
+	rawudp \
+	multicast
 	"
 AC_SUBST(FS2_TRANSMITTER_PLUGINS_ALL)
 
@@ -357,6 +358,7 @@ gst-libs/gst/Makefile
 gst-libs/gst/farsight/Makefile
 transmitters/Makefile
 transmitters/rawudp/Makefile
+transmitters/multicast/Makefile
 dnl pkgconfig/Makefile
 dnl pkgconfig/farsight2.pc
 dnl pkgconfig/farsight2-uninstalled.pc
diff --git a/transmitters/multicast/Makefile.am b/transmitters/multicast/Makefile.am
new file mode 100644
index 0000000..8d6a5da
--- /dev/null
+++ b/transmitters/multicast/Makefile.am
@@ -0,0 +1,23 @@
+
+plugindir = $(FS2_PLUGIN_PATH)
+
+plugin_LTLIBRARIES = libmulticast-transmitter.la
+
+# sources used to compile this lib
+libmulticast_transmitter_la_SOURCES = \
+	fs-multicast-transmitter.c \
+	fs-multicast-stream-transmitter.c \
+	fs-interfaces.c \
+
+# flags used to compile this plugin
+libmulticast_transmitter_la_CFLAGS = $(FS2_INTERNAL_CFLAGS) $(FS2_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libmulticast_transmitter_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libmulticast_transmitter_la_LIBADD = \
+	$(top_builddir)/gst-libs/gst/farsight/libgstfarsight-0.10.la \
+	$(FS2_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
+
+noinst_HEADERS = \
+	fs-multicast-transmitter.h \
+	fs-multicast-stream-transmitter.h \
+	fs-interfaces.h
diff --git a/transmitters/multicast/fs-interfaces.c b/transmitters/multicast/fs-interfaces.c
new file mode 120000
index 0000000..802b11e
--- /dev/null
+++ b/transmitters/multicast/fs-interfaces.c
@@ -0,0 +1 @@
+../rawudp/fs-interfaces.c
\ No newline at end of file
diff --git a/transmitters/multicast/fs-interfaces.h b/transmitters/multicast/fs-interfaces.h
new file mode 120000
index 0000000..c4a09b0
--- /dev/null
+++ b/transmitters/multicast/fs-interfaces.h
@@ -0,0 +1 @@
+../rawudp/fs-interfaces.h
\ No newline at end of file
diff --git a/transmitters/multicast/fs-multicast-stream-transmitter.c b/transmitters/multicast/fs-multicast-stream-transmitter.c
new file mode 100644
index 0000000..8a49526
--- /dev/null
+++ b/transmitters/multicast/fs-multicast-stream-transmitter.c
@@ -0,0 +1,1161 @@
+/*
+ * Farsight2 - Farsight RAW UDP with STUN Transmitter
+ *
+ * Copyright 2007 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-rawudp-transmitter.c - A Farsight UDP transmitter with STUN
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+/**
+ * SECTION:fs-stream-transmitter
+ * @short_description: A stream transmitter object for UDP with STUN
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fs-rawudp-stream-transmitter.h"
+
+#include "stun.h"
+#include "fs-interfaces.h"
+
+#include <gst/farsight/fs-candidate.h>
+#include <gst/farsight/fs-conference-iface.h>
+
+#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>
+
+GST_DEBUG_CATEGORY_EXTERN (fs_rawudp_transmitter_debug);
+#define GST_CAT_DEFAULT fs_rawudp_transmitter_debug
+
+/* Signals */
+enum
+{
+  LAST_SIGNAL
+};
+
+/* props */
+enum
+{
+  PROP_0,
+  PROP_SENDING,
+  PROP_PREFERED_LOCAL_CANDIDATES,
+  PROP_STUN_IP,
+  PROP_STUN_PORT,
+  PROP_STUN_TIMEOUT
+};
+
+struct _FsRawUdpStreamTransmitterPrivate
+{
+  gboolean disposed;
+
+  /* We don't actually hold a ref to this,
+   * But since our parent FsStream can not exist without its parent
+   * FsSession, we should be safe
+   */
+  FsRawUdpTransmitter *transmitter;
+
+  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;
+
+  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 *prefered_local_candidates;
+
+  guint next_candidate_id;
+
+  GMutex *sources_mutex;
+  GList *sources;
+};
+
+#define FS_RAWUDP_STREAM_TRANSMITTER_GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_RAWUDP_STREAM_TRANSMITTER, \
+                                FsRawUdpStreamTransmitterPrivate))
+
+static void fs_rawudp_stream_transmitter_class_init (FsRawUdpStreamTransmitterClass *klass);
+static void fs_rawudp_stream_transmitter_init (FsRawUdpStreamTransmitter *self);
+static void fs_rawudp_stream_transmitter_dispose (GObject *object);
+static void fs_rawudp_stream_transmitter_finalize (GObject *object);
+
+static void fs_rawudp_stream_transmitter_get_property (GObject *object,
+                                                guint prop_id,
+                                                GValue *value,
+                                                GParamSpec *pspec);
+static void fs_rawudp_stream_transmitter_set_property (GObject *object,
+                                                guint prop_id,
+                                                const GValue *value,
+                                                GParamSpec *pspec);
+
+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, 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 (
+    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 GObjectClass *parent_class = NULL;
+// static guint signals[LAST_SIGNAL] = { 0 };
+
+static GType type = 0;
+
+GType
+fs_rawudp_stream_transmitter_get_type (void)
+{
+  return type;
+}
+
+GType
+fs_rawudp_stream_transmitter_register_type (FsPlugin *module)
+{
+  static const GTypeInfo info = {
+    sizeof (FsRawUdpStreamTransmitterClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) fs_rawudp_stream_transmitter_class_init,
+    NULL,
+    NULL,
+    sizeof (FsRawUdpStreamTransmitter),
+    0,
+    (GInstanceInitFunc) fs_rawudp_stream_transmitter_init
+  };
+
+  type = g_type_module_register_type (G_TYPE_MODULE (module),
+    FS_TYPE_STREAM_TRANSMITTER, "FsRawUdpStreamTransmitter", &info, 0);
+
+  return type;
+}
+
+static void
+fs_rawudp_stream_transmitter_class_init (FsRawUdpStreamTransmitterClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  FsStreamTransmitterClass *streamtransmitterclass =
+    FS_STREAM_TRANSMITTER_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = fs_rawudp_stream_transmitter_set_property;
+  gobject_class->get_property = fs_rawudp_stream_transmitter_get_property;
+
+  streamtransmitterclass->add_remote_candidate =
+    fs_rawudp_stream_transmitter_add_remote_candidate;
+
+  g_object_class_override_property (gobject_class, PROP_SENDING, "sending");
+  g_object_class_override_property (gobject_class,
+    PROP_PREFERED_LOCAL_CANDIDATES, "prefered-local-candidates");
+
+  g_object_class_install_property (gobject_class,
+    PROP_STUN_IP,
+    g_param_spec_string ("stun-ip",
+      "The IP address of the STUN server",
+      "The IPv4 address of the STUN server as a x.x.x.x string",
+      NULL,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+    PROP_STUN_PORT,
+    g_param_spec_uint ("stun-port",
+      "The port of the STUN server",
+      "The IPv4 UDP port of the STUN server as a ",
+      1, 65535, 3478,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+    PROP_STUN_TIMEOUT,
+    g_param_spec_uint ("stun-timeout",
+      "The timeout for the STUN reply",
+      "How long to wait for for the STUN reply (in seconds) before giving up",
+      1, G_MAXUINT, 30,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  gobject_class->dispose = fs_rawudp_stream_transmitter_dispose;
+  gobject_class->finalize = fs_rawudp_stream_transmitter_finalize;
+
+  g_type_class_add_private (klass, sizeof (FsRawUdpStreamTransmitterPrivate));
+}
+
+static void
+fs_rawudp_stream_transmitter_init (FsRawUdpStreamTransmitter *self)
+{
+  /* member init */
+  self->priv = FS_RAWUDP_STREAM_TRANSMITTER_GET_PRIVATE (self);
+  self->priv->disposed = FALSE;
+
+  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 ();
+}
+
+static void
+fs_rawudp_stream_transmitter_dispose (GObject *object)
+{
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (object);
+  gint c;
+
+  if (self->priv->disposed) {
+    /* If dispose did already run, return. */
+    return;
+  }
+
+  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;
+
+  parent_class->dispose (object);
+}
+
+static void
+fs_rawudp_stream_transmitter_finalize (GObject *object)
+{
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (object);
+  gint c; /* component_id */
+
+  if (self->priv->stun_ip) {
+    g_free (self->priv->stun_ip);
+    self->priv->stun_ip = NULL;
+  }
+
+  if (self->priv->prefered_local_candidates) {
+    fs_candidate_list_destroy (self->priv->prefered_local_candidates);
+    self->priv->prefered_local_candidates = 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] &&
+          self->priv->sending)
+          fs_rawudp_transmitter_udpport_remove_dest (self->priv->udpports[c],
+            self->priv->remote_candidate[c]->ip,
+            self->priv->remote_candidate[c]->port);
+        fs_candidate_destroy (self->priv->remote_candidate[c]);
+      }
+    }
+
+    g_free (self->priv->remote_candidate);
+    self->priv->remote_candidate = NULL;
+  }
+
+  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]);
+        self->priv->udpports[c] = NULL;
+      }
+    }
+
+    g_free (self->priv->udpports);
+    self->priv->udpports = NULL;
+  }
+
+  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]);
+        self->priv->local_forced_candidate[c] = NULL;
+      }
+    }
+    g_free (self->priv->local_forced_candidate);
+    self->priv->local_forced_candidate = NULL;
+  }
+
+  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]);
+        self->priv->local_stun_candidate[c] = NULL;
+      }
+    }
+    g_free (self->priv->local_stun_candidate);
+    self->priv->local_stun_candidate = NULL;
+  }
+
+  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);
+    self->priv->local_active_candidate = NULL;
+  }
+
+  if (self->priv->sources_mutex) {
+    g_mutex_free (self->priv->sources_mutex);
+    self->priv->sources_mutex = NULL;
+  }
+
+  if (self->priv->stun_recv_id) {
+    g_free (self->priv->stun_recv_id);
+    self->priv->stun_recv_id = NULL;
+  }
+
+  if (self->priv->stun_timeout_id) {
+    g_free (self->priv->stun_timeout_id);
+    self->priv->stun_timeout_id = NULL;
+  }
+
+  parent_class->finalize (object);
+}
+
+static void
+fs_rawudp_stream_transmitter_get_property (GObject *object,
+                                           guint prop_id,
+                                           GValue *value,
+                                           GParamSpec *pspec)
+{
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (object);
+
+  switch (prop_id) {
+    case PROP_SENDING:
+      g_value_set_boolean (value, self->priv->sending);
+      break;
+    case PROP_PREFERED_LOCAL_CANDIDATES:
+      g_value_set_boxed (value, self->priv->prefered_local_candidates);
+      break;
+    case PROP_STUN_IP:
+      g_value_set_string (value, self->priv->stun_ip);
+      break;
+    case PROP_STUN_PORT:
+      g_value_set_uint (value, self->priv->stun_port);
+      break;
+    case PROP_STUN_TIMEOUT:
+      g_value_set_uint (value, self->priv->stun_timeout);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+fs_rawudp_stream_transmitter_set_property (GObject *object,
+                                           guint prop_id,
+                                           const GValue *value,
+                                           GParamSpec *pspec)
+{
+  FsRawUdpStreamTransmitter *self = FS_RAWUDP_STREAM_TRANSMITTER (object);
+
+  switch (prop_id) {
+    case PROP_SENDING:
+      {
+        gboolean old_sending = self->priv->sending;
+        gint c;
+
+        self->priv->sending = g_value_get_boolean (value);
+
+        if (self->priv->sending != old_sending) {
+          if (self->priv->sending) {
+
+            for (c = 1; c <= self->priv->transmitter->components; c++)
+              if (self->priv->remote_candidate[c])
+                fs_rawudp_transmitter_udpport_add_dest (
+                    self->priv->udpports[c],
+                    self->priv->remote_candidate[c]->ip,
+                    self->priv->remote_candidate[c]->port);
+          } else {
+
+            for (c = 1; c <= self->priv->transmitter->components; c++)
+              if (self->priv->remote_candidate[c])
+                fs_rawudp_transmitter_udpport_remove_dest (
+                    self->priv->udpports[c],
+                    self->priv->remote_candidate[c]->ip,
+                    self->priv->remote_candidate[c]->port);
+          }
+        }
+      }
+      break;
+    case PROP_PREFERED_LOCAL_CANDIDATES:
+      self->priv->prefered_local_candidates = g_value_dup_boxed (value);
+      break;
+    case PROP_STUN_IP:
+      g_free (self->priv->stun_ip);
+      self->priv->stun_ip = g_value_dup_string (value);
+      break;
+    case PROP_STUN_PORT:
+      self->priv->stun_port = g_value_get_uint (value);
+      break;
+    case PROP_STUN_TIMEOUT:
+      self->priv->stun_timeout = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+fs_rawudp_stream_transmitter_build (FsRawUdpStreamTransmitter *self,
+  GError **error)
+{
+  const gchar **ips = g_new0 (const gchar *,
+    self->priv->transmitter->components + 1);
+  guint16 *ports = g_new0 (guint16, self->priv->transmitter->components + 1);
+
+  GList *item;
+  gint c;
+  guint16 next_port;
+
+  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->transmitter->components + 1);
+
+  for (item = g_list_first (self->priv->prefered_local_candidates);
+       item;
+       item = g_list_next (item)) {
+    FsCandidate *candidate = item->data;
+
+    if (candidate->proto != FS_NETWORK_PROTOCOL_UDP) {
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+        "You set prefered candidate of a type %d that is not"
+        " FS_NETWORK_PROTOCOL_UDP",
+        candidate->proto);
+      goto error;
+    }
+
+    if (candidate->component_id == 0) {
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+        "Component id 0 is invalid");
+      goto error;
+    }
+
+    if (candidate->component_id > self->priv->transmitter->components) {
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+        "You specified an invalid component id %d with is higher"
+        " than the maximum %d", candidate->component_id,
+        self->priv->transmitter->components);
+      goto error;
+    }
+
+    if (ips[candidate->component_id] || ports[candidate->component_id]) {
+      g_set_error (error, FS_ERROR,
+        FS_ERROR_INVALID_ARGUMENTS,
+        "You set more than one prefered local candidate for component %u",
+        candidate->component_id);
+      goto error;
+    }
+
+    /*
+     * We should verify that the IP is valid now!!
+     *
+     */
+
+    ips[candidate->component_id] = candidate->ip;
+    if (candidate->port)
+      ports[candidate->component_id] = candidate->port;
+  }
+
+  /* Lets make sure we start from a reasonnable value */
+  if (ports[1] == 0)
+    ports[1] = 7078;
+
+  next_port = ports[1];
+
+  for (c = 1; c <= self->priv->transmitter->components; c++) {
+    gint requested_port = ports[c];
+    gint 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])
+      goto error;
+
+    used_port = fs_rawudp_transmitter_udpport_get_port (self->priv->udpports[c]);
+
+    /* 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
+     * package of components, all non-forced ports must be consecutive!
+     */
+
+    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;
+        }
+
+        c--;
+      } while (!ports[c]);  /* Will always stop because ports[1] != 0 */
+      ports[c] += self->priv->transmitter->components;
+      next_port = ports[c];
+      continue;
+    }
+
+    if (ips[c])
+      self->priv->local_forced_candidate[c] =
+        fs_rawudp_stream_transmitter_build_forced_candidate (self, ips[c],
+          used_port, c);
+
+    next_port = used_port+1;
+  }
+
+  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);
+  }
+
+  g_free (ips);
+  g_free (ports);
+
+  return TRUE;
+
+ error:
+  g_free (ips);
+  g_free (ports);
+
+  return FALSE;
+}
+
+/**
+ * fs_rawudp_stream_transmitter_add_remote_candidate
+ * @streamtransmitter: a #FsStreamTransmitter
+ * @candidate: a remote #FsCandidate to add
+ * @error: location of a #GError, or NULL if no error occured
+ *
+ * This function is used to add remote candidates to the transmitter
+ *
+ * Returns: TRUE of the candidate could be added, FALSE if it couldnt
+ *   (and the #GError will be set)
+ */
+
+static gboolean
+fs_rawudp_stream_transmitter_add_remote_candidate (
+    FsStreamTransmitter *streamtransmitter, FsCandidate *candidate,
+    GError **error)
+{
+  FsRawUdpStreamTransmitter *self =
+    FS_RAWUDP_STREAM_TRANSMITTER (streamtransmitter);
+
+  if (candidate->proto != FS_NETWORK_PROTOCOL_UDP) {
+    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+      "You set a candidate of a type %d that is not  FS_NETWORK_PROTOCOL_UDP",
+      candidate->proto);
+    return FALSE;
+  }
+
+  if (!candidate->ip || !candidate->port) {
+    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+      "The candidate passed does not contain a valid ip or port");
+    return FALSE;
+  }
+
+  if (candidate->component_id == 0 ||
+    candidate->component_id > self->priv->transmitter->components) {
+    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+      "The candidate passed has has an invalid component id %u (not in [0,%u])",
+      candidate->component_id, self->priv->transmitter->components);
+    return FALSE;
+  }
+
+  /*
+   * IMPROVE ME: We should probably check that the candidate's IP
+   *  has the format x.x.x.x where x is [0,255] using GRegex, etc
+   */
+  if (self->priv->sending) {
+    fs_rawudp_transmitter_udpport_add_dest (
+        self->priv->udpports[candidate->component_id],
+        candidate->ip, candidate->port);
+  }
+  if (self->priv->remote_candidate[candidate->component_id]) {
+    fs_rawudp_transmitter_udpport_remove_dest (
+        self->priv->udpports[candidate->component_id],
+        self->priv->remote_candidate[candidate->component_id]->ip,
+        self->priv->remote_candidate[candidate->component_id]->port);
+    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;
+}
+
+
+FsRawUdpStreamTransmitter *
+fs_rawudp_stream_transmitter_newv (FsRawUdpTransmitter *transmitter,
+  guint n_parameters, GParameter *parameters, GError **error)
+{
+  FsRawUdpStreamTransmitter *streamtransmitter = NULL;
+
+  streamtransmitter = g_object_newv (FS_TYPE_RAWUDP_STREAM_TRANSMITTER,
+    n_parameters, parameters);
+
+  if (!streamtransmitter) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not build the stream transmitter");
+    return NULL;
+  }
+
+  streamtransmitter->priv->transmitter = transmitter;
+
+  if (!fs_rawudp_stream_transmitter_build (streamtransmitter, error)) {
+    g_object_unref (streamtransmitter);
+    return NULL;
+  }
+
+  return streamtransmitter;
+}
+
+struct CandidateTransit {
+  FsRawUdpStreamTransmitter *self;
+  FsCandidate *candidate;
+  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 1
+  /* This is MAY broken in GLib 2.14 (gnome bug #448943) */
+  /* If the test does not stop (and times out), this may be the cause
+   * and in this case should be investigated further
+   */
+  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,
+    guint component_id)
+{
+  FsCandidate *candidate = g_new0 (FsCandidate, 1);
+
+  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 (ip);
+  candidate->port = port;
+  candidate->proto = FS_NETWORK_PROTOCOL_UDP;
+  candidate->type = FS_CANDIDATE_TYPE_HOST;
+
+  return candidate;
+}
+
+static gboolean
+fs_rawudp_stream_transmitter_emit_local_candidates (
+    FsRawUdpStreamTransmitter *self, guint component_id)
+{
+  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;
+  }
+
+  fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (self,
+    component_id);
+
+  return TRUE;
+}
+
+/*
+ * This is called when there is no stun
+ */
+
+static gboolean
+fs_rawudp_stream_transmitter_no_stun (gpointer user_data)
+{
+  FsRawUdpStreamTransmitter *self = user_data;
+  GSource *source;
+  gint c;
+
+  /* If we have a STUN'd candidate, dont send the locally generated
+   * ones */
+
+  for (c = 1; c <= self->priv->transmitter->components; c++) {
+    if (!self->priv->local_active_candidate[c]) {
+      if (!fs_rawudp_stream_transmitter_emit_local_candidates (self, c))
+        return FALSE;
+    }
+    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);
+  }
+
+  return FALSE;
+}
+
+static void
+fs_rawudp_stream_transmitter_maybe_new_active_candidate_pair (
+    FsRawUdpStreamTransmitter *self, guint component_id)
+{
+  if (self->priv->local_active_candidate[component_id] &&
+    self->priv->remote_candidate[component_id]) {
+
+    g_signal_emit_by_name (self, "new-active-candidate-pair",
+      self->priv->local_active_candidate[component_id],
+      self->priv->remote_candidate[component_id]);
+  }
+}
diff --git a/transmitters/multicast/fs-multicast-stream-transmitter.h b/transmitters/multicast/fs-multicast-stream-transmitter.h
new file mode 100644
index 0000000..ad49d4e
--- /dev/null
+++ b/transmitters/multicast/fs-multicast-stream-transmitter.h
@@ -0,0 +1,97 @@
+/*
+ * Farsight2 - Farsight RAW UDP with STUN Stream Transmitter
+ *
+ * Copyright 2007 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-stream-transmitter.h - A Farsight UDP stream transmitter with STUN
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FS_RAWUDP_STREAM_TRANSMITTER_H__
+#define __FS_RAWUDP_STREAM_TRANSMITTER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gst/farsight/fs-stream-transmitter.h>
+#include <gst/farsight/fs-plugin.h>
+#include "fs-rawudp-transmitter.h"
+
+G_BEGIN_DECLS
+
+/* TYPE MACROS */
+#define FS_TYPE_RAWUDP_STREAM_TRANSMITTER \
+  (fs_rawudp_stream_transmitter_get_type())
+#define FS_RAWUDP_STREAM_TRANSMITTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_RAWUDP_STREAM_TRANSMITTER, \
+                              FsRawUdpStreamTransmitter))
+#define FS_RAWUDP_STREAM_TRANSMITTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_RAWUDP_STREAM_TRANSMITTER, \
+                           FsRawUdpStreamTransmitterClass))
+#define FS_IS_RAWUDP_STREAM_TRANSMITTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_RAWUDP_STREAM_TRANSMITTER))
+#define FS_IS_RAWUDP_STREAM_TRANSMITTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_RAWUDP_STREAM_TRANSMITTER))
+#define FS_RAWUDP_STREAM_TRANSMITTER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_RAWUDP_STREAM_TRANSMITTER, \
+                              FsRawUdpStreamTransmitterClass))
+#define FS_RAWUDP_STREAM_TRANSMITTER_CAST(obj) ((FsRawUdpStreamTransmitter *) (obj))
+
+typedef struct _FsRawUdpStreamTransmitter FsRawUdpStreamTransmitter;
+typedef struct _FsRawUdpStreamTransmitterClass FsRawUdpStreamTransmitterClass;
+typedef struct _FsRawUdpStreamTransmitterPrivate FsRawUdpStreamTransmitterPrivate;
+
+/**
+ * FsRawUdpStreamTransmitterClass:
+ * @parent_class: Our parent
+ *
+ * The Raw UDP stream transmitter class
+ */
+
+struct _FsRawUdpStreamTransmitterClass
+{
+  FsStreamTransmitterClass parent_class;
+
+  /*virtual functions */
+  /*< private >*/
+};
+
+/**
+ * FsRawUdpStreamTransmitter:
+ *
+ * All members are private, access them using methods and properties
+ */
+struct _FsRawUdpStreamTransmitter
+{
+  FsStreamTransmitter parent;
+
+  /*< private >*/
+  FsRawUdpStreamTransmitterPrivate *priv;
+};
+
+GType fs_rawudp_stream_transmitter_register_type (FsPlugin *module);
+
+GType fs_rawudp_stream_transmitter_get_type (void);
+
+FsRawUdpStreamTransmitter *
+fs_rawudp_stream_transmitter_newv (FsRawUdpTransmitter *transmitter,
+  guint n_parameters, GParameter *parameters, GError **error);
+
+G_END_DECLS
+
+#endif /* __FS_RAWUDP_STREAM_TRANSMITTER_H__ */
diff --git a/transmitters/multicast/fs-multicast-transmitter.c b/transmitters/multicast/fs-multicast-transmitter.c
new file mode 100644
index 0000000..13c27e2
--- /dev/null
+++ b/transmitters/multicast/fs-multicast-transmitter.c
@@ -0,0 +1,854 @@
+/*
+ * Farsight2 - Farsight RAW UDP with STUN Transmitter
+ *
+ * Copyright 2007 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-rawudp-transmitter.h - A Farsight UDP transmitter with STUN
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/**
+ * SECTION:fs-rawudp-transmitter
+ * @short_description: A transmitter for raw udp (with STUN)
+ *
+ * This transmitter provides RAW udp (with stun)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fs-rawudp-transmitter.h"
+#include "fs-rawudp-stream-transmitter.h"
+
+#include <gst/farsight/fs-conference-iface.h>
+#include <gst/farsight/fs-plugin.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>
+
+GST_DEBUG_CATEGORY (fs_rawudp_transmitter_debug);
+#define GST_CAT_DEFAULT fs_rawudp_transmitter_debug
+
+/* Signals */
+enum
+{
+  LAST_SIGNAL
+};
+
+/* props */
+enum
+{
+  PROP_0,
+  PROP_GST_SINK,
+  PROP_GST_SRC,
+  PROP_COMPONENTS
+};
+
+struct _FsRawUdpTransmitterPrivate
+{
+  /* We hold references to this element */
+  GstElement *gst_sink;
+  GstElement *gst_src;
+
+  /* We don't hold a reference to these elements, they are owned
+     by the bins */
+  /* They are tables of pointers, one per component */
+  GstElement **udpsrc_funnels;
+  GstElement **udpsink_tees;
+
+  GList **udpports;
+
+  gboolean disposed;
+};
+
+#define FS_RAWUDP_TRANSMITTER_GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_RAWUDP_TRANSMITTER, \
+    FsRawUdpTransmitterPrivate))
+
+static void fs_rawudp_transmitter_class_init (FsRawUdpTransmitterClass *klass);
+static void fs_rawudp_transmitter_init (FsRawUdpTransmitter *self);
+static void fs_rawudp_transmitter_constructed (GObject *object);
+static void fs_rawudp_transmitter_dispose (GObject *object);
+static void fs_rawudp_transmitter_finalize (GObject *object);
+
+static void fs_rawudp_transmitter_get_property (GObject *object,
+                                                guint prop_id,
+                                                GValue *value,
+                                                GParamSpec *pspec);
+static void fs_rawudp_transmitter_set_property (GObject *object,
+                                                guint prop_id,
+                                                const GValue *value,
+                                                GParamSpec *pspec);
+
+static FsStreamTransmitter *fs_rawudp_transmitter_new_stream_transmitter (
+    FsTransmitter *transmitter, FsParticipant *participant,
+    guint n_parameters, GParameter *parameters, GError **error);
+static GType fs_rawudp_transmitter_get_stream_transmitter_type (
+    FsTransmitter *transmitter,
+    GError **error);
+
+
+static GObjectClass *parent_class = NULL;
+//static guint signals[LAST_SIGNAL] = { 0 };
+
+
+/*
+ * Lets register the plugin
+ */
+
+static GType type = 0;
+
+GType
+fs_rawudp_transmitter_get_type (void)
+{
+  g_assert (type);
+  return type;
+}
+
+static GType
+fs_rawudp_transmitter_register_type (FsPlugin *module)
+{
+  static const GTypeInfo info = {
+    sizeof (FsRawUdpTransmitterClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) fs_rawudp_transmitter_class_init,
+    NULL,
+    NULL,
+    sizeof (FsRawUdpTransmitter),
+    0,
+    (GInstanceInitFunc) fs_rawudp_transmitter_init
+  };
+
+  if (fs_rawudp_transmitter_debug == NULL)
+    GST_DEBUG_CATEGORY_INIT (fs_rawudp_transmitter_debug,
+        "fsrawudptransmitter", 0,
+        "Farsight raw UDP transmitter");
+
+  fs_rawudp_stream_transmitter_register_type (module);
+
+  type = g_type_module_register_type (G_TYPE_MODULE (module),
+    FS_TYPE_TRANSMITTER, "FsRawUdpTransmitter", &info, 0);
+
+  return type;
+}
+
+static void
+fs_rawudp_transmitter_unload (FsPlugin *plugin)
+{
+  if (fs_rawudp_transmitter_debug)
+  {
+    gst_debug_category_free (fs_rawudp_transmitter_debug);
+    fs_rawudp_transmitter_debug = NULL;
+  }
+}
+
+FS_INIT_PLUGIN (fs_rawudp_transmitter_register_type,
+    fs_rawudp_transmitter_unload)
+
+static void
+fs_rawudp_transmitter_class_init (FsRawUdpTransmitterClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  FsTransmitterClass *transmitter_class = FS_TRANSMITTER_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = fs_rawudp_transmitter_set_property;
+  gobject_class->get_property = fs_rawudp_transmitter_get_property;
+
+  gobject_class->constructed = fs_rawudp_transmitter_constructed;
+
+  g_object_class_override_property (gobject_class, PROP_GST_SRC, "gst-src");
+  g_object_class_override_property (gobject_class, PROP_GST_SINK, "gst-sink");
+  g_object_class_override_property (gobject_class, PROP_COMPONENTS,
+    "components");
+
+  transmitter_class->new_stream_transmitter =
+    fs_rawudp_transmitter_new_stream_transmitter;
+  transmitter_class->get_stream_transmitter_type =
+    fs_rawudp_transmitter_get_stream_transmitter_type;
+
+  gobject_class->dispose = fs_rawudp_transmitter_dispose;
+  gobject_class->finalize = fs_rawudp_transmitter_finalize;
+
+  g_type_class_add_private (klass, sizeof (FsRawUdpTransmitterPrivate));
+}
+
+static void
+fs_rawudp_transmitter_init (FsRawUdpTransmitter *self)
+{
+
+  /* member init */
+  self->priv = FS_RAWUDP_TRANSMITTER_GET_PRIVATE (self);
+  self->priv->disposed = FALSE;
+
+  self->components = 2;
+}
+
+static void
+fs_rawudp_transmitter_constructed (GObject *object)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER_CAST (object);
+  FsTransmitter *trans = FS_TRANSMITTER_CAST (self);
+  GstPad *pad = NULL, *pad2 = NULL;
+  GstPad *ghostpad = NULL;
+  gchar *padname;
+  GstPadLinkReturn ret;
+  int c; /* component_id */
+
+
+  /* We waste one space in order to have the index be the component_id */
+  self->priv->udpsrc_funnels = g_new0 (GstElement *, self->components+1);
+  self->priv->udpsink_tees = g_new0 (GstElement *, self->components+1);
+  self->priv->udpports = g_new0 (GList *, self->components+1);
+
+  /* First we need the src elemnet */
+
+  self->priv->gst_src = gst_bin_new (NULL);
+
+  if (!self->priv->gst_src) {
+    trans->construction_error = g_error_new (FS_ERROR,
+      FS_ERROR_CONSTRUCTION,
+      "Could not build the transmitter src bin");
+    return;
+  }
+
+  gst_object_ref (self->priv->gst_src);
+
+
+  /* Second, we do the sink element */
+
+  self->priv->gst_sink = gst_bin_new (NULL);
+
+  if (!self->priv->gst_sink) {
+    trans->construction_error = g_error_new (FS_ERROR,
+      FS_ERROR_CONSTRUCTION,
+      "Could not build the transmitter sink bin");
+    return;
+  }
+
+  gst_object_ref (self->priv->gst_sink);
+
+  for (c = 1; c <= self->components; c++) {
+    GstElement *fakesink = NULL;
+
+    /* Lets create the RTP source funnel */
+
+    self->priv->udpsrc_funnels[c] = gst_element_factory_make ("fsfunnel", NULL);
+
+    if (!self->priv->udpsrc_funnels[c]) {
+      trans->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_CONSTRUCTION,
+        "Could not make the fsfunnel element");
+      return;
+    }
+
+    if (!gst_bin_add (GST_BIN (self->priv->gst_src),
+        self->priv->udpsrc_funnels[c])) {
+      trans->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_CONSTRUCTION,
+        "Could not add the fsfunnel element to the transmitter src bin");
+    }
+
+    pad = gst_element_get_static_pad (self->priv->udpsrc_funnels[c], "src");
+    padname = g_strdup_printf ("src%d", c);
+    ghostpad = gst_ghost_pad_new (padname, pad);
+    g_free (padname);
+    gst_object_unref (pad);
+
+    gst_pad_set_active (ghostpad, TRUE);
+    gst_element_add_pad (self->priv->gst_src, ghostpad);
+
+
+    /* Lets create the RTP sink tee */
+
+    self->priv->udpsink_tees[c] = gst_element_factory_make ("tee", NULL);
+
+    if (!self->priv->udpsink_tees[c]) {
+      trans->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_CONSTRUCTION,
+        "Could not make the tee element");
+      return;
+    }
+
+    if (!gst_bin_add (GST_BIN (self->priv->gst_sink),
+        self->priv->udpsink_tees[c])) {
+      trans->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_CONSTRUCTION,
+        "Could not add the tee element to the transmitter sink bin");
+    }
+
+    pad = gst_element_get_static_pad (self->priv->udpsink_tees[c], "sink");
+    padname = g_strdup_printf ("sink%d", c);
+    ghostpad = gst_ghost_pad_new (padname, pad);
+    g_free (padname);
+    gst_object_unref (pad);
+
+    gst_pad_set_active (ghostpad, TRUE);
+    gst_element_add_pad (self->priv->gst_sink, ghostpad);
+
+    fakesink = gst_element_factory_make ("fakesink", NULL);
+
+    if (!fakesink) {
+      trans->construction_error = g_error_new (FS_ERROR,
+        FS_ERROR_CONSTRUCTION,
+        "Could not make the fakesink element");
+      return;
+    }
+
+    if (!gst_bin_add (GST_BIN (self->priv->gst_sink), fakesink))
+    {
+      gst_object_unref (fakesink);
+      trans->construction_error = g_error_new (FS_ERROR,
+          FS_ERROR_CONSTRUCTION,
+          "Could not add the fakesink element to the transmitter sink bin");
+      return;
+    }
+
+    g_object_set (fakesink,
+        "async", FALSE,
+        "sync" , FALSE,
+        NULL);
+
+    pad = gst_element_get_request_pad (self->priv->udpsink_tees[c], "src%d");
+    pad2 = gst_element_get_static_pad (fakesink, "sink");
+
+    ret = gst_pad_link (pad, pad2);
+
+    gst_object_unref (pad2);
+    gst_object_unref (pad);
+
+    if (GST_PAD_LINK_FAILED(ret)) {
+      trans->construction_error = g_error_new (FS_ERROR,
+          FS_ERROR_CONSTRUCTION,
+          "Could not link the tee to the fakesink");
+      return;
+    }
+  }
+}
+
+static void
+fs_rawudp_transmitter_dispose (GObject *object)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER (object);
+
+  if (self->priv->disposed) {
+    /* If dispose did already run, return. */
+    return;
+  }
+
+  if (self->priv->gst_src) {
+    gst_object_unref (self->priv->gst_src);
+    self->priv->gst_src = NULL;
+  }
+
+  if (self->priv->gst_sink) {
+    gst_object_unref (self->priv->gst_sink);
+    self->priv->gst_sink = NULL;
+  }
+
+  /* Make sure dispose does not run twice. */
+  self->priv->disposed = TRUE;
+
+  parent_class->dispose (object);
+}
+
+static void
+fs_rawudp_transmitter_finalize (GObject *object)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER (object);
+
+  if (self->priv->udpsrc_funnels) {
+    g_free (self->priv->udpsrc_funnels);
+    self->priv->udpsrc_funnels = NULL;
+  }
+
+  if (self->priv->udpsink_tees) {
+    g_free (self->priv->udpsink_tees);
+    self->priv->udpsink_tees = NULL;
+  }
+
+  if (self->priv->udpports) {
+    g_free (self->priv->udpports);
+    self->priv->udpports = NULL;
+  }
+
+  parent_class->finalize (object);
+}
+
+static void
+fs_rawudp_transmitter_get_property (GObject *object,
+                             guint prop_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER (object);
+
+  switch (prop_id) {
+    case PROP_GST_SINK:
+      g_value_set_object (value, self->priv->gst_sink);
+      break;
+    case PROP_GST_SRC:
+      g_value_set_object (value, self->priv->gst_src);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+fs_rawudp_transmitter_set_property (GObject *object,
+                                    guint prop_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER (object);
+
+  switch (prop_id) {
+    case PROP_COMPONENTS:
+      self->components = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+/**
+ * fs_rawudp_transmitter_new_stream_rawudp_transmitter:
+ * @transmitter: a #FsTranmitter
+ * @participant: the #FsParticipant for which the #FsStream using this
+ * new #FsStreamTransmitter is created
+ *
+ * This function will create a new #FsStreamTransmitter element for a
+ * specific participant for this #FsRawUdpTransmitter
+ *
+ * Returns: a new #FsStreamTransmitter
+ */
+
+static FsStreamTransmitter *
+fs_rawudp_transmitter_new_stream_transmitter (FsTransmitter *transmitter,
+  FsParticipant *participant, guint n_parameters, GParameter *parameters,
+  GError **error)
+{
+  FsRawUdpTransmitter *self = FS_RAWUDP_TRANSMITTER (transmitter);
+
+  return FS_STREAM_TRANSMITTER (fs_rawudp_stream_transmitter_newv (
+        self, n_parameters, parameters, error));
+}
+
+
+/*
+ * The UdpPort structure is a ref-counted pseudo-object use to represent
+ * one ip:port combo on which we listen and send, so it includes  a udpsrc
+ * and a multiudpsink
+ */
+
+struct _UdpPort {
+  gint refcount;
+
+  GstElement *udpsrc;
+  GstPad *udpsrc_requested_pad;
+
+  GstElement *udpsink;
+  GstPad *udpsink_requested_pad;
+
+  gchar *requested_ip;
+  guint requested_port;
+
+  guint port;
+
+  gint fd;
+
+  /* These are just convenience pointers to our parent transmitter */
+  GstElement *funnel;
+  GstElement *tee;
+
+  guint component_id;
+};
+
+static gint
+_bind_port (const gchar *ip, guint port, guint *used_port, GError **error)
+{
+  int sock;
+  struct sockaddr_in address;
+  int retval;
+
+  address.sin_family = AF_INET;
+  address.sin_addr.s_addr = INADDR_ANY;
+
+  if (ip) {
+    struct addrinfo hints;
+    struct addrinfo *result = NULL;
+
+    memset (&hints, 0, sizeof (struct addrinfo));
+    hints.ai_family = AF_INET;
+    hints.ai_flags = AI_NUMERICHOST;
+    retval = getaddrinfo (ip, NULL, &hints, &result);
+    if (retval != 0) {
+      g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+        "Invalid IP address %s passed: %s", ip, gai_strerror (retval));
+      return -1;
+    }
+    memcpy (&address, result->ai_addr, sizeof(struct sockaddr_in));
+    freeaddrinfo (result);
+  }
+
+  if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) <= 0) {
+    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+      "Error creating socket: %s", g_strerror (errno));
+    return -1;
+  }
+
+  do {
+    address.sin_port = htons (port);
+    retval = bind (sock, (struct sockaddr *) &address, sizeof (address));
+    if (retval != 0)
+    {
+      GST_INFO ("could not bind port %d", port);
+      port += 2;
+      if (port > 65535) {
+        g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+          "Could not bind the socket to a port");
+        close (sock);
+        return -1;
+      }
+    }
+  } while (retval != 0);
+
+  *used_port = port;
+
+  return sock;
+}
+
+static GstElement *
+_create_sinksource (gchar *elementname, GstBin *bin,
+  GstElement *teefunnel, gint fd, GstPadDirection direction,
+  GstPad **requested_pad, GError **error)
+{
+  GstElement *elem;
+  GstPadLinkReturn ret;
+  GstPad *elempad = NULL;
+  GstStateChangeReturn state_ret;
+
+  g_assert (direction == GST_PAD_SINK || direction == GST_PAD_SRC);
+
+  elem = gst_element_factory_make (elementname, NULL);
+  if (!elem) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not create the %s element", elementname);
+    return NULL;
+  }
+
+  g_object_set (elem,
+    "closefd", FALSE,
+    "sockfd", fd,
+    NULL);
+
+  if (!gst_bin_add (bin, elem)) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not add the %s element to the gst %s bin", elementname,
+      (direction == GST_PAD_SINK) ? "sink" : "src");
+    gst_object_unref (elem);
+    return NULL;
+  }
+
+  if (direction == GST_PAD_SINK)
+    *requested_pad = gst_element_get_request_pad (teefunnel, "src%d");
+  else
+    *requested_pad = gst_element_get_request_pad (teefunnel, "sink%d");
+
+  if (!*requested_pad) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not get the %s request pad from the %s",
+      (direction == GST_PAD_SINK) ? "src" : "sink",
+      (direction == GST_PAD_SINK) ? "tee" : "funnel");
+    goto error;
+  }
+
+  if (direction == GST_PAD_SINK)
+    elempad = gst_element_get_static_pad (elem, "sink");
+  else
+    elempad = gst_element_get_static_pad (elem, "src");
+
+  if (direction == GST_PAD_SINK)
+    ret = gst_pad_link (*requested_pad, elempad);
+  else
+    ret = gst_pad_link (elempad, *requested_pad);
+
+  gst_object_unref (elempad);
+
+  if (GST_PAD_LINK_FAILED(ret)) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not link the new element %s (%d)", elementname, ret);
+    goto error;
+  }
+
+  if (!gst_element_sync_state_with_parent (elem)) {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+      "Could not sync the state of the new %s with its parent",
+      elementname);
+    goto error;
+  }
+
+  return elem;
+
+ error:
+
+  gst_object_ref (elem);
+  gst_element_set_state (elem, GST_STATE_NULL);
+  gst_bin_remove (bin, elem);
+  state_ret = gst_element_set_state (elem, GST_STATE_NULL);
+  if (state_ret != GST_STATE_CHANGE_SUCCESS) {
+    GST_ERROR ("On error, could not reset %s to state NULL (%s)", elementname,
+      gst_element_state_change_return_get_name (state_ret));
+  }
+  gst_object_unref (elem);
+
+  if (elempad)
+    gst_object_unref (elempad);
+
+  return NULL;
+}
+
+
+UdpPort *
+fs_rawudp_transmitter_get_udpport (FsRawUdpTransmitter *trans,
+  guint component_id, const gchar *requested_ip, guint requested_port,
+  GError **error)
+{
+  UdpPort *udpport;
+  GList *udpport_e;
+
+  /* First lets check if we already have one */
+  if (component_id > trans->components) {
+    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+      "Invalid component %d > %d", component_id, trans->components);
+    return NULL;
+  }
+
+  for (udpport_e = g_list_first (trans->priv->udpports[component_id]);
+       udpport_e;
+       udpport_e = g_list_next (udpport_e)) {
+    udpport = udpport_e->data;
+    if (requested_port == udpport->requested_port &&
+        ((requested_ip == NULL && udpport->requested_ip == NULL) ||
+          !strcmp (requested_ip, udpport->requested_ip))) {
+      udpport->refcount++;
+      return udpport;
+    }
+  }
+
+  udpport = g_new0 (UdpPort, 1);
+
+  udpport->refcount = 1;
+  udpport->requested_ip = g_strdup (requested_ip);
+  udpport->requested_port = requested_port;
+  udpport->fd = -1;
+  udpport->component_id = component_id;
+
+  /* Now lets bind both ports */
+
+  udpport->fd = _bind_port (requested_ip, requested_port, &udpport->port,
+    error);
+  if (udpport->fd < 0)
+    goto error;
+
+  /* Now lets create the elements */
+
+  udpport->tee = trans->priv->udpsink_tees[component_id];
+  udpport->funnel = trans->priv->udpsrc_funnels[component_id];
+
+  udpport->udpsrc = _create_sinksource ("udpsrc",
+    GST_BIN (trans->priv->gst_src), udpport->funnel, udpport->fd, GST_PAD_SRC,
+    &udpport->udpsrc_requested_pad, error);
+  if (!udpport->udpsrc)
+    goto error;
+
+  udpport->udpsink = _create_sinksource ("multiudpsink",
+    GST_BIN (trans->priv->gst_sink), udpport->tee, udpport->fd, GST_PAD_SINK,
+    &udpport->udpsink_requested_pad, error);
+  if (!udpport->udpsink)
+    goto error;
+
+  g_object_set (udpport->udpsink, "async", FALSE, NULL);
+
+  trans->priv->udpports[component_id] =
+    g_list_prepend (trans->priv->udpports[component_id], udpport);
+
+  return udpport;
+
+ error:
+  if (udpport)
+    fs_rawudp_transmitter_put_udpport (trans, udpport);
+  return NULL;
+}
+
+void
+fs_rawudp_transmitter_put_udpport (FsRawUdpTransmitter *trans,
+  UdpPort *udpport)
+{
+  if (udpport->refcount > 1) {
+    udpport->refcount--;
+    return;
+  }
+
+  trans->priv->udpports[udpport->component_id] =
+    g_list_remove (trans->priv->udpports[udpport->component_id], udpport);
+
+  if (udpport->udpsrc) {
+    GstStateChangeReturn ret;
+    gst_object_ref (udpport->udpsrc);
+    gst_element_set_state (udpport->udpsrc, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (trans->priv->gst_src), udpport->udpsrc);
+    ret = gst_element_set_state (udpport->udpsrc, GST_STATE_NULL);
+    if (ret != GST_STATE_CHANGE_SUCCESS) {
+      GST_ERROR ("Error changing state of udpsrc: %s",
+        gst_element_state_change_return_get_name (ret));
+    }
+    gst_object_unref (udpport->udpsrc);
+  }
+
+  if (udpport->udpsrc_requested_pad) {
+    gst_element_release_request_pad (udpport->funnel,
+      udpport->udpsrc_requested_pad);
+    gst_object_unref (udpport->udpsrc_requested_pad);
+  }
+
+  if (udpport->udpsink) {
+    GstStateChangeReturn ret;
+    gst_object_ref (udpport->udpsink);
+    gst_element_set_state (udpport->udpsink, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (trans->priv->gst_sink), udpport->udpsink);
+    ret = gst_element_set_state (udpport->udpsink, GST_STATE_NULL);
+    if (ret != GST_STATE_CHANGE_SUCCESS) {
+      GST_ERROR ("Error changing state of udpsink: %s",
+        gst_element_state_change_return_get_name (ret));
+    }
+    gst_object_unref (udpport->udpsink);
+  }
+
+  if (udpport->udpsink_requested_pad) {
+    gst_element_release_request_pad (udpport->tee,
+      udpport->udpsink_requested_pad);
+    gst_object_unref (udpport->udpsink_requested_pad);
+  }
+
+  if (udpport->fd >= 0)
+    close (udpport->fd);
+
+  g_free (udpport->requested_ip);
+  g_free (udpport);
+}
+
+void
+fs_rawudp_transmitter_udpport_add_dest (UdpPort *udpport,
+  const gchar *ip, gint port)
+{
+  GST_DEBUG ("Adding dest %s:%d", ip, port);
+  g_signal_emit_by_name (udpport->udpsink, "add", ip, port);
+}
+
+
+void
+fs_rawudp_transmitter_udpport_remove_dest (UdpPort *udpport,
+  const gchar *ip, gint port)
+{
+  g_signal_emit_by_name (udpport->udpsink, "remove", ip, port);
+}
+
+gboolean
+fs_rawudp_transmitter_udpport_sendto (UdpPort *udpport,
+  gchar *msg, size_t len, const struct sockaddr *to, socklen_t tolen,
+  GError **error)
+{
+  if (sendto (udpport->fd, msg, len, 0, to, tolen) != len) {
+    g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
+      "Could not send STUN request: %s", g_strerror (errno));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+gulong
+fs_rawudp_transmitter_udpport_connect_recv (UdpPort *udpport,
+  GCallback callback, gpointer user_data)
+{
+  GstPad *pad;
+  gulong id;
+
+  pad = gst_element_get_static_pad (udpport->udpsrc, "src");
+
+  id = gst_pad_add_buffer_probe (pad, callback, user_data);
+
+  gst_object_unref (pad);
+
+  return id;
+}
+
+
+void
+fs_rawudp_transmitter_udpport_disconnect_recv (UdpPort *udpport, gulong id)
+{
+  GstPad *pad = gst_element_get_static_pad (udpport->udpsrc, "src");
+
+  gst_pad_remove_buffer_probe (pad, id);
+
+  gst_object_unref (pad);
+}
+
+gboolean
+fs_rawudp_transmitter_udpport_is_pad (UdpPort *udpport, GstPad *pad)
+{
+  GstPad *mypad;
+  gboolean res;
+
+  mypad =  gst_element_get_static_pad (udpport->udpsrc, "src");
+
+  res = (mypad == pad);
+
+  gst_object_unref (mypad);
+
+  return res;
+}
+
+
+gboolean
+fs_rawudp_transmitter_udpport_get_port (UdpPort *udpport)
+{
+  return udpport->port;
+}
+
+
+static GType
+fs_rawudp_transmitter_get_stream_transmitter_type (FsTransmitter *transmitter,
+    GError **error)
+{
+  return FS_TYPE_RAWUDP_STREAM_TRANSMITTER;
+}
diff --git a/transmitters/multicast/fs-multicast-transmitter.h b/transmitters/multicast/fs-multicast-transmitter.h
new file mode 100644
index 0000000..18c9978
--- /dev/null
+++ b/transmitters/multicast/fs-multicast-transmitter.h
@@ -0,0 +1,122 @@
+/*
+ * Farsight2 - Farsight RAW UDP with STUN Transmitter
+ *
+ * Copyright 2007 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-rawudp-transmitter.h - A Farsight UDP transmitter with STUN
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FS_RAWUDP_TRANSMITTER_H__
+#define __FS_RAWUDP_TRANSMITTER_H__
+
+#include <gst/farsight/fs-transmitter.h>
+
+#include <gst/gst.h>
+
+#include <arpa/inet.h>
+
+G_BEGIN_DECLS
+
+/* TYPE MACROS */
+#define FS_TYPE_RAWUDP_TRANSMITTER \
+  (fs_rawudp_transmitter_get_type())
+#define FS_RAWUDP_TRANSMITTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_RAWUDP_TRANSMITTER, \
+    FsRawUdpTransmitter))
+#define FS_RAWUDP_TRANSMITTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_RAWUDP_TRANSMITTER, \
+    FsRawUdpTransmitterClass))
+#define FS_IS_RAWUDP_TRANSMITTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_RAWUDP_TRANSMITTER))
+#define FS_IS_RAWUDP_TRANSMITTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_RAWUDP_TRANSMITTER))
+#define FS_RAWUDP_TRANSMITTER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_RAWUDP_TRANSMITTER, \
+    FsRawUdpTransmitterClass))
+#define FS_RAWUDP_TRANSMITTER_CAST(obj) ((FsRawUdpTransmitter *) (obj))
+
+typedef struct _FsRawUdpTransmitter FsRawUdpTransmitter;
+typedef struct _FsRawUdpTransmitterClass FsRawUdpTransmitterClass;
+typedef struct _FsRawUdpTransmitterPrivate FsRawUdpTransmitterPrivate;
+
+/**
+ * FsRawUdpTransmitterClass:
+ * @parent_class: Our parent
+ *
+ * The Raw UDP transmitter class
+ */
+
+struct _FsRawUdpTransmitterClass
+{
+  FsTransmitterClass parent_class;
+};
+
+/**
+ * FsRawUdpTransmitter:
+ *
+ * All members are private, access them using methods and properties
+ */
+struct _FsRawUdpTransmitter
+{
+  FsTransmitter parent;
+
+  /* The number of components (READONLY)*/
+  gint components;
+
+  /*< private >*/
+  FsRawUdpTransmitterPrivate *priv;
+};
+
+/* Private declaration */
+typedef struct _UdpPort UdpPort;
+
+GType fs_rawudp_transmitter_get_type (void);
+
+
+
+UdpPort *fs_rawudp_transmitter_get_udpport (FsRawUdpTransmitter *trans,
+  guint component_id, const gchar *requested_ip, guint requested_port,
+  GError **error);
+
+void fs_rawudp_transmitter_put_udpport (FsRawUdpTransmitter *trans,
+  UdpPort *udpport);
+
+void fs_rawudp_transmitter_udpport_add_dest (UdpPort *udpport,
+  const gchar *ip, gint port);
+void fs_rawudp_transmitter_udpport_remove_dest (UdpPort *udpport,
+  const gchar *ip, gint port);
+
+gboolean fs_rawudp_transmitter_udpport_sendto (UdpPort *udpport,
+  gchar *msg, size_t len, const struct sockaddr *to, socklen_t tolen,
+  GError **error);
+
+gulong fs_rawudp_transmitter_udpport_connect_recv (UdpPort *udpport,
+  GCallback callback, gpointer user_data);
+void fs_rawudp_transmitter_udpport_disconnect_recv (UdpPort *udpport,
+  gulong id);
+
+gboolean fs_rawudp_transmitter_udpport_is_pad (UdpPort *udpport, GstPad *pad);
+
+gboolean fs_rawudp_transmitter_udpport_get_port (UdpPort *udpport);
+
+
+
+G_END_DECLS
+
+#endif /* __FS_RAWUDP_TRANSMITTER_H__ */
-- 
1.5.6.5




More information about the farsight-commits mailing list