[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