Commit 93ac1313 authored by Youness Alaoui's avatar Youness Alaoui
Browse files

Adding compatibility mode and improvements on the main loop integration.

darcs-hash:20080422161414-4f0f6-388208b2ac7bb2a7ab06e48151e2152fc0621331.gz
parent 8d3f8b25
......@@ -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 */
};
......
......@@ -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;
}
/**
......
......@@ -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);
......
......@@ -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):
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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);
}
}
}
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment