[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