[farsight2/master] Complete untested version of the multicast transmitter
Olivier Crête
olivier.crete at collabora.co.uk
Tue Dec 23 15:21:02 PST 2008
---
.../multicast/fs-multicast-stream-transmitter.c | 474 ++++++--------------
transmitters/multicast/fs-multicast-transmitter.c | 175 +++++++-
transmitters/multicast/fs-multicast-transmitter.h | 15 +-
3 files changed, 314 insertions(+), 350 deletions(-)
diff --git a/transmitters/multicast/fs-multicast-stream-transmitter.c b/transmitters/multicast/fs-multicast-stream-transmitter.c
index a47e934..51f79e0 100644
--- a/transmitters/multicast/fs-multicast-stream-transmitter.c
+++ b/transmitters/multicast/fs-multicast-stream-transmitter.c
@@ -34,6 +34,9 @@
#include "config.h"
#endif
+#include "fs-multicast-stream-transmitter.h"
+#include "fs-multicast-transmitter.h"
+
#include "fs-interfaces.h"
#include <gst/farsight/fs-candidate.h>
@@ -63,7 +66,7 @@ enum
{
PROP_0,
PROP_SENDING,
- PROP_PREFERED_LOCAL_CANDIDATES
+ PROP_PREFERRED_LOCAL_CANDIDATES
};
struct _FsMulticastStreamTransmitterPrivate
@@ -82,17 +85,13 @@ struct _FsMulticastStreamTransmitterPrivate
* We have at most of those per component (index 0 is unused)
*/
FsCandidate **remote_candidate;
+ FsCandidate **local_candidate;
- FsCandidate **local_forced_candidate;
- FsCandidate **local_active_candidate;
-
- UdpPort **udpports;
+ UdpMulticastGroup **mcasts;
- GList *prefered_local_candidates;
+ GList *preferred_local_candidates;
guint next_candidate_id;
-
- GList *sources;
};
#define FS_MULTICAST_STREAM_TRANSMITTER_GET_PRIVATE(o) \
@@ -117,15 +116,6 @@ static gboolean fs_multicast_stream_transmitter_add_remote_candidate (
FsStreamTransmitter *streamtransmitter, FsCandidate *candidate,
GError **error);
-static FsCandidate * fs_multicast_stream_transmitter_build_forced_candidate (
- FsMulticastStreamTransmitter *self, const char *ip, gint port,
- guint component_id);
-static void fs_multicast_stream_transmitter_maybe_new_active_candidate_pair (
- FsMulticastStreamTransmitter *self, guint component_id);
-static gboolean
-fs_multicast_stream_transmitter_emit_local_candidates (
- FsMulticastStreamTransmitter *self, guint component_id);
-
static GObjectClass *parent_class = NULL;
// static guint signals[LAST_SIGNAL] = { 0 };
@@ -176,7 +166,7 @@ fs_multicast_stream_transmitter_class_init (FsMulticastStreamTransmitterClass *k
g_object_class_override_property (gobject_class, PROP_SENDING, "sending");
g_object_class_override_property (gobject_class,
- PROP_PREFERED_LOCAL_CANDIDATES, "prefered-local-candidates");
+ PROP_PREFERRED_LOCAL_CANDIDATES, "preferred-local-candidates");
gobject_class->dispose = fs_multicast_stream_transmitter_dispose;
gobject_class->finalize = fs_multicast_stream_transmitter_finalize;
@@ -205,13 +195,19 @@ fs_multicast_stream_transmitter_dispose (GObject *object)
return;
}
- 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;
+ if (self->priv->mcasts) {
+ for (c = 1; c <= self->priv->transmitter->components; c++) {
+ if (self->priv->mcasts[c]) {
+ if (self->priv->sending)
+ fs_multicast_transmitter_set_group_sending (self->priv->mcasts[c],
+ FALSE);
+ fs_multicast_transmitter_put_group (self->priv->transmitter,
+ self->priv->mcasts[c]);
+ self->priv->mcasts[c] = NULL;
+ }
+ }
}
-
/* Make sure dispose does not run twice. */
self->priv->disposed = TRUE;
@@ -224,61 +220,26 @@ fs_multicast_stream_transmitter_finalize (GObject *object)
FsMulticastStreamTransmitter *self = FS_MULTICAST_STREAM_TRANSMITTER (object);
gint c; /* component_id */
- if (self->priv->prefered_local_candidates) {
- fs_candidate_list_destroy (self->priv->prefered_local_candidates);
- self->priv->prefered_local_candidates = NULL;
+ if (self->priv->preferred_local_candidates)
+ {
+ fs_candidate_list_destroy (self->priv->preferred_local_candidates);
+ self->priv->preferred_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_multicast_transmitter_udpport_remove_dest (self->priv->udpports[c],
- self->priv->remote_candidate[c]->ip,
- self->priv->remote_candidate[c]->port);
+ if (self->priv->remote_candidate)
+ {
+ for (c = 1; c <= self->priv->transmitter->components; c++)
+ {
+ if (self->priv->remote_candidate[c])
fs_candidate_destroy (self->priv->remote_candidate[c]);
- }
+ self->priv->remote_candidate[c] = NULL;
}
-
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_multicast_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_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;
- }
+ g_free (self->priv->mcasts);
+ self->priv->mcasts = NULL;
parent_class->finalize (object);
}
@@ -295,8 +256,8 @@ fs_multicast_stream_transmitter_get_property (GObject *object,
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);
+ case PROP_PREFERRED_LOCAL_CANDIDATES:
+ g_value_set_boxed (value, self->priv->preferred_local_candidates);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -320,29 +281,15 @@ fs_multicast_stream_transmitter_set_property (GObject *object,
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_multicast_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_multicast_transmitter_udpport_remove_dest (
- self->priv->udpports[c],
- self->priv->remote_candidate[c]->ip,
- self->priv->remote_candidate[c]->port);
- }
- }
+ if (self->priv->sending != old_sending)
+ for (c = 1; c <= self->priv->transmitter->components; c++)
+ if (self->priv->mcasts[c])
+ fs_multicast_transmitter_set_group_sending (self->priv->mcasts[c],
+ self->priv->sending);
}
break;
- case PROP_PREFERED_LOCAL_CANDIDATES:
- self->priv->prefered_local_candidates = g_value_dup_boxed (value);
+ case PROP_PREFERRED_LOCAL_CANDIDATES:
+ self->priv->preferred_local_candidates = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -354,130 +301,78 @@ static gboolean
fs_multicast_stream_transmitter_build (FsMulticastStreamTransmitter *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->mcasts = g_new0 (UdpMulticastGroup *,
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_active_candidate = g_new0 (FsCandidate *,
+ self->priv->local_candidate = g_new0 (FsCandidate *,
+ self->priv->transmitter->components + 1)
+; self->priv->remote_candidate = g_new0 (FsCandidate *,
self->priv->transmitter->components + 1);
- for (item = g_list_first (self->priv->prefered_local_candidates);
+ for (item = g_list_first (self->priv->preferred_local_candidates);
item;
- item = g_list_next (item)) {
+ item = g_list_next (item))
+ {
FsCandidate *candidate = item->data;
- if (candidate->proto != FS_NETWORK_PROTOCOL_UDP) {
+ 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"
+ "You set preferred candidate of a type %d that is not"
" FS_NETWORK_PROTOCOL_UDP",
candidate->proto);
- goto error;
+ return FALSE;
}
- if (candidate->component_id == 0) {
+ if (candidate->component_id == 0)
+ {
g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
"Component id 0 is invalid");
- goto error;
+ return FALSE;
}
- if (candidate->component_id > self->priv->transmitter->components) {
+ 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;
+ return FALSE;
}
- if (ips[candidate->component_id] || ports[candidate->component_id]) {
+ if (self->priv->local_candidate[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;
+ FS_ERROR_INVALID_ARGUMENTS,
+ "You set more than one preferred local candidate for component %u",
+ candidate->component_id);
+ return FALSE;
}
- /*
- * We should verify that the IP is valid now!!
- *
- */
+ if (candidate->ip == NULL)
+ {
+ g_set_error (error, FS_ERROR,
+ FS_ERROR_INVALID_ARGUMENTS,
+ "You have not set the local ip address for the preferred candidate"
+ " for this component");
+ return FALSE;
+ }
- ips[candidate->component_id] = candidate->ip;
- if (candidate->port)
- ports[candidate->component_id] = candidate->port;
+ self->priv->local_candidate[candidate->component_id] = candidate;
}
- /* 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_multicast_transmitter_get_udpport (self->priv->transmitter, c, ips[c],
- requested_port, error);
- if (!self->priv->udpports[c])
- goto error;
-
- used_port = fs_multicast_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_multicast_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;
+ for (c = 1; c <= self->priv->transmitter->components; c++)
+ {
+ if (!self->priv->local_candidate[c])
+ {
+ self->priv->local_candidate[c] = fs_candidate_new (NULL,
+ FS_CANDIDATE_TYPE_MULTICAST, FS_NETWORK_PROTOCOL_UDP, NULL, 0);
}
-
- if (ips[c])
- self->priv->local_forced_candidate[c] =
- fs_multicast_stream_transmitter_build_forced_candidate (self, ips[c],
- used_port, c);
-
- next_port = used_port+1;
}
- g_free (ips);
- g_free (ports);
-
return TRUE;
-
- error:
- g_free (ips);
- g_free (ports);
-
- return FALSE;
}
/**
@@ -499,6 +394,7 @@ fs_multicast_stream_transmitter_add_remote_candidate (
{
FsMulticastStreamTransmitter *self =
FS_MULTICAST_STREAM_TRANSMITTER (streamtransmitter);
+ UdpMulticastGroup *newmcast = NULL;
if (candidate->proto != FS_NETWORK_PROTOCOL_UDP) {
g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
@@ -507,6 +403,14 @@ fs_multicast_stream_transmitter_add_remote_candidate (
return FALSE;
}
+ if (candidate->type != FS_CANDIDATE_TYPE_MULTICAST)
+ {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "The remote candidate is not of the right type, it should be"
+ " FS_ERROR_INVALID_ARGUMENTS, but it is %d", candidate->type);
+ 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");
@@ -521,28 +425,59 @@ fs_multicast_stream_transmitter_add_remote_candidate (
return FALSE;
}
+ if (self->priv->remote_candidate[candidate->component_id])
+ {
+ FsCandidate *old_candidate =
+ self->priv->remote_candidate[candidate->component_id];
+ if (old_candidate->port == candidate->port &&
+ !strcmp (old_candidate->ip, candidate->ip))
+ {
+ GST_DEBUG ("Re-set the same candidate, ignoring");
+ return TRUE;
+ }
+ fs_candidate_destroy (old_candidate);
+ self->priv->remote_candidate[candidate->component_id] = NULL;
+ }
+
/*
* 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
+ * We should also check if the address is in the multicast range
*/
- if (self->priv->sending) {
- fs_multicast_transmitter_udpport_add_dest (
- self->priv->udpports[candidate->component_id],
- candidate->ip, candidate->port);
- }
- if (self->priv->remote_candidate[candidate->component_id]) {
- fs_multicast_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]);
+
+ newmcast = fs_multicast_transmitter_get_group (self->priv->transmitter,
+ candidate->component_id, candidate->ip, candidate->port,
+ self->priv->local_candidate[candidate->component_id]->ip, error);
+
+ if (!newmcast)
+ return FALSE;
+
+ if (self->priv->mcasts[candidate->component_id])
+ {
+ if (self->priv->sending)
+ fs_multicast_transmitter_set_group_sending (
+ self->priv->mcasts[candidate->component_id],
+ FALSE);
+ fs_multicast_transmitter_put_group (self->priv->transmitter,
+ self->priv->mcasts[candidate->component_id]);
}
+
+ self->priv->mcasts[candidate->component_id] = newmcast;
+
+ if (self->priv->sending)
+ fs_multicast_transmitter_set_group_sending (
+ self->priv->mcasts[candidate->component_id],
+ TRUE);
+
self->priv->remote_candidate[candidate->component_id] =
fs_candidate_copy (candidate);
- fs_multicast_stream_transmitter_maybe_new_active_candidate_pair (self,
- candidate->component_id);
+ self->priv->local_candidate[candidate->component_id]->port = candidate->port;
+
+
+ g_signal_emit_by_name (self, "new-active-candidate-pair",
+ self->priv->local_candidate[candidate->component_id],
+ self->priv->remote_candidate[candidate->component_id]);
return TRUE;
}
@@ -572,148 +507,3 @@ fs_multicast_stream_transmitter_newv (FsMulticastTransmitter *transmitter,
return streamtransmitter;
}
-
-struct CandidateTransit {
- FsMulticastStreamTransmitter *self;
- FsCandidate *candidate;
- guint component_id;
-};
-
-static FsCandidate *
-fs_multicast_stream_transmitter_build_forced_candidate (
- FsMulticastStreamTransmitter *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_multicast_stream_transmitter_emit_local_candidates (
- FsMulticastStreamTransmitter *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_multicast_stream_transmitter_maybe_new_active_candidate_pair (self,
- component_id);
- return TRUE;
- }
-
- port = fs_multicast_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_multicast_stream_transmitter_maybe_new_active_candidate_pair (self,
- component_id);
-
- return TRUE;
-}
-
-static gboolean
-fs_multicast_stream_transmitter_no_stun (gpointer user_data)
-{
- FsMulticastStreamTransmitter *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_multicast_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);
-
- self->priv->sources = g_list_remove (self->priv->sources,
- GUINT_TO_POINTER (id));
- }
-
- return FALSE;
-}
-
-static void
-fs_multicast_stream_transmitter_maybe_new_active_candidate_pair (
- FsMulticastStreamTransmitter *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-transmitter.c b/transmitters/multicast/fs-multicast-transmitter.c
index 34fefd4..66fb927 100644
--- a/transmitters/multicast/fs-multicast-transmitter.c
+++ b/transmitters/multicast/fs-multicast-transmitter.c
@@ -491,14 +491,17 @@ struct _UdpPort {
GstElement *tee;
guint component_id;
+
+ GList *multicast_groups;
};
static gint
_bind_port (const gchar *ip, guint port, guint *used_port, GError **error)
{
- int sock;
+ int sock = -1;
struct sockaddr_in address;
int retval;
+ guchar ttl = 64, loop = 0;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
@@ -523,7 +526,7 @@ _bind_port (const gchar *ip, guint port, guint *used_port, GError **error)
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;
+ goto error;
}
do {
@@ -536,15 +539,36 @@ _bind_port (const gchar *ip, guint port, guint *used_port, GError **error)
if (port > 65535) {
g_set_error (error, FS_ERROR, FS_ERROR_NETWORK,
"Could not bind the socket to a port");
- close (sock);
- return -1;
+ goto error;
}
}
} while (retval != 0);
*used_port = port;
+ if (setsockopt (sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
+ sizeof (ttl)) < 0)
+ {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "Error setting the multicast TTL: %s",
+ g_strerror (errno));
+ goto error;
+ }
+
+ if (setsockopt (sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
+ sizeof (loop)) < 0)
+ {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "Error setting the multicast loop to FALSE: %s",
+ g_strerror (errno));
+ goto error;
+ }
return sock;
+
+ error:
+ if (sock >= 0)
+ close (sock);
+ return -1;
}
static GstElement *
@@ -571,6 +595,9 @@ _create_sinksource (gchar *elementname, GstBin *bin,
"sockfd", fd,
NULL);
+ if (direction == GST_PAD_SINK)
+ g_object_set (elem, "auto-multicast", FALSE, 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,
@@ -705,8 +732,10 @@ fs_multicast_transmitter_get_udpport (FsMulticastTransmitter *trans,
return udpport;
error:
+
if (udpport)
fs_multicast_transmitter_put_udpport (trans, udpport);
+
return NULL;
}
@@ -839,14 +868,12 @@ fs_multicast_transmitter_udpport_is_pad (UdpPort *udpport, GstPad *pad)
return res;
}
-
-gboolean
+gint
fs_multicast_transmitter_udpport_get_port (UdpPort *udpport)
{
return udpport->port;
}
-
static GType
fs_multicast_transmitter_get_stream_transmitter_type (
FsTransmitter *transmitter,
@@ -854,3 +881,137 @@ fs_multicast_transmitter_get_stream_transmitter_type (
{
return FS_TYPE_MULTICAST_STREAM_TRANSMITTER;
}
+
+/*
+ * The following functions are for counting the use of Multicast
+ */
+
+struct _UdpMulticastGroup
+{
+ UdpPort *udpport;
+
+ gint refcount;
+
+ gint sendcount;
+
+ gchar *multicast_ip;
+
+ struct ip_mreqn mreqn;
+};
+
+UdpMulticastGroup *
+fs_multicast_transmitter_get_group (FsMulticastTransmitter *trans,
+ guint component_id,
+ const gchar *multicast_ip,
+ guint port,
+ const gchar *local_ip,
+ GError **error)
+{
+ UdpPort *udpport;
+ UdpMulticastGroup *mcast = NULL;
+ GList *item = NULL;
+
+ udpport = fs_multicast_transmitter_get_udpport (trans, component_id,
+ local_ip, port, error);
+ if (!udpport)
+ return NULL;
+
+ for (item = g_list_first (udpport->multicast_groups);
+ item;
+ item = g_list_next (item))
+ {
+ mcast = item->data;
+
+ if (!strcmp (mcast->multicast_ip, multicast_ip))
+ {
+ mcast->refcount++;
+ return mcast;
+ }
+ }
+
+ mcast = g_new0 (UdpMulticastGroup, 1);
+
+ mcast->refcount = 1;
+ mcast->sendcount = 0;
+ mcast->udpport = udpport;
+ mcast->multicast_ip = g_strdup (multicast_ip);
+
+ if (!inet_aton (multicast_ip, &mcast->mreqn.imr_multiaddr))
+ {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "Invalid multicast IP");
+ goto error;
+ }
+
+ if (udpport->requested_ip &&
+ !inet_aton (udpport->requested_ip, &mcast->mreqn.imr_address)) {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "UdpPort address invalid");
+ goto error;
+ }
+
+ if (setsockopt (udpport->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mcast->mreqn), sizeof (mcast->mreqn)) < 0)
+ {
+ g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+ "Could not join the socket to the multicast group: %s",
+ g_strerror (errno));
+ goto error;
+ }
+
+ return mcast;
+
+ error:
+
+ if (mcast)
+ {
+ g_free (mcast->multicast_ip);
+ g_free (mcast);
+ }
+
+ return NULL;
+}
+
+void
+fs_multicast_transmitter_put_group (FsMulticastTransmitter *trans,
+ UdpMulticastGroup *mcast)
+{
+
+ mcast->refcount--;
+
+ if (mcast->refcount > 0)
+ return;
+
+ if (setsockopt (mcast->udpport->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ &(mcast->mreqn), sizeof (mcast->mreqn)) < 0)
+ GST_ERROR ("Could not remove the socket from the multicast group: %s",
+ g_strerror (errno));
+
+ mcast->udpport->multicast_groups = g_list_remove (
+ mcast->udpport->multicast_groups,
+ mcast);
+
+ fs_multicast_transmitter_put_udpport (trans, mcast->udpport);
+
+ g_free (mcast->multicast_ip);
+ g_free (mcast);
+}
+
+void
+fs_multicast_transmitter_set_group_sending (UdpMulticastGroup *mcast,
+ gboolean sending)
+{
+ if (sending) {
+ if (mcast->sendcount == 0)
+ fs_multicast_transmitter_udpport_add_dest (mcast->udpport,
+ mcast->multicast_ip, mcast->udpport->port);
+
+ mcast->sendcount++;
+ } else {
+ mcast->sendcount--;
+
+ if (mcast->sendcount == 0)
+ fs_multicast_transmitter_udpport_remove_dest (mcast->udpport,
+ mcast->multicast_ip, mcast->udpport->port);
+ }
+}
diff --git a/transmitters/multicast/fs-multicast-transmitter.h b/transmitters/multicast/fs-multicast-transmitter.h
index 2bfec78..f07b16a 100644
--- a/transmitters/multicast/fs-multicast-transmitter.h
+++ b/transmitters/multicast/fs-multicast-transmitter.h
@@ -83,8 +83,9 @@ struct _FsMulticastTransmitter
FsMulticastTransmitterPrivate *priv;
};
-/* Private declaration */
+/* Private declarations */
typedef struct _UdpPort UdpPort;
+typedef struct _UdpMulticastGroup UdpMulticastGroup;
GType fs_multicast_transmitter_get_type (void);
@@ -117,6 +118,18 @@ gboolean fs_multicast_transmitter_udpport_is_pad (UdpPort *udpport,
gboolean fs_multicast_transmitter_udpport_get_port (UdpPort *udpport);
+UdpMulticastGroup *fs_multicast_transmitter_get_group (
+ FsMulticastTransmitter *trans,
+ guint component_id,
+ const gchar *multicast_ip,
+ guint port,
+ const gchar *local_ip,
+ GError **error);
+void fs_multicast_transmitter_put_group (FsMulticastTransmitter *trans,
+ UdpMulticastGroup *mcast);
+void fs_multicast_transmitter_set_group_sending (UdpMulticastGroup *mcast,
+ gboolean sending);
+
G_END_DECLS
--
1.5.6.5
More information about the farsight-commits
mailing list