[Nice] [nice/master] Adding compatibility mode and improvements on the main loop integration.

Youness Alaoui youness.alaoui at collabora.co.uk
Wed Nov 5 14:00:59 PST 2008


darcs-hash:20080422161414-4f0f6-388208b2ac7bb2a7ab06e48151e2152fc0621331.gz
---
 agent/agent-priv.h |    4 +-
 agent/agent.c      |  192 +++++++++++++++++++++++++++++++---------------------
 agent/agent.h      |   14 +++-
 agent/candidate.c  |   15 ++++
 agent/candidate.h  |    3 +
 agent/component.h  |    1 +
 agent/conncheck.c  |   26 +++++--
 agent/discovery.c  |    6 +-
 nice/libnice.sym   |    2 +-
 9 files changed, 169 insertions(+), 94 deletions(-)

diff --git a/agent/agent-priv.h b/agent/agent-priv.h
index 32b7198..e766cf9 100644
--- a/agent/agent-priv.h
+++ b/agent/agent-priv.h
@@ -80,10 +80,7 @@ struct _NiceAgent
   GSList *local_addresses;        /**< list of NiceAddresses for local
 				     interfaces */
   GSList *streams;                /**< list of Stream objects */
-  gboolean main_context_set;      /**< is the main context set */
   GMainContext *main_context;     /**< main context pointer */
-  NiceAgentRecvFunc read_func;    /**< callback for media deliver */
-  gpointer read_func_data;        /**< media delivery callback context */
   guint next_candidate_id;        /**< id of next created candidate */
   guint next_stream_id;           /**< id of next created candidate */
   NiceRNG *rng;                   /**< random number generator */
@@ -95,6 +92,7 @@ struct _NiceAgent
   guint64 tie_breaker;            /**< tie breaker (ICE sect 5.2
 				     "Determining Role" ID-19) */
   GMutex * mutex;                 /* Mutex used for thread-safe lib */
+  NiceCompatibility compatibility; /* property: Compatibility mode */
   /* XXX: add pointer to internal data struct for ABI-safe extensions */
 };
 
diff --git a/agent/agent.c b/agent/agent.c
index 4e632ff..325c86f 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -74,7 +74,8 @@ G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
 enum
 {
   PROP_SOCKET_FACTORY = 1,
-  PROP_STUN_SERVER, 
+  PROP_COMPATIBILITY,
+  PROP_STUN_SERVER,
   PROP_STUN_SERVER_PORT,
   PROP_TURN_SERVER, 
   PROP_TURN_SERVER_PORT,
@@ -99,8 +100,13 @@ enum
 
 static guint signals[N_SIGNALS];
 
-static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream);
-static void priv_deattach_stream (Stream *stream);
+static gboolean priv_attach_stream_component (NiceAgent *agent,
+    Stream *stream,
+    Component *component,
+    GMainContext *ctx,
+    NiceAgentRecvFunc func,
+    gpointer data );
+static void priv_dettach_stream_component (Stream *stream, Component *component);
 
 Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
 {
@@ -179,6 +185,15 @@ nice_agent_class_init (NiceAgentClass *klass)
          "The socket factory used to create new UDP sockets",
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+  g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
+      g_param_spec_uint (
+         "compatibility",
+         "ICE specification compatibility",
+         "The compatibility mode for the agent",
+         NICE_COMPATIBILITY_ID19, NICE_COMPATIBILITY_MSN,
+         NICE_COMPATIBILITY_ID19,
+         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
   g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
       g_param_spec_string (
         "stun-server",
@@ -366,6 +381,7 @@ nice_agent_init (NiceAgent *agent)
   agent->discovery_timer_id = 0;
   agent->conncheck_timer_id = 0;
   agent->keepalive_timer_id = 0;
+  agent->compatibility = NICE_COMPATIBILITY_ID19;
 
   agent->rng = nice_rng_new ();
   priv_generate_tie_breaker (agent);
@@ -382,11 +398,17 @@ nice_agent_init (NiceAgent *agent)
  * Returns: the new agent
  **/
 NICEAPI_EXPORT NiceAgent *
-nice_agent_new (NiceUDPSocketFactory *factory)
+nice_agent_new (NiceUDPSocketFactory *factory,
+    GMainContext *ctx, NiceCompatibility compat)
 {
-  return g_object_new (NICE_TYPE_AGENT,
+  NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
       "socket-factory", factory,
+      "compatibility", compat,
       NULL);
+
+  agent->main_context = ctx;
+
+  return agent;
 }
 
 
@@ -407,6 +429,10 @@ nice_agent_get_property (
       g_value_set_pointer (value, agent->socket_factory);
       break;
 
+    case PROP_COMPATIBILITY:
+      g_value_set_uint (value, agent->compatibility);
+      break;
+
     case PROP_STUN_SERVER:
       g_value_set_string (value, agent->stun_server_ip);
       break;
@@ -465,6 +491,10 @@ nice_agent_set_property (
       agent->socket_factory = g_value_get_pointer (value);
       break;
 
+    case PROP_COMPATIBILITY:
+      agent->compatibility = g_value_get_uint (value);
+      break;
+
     case PROP_STUN_SERVER:
       agent->stun_server_ip = g_value_dup_string (value);
       break;
@@ -690,11 +720,6 @@ nice_agent_add_stream (
     }
 
 
-  /* step: attach the newly created sockets to the mainloop
-   *       context */
-  if (agent->main_context_set && stream->id > 0)
-    priv_attach_new_stream (agent, stream);
-
   /* note: no async discoveries pending, signal that we are ready */
   if (agent->discovery_unsched_items == 0)
     agent_signal_gathering_done (agent);
@@ -728,6 +753,7 @@ nice_agent_remove_stream (
   /* note that streams/candidates can be in use by other threads */
 
   Stream *stream;
+  GSList *i;
 
   g_mutex_lock (agent->mutex);
   stream = agent_find_stream (agent, stream_id);
@@ -742,7 +768,10 @@ nice_agent_remove_stream (
   discovery_prune_stream (agent, stream_id);
 
   /* remove the stream itself */
-  priv_deattach_stream (stream);
+  for (i = stream->components; i; i = i->next) {
+    priv_dettach_stream_component (stream, (Component *) i->data);
+  }
+
   agent->streams = g_slist_remove (agent->streams, stream);
   stream_free (stream);
 
@@ -943,9 +972,11 @@ nice_agent_get_local_credentials (
   guint stream_id,
   const gchar **ufrag, const gchar **pwd)
 {
-  Stream *stream = agent_find_stream (agent, stream_id);
+  Stream *stream;
 
   g_mutex_lock (agent->mutex);
+
+  stream = agent_find_stream (agent, stream_id);
   if (stream == NULL) {
     g_mutex_unlock (agent->mutex);
     return FALSE;
@@ -990,6 +1021,10 @@ nice_agent_add_remote_candidate (
   const gchar *password)
 {
 
+  /* XXX: to be deprecated */
+
+  g_mutex_lock (agent->mutex);
+
   /* XXX: should we allow use of this method without an 
    *      initial call to nice_agent_set_remote_candidates()
    *      with an empty set? */
@@ -1037,8 +1072,11 @@ nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint compo
   const GSList *i; 
   int added = 0;
 
- /* XXX: clean up existing remote candidates, and abort any 
-  *      connectivity checks using these candidates */
+
+  if (agent->discovery_unsched_items > 0)
+    return -1;
+
+  g_mutex_lock (agent->mutex);
 
  for (i = candidates; i && added >= 0; i = i->next) {
    NiceCandidateDesc *d = (NiceCandidateDesc*) i->data;
@@ -1589,6 +1627,8 @@ struct _IOCtx
   Stream *stream;
   Component *component;
   NiceUDPSocket *socket;
+  NiceAgentRecvFunc recv_func;
+  gpointer recv_data;
 };
 
 
@@ -1597,7 +1637,9 @@ io_ctx_new (
   NiceAgent *agent,
   Stream *stream,
   Component *component,
-  NiceUDPSocket *socket)
+  NiceUDPSocket *socket,
+  NiceAgentRecvFunc func,
+  gpointer data)
 {
   IOCtx *ctx;
 
@@ -1607,6 +1649,8 @@ io_ctx_new (
     ctx->stream = stream;
     ctx->component = component;
     ctx->socket = socket;
+    ctx->recv_func = func;
+    ctx->recv_data = data;
   }
   return ctx;
 }
@@ -1643,8 +1687,8 @@ nice_agent_g_source_cb (
 			  MAX_STUN_DATAGRAM_PAYLOAD, buf);
 
   if (len > 0)
-    agent->read_func (agent, stream->id, component->id,
-        len, buf, agent->read_func_data);
+    ctx->recv_func (agent, stream->id, component->id,
+        len, buf, ctx->recv_data);
 
   g_mutex_unlock (agent->mutex);
   return TRUE;
@@ -1654,38 +1698,38 @@ nice_agent_g_source_cb (
  * Attaches socket handles of 'stream' to the main eventloop
  * context.
  *
- * @pre agent->main_context_set == TRUE
  */
-static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream)
+static gboolean priv_attach_stream_component (NiceAgent *agent,
+    Stream *stream,
+    Component *component,
+    GMainContext *context,
+    NiceAgentRecvFunc func,
+    gpointer data)
 {
-  GSList *i, *j;
+  GSList *i;
 
-  for (i = stream->components; i; i = i->next) {
-    Component *component = i->data;
-
-    for (j = component->sockets; j; j = j->next) {
-      NiceUDPSocket *udp_socket = j->data;
-      GIOChannel *io;
-      GSource *source;
-      IOCtx *ctx;
-      GSList *modified_list;
-    
-      io = g_io_channel_unix_new (udp_socket->fileno);
-      /* note: without G_IO_ERR the glib mainloop goes into
-       *       busyloop if errors are encountered */
-      source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
-      ctx = io_ctx_new (agent, stream, component, udp_socket);
-      g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
-			     ctx, (GDestroyNotify) io_ctx_free);
-      g_debug ("Attach source %p (stream %u).", source, stream->id);
-      g_source_attach (source, NULL);
-      modified_list = g_slist_append (component->gsources, source);
-      if (!modified_list) {
-	g_source_destroy (source);
-	return FALSE;
-      }
-      component->gsources = modified_list;
+  for (i = component->sockets; i; i = i->next) {
+    NiceUDPSocket *udp_socket = i->data;
+    GIOChannel *io;
+    GSource *source;
+    IOCtx *ctx;
+    GSList *modified_list;
+
+    io = g_io_channel_unix_new (udp_socket->fileno);
+    /* note: without G_IO_ERR the glib mainloop goes into
+     *       busyloop if errors are encountered */
+    source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
+    ctx = io_ctx_new (agent, stream, component, udp_socket, func, data);
+    g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
+        ctx, (GDestroyNotify) io_ctx_free);
+    g_debug ("Attach source %p (stream %u).", source, stream->id);
+    g_source_attach (source, context);
+    modified_list = g_slist_append (component->gsources, source);
+    if (!modified_list) {
+      g_source_destroy (source);
+      return FALSE;
     }
+    component->gsources = modified_list;
   }
 
   return TRUE;
@@ -1695,59 +1739,51 @@ static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream)
  * Detaches socket handles of 'stream' from the main eventloop
  * context.
  *
- * @pre agent->main_context_set == TRUE
  */
-static void priv_deattach_stream (Stream *stream)
+static void priv_dettach_stream_component (Stream *stream, Component *component)
 {
-  GSList *i, *j;
-
-  for (i = stream->components; i; i = i->next) {
-    Component *component = i->data;
-
-    for (j = component->gsources; j; j = j->next) {
-      GSource *source = j->data;
-      g_debug ("Detach source %p (stream %u).", source, stream->id);
-      g_source_destroy (source);
-    }
+  GSList *i;
 
-    g_slist_free (component->gsources),
-    component->gsources = NULL;
+  for (i = component->gsources; i; i = i->next) {
+    GSource *source = i->data;
+    g_debug ("Detach source %p (stream %u).", source, stream->id);
+    g_source_destroy (source);
   }
+
+  g_slist_free (component->gsources);
+  component->gsources = NULL;
 }
 
 NICEAPI_EXPORT gboolean
-nice_agent_main_context_attach (
+nice_agent_attach_recv (
   NiceAgent *agent,
+  guint stream_id,
+  guint component_id,
   GMainContext *ctx,
   NiceAgentRecvFunc func,
   gpointer data)
 {
-  GSList *i;
+  Component *component = NULL;
+  Stream *stream = NULL;
+  gboolean res = TRUE;
 
   g_mutex_lock (agent->mutex);
-  if (agent->main_context_set) {
-    g_mutex_unlock (agent->mutex);
-    return FALSE;
-  }
 
   /* attach candidates */
 
-  for (i = agent->streams; i; i = i->next) {
-    Stream *stream = i->data;
-    gboolean res = priv_attach_new_stream (agent, stream);
-    if (!res) {
-      g_mutex_unlock (agent->mutex);
-      return FALSE;
-    }
+  /* step: check that params specify an existing pair */
+  if (!agent_find_component (agent, stream_id, component_id,
+          &stream, &component) || component == NULL) {
+    g_mutex_unlock (agent->mutex);
+    return FALSE;
   }
-  
-  agent->main_context = ctx;
-  agent->main_context_set = TRUE;
-  agent->read_func = func;
-  agent->read_func_data = data;
+
+  priv_dettach_stream_component (stream, component);
+  if (func != NULL)
+    res = priv_attach_stream_component (agent, stream, component, ctx, func, data);
 
   g_mutex_unlock (agent->mutex);
-  return TRUE;
+  return res;
 }
 
 /**
diff --git a/agent/agent.h b/agent/agent.h
index 961cd96..72a14b1 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -96,6 +96,13 @@ typedef enum
   NICE_COMPONENT_TYPE_RTCP = 2
 } NiceComponentType;
 
+typedef enum
+{
+  NICE_COMPATIBILITY_ID19 = 1,
+  NICE_COMPATIBILITY_GOOGLE = 2,
+  NICE_COMPATIBILITY_MSN = 3
+} NiceCompatibility;
+
 typedef struct _NiceCandidateDesc NiceCandidateDesc;
 
 struct _NiceCandidateDesc {
@@ -125,7 +132,8 @@ struct _NiceAgentClass
 GType nice_agent_get_type (void);
 
 NiceAgent *
-nice_agent_new (NiceUDPSocketFactory *factory);
+nice_agent_new (NiceUDPSocketFactory *factory,
+    GMainContext *ctx, NiceCompatibility compat);
 
 gboolean
 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr);
@@ -218,8 +226,10 @@ nice_agent_restart (
   NiceAgent *agent);
 
 gboolean
-nice_agent_main_context_attach (
+nice_agent_attach_recv (
   NiceAgent *agent,
+  guint stream_id,
+  guint component_id,
   GMainContext *ctx,
   NiceAgentRecvFunc func,
   gpointer data);
diff --git a/agent/candidate.c b/agent/candidate.c
index b0d3025..4e180c8 100644
--- a/agent/candidate.c
+++ b/agent/candidate.c
@@ -94,6 +94,21 @@ nice_candidate_jingle_priority (NiceCandidate *candidate)
   return 0;
 }
 
+NICEAPI_EXPORT gfloat
+nice_candidate_msn_priority (NiceCandidate *candidate)
+{
+  switch (candidate->type)
+    {
+    case NICE_CANDIDATE_TYPE_HOST:             return 0.830;
+    case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: return 0.550;
+    case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:   return 0.550;
+    case NICE_CANDIDATE_TYPE_RELAYED:          return 0.450;
+    }
+
+  /* appease GCC */
+  return 0;
+}
+
 
 /**
  * ICE 4.1.2.1. "Recommended Formula" (ID-19):
diff --git a/agent/candidate.h b/agent/candidate.h
index 2f1de45..4c89851 100644
--- a/agent/candidate.h
+++ b/agent/candidate.h
@@ -91,6 +91,9 @@ nice_candidate_free (NiceCandidate *candidate);
 gfloat
 nice_candidate_jingle_priority (NiceCandidate *candidate);
 
+gfloat
+nice_candidate_msn_priority (NiceCandidate *candidate);
+
 guint32
 nice_candidate_ice_priority_full (guint type_pref, guint local_pref, guint component_id);
 
diff --git a/agent/component.h b/agent/component.h
index fd42810..4b7bf85 100644
--- a/agent/component.h
+++ b/agent/component.h
@@ -46,6 +46,7 @@
 
 G_BEGIN_DECLS
 
+
 /* (ICE §4.1.1.1, ID-19) ""For RTP-based media streams, the RTP itself has a component
  * ID of 1, and RTCP a component ID of 2.  If an agent is using RTCP it MUST
  * obtain a candidate for it.  If an agent is using both RTP and RTCP, it
diff --git a/agent/conncheck.c b/agent/conncheck.c
index e53742b..fe64a95 100644
--- a/agent/conncheck.c
+++ b/agent/conncheck.c
@@ -481,14 +481,20 @@ gboolean conn_check_schedule_next (NiceAgent *agent)
     res = priv_conn_check_tick_unlocked ((gpointer) agent);
 
     /* step: schedule timer if not running yet */
-    if (res && agent->conncheck_timer_id == 0) 
-      agent->conncheck_timer_id = 
-	g_timeout_add (agent->timer_ta, priv_conn_check_tick, agent);
+    if (res && agent->conncheck_timer_id == 0) {
+      GSource *source = g_timeout_source_new (agent->timer_ta);
+      g_source_set_callback (source, priv_conn_check_tick, agent, NULL);
+      agent->conncheck_timer_id = g_source_attach (source, agent->main_context);
+      g_source_unref (source);
+    }
 
     /* step: also start the keepalive timer */
-    if (agent->keepalive_timer_id == 0) 
-      agent->keepalive_timer_id = 
-	g_timeout_add (NICE_AGENT_TIMER_TR_DEFAULT, priv_conn_keepalive_tick, agent);
+    if (agent->keepalive_timer_id == 0) {
+      GSource *source = g_timeout_source_new (NICE_AGENT_TIMER_TR_DEFAULT);
+      g_source_set_callback (source, priv_conn_keepalive_tick, agent, NULL);
+      agent->keepalive_timer_id = g_source_attach (source, agent->main_context);
+      g_source_unref (source);
+    }
 
   }
 
@@ -950,13 +956,17 @@ static gboolean priv_create_check_username (NiceAgent *agent, CandidateCheckPair
   if (pair &&
       pair->remote && pair->remote->username &&
       pair->local && pair->local->username) {
-    g_snprintf (dest, dest_len, "%s:%s", pair->remote->username, pair->local->username);
+    g_snprintf (dest, dest_len, "%s%s%s", pair->remote->username,
+        agent->compatibility == NICE_COMPATIBILITY_ID19 ? ":" : "",
+        pair->local->username);
     return TRUE;
   }
 
   stream = agent_find_stream (agent, pair->stream_id);
   if (stream) {
-    g_snprintf (dest, dest_len, "%s:%s", stream->remote_ufrag, stream->local_ufrag);
+    g_snprintf (dest, dest_len, "%s%s%s", stream->remote_ufrag,
+        agent->compatibility == NICE_COMPATIBILITY_ID19 ? ":" : "",
+        stream->local_ufrag);
     return TRUE;
   }
 
diff --git a/agent/discovery.c b/agent/discovery.c
index 14d0d9c..17d86b3 100644
--- a/agent/discovery.c
+++ b/agent/discovery.c
@@ -597,8 +597,10 @@ void discovery_schedule (NiceAgent *agent)
       /* step: run first iteration immediately */
       gboolean res = priv_discovery_tick_unlocked (agent);
       if (res == TRUE) {
-	agent->discovery_timer_id = 
-	  g_timeout_add (agent->timer_ta, priv_discovery_tick, agent);
+        GSource *source = g_timeout_source_new (agent->timer_ta);
+        g_source_set_callback (source, priv_discovery_tick, agent, NULL);
+        agent->discovery_timer_id = g_source_attach (source, agent->main_context);
+        g_source_unref (source);
       }
     }
   }
diff --git a/nice/libnice.sym b/nice/libnice.sym
index aa3ac1d..1c201de 100644
--- a/nice/libnice.sym
+++ b/nice/libnice.sym
@@ -14,11 +14,11 @@ nice_address_to_string
 nice_agent_add_local_address
 nice_agent_add_remote_candidate
 nice_agent_add_stream
+nice_agent_attach_recv
 nice_agent_get_local_candidates
 nice_agent_get_local_credentials
 nice_agent_get_remote_candidates
 nice_agent_get_type
-nice_agent_main_context_attach
 nice_agent_new
 nice_agent_poll_read
 nice_agent_recv
-- 
1.5.6.5




More information about the Nice mailing list