[farsight2/master] Find agent on participant if one exists, otherwise build one

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


---
 transmitters/nice/fs-nice-stream-transmitter.c |  240 ++++++++++++++++++++----
 1 files changed, 201 insertions(+), 39 deletions(-)

diff --git a/transmitters/nice/fs-nice-stream-transmitter.c b/transmitters/nice/fs-nice-stream-transmitter.c
index fec4f68..d80adbd 100644
--- a/transmitters/nice/fs-nice-stream-transmitter.c
+++ b/transmitters/nice/fs-nice-stream-transmitter.c
@@ -36,6 +36,7 @@
 
 #include "fs-nice-stream-transmitter.h"
 #include "fs-nice-transmitter.h"
+#include "fs-nice-thread.h"
 
 #include <gst/farsight/fs-conference-iface.h>
 #include <gst/farsight/fs-interfaces.h>
@@ -47,7 +48,6 @@
 
 #include <udp-bsd.h>
 
-
 GST_DEBUG_CATEGORY_EXTERN (fs_nice_transmitter_debug);
 #define GST_CAT_DEFAULT fs_nice_transmitter_debug
 
@@ -90,6 +90,8 @@ struct _FsNiceStreamTransmitterPrivate
 
   gboolean controlling_mode;
 
+  guint compatibility_mode;
+
   GMutex *mutex;
 
   GList *preferred_local_candidates;
@@ -394,6 +396,8 @@ fs_nice_stream_transmitter_get_property (GObject *object,
       g_value_set_uint (value, self->priv->stream_id);
       FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
       break;
+    case PROP_COMPATIBILITY_MODE:
+      g_value_set_uint (value, self->priv->compatibility_mode);
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -418,27 +422,15 @@ fs_nice_stream_transmitter_set_property (GObject *object,
       break;
     case PROP_STUN_IP:
       self->priv->stun_ip = g_value_dup_string (value);
-      if (self->priv->transmitter && self->priv->agent)
-        g_object_set_property (G_OBJECT (self->priv->agent),
-            g_param_spec_get_name (pspec), value);
       break;
     case PROP_STUN_PORT:
       self->priv->stun_port = g_value_get_uint (value);
-      if (self->priv->transmitter && self->priv->agent)
-        g_object_set_property (G_OBJECT (self->priv->agent),
-            g_param_spec_get_name (pspec), value);
       break;
     case PROP_TURN_IP:
       self->priv->turn_ip = g_value_dup_string (value);
-      if (self->priv->transmitter && self->priv->agent)
-        g_object_set_property (G_OBJECT (self->priv->agent),
-            g_param_spec_get_name (pspec), value);
       break;
     case PROP_TURN_PORT:
       self->priv->turn_port = g_value_get_uint (value);
-      if (self->priv->transmitter && self->priv->agent)
-        g_object_set_property (G_OBJECT (self->priv->agent),
-            g_param_spec_get_name (pspec), value);
       break;
     case PROP_CONTROLLING_MODE:
       self->priv->controlling_mode = g_value_get_boolean (value);
@@ -447,7 +439,7 @@ fs_nice_stream_transmitter_set_property (GObject *object,
             g_param_spec_get_name (pspec), value);
       break;
     case PROP_COMPATIBILITY_MODE:
-      /* ignore it here, its been intercepted by our parent */
+      self->priv->compatibility_mode = g_value_get_uint (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -758,6 +750,24 @@ nice_candidate_to_fs_candidate (NiceAgent *agent, NiceCandidate *nicecandidate)
   return fscandidate;
 }
 
+
+static gboolean
+candidate_list_are_equal (GList *list1, GList *list2)
+{
+  for (;
+       list1 && list2;
+       list1 = list1->next, list2 = list2->next)
+  {
+    FsCandidate *cand1 = list1->data;
+    FsCandidate *cand2 = list2->data;
+
+    if (strcmp (cand1->ip, cand2->ip))
+        return FALSE;
+  }
+
+  return TRUE;
+}
+
 static gboolean
 fs_nice_stream_transmitter_build (FsNiceStreamTransmitter *self,
     FsParticipant *participant,
@@ -765,56 +775,171 @@ fs_nice_stream_transmitter_build (FsNiceStreamTransmitter *self,
 {
   GList *item;
   gboolean set = FALSE;
+  GList *agents  = NULL;
+  FsNiceThread *thread = NULL;
+  NiceAgent *agent = NULL;
 
-  self->priv->component_states = g_new0 (FsStreamState,
-      self->priv->transmitter->components);
+  /* Before going any further, check that the list of candidates are ok */
 
-  for (item = self->priv->preferred_local_candidates;
+  for (item = g_list_first (self->priv->preferred_local_candidates);
        item;
        item = g_list_next (item))
   {
     FsCandidate *cand = item->data;
-    NiceAddress *addr = nice_address_new ();
 
-    if (nice_address_set_from_string (addr, cand->ip))
+    if (cand->ip == NULL)
     {
-      if (!nice_agent_add_local_address (self->priv->agent, addr))
-      {
-        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
-            "Unable to set preferred local candidate");
-        return FALSE;
-      }
-      set = TRUE;
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+          "You have to set an ip on your preferred candidate");
+      return FALSE;
     }
-    else
+
+    if (cand->port || cand->component_id)
     {
       g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
-          "Invalid local address passed");
-      nice_address_free (addr);
+          "You can not set a port or component id"
+          " for the preferred nice candidate");
       return FALSE;
     }
-    nice_address_free (addr);
+
+    if (cand->type != FS_CANDIDATE_TYPE_HOST)
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+          "You can only set preferred candidates of type host");
+      return FALSE;
+    }
+
+    if (cand->proto != FS_NETWORK_PROTOCOL_UDP)
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+          "Only UDP preferred candidates can be set");
+      return FALSE;
+    }
+  }
+
+
+  /* First find if there is already a matching agent */
+
+  agents = g_object_get_data (G_OBJECT (participant), "nice-agents");
+
+  for (item = g_list_first (agents);
+       item;
+       item = g_list_next (item))
+  {
+    guint stun_port, turn_port;
+    gchar *stun_server, *turn_server;
+    guint compatibility;
+
+    agent = item->data;
+
+    g_object_get (agent,
+        "stun-server", &stun_server,
+        "stun-server-port", &stun_port,
+        "turn-server", &turn_server,
+        "turn-server-port", &turn_port,
+        "compatibility", &compatibility,
+        NULL);
+
+    if (!thread)
+      thread = g_object_get_data (G_OBJECT (agent), "nice-thread");
+
+    /*
+     * Check if the agent matches our requested criteria
+     */
+    if (compatibility == self->priv->compatibility_mode &&
+        stun_port == self->priv->stun_port &&
+        turn_port == self->priv->turn_port &&
+        (stun_server == self->priv->stun_ip ||
+            (stun_server && self->priv->stun_ip &&
+                !strcmp (stun_server, self->priv->stun_ip))) &&
+        (turn_server == self->priv->turn_ip ||
+            (turn_server && self->priv->turn_ip &&
+                !strcmp (turn_server, self->priv->turn_ip))))
+    {
+      GList *prefs = g_object_get_data (G_OBJECT (agent),
+          "preferred-local-candidates");
+
+      if (candidate_list_are_equal (prefs,
+              self->priv->preferred_local_candidates))
+        break;
+    }
   }
 
-  if (!set)
+
+  /* In this case we need to build a new agent */
+  if (item == NULL)
   {
-    GList *addresses = fs_interfaces_get_local_ips (FALSE);
+    GMainContext *ctx = NULL;
+    GList *local_prefs_copy;
+
+    /* If we don't have a thread, build one */
+    if (thread == NULL)
+    {
+      thread = fs_nice_thread_new (error);
+      if (!thread)
+        return FALSE;
+    }
+
+    ctx = fs_nice_thread_get_context (thread);
+
+    agent = nice_agent_new (&udpfactory, ctx, self->priv->compatibility_mode);
+
+    if (!agent)
+    {
+      g_object_unref (thread);
+      g_object_unref (thread);
+      g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
+          "Could not make nice agent");
+      return FALSE;
+    }
+
+    fs_nice_thread_add_weak_object (thread, G_OBJECT (agent));
+
+    g_object_set_data (G_OBJECT (thread), "nice-thread", thread);
+
+    g_object_unref (thread);
 
-    for (item = addresses;
+    if (self->priv->stun_ip && self->priv->stun_port)
+      g_object_set (agent,
+          "stun-server", self->priv->stun_ip,
+          "stun-server-port", self->priv->stun_port,
+          NULL);
+
+    if (self->priv->turn_ip && self->priv->turn_port)
+      g_object_set (agent,
+          "turn-server", self->priv->turn_ip,
+          "turn-server-port", self->priv->turn_port,
+          NULL);
+
+    local_prefs_copy = fs_candidate_list_copy (
+        self->priv->preferred_local_candidates);
+    g_object_set_data (G_OBJECT (agent), "preferred-local-candidates",
+        local_prefs_copy);
+    g_object_weak_ref (G_OBJECT (agent),
+        (GWeakNotify) fs_candidate_list_destroy,
+        local_prefs_copy);
+
+    agents = g_list_prepend (agents, agents);
+    g_object_set_data (G_OBJECT (participant), "nice-agents", agents);
+
+    self->priv->agent = agent;
+
+    for (item = self->priv->preferred_local_candidates;
          item;
          item = g_list_next (item))
     {
-      NiceAddress *addr = nice_address_new ();;
+      FsCandidate *cand = item->data;
+      NiceAddress *addr = nice_address_new ();
 
-      if (nice_address_set_from_string (addr, item->data))
+      if (nice_address_set_from_string (addr, cand->ip))
       {
-        if (!nice_agent_add_local_address (self->priv->agent,
-                addr))
+        if (!nice_agent_add_local_address (self->priv->agent, addr))
         {
           g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
               "Unable to set preferred local candidate");
           return FALSE;
         }
+        set = TRUE;
       }
       else
       {
@@ -826,10 +951,47 @@ fs_nice_stream_transmitter_build (FsNiceStreamTransmitter *self,
       nice_address_free (addr);
     }
 
-    g_list_foreach (addresses, (GFunc) g_free, NULL);
-    g_list_free (addresses);
+    if (!set)
+    {      GList *addresses = fs_interfaces_get_local_ips (FALSE);
+
+      for (item = addresses;
+           item;
+           item = g_list_next (item))
+      {
+        NiceAddress *addr = nice_address_new ();;
+
+        if (nice_address_set_from_string (addr, item->data))
+        {
+          if (!nice_agent_add_local_address (self->priv->agent,
+                  addr))
+          {
+            g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+                "Unable to set preferred local candidate");
+            return FALSE;
+          }
+        }
+        else
+        {
+          g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
+              "Invalid local address passed");
+          nice_address_free (addr);
+          return FALSE;
+        }
+        nice_address_free (addr);
+      }
+
+      g_list_foreach (addresses, (GFunc) g_free, NULL);
+      g_list_free (addresses);
+    }
+
+
+  } else {
+    self->priv->agent = g_object_ref (agent);
   }
 
+  self->priv->component_states = g_new0 (FsStreamState,
+      self->priv->transmitter->components);
+
 
   self->priv->stream_id = nice_agent_add_stream (
       self->priv->agent,
-- 
1.5.6.5




More information about the farsight-commits mailing list