* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/94/94031aadad1104cd64dac0fdc20b9b73941856d4.svn-base b/jni/pjproject-android/.svn/pristine/94/94031aadad1104cd64dac0fdc20b9b73941856d4.svn-base
new file mode 100644
index 0000000..bd81727
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/94031aadad1104cd64dac0fdc20b9b73941856d4.svn-base
@@ -0,0 +1,1775 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjnath/ice_strans.h>
+#include <pjnath/errno.h>
+#include <pj/addr_resolv.h>
+#include <pj/array.h>
+#include <pj/assert.h>
+#include <pj/ip_helper.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+
+#define ENABLE_TRACE 0
+
+#if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
+#  define TRACE_PKT(expr)	    PJ_LOG(5,expr)
+#else
+#  define TRACE_PKT(expr)
+#endif
+
+
+/* Transport IDs */
+enum tp_type
+{
+    TP_NONE,
+    TP_STUN,
+    TP_TURN
+};
+
+/* Candidate's local preference values. This is mostly used to
+ * specify preference among candidates with the same type. Since
+ * we don't have the facility to specify that, we'll just set it
+ * all to the same value.
+ */
+#if PJNATH_ICE_PRIO_STD
+#   define SRFLX_PREF  65535
+#   define HOST_PREF   65535
+#   define RELAY_PREF  65535
+#else
+#   define SRFLX_PREF  0
+#   define HOST_PREF   0
+#   define RELAY_PREF  0
+#endif
+
+
+/* The candidate type preference when STUN candidate is used */
+static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] = 
+{
+#if PJNATH_ICE_PRIO_STD
+    100,    /**< PJ_ICE_HOST_PREF	    */
+    110,    /**< PJ_ICE_SRFLX_PREF	    */
+    126,    /**< PJ_ICE_PRFLX_PREF	    */
+    0	    /**< PJ_ICE_RELAYED_PREF    */
+#else
+    /* Keep it to 2 bits */
+    1,	/**< PJ_ICE_HOST_PREF	    */
+    2,	/**< PJ_ICE_SRFLX_PREF	    */
+    3,	/**< PJ_ICE_PRFLX_PREF	    */
+    0	/**< PJ_ICE_RELAYED_PREF    */
+#endif
+};
+
+
+/* ICE callbacks */
+static void	   on_ice_complete(pj_ice_sess *ice, pj_status_t status);
+static pj_status_t ice_tx_pkt(pj_ice_sess *ice, 
+			      unsigned comp_id,
+			      unsigned transport_id,
+			      const void *pkt, pj_size_t size,
+			      const pj_sockaddr_t *dst_addr,
+			      unsigned dst_addr_len);
+static void	   ice_rx_data(pj_ice_sess *ice, 
+			       unsigned comp_id, 
+			       unsigned transport_id,
+			       void *pkt, pj_size_t size,
+			       const pj_sockaddr_t *src_addr,
+			       unsigned src_addr_len);
+
+
+/* STUN socket callbacks */
+/* Notification when incoming packet has been received. */
+static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
+				 void *pkt,
+				 unsigned pkt_len,
+				 const pj_sockaddr_t *src_addr,
+				 unsigned addr_len);
+/* Notifification when asynchronous send operation has completed. */
+static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
+				   pj_ioqueue_op_key_t *send_key,
+				   pj_ssize_t sent);
+/* Notification when the status of the STUN transport has changed. */
+static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, 
+				pj_stun_sock_op op,
+				pj_status_t status);
+
+
+/* TURN callbacks */
+static void turn_on_rx_data(pj_turn_sock *turn_sock,
+			    void *pkt,
+			    unsigned pkt_len,
+			    const pj_sockaddr_t *peer_addr,
+			    unsigned addr_len);
+static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
+			  pj_turn_state_t new_state);
+
+
+
+/* Forward decls */
+static void ice_st_on_destroy(void *obj);
+static void destroy_ice_st(pj_ice_strans *ice_st);
+#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
+static void sess_init_update(pj_ice_strans *ice_st);
+
+/**
+ * This structure describes an ICE stream transport component. A component
+ * in ICE stream transport typically corresponds to a single socket created
+ * for this component, and bound to a specific transport address. This
+ * component may have multiple alias addresses, for example one alias 
+ * address for each interfaces in multi-homed host, another for server
+ * reflexive alias, and another for relayed alias. For each transport
+ * address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will
+ * be created, and these candidates will eventually registered to the ICE
+ * session.
+ */
+typedef struct pj_ice_strans_comp
+{
+    pj_ice_strans	*ice_st;	/**< ICE stream transport.	*/
+    unsigned		 comp_id;	/**< Component ID.		*/
+
+    pj_stun_sock	*stun_sock;	/**< STUN transport.		*/
+    pj_turn_sock	*turn_sock;	/**< TURN relay transport.	*/
+    pj_bool_t		 turn_log_off;	/**< TURN loggin off?		*/
+    unsigned		 turn_err_cnt;	/**< TURN disconnected count.	*/
+
+    unsigned		 cand_cnt;	/**< # of candidates/aliaes.	*/
+    pj_ice_sess_cand	 cand_list[PJ_ICE_ST_MAX_CAND];	/**< Cand array	*/
+
+    unsigned		 default_cand;	/**< Default candidate.		*/
+
+} pj_ice_strans_comp;
+
+
+/**
+ * This structure represents the ICE stream transport.
+ */
+struct pj_ice_strans
+{
+    char		    *obj_name;	/**< Log ID.			*/
+    pj_pool_t		    *pool;	/**< Pool used by this object.	*/
+    void		    *user_data;	/**< Application data.		*/
+    pj_ice_strans_cfg	     cfg;	/**< Configuration.		*/
+    pj_ice_strans_cb	     cb;	/**< Application callback.	*/
+    pj_grp_lock_t	    *grp_lock;  /**< Group lock.		*/
+
+    pj_ice_strans_state	     state;	/**< Session state.		*/
+    pj_ice_sess		    *ice;	/**< ICE session.		*/
+    pj_time_val		     start_time;/**< Time when ICE was started	*/
+
+    unsigned		     comp_cnt;	/**< Number of components.	*/
+    pj_ice_strans_comp	   **comp;	/**< Components array.		*/
+
+    pj_timer_entry	     ka_timer;	/**< STUN keep-alive timer.	*/
+
+    pj_bool_t		     destroy_req;/**< Destroy has been called?	*/
+    pj_bool_t		     cb_called;	/**< Init error callback called?*/
+};
+
+
+/* Validate configuration */
+static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg)
+{
+    pj_status_t status;
+
+    status = pj_stun_config_check_valid(&cfg->stun_cfg);
+    if (!status)
+	return status;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize ICE transport configuration with default values.
+ */
+PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
+{
+    pj_bzero(cfg, sizeof(*cfg));
+
+    pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
+    pj_stun_sock_cfg_default(&cfg->stun.cfg);
+    pj_turn_alloc_param_default(&cfg->turn.alloc_param);
+    pj_turn_sock_cfg_default(&cfg->turn.cfg);
+
+    pj_ice_sess_options_default(&cfg->opt);
+
+    cfg->af = pj_AF_INET();
+    cfg->stun.port = PJ_STUN_PORT;
+    cfg->turn.conn_type = PJ_TURN_TP_UDP;
+
+    cfg->stun.max_host_cands = 64;
+    cfg->stun.ignore_stun_error = PJ_FALSE;
+}
+
+
+/*
+ * Copy configuration.
+ */
+PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool,
+				     pj_ice_strans_cfg *dst,
+				     const pj_ice_strans_cfg *src)
+{
+    pj_memcpy(dst, src, sizeof(*src));
+
+    if (src->stun.server.slen)
+	pj_strdup(pool, &dst->stun.server, &src->stun.server);
+    if (src->turn.server.slen)
+	pj_strdup(pool, &dst->turn.server, &src->turn.server);
+    pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred,
+			  &src->turn.auth_cred);
+}
+
+
+/*
+ * Add or update TURN candidate.
+ */
+static pj_status_t add_update_turn(pj_ice_strans *ice_st,
+				   pj_ice_strans_comp *comp)
+{
+    pj_turn_sock_cb turn_sock_cb;
+    pj_ice_sess_cand *cand = NULL;
+    unsigned i;
+    pj_status_t status;
+
+    /* Find relayed candidate in the component */
+    for (i=0; i<comp->cand_cnt; ++i) {
+	if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
+	    cand = &comp->cand_list[i];
+	    break;
+	}
+    }
+
+    /* If candidate is found, invalidate it first */
+    if (cand) {
+	cand->status = PJ_EPENDING;
+
+	/* Also if this component's default candidate is set to relay,
+	 * move it temporarily to something else.
+	 */
+	if ((int)comp->default_cand == cand - comp->cand_list) {
+	    /* Init to something */
+	    comp->default_cand = 0;
+	    /* Use srflx candidate as the default, if any */
+	    for (i=0; i<comp->cand_cnt; ++i) {
+		if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
+		    comp->default_cand = i;
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* Init TURN socket */
+    pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
+    turn_sock_cb.on_rx_data = &turn_on_rx_data;
+    turn_sock_cb.on_state = &turn_on_state;
+
+    /* Override with component specific QoS settings, if any */
+    if (ice_st->cfg.comp[comp->comp_id-1].qos_type) {
+	ice_st->cfg.turn.cfg.qos_type =
+	    ice_st->cfg.comp[comp->comp_id-1].qos_type;
+    }
+    if (ice_st->cfg.comp[comp->comp_id-1].qos_params.flags) {
+	pj_memcpy(&ice_st->cfg.turn.cfg.qos_params,
+		  &ice_st->cfg.comp[comp->comp_id-1].qos_params,
+		  sizeof(ice_st->cfg.turn.cfg.qos_params));
+    }
+
+    /* Override with component specific socket buffer size settings, if any */
+    if (ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size > 0) {
+	ice_st->cfg.turn.cfg.so_rcvbuf_size = 
+	    ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size;
+    }
+    if (ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size > 0) {
+	ice_st->cfg.turn.cfg.so_sndbuf_size = 
+	    ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size;
+    }
+
+    /* Create the TURN transport */
+    status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af,
+				 ice_st->cfg.turn.conn_type,
+				 &turn_sock_cb, &ice_st->cfg.turn.cfg,
+				 comp, &comp->turn_sock);
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
+
+    /* Add pending job */
+    ///sess_add_ref(ice_st);
+
+    /* Start allocation */
+    status=pj_turn_sock_alloc(comp->turn_sock,
+			      &ice_st->cfg.turn.server,
+			      ice_st->cfg.turn.port,
+			      ice_st->cfg.resolver,
+			      &ice_st->cfg.turn.auth_cred,
+			      &ice_st->cfg.turn.alloc_param);
+    if (status != PJ_SUCCESS) {
+	///sess_dec_ref(ice_st);
+	return status;
+    }
+
+    /* Add relayed candidate with pending status if there's no existing one */
+    if (cand == NULL) {
+	cand = &comp->cand_list[comp->cand_cnt++];
+	cand->type = PJ_ICE_CAND_TYPE_RELAYED;
+	cand->status = PJ_EPENDING;
+	cand->local_pref = RELAY_PREF;
+	cand->transport_id = TP_TURN;
+	cand->comp_id = (pj_uint8_t) comp->comp_id;
+    }
+
+    PJ_LOG(4,(ice_st->obj_name,
+		  "Comp %d: TURN relay candidate waiting for allocation",
+		  comp->comp_id));
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Create the component.
+ */
+static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id)
+{
+    pj_ice_strans_comp *comp = NULL;
+    pj_status_t status;
+
+    /* Verify arguments */
+    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
+
+    /* Check that component ID present */
+    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
+
+    /* Create component */
+    comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp);
+    comp->ice_st = ice_st;
+    comp->comp_id = comp_id;
+
+    ice_st->comp[comp_id-1] = comp;
+
+    /* Initialize default candidate */
+    comp->default_cand = 0;
+
+    /* Create STUN transport if configured */
+    if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) {
+	pj_stun_sock_cb stun_sock_cb;
+	pj_ice_sess_cand *cand;
+
+	pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
+	stun_sock_cb.on_rx_data = &stun_on_rx_data;
+	stun_sock_cb.on_status = &stun_on_status;
+	stun_sock_cb.on_data_sent = &stun_on_data_sent;
+	
+	/* Override component specific QoS settings, if any */
+	if (ice_st->cfg.comp[comp_id-1].qos_type) {
+	    ice_st->cfg.stun.cfg.qos_type = 
+		ice_st->cfg.comp[comp_id-1].qos_type;
+	}
+	if (ice_st->cfg.comp[comp_id-1].qos_params.flags) {
+	    pj_memcpy(&ice_st->cfg.stun.cfg.qos_params,
+		      &ice_st->cfg.comp[comp_id-1].qos_params,
+		      sizeof(ice_st->cfg.stun.cfg.qos_params));
+	}
+
+	/* Override component specific socket buffer size settings, if any */
+	if (ice_st->cfg.comp[comp_id-1].so_rcvbuf_size > 0) {
+	    ice_st->cfg.stun.cfg.so_rcvbuf_size = 
+		ice_st->cfg.comp[comp_id-1].so_rcvbuf_size;
+	}
+	if (ice_st->cfg.comp[comp_id-1].so_sndbuf_size > 0) {
+	    ice_st->cfg.stun.cfg.so_sndbuf_size = 
+		ice_st->cfg.comp[comp_id-1].so_sndbuf_size;
+	}
+
+	/* Create the STUN transport */
+	status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
+				     ice_st->cfg.af, &stun_sock_cb,
+				     &ice_st->cfg.stun.cfg,
+				     comp, &comp->stun_sock);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Start STUN Binding resolution and add srflx candidate 
+	 * only if server is set 
+	 */
+	if (ice_st->cfg.stun.server.slen) {
+	    pj_stun_sock_info stun_sock_info;
+
+	    /* Add pending job */
+	    ///sess_add_ref(ice_st);
+
+	    PJ_LOG(4,(ice_st->obj_name, 
+		      "Comp %d: srflx candidate starts Binding discovery",
+		      comp_id));
+
+	    pj_log_push_indent();
+
+	    /* Start Binding resolution */
+	    status = pj_stun_sock_start(comp->stun_sock, 
+					&ice_st->cfg.stun.server,
+					ice_st->cfg.stun.port, 
+					ice_st->cfg.resolver);
+	    if (status != PJ_SUCCESS) {
+		///sess_dec_ref(ice_st);
+		pj_log_pop_indent();
+		return status;
+	    }
+
+	    /* Enumerate addresses */
+	    status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
+	    if (status != PJ_SUCCESS) {
+		///sess_dec_ref(ice_st);
+		pj_log_pop_indent();
+		return status;
+	    }
+
+	    /* Add srflx candidate with pending status. */
+	    cand = &comp->cand_list[comp->cand_cnt++];
+	    cand->type = PJ_ICE_CAND_TYPE_SRFLX;
+	    cand->status = PJ_EPENDING;
+	    cand->local_pref = SRFLX_PREF;
+	    cand->transport_id = TP_STUN;
+	    cand->comp_id = (pj_uint8_t) comp_id;
+	    pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]);
+	    pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr);
+	    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
+				   cand->type, &cand->base_addr);
+
+	    /* Set default candidate to srflx */
+	    comp->default_cand = (unsigned)(cand - comp->cand_list);
+
+	    pj_log_pop_indent();
+	}
+
+	/* Add local addresses to host candidates, unless max_host_cands
+	 * is set to zero.
+	 */
+	if (ice_st->cfg.stun.max_host_cands) {
+	    pj_stun_sock_info stun_sock_info;
+	    unsigned i;
+
+	    /* Enumerate addresses */
+	    status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    for (i=0; i<stun_sock_info.alias_cnt && 
+		      i<ice_st->cfg.stun.max_host_cands; ++i) 
+	    {
+		char addrinfo[PJ_INET6_ADDRSTRLEN+10];
+		const pj_sockaddr *addr = &stun_sock_info.aliases[i];
+
+		/* Leave one candidate for relay */
+		if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) {
+		    PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
+		    break;
+		}
+
+		/* Ignore loopback addresses unless cfg->stun.loop_addr 
+		 * is set 
+		 */
+		if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) {
+		    if (ice_st->cfg.stun.loop_addr==PJ_FALSE)
+			continue;
+		}
+
+		cand = &comp->cand_list[comp->cand_cnt++];
+
+		cand->type = PJ_ICE_CAND_TYPE_HOST;
+		cand->status = PJ_SUCCESS;
+		cand->local_pref = HOST_PREF;
+		cand->transport_id = TP_STUN;
+		cand->comp_id = (pj_uint8_t) comp_id;
+		pj_sockaddr_cp(&cand->addr, addr);
+		pj_sockaddr_cp(&cand->base_addr, addr);
+		pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr));
+		pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
+				       cand->type, &cand->base_addr);
+
+		PJ_LOG(4,(ice_st->obj_name, 
+			  "Comp %d: host candidate %s added",
+			  comp_id, pj_sockaddr_print(&cand->addr, addrinfo,
+						     sizeof(addrinfo), 3)));
+	    }
+	}
+    }
+
+    /* Create TURN relay if configured. */
+    if (ice_st->cfg.turn.server.slen) {
+	add_update_turn(ice_st, comp);
+    }
+
+    /* It's possible that we end up without any candidates */
+    if (comp->cand_cnt == 0) {
+	PJ_LOG(4,(ice_st->obj_name,
+		  "Error: no candidate is created due to settings"));
+	return PJ_EINVAL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/* 
+ * Create ICE stream transport 
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
+					  const pj_ice_strans_cfg *cfg,
+					  unsigned comp_cnt,
+					  void *user_data,
+					  const pj_ice_strans_cb *cb,
+					  pj_ice_strans **p_ice_st)
+{
+    pj_pool_t *pool;
+    pj_ice_strans *ice_st;
+    unsigned i;
+    pj_status_t status;
+
+    status = pj_ice_strans_cfg_check_valid(cfg);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st &&
+		     comp_cnt <= PJ_ICE_MAX_COMP , PJ_EINVAL);
+
+    if (name == NULL)
+	name = "ice%p";
+
+    pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS,
+			  PJNATH_POOL_INC_ICE_STRANS, NULL);
+    ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans);
+    ice_st->pool = pool;
+    ice_st->obj_name = pool->obj_name;
+    ice_st->user_data = user_data;
+
+    PJ_LOG(4,(ice_st->obj_name, 
+	      "Creating ICE stream transport with %d component(s)",
+	      comp_cnt));
+    pj_log_push_indent();
+
+    status = pj_grp_lock_create(pool, NULL, &ice_st->grp_lock);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	pj_log_pop_indent();
+	return status;
+    }
+
+    pj_grp_lock_add_ref(ice_st->grp_lock);
+    pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st,
+			    &ice_st_on_destroy);
+
+    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
+    ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock;
+    ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock;
+    pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
+
+    ice_st->comp_cnt = comp_cnt;
+    ice_st->comp = (pj_ice_strans_comp**) 
+		   pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*));
+
+    /* Move state to candidate gathering */
+    ice_st->state = PJ_ICE_STRANS_STATE_INIT;
+
+    /* Acquire initialization mutex to prevent callback to be 
+     * called before we finish initialization.
+     */
+    pj_grp_lock_acquire(ice_st->grp_lock);
+
+    for (i=0; i<comp_cnt; ++i) {
+	status = create_comp(ice_st, i+1);
+	if (status != PJ_SUCCESS) {
+	    pj_grp_lock_release(ice_st->grp_lock);
+	    destroy_ice_st(ice_st);
+	    pj_log_pop_indent();
+	    return status;
+	}
+    }
+
+    /* Done with initialization */
+    pj_grp_lock_release(ice_st->grp_lock);
+
+    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p created", ice_st));
+
+    *p_ice_st = ice_st;
+
+    /* Check if all candidates are ready (this may call callback) */
+    sess_init_update(ice_st);
+
+    pj_log_pop_indent();
+
+    return PJ_SUCCESS;
+}
+
+/* REALLY destroy ICE */
+static void ice_st_on_destroy(void *obj)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)obj;
+
+    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p destroyed", obj));
+
+    /* Done */
+    pj_pool_release(ice_st->pool);
+}
+
+/* Destroy ICE */
+static void destroy_ice_st(pj_ice_strans *ice_st)
+{
+    unsigned i;
+
+    PJ_LOG(5,(ice_st->obj_name, "ICE stream transport %p destroy request..",
+	      ice_st));
+    pj_log_push_indent();
+
+    pj_grp_lock_acquire(ice_st->grp_lock);
+
+    if (ice_st->destroy_req) {
+	pj_grp_lock_release(ice_st->grp_lock);
+	return;
+    }
+
+    ice_st->destroy_req = PJ_TRUE;
+
+    /* Destroy ICE if we have ICE */
+    if (ice_st->ice) {
+	pj_ice_sess_destroy(ice_st->ice);
+	ice_st->ice = NULL;
+    }
+
+    /* Destroy all components */
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	if (ice_st->comp[i]) {
+	    if (ice_st->comp[i]->stun_sock) {
+		pj_stun_sock_destroy(ice_st->comp[i]->stun_sock);
+		ice_st->comp[i]->stun_sock = NULL;
+	    }
+	    if (ice_st->comp[i]->turn_sock) {
+		pj_turn_sock_destroy(ice_st->comp[i]->turn_sock);
+		ice_st->comp[i]->turn_sock = NULL;
+	    }
+	}
+    }
+
+    pj_grp_lock_dec_ref(ice_st->grp_lock);
+    pj_grp_lock_release(ice_st->grp_lock);
+
+    pj_log_pop_indent();
+}
+
+/* Get ICE session state. */
+PJ_DEF(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st)
+{
+    return ice_st->state;
+}
+
+/* State string */
+PJ_DEF(const char*) pj_ice_strans_state_name(pj_ice_strans_state state)
+{
+    const char *names[] = {
+	"Null",
+	"Candidate Gathering",
+	"Candidate Gathering Complete",
+	"Session Initialized",
+	"Negotiation In Progress",
+	"Negotiation Success",
+	"Negotiation Failed"
+    };
+
+    PJ_ASSERT_RETURN(state <= PJ_ICE_STRANS_STATE_FAILED, "???");
+    return names[state];
+}
+
+/* Notification about failure */
+static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op,
+		      const char *title, pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+
+    pj_strerror(status, errmsg, sizeof(errmsg));
+    PJ_LOG(4,(ice_st->obj_name, "%s: %s", title, errmsg));
+    pj_log_push_indent();
+
+    if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) {
+	pj_log_pop_indent();
+	return;
+    }
+
+    ice_st->cb_called = PJ_TRUE;
+
+    if (ice_st->cb.on_ice_complete)
+	(*ice_st->cb.on_ice_complete)(ice_st, op, status);
+
+    pj_log_pop_indent();
+}
+
+/* Update initialization status */
+static void sess_init_update(pj_ice_strans *ice_st)
+{
+    unsigned i;
+
+    /* Ignore if init callback has been called */
+    if (ice_st->cb_called)
+	return;
+
+    /* Notify application when all candidates have been gathered */
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	unsigned j;
+	pj_ice_strans_comp *comp = ice_st->comp[i];
+
+	for (j=0; j<comp->cand_cnt; ++j) {
+	    pj_ice_sess_cand *cand = &comp->cand_list[j];
+
+	    if (cand->status == PJ_EPENDING)
+		return;
+	}
+    }
+
+    /* All candidates have been gathered */
+    ice_st->cb_called = PJ_TRUE;
+    ice_st->state = PJ_ICE_STRANS_STATE_READY;
+    if (ice_st->cb.on_ice_complete)
+	(*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT, 
+				      PJ_SUCCESS);
+}
+
+/*
+ * Destroy ICE stream transport.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st)
+{
+    destroy_ice_st(ice_st);
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get user data
+ */
+PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st, NULL);
+    return ice_st->user_data;
+}
+
+
+/*
+ * Get the value of various options of the ICE stream transport.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_get_options( pj_ice_strans *ice_st,
+					       pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
+    pj_memcpy(opt, &ice_st->cfg.opt, sizeof(*opt));
+    return PJ_SUCCESS;
+}
+
+/*
+ * Specify various options for this ICE stream transport. 
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
+					      const pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
+    pj_memcpy(&ice_st->cfg.opt, opt, sizeof(*opt));
+    if (ice_st->ice)
+	pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
+    return PJ_SUCCESS;
+}
+
+/**
+ * Get the group lock for this ICE stream transport.
+ */
+PJ_DEF(pj_grp_lock_t *) pj_ice_strans_get_grp_lock(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st, NULL);
+    return ice_st->grp_lock;
+}
+
+/*
+ * Create ICE!
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
+					   pj_ice_sess_role role,
+					   const pj_str_t *local_ufrag,
+					   const pj_str_t *local_passwd)
+{
+    pj_status_t status;
+    unsigned i;
+    pj_ice_sess_cb ice_cb;
+    //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
+
+    /* Check arguments */
+    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+    /* Must not have ICE */
+    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
+    /* Components must have been created */
+    PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP);
+
+    /* Init callback */
+    pj_bzero(&ice_cb, sizeof(ice_cb));
+    ice_cb.on_ice_complete = &on_ice_complete;
+    ice_cb.on_rx_data = &ice_rx_data;
+    ice_cb.on_tx_pkt = &ice_tx_pkt;
+
+    /* Create! */
+    status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
+			        ice_st->comp_cnt, &ice_cb, 
+			        local_ufrag, local_passwd,
+			        ice_st->grp_lock,
+			        &ice_st->ice);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Associate user data */
+    ice_st->ice->user_data = (void*)ice_st;
+
+    /* Set options */
+    pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
+
+    /* If default candidate for components are SRFLX one, upload a custom
+     * type priority to ICE session so that SRFLX candidates will get
+     * checked first.
+     */
+    if (ice_st->comp[0]->default_cand >= 0 &&
+	ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type 
+	    == PJ_ICE_CAND_TYPE_SRFLX)
+    {
+	pj_ice_sess_set_prefs(ice_st->ice, srflx_pref_table);
+    }
+
+    /* Add components/candidates */
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	unsigned j;
+	pj_ice_strans_comp *comp = ice_st->comp[i];
+
+	/* Re-enable logging for Send/Data indications */
+	if (comp->turn_sock) {
+	    PJ_LOG(5,(ice_st->obj_name, 
+		      "Disabling STUN Indication logging for "
+		      "component %d", i+1));
+	    pj_turn_sock_set_log(comp->turn_sock, 0xFFFF);
+	    comp->turn_log_off = PJ_FALSE;
+	}
+
+	for (j=0; j<comp->cand_cnt; ++j) {
+	    pj_ice_sess_cand *cand = &comp->cand_list[j];
+	    unsigned ice_cand_id;
+
+	    /* Skip if candidate is not ready */
+	    if (cand->status != PJ_SUCCESS) {
+		PJ_LOG(5,(ice_st->obj_name, 
+			  "Candidate %d of comp %d is not added (pending)",
+			  j, i));
+		continue;
+	    }
+
+	    /* Must have address */
+	    pj_assert(pj_sockaddr_has_addr(&cand->addr));
+
+	    /* Add the candidate */
+	    status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id, 
+					  cand->transport_id, cand->type, 
+					  cand->local_pref, 
+					  &cand->foundation, &cand->addr, 
+					  &cand->base_addr,  &cand->rel_addr,
+					  pj_sockaddr_get_len(&cand->addr),
+					  (unsigned*)&ice_cand_id);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+    }
+
+    /* ICE session is ready for negotiation */
+    ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
+
+    return PJ_SUCCESS;
+
+on_error:
+    pj_ice_strans_stop_ice(ice_st);
+    return status;
+}
+
+/*
+ * Check if the ICE stream transport has the ICE session created. 
+ */
+PJ_DEF(pj_bool_t) pj_ice_strans_has_sess(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st, PJ_FALSE);
+    return ice_st->ice != NULL;
+}
+
+/*
+ * Check if ICE negotiation is still running.
+ */
+PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_running(pj_ice_strans *ice_st)
+{
+    return ice_st && ice_st->ice && ice_st->ice->rcand_cnt &&
+	   !pj_ice_strans_sess_is_complete(ice_st);
+}
+
+
+/*
+ * Check if ICE negotiation has completed.
+ */
+PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_complete(pj_ice_strans *ice_st)
+{
+    return ice_st && ice_st->ice && ice_st->ice->is_complete;
+}
+
+
+/*
+ * Get the current/running component count.
+ */
+PJ_DEF(unsigned) pj_ice_strans_get_running_comp_cnt(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+
+    if (ice_st->ice && ice_st->ice->rcand_cnt) {
+	return ice_st->ice->comp_cnt;
+    } else {
+	return ice_st->comp_cnt;
+    }
+}
+
+
+/*
+ * Get the ICE username fragment and password of the ICE session.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_get_ufrag_pwd( pj_ice_strans *ice_st,
+						 pj_str_t *loc_ufrag,
+						 pj_str_t *loc_pwd,
+						 pj_str_t *rem_ufrag,
+						 pj_str_t *rem_pwd)
+{
+    PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
+
+    if (loc_ufrag) *loc_ufrag = ice_st->ice->rx_ufrag;
+    if (loc_pwd) *loc_pwd = ice_st->ice->rx_pass;
+
+    if (rem_ufrag || rem_pwd) {
+	PJ_ASSERT_RETURN(ice_st->ice->rcand_cnt != 0, PJ_EINVALIDOP);
+	if (rem_ufrag) *rem_ufrag = ice_st->ice->tx_ufrag;
+	if (rem_pwd) *rem_pwd = ice_st->ice->tx_pass;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Get number of candidates
+ */
+PJ_DEF(unsigned) pj_ice_strans_get_cands_count(pj_ice_strans *ice_st,
+					       unsigned comp_id)
+{
+    unsigned i, cnt;
+
+    PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id && 
+		     comp_id <= ice_st->comp_cnt, 0);
+
+    cnt = 0;
+    for (i=0; i<ice_st->ice->lcand_cnt; ++i) {
+	if (ice_st->ice->lcand[i].comp_id != comp_id)
+	    continue;
+	++cnt;
+    }
+
+    return cnt;
+}
+
+/*
+ * Enum candidates
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
+					     unsigned comp_id,
+					     unsigned *count,
+					     pj_ice_sess_cand cand[])
+{
+    unsigned i, cnt;
+
+    PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id && 
+		     comp_id <= ice_st->comp_cnt && count && cand, PJ_EINVAL);
+
+    cnt = 0;
+    for (i=0; i<ice_st->ice->lcand_cnt && cnt<*count; ++i) {
+	if (ice_st->ice->lcand[i].comp_id != comp_id)
+	    continue;
+	pj_memcpy(&cand[cnt], &ice_st->ice->lcand[i],
+		  sizeof(pj_ice_sess_cand));
+	++cnt;
+    }
+
+    *count = cnt;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Get default candidate.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st,
+						unsigned comp_id,
+						pj_ice_sess_cand *cand)
+{
+    const pj_ice_sess_check *valid_pair;
+
+    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
+		      cand, PJ_EINVAL);
+
+    valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id);
+    if (valid_pair) {
+	pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand));
+    } else {
+	pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1];
+	pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt);
+	pj_memcpy(cand, &comp->cand_list[comp->default_cand], 
+		  sizeof(pj_ice_sess_cand));
+    }
+    return PJ_SUCCESS;
+}
+
+/*
+ * Get the current ICE role.
+ */
+PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN);
+    return ice_st->ice->role;
+}
+
+/*
+ * Change session role.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st,
+					       pj_ice_sess_role new_role)
+{
+    PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
+    return pj_ice_sess_change_role(ice_st->ice, new_role);
+}
+
+/*
+ * Start ICE processing !
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st,
+					     const pj_str_t *rem_ufrag,
+					     const pj_str_t *rem_passwd,
+					     unsigned rem_cand_cnt,
+					     const pj_ice_sess_cand rem_cand[])
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd &&
+		     rem_cand_cnt && rem_cand, PJ_EINVAL);
+
+    /* Mark start time */
+    pj_gettimeofday(&ice_st->start_time);
+
+    /* Build check list */
+    status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd,
+					   rem_cand_cnt, rem_cand);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* If we have TURN candidate, now is the time to create the permissions */
+    if (ice_st->comp[0]->turn_sock) {
+	unsigned i;
+
+	for (i=0; i<ice_st->comp_cnt; ++i) {
+	    pj_ice_strans_comp *comp = ice_st->comp[i];
+	    pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
+	    unsigned j, count=0;
+
+	    /* Gather remote addresses for this component */
+	    for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
+		if (rem_cand[j].comp_id==i+1) {
+		    pj_memcpy(&addrs[count++], &rem_cand[j].addr,
+			      pj_sockaddr_get_len(&rem_cand[j].addr));
+		}
+	    }
+
+	    if (count) {
+		status = pj_turn_sock_set_perm(comp->turn_sock, count, 
+					       addrs, 0);
+		if (status != PJ_SUCCESS) {
+		    pj_ice_strans_stop_ice(ice_st);
+		    return status;
+		}
+	    }
+	}
+    }
+
+    /* Start ICE negotiation! */
+    status = pj_ice_sess_start_check(ice_st->ice);
+    if (status != PJ_SUCCESS) {
+	pj_ice_strans_stop_ice(ice_st);
+	return status;
+    }
+
+    ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
+    return status;
+}
+
+/*
+ * Get valid pair.
+ */
+PJ_DEF(const pj_ice_sess_check*) 
+pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
+			     unsigned comp_id)
+{
+    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt,
+		     NULL);
+    
+    if (ice_st->ice == NULL)
+	return NULL;
+    
+    return ice_st->ice->comp[comp_id-1].valid_check;
+}
+
+/*
+ * Stop ICE!
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
+{
+    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+
+    if (ice_st->ice) {
+	pj_ice_sess_destroy(ice_st->ice);
+	ice_st->ice = NULL;
+    }
+
+    ice_st->state = PJ_ICE_STRANS_STATE_INIT;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Application wants to send outgoing packet.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
+					  unsigned comp_id,
+					  const void *data,
+					  pj_size_t data_len,
+					  const pj_sockaddr_t *dst_addr,
+					  int dst_addr_len)
+{
+    pj_ssize_t pkt_size;
+    pj_ice_strans_comp *comp;
+    unsigned def_cand;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
+		     dst_addr && dst_addr_len, PJ_EINVAL);
+
+    comp = ice_st->comp[comp_id-1];
+
+    /* Check that default candidate for the component exists */
+    def_cand = comp->default_cand;
+    if (def_cand >= comp->cand_cnt)
+	return PJ_EINVALIDOP;
+
+    /* If ICE is available, send data with ICE, otherwise send with the
+     * default candidate selected during initialization.
+     *
+     * https://trac.pjsip.org/repos/ticket/1416:
+     * Once ICE has failed, also send data with the default candidate.
+     */
+    if (ice_st->ice && ice_st->state == PJ_ICE_STRANS_STATE_RUNNING) {
+	if (comp->turn_sock) {
+	    pj_turn_sock_lock(comp->turn_sock);
+	}
+	status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
+	if (comp->turn_sock) {
+	    pj_turn_sock_unlock(comp->turn_sock);
+	}
+	return status;
+
+    } else if (comp->cand_list[def_cand].status == PJ_SUCCESS) {
+
+	if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) {
+
+	    enum {
+		msg_disable_ind = 0xFFFF &
+				  ~(PJ_STUN_SESS_LOG_TX_IND|
+				    PJ_STUN_SESS_LOG_RX_IND)
+	    };
+
+	    /* https://trac.pjsip.org/repos/ticket/1316 */
+	    if (comp->turn_sock == NULL) {
+		/* TURN socket error */
+		return PJ_EINVALIDOP;
+	    }
+
+	    if (!comp->turn_log_off) {
+		/* Disable logging for Send/Data indications */
+		PJ_LOG(5,(ice_st->obj_name, 
+			  "Disabling STUN Indication logging for "
+			  "component %d", comp->comp_id));
+		pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind);
+		comp->turn_log_off = PJ_TRUE;
+	    }
+
+	    status = pj_turn_sock_sendto(comp->turn_sock, 
+					 (const pj_uint8_t*)data, 
+					 (unsigned)data_len,
+					 dst_addr, dst_addr_len);
+	    return (status==PJ_SUCCESS||status==PJ_EPENDING) ? 
+		    PJ_SUCCESS : status;
+	} else {
+	    pkt_size = data_len;
+	    status = pj_stun_sock_sendto(comp->stun_sock, NULL, data, 
+					 (unsigned)data_len, 0, dst_addr, 
+					 dst_addr_len);
+	    return (status==PJ_SUCCESS||status==PJ_EPENDING) ? 
+		    PJ_SUCCESS : status;
+	}
+
+    } else
+	return PJ_EINVALIDOP;
+}
+
+/*
+ * Callback called by ICE session when ICE processing is complete, either
+ * successfully or with failure.
+ */
+static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
+    pj_time_val t;
+    unsigned msec;
+
+    pj_grp_lock_add_ref(ice_st->grp_lock);
+
+    pj_gettimeofday(&t);
+    PJ_TIME_VAL_SUB(t, ice_st->start_time);
+    msec = PJ_TIME_VAL_MSEC(t);
+
+    if (ice_st->cb.on_ice_complete) {
+	if (status != PJ_SUCCESS) {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    PJ_LOG(4,(ice_st->obj_name, 
+		      "ICE negotiation failed after %ds:%03d: %s", 
+		      msec/1000, msec%1000, errmsg));
+	} else {
+	    unsigned i;
+	    enum {
+		msg_disable_ind = 0xFFFF &
+				  ~(PJ_STUN_SESS_LOG_TX_IND|
+				    PJ_STUN_SESS_LOG_RX_IND)
+	    };
+
+	    PJ_LOG(4,(ice_st->obj_name, 
+		      "ICE negotiation success after %ds:%03d",
+		      msec/1000, msec%1000));
+
+	    for (i=0; i<ice_st->comp_cnt; ++i) {
+		const pj_ice_sess_check *check;
+
+		check = pj_ice_strans_get_valid_pair(ice_st, i+1);
+		if (check) {
+		    char lip[PJ_INET6_ADDRSTRLEN+10];
+		    char rip[PJ_INET6_ADDRSTRLEN+10];
+
+		    pj_sockaddr_print(&check->lcand->addr, lip, 
+				      sizeof(lip), 3);
+		    pj_sockaddr_print(&check->rcand->addr, rip, 
+				      sizeof(rip), 3);
+
+		    if (check->lcand->transport_id == TP_TURN) {
+			/* Activate channel binding for the remote address
+			 * for more efficient data transfer using TURN.
+			 */
+			status = pj_turn_sock_bind_channel(
+					ice_st->comp[i]->turn_sock,
+					&check->rcand->addr,
+					sizeof(check->rcand->addr));
+
+			/* Disable logging for Send/Data indications */
+			PJ_LOG(5,(ice_st->obj_name, 
+				  "Disabling STUN Indication logging for "
+				  "component %d", i+1));
+			pj_turn_sock_set_log(ice_st->comp[i]->turn_sock,
+					     msg_disable_ind);
+			ice_st->comp[i]->turn_log_off = PJ_TRUE;
+		    }
+
+		    PJ_LOG(4,(ice_st->obj_name, " Comp %d: "
+			      "sending from %s candidate %s to "
+			      "%s candidate %s",
+			      i+1, 
+			      pj_ice_get_cand_type_name(check->lcand->type),
+			      lip,
+			      pj_ice_get_cand_type_name(check->rcand->type),
+			      rip));
+			      
+		} else {
+		    PJ_LOG(4,(ice_st->obj_name, 
+			      "Comp %d: disabled", i+1));
+		}
+	    }
+	}
+
+	ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
+					       PJ_ICE_STRANS_STATE_FAILED;
+
+	pj_log_push_indent();
+	(*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, 
+				      status);
+	pj_log_pop_indent();
+	
+    }
+
+    pj_grp_lock_dec_ref(ice_st->grp_lock);
+}
+
+/*
+ * Callback called by ICE session when it wants to send outgoing packet.
+ */
+static pj_status_t ice_tx_pkt(pj_ice_sess *ice, 
+			      unsigned comp_id, 
+			      unsigned transport_id,
+			      const void *pkt, pj_size_t size,
+			      const pj_sockaddr_t *dst_addr,
+			      unsigned dst_addr_len)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
+    pj_ice_strans_comp *comp;
+    pj_status_t status;
+#if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
+    char daddr[PJ_INET6_ADDRSTRLEN];
+#endif
+
+    PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
+
+    comp = ice_st->comp[comp_id-1];
+
+    TRACE_PKT((comp->ice_st->obj_name, 
+	       "Component %d TX packet to %s:%d with transport %d",
+	       comp_id, 
+	       pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 0),
+	       pj_sockaddr_get_port(dst_addr),
+	       transport_id));
+
+    if (transport_id == TP_TURN) {
+	if (comp->turn_sock) {
+	    status = pj_turn_sock_sendto(comp->turn_sock, 
+					 (const pj_uint8_t*)pkt, 
+					 (unsigned)size,
+					 dst_addr, dst_addr_len);
+	} else {
+	    status = PJ_EINVALIDOP;
+	}
+    } else if (transport_id == TP_STUN) {
+	status = pj_stun_sock_sendto(comp->stun_sock, NULL, 
+				     pkt, (unsigned)size, 0,
+				     dst_addr, dst_addr_len);
+    } else {
+	pj_assert(!"Invalid transport ID");
+	status = PJ_EINVALIDOP;
+    }
+    
+    return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
+}
+
+/*
+ * Callback called by ICE session when it receives application data.
+ */
+static void ice_rx_data(pj_ice_sess *ice, 
+		        unsigned comp_id, 
+			unsigned transport_id,
+		        void *pkt, pj_size_t size,
+		        const pj_sockaddr_t *src_addr,
+		        unsigned src_addr_len)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
+
+    PJ_UNUSED_ARG(transport_id);
+
+    if (ice_st->cb.on_rx_data) {
+	(*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size, 
+				 src_addr, src_addr_len);
+    }
+}
+
+/* Notification when incoming packet has been received from
+ * the STUN socket. 
+ */
+static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
+				 void *pkt,
+				 unsigned pkt_len,
+				 const pj_sockaddr_t *src_addr,
+				 unsigned addr_len)
+{
+    pj_ice_strans_comp *comp;
+    pj_ice_strans *ice_st;
+    pj_status_t status;
+
+    comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
+    if (comp == NULL) {
+	/* We have disassociated ourselves from the STUN socket */
+	return PJ_FALSE;
+    }
+
+    ice_st = comp->ice_st;
+
+    pj_grp_lock_add_ref(ice_st->grp_lock);
+
+    if (ice_st->ice == NULL) {
+	/* The ICE session is gone, but we're still receiving packets.
+	 * This could also happen if remote doesn't do ICE. So just
+	 * report this to application.
+	 */
+	if (ice_st->cb.on_rx_data) {
+	    (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len, 
+				     src_addr, addr_len);
+	}
+
+    } else {
+
+	/* Hand over the packet to ICE session */
+	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 
+				       TP_STUN, pkt, pkt_len,
+				       src_addr, addr_len);
+
+	if (status != PJ_SUCCESS) {
+	    ice_st_perror(comp->ice_st, "Error processing packet", 
+			  status);
+	}
+    }
+
+    return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
+}
+
+/* Notifification when asynchronous send operation to the STUN socket
+ * has completed. 
+ */
+static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
+				   pj_ioqueue_op_key_t *send_key,
+				   pj_ssize_t sent)
+{
+    PJ_UNUSED_ARG(stun_sock);
+    PJ_UNUSED_ARG(send_key);
+    PJ_UNUSED_ARG(sent);
+    return PJ_TRUE;
+}
+
+/* Notification when the status of the STUN transport has changed. */
+static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, 
+				pj_stun_sock_op op,
+				pj_status_t status)
+{
+    pj_ice_strans_comp *comp;
+    pj_ice_strans *ice_st;
+    pj_ice_sess_cand *cand = NULL;
+    unsigned i;
+
+    pj_assert(status != PJ_EPENDING);
+
+    comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
+    ice_st = comp->ice_st;
+
+    pj_grp_lock_add_ref(ice_st->grp_lock);
+
+    /* Wait until initialization completes */
+    pj_grp_lock_acquire(ice_st->grp_lock);
+
+    /* Find the srflx cancidate */
+    for (i=0; i<comp->cand_cnt; ++i) {
+	if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
+	    cand = &comp->cand_list[i];
+	    break;
+	}
+    }
+
+    pj_grp_lock_release(ice_st->grp_lock);
+
+    /* It is possible that we don't have srflx candidate even though this
+     * callback is called. This could happen when we cancel adding srflx
+     * candidate due to initialization error.
+     */
+    if (cand == NULL) {
+	return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
+    }
+
+    switch (op) {
+    case PJ_STUN_SOCK_DNS_OP:
+	if (status != PJ_SUCCESS) {
+	    /* May not have cand, e.g. when error during init */
+	    if (cand)
+		cand->status = status;
+	    if (!ice_st->cfg.stun.ignore_stun_error) {
+		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
+		          "DNS resolution failed", status);
+	    } else {
+		PJ_LOG(4,(ice_st->obj_name,
+			  "STUN error is ignored for comp %d",
+			  comp->comp_id));
+	    }
+	}
+	break;
+    case PJ_STUN_SOCK_BINDING_OP:
+    case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
+	if (status == PJ_SUCCESS) {
+	    pj_stun_sock_info info;
+
+	    status = pj_stun_sock_get_info(stun_sock, &info);
+	    if (status == PJ_SUCCESS) {
+		char ipaddr[PJ_INET6_ADDRSTRLEN+10];
+		const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
+				    "Binding discovery complete" :
+				    "srflx address changed";
+		pj_bool_t dup = PJ_FALSE;
+
+		/* Eliminate the srflx candidate if the address is
+		 * equal to other (host) candidates.
+		 */
+		for (i=0; i<comp->cand_cnt; ++i) {
+		    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST &&
+			pj_sockaddr_cmp(&comp->cand_list[i].addr,
+					&info.mapped_addr) == 0)
+		    {
+			dup = PJ_TRUE;
+			break;
+		    }
+		}
+
+		if (dup) {
+		    /* Duplicate found, remove the srflx candidate */
+		    unsigned idx = (unsigned)(cand - comp->cand_list);
+
+		    /* Update default candidate index */
+		    if (comp->default_cand > idx) {
+			--comp->default_cand;
+		    } else if (comp->default_cand == idx) {
+			comp->default_cand = 0;
+		    }
+
+		    /* Remove srflx candidate */
+		    pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]),
+				   comp->cand_cnt, idx);
+		    --comp->cand_cnt;
+		} else {
+		    /* Otherwise update the address */
+		    pj_sockaddr_cp(&cand->addr, &info.mapped_addr);
+		    cand->status = PJ_SUCCESS;
+		}
+
+		PJ_LOG(4,(comp->ice_st->obj_name, 
+			  "Comp %d: %s, "
+			  "srflx address is %s",
+			  comp->comp_id, op_name, 
+			  pj_sockaddr_print(&info.mapped_addr, ipaddr, 
+					     sizeof(ipaddr), 3)));
+
+		sess_init_update(ice_st);
+	    }
+	}
+
+	if (status != PJ_SUCCESS) {
+	    /* May not have cand, e.g. when error during init */
+	    if (cand)
+		cand->status = status;
+	    if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) {
+		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
+			  "STUN binding request failed", status);
+	    } else {
+		PJ_LOG(4,(ice_st->obj_name,
+			  "STUN error is ignored for comp %d",
+			  comp->comp_id));
+
+		if (cand) {
+		    unsigned idx = (unsigned)(cand - comp->cand_list);
+
+		    /* Update default candidate index */
+		    if (comp->default_cand == idx) {
+			comp->default_cand = !idx;
+		    }
+		}
+
+		sess_init_update(ice_st);
+	    }
+	}
+	break;
+    case PJ_STUN_SOCK_KEEP_ALIVE_OP:
+	if (status != PJ_SUCCESS) {
+	    pj_assert(cand != NULL);
+	    cand->status = status;
+	    if (!ice_st->cfg.stun.ignore_stun_error) {
+		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
+			  "STUN keep-alive failed", status);
+	    } else {
+		PJ_LOG(4,(ice_st->obj_name, "STUN error is ignored"));
+	    }
+	}
+	break;
+    }
+
+    return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
+}
+
+/* Callback when TURN socket has received a packet */
+static void turn_on_rx_data(pj_turn_sock *turn_sock,
+			    void *pkt,
+			    unsigned pkt_len,
+			    const pj_sockaddr_t *peer_addr,
+			    unsigned addr_len)
+{
+    pj_ice_strans_comp *comp;
+    pj_status_t status;
+
+    comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
+    if (comp == NULL) {
+	/* We have disassociated ourselves from the TURN socket */
+	return;
+    }
+
+    pj_grp_lock_add_ref(comp->ice_st->grp_lock);
+
+    if (comp->ice_st->ice == NULL) {
+	/* The ICE session is gone, but we're still receiving packets.
+	 * This could also happen if remote doesn't do ICE and application
+	 * specifies TURN as the default address in SDP.
+	 * So in this case just give the packet to application.
+	 */
+	if (comp->ice_st->cb.on_rx_data) {
+	    (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt,
+					   pkt_len, peer_addr, addr_len);
+	}
+
+    } else {
+
+	/* Hand over the packet to ICE */
+	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
+				       TP_TURN, pkt, pkt_len,
+				       peer_addr, addr_len);
+
+	if (status != PJ_SUCCESS) {
+	    ice_st_perror(comp->ice_st, 
+			  "Error processing packet from TURN relay", 
+			  status);
+	}
+    }
+
+    pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
+}
+
+
+/* Callback when TURN client state has changed */
+static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
+			  pj_turn_state_t new_state)
+{
+    pj_ice_strans_comp *comp;
+
+    comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
+    if (comp == NULL) {
+	/* Not interested in further state notification once the relay is
+	 * disconnecting.
+	 */
+	return;
+    }
+
+    PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
+	      pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
+    pj_log_push_indent();
+
+    pj_grp_lock_add_ref(comp->ice_st->grp_lock);
+
+    if (new_state == PJ_TURN_STATE_READY) {
+	pj_turn_session_info rel_info;
+	char ipaddr[PJ_INET6_ADDRSTRLEN+8];
+	pj_ice_sess_cand *cand = NULL;
+	unsigned i;
+
+	comp->turn_err_cnt = 0;
+
+	/* Get allocation info */
+	pj_turn_sock_get_info(turn_sock, &rel_info);
+
+	/* Wait until initialization completes */
+	pj_grp_lock_acquire(comp->ice_st->grp_lock);
+
+	/* Find relayed candidate in the component */
+	for (i=0; i<comp->cand_cnt; ++i) {
+	    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
+		cand = &comp->cand_list[i];
+		break;
+	    }
+	}
+	pj_assert(cand != NULL);
+
+	pj_grp_lock_release(comp->ice_st->grp_lock);
+
+	/* Update candidate */
+	pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
+	pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr);
+	pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr);
+	pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation, 
+			       PJ_ICE_CAND_TYPE_RELAYED, 
+			       &rel_info.relay_addr);
+	cand->status = PJ_SUCCESS;
+
+	/* Set default candidate to relay */
+	comp->default_cand = (unsigned)(cand - comp->cand_list);
+
+	PJ_LOG(4,(comp->ice_st->obj_name, 
+		  "Comp %d: TURN allocation complete, relay address is %s",
+		  comp->comp_id, 
+		  pj_sockaddr_print(&rel_info.relay_addr, ipaddr, 
+				     sizeof(ipaddr), 3)));
+
+	sess_init_update(comp->ice_st);
+
+    } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
+	pj_turn_session_info info;
+
+	++comp->turn_err_cnt;
+
+	pj_turn_sock_get_info(turn_sock, &info);
+
+	/* Unregister ourself from the TURN relay */
+	pj_turn_sock_set_user_data(turn_sock, NULL);
+	comp->turn_sock = NULL;
+
+	/* Set session to fail on error. last_status PJ_SUCCESS means normal
+	 * deallocation, which should not trigger sess_fail as it may have
+	 * been initiated by ICE destroy
+	 */
+	if (info.last_status != PJ_SUCCESS) {
+	    if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
+		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
+			  "TURN allocation failed", info.last_status);
+	    } else if (comp->turn_err_cnt > 1) {
+		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
+			  "TURN refresh failed", info.last_status);
+	    } else {
+		PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
+			  "Comp %d: TURN allocation failed, retrying",
+			  comp->comp_id));
+		add_update_turn(comp->ice_st, comp);
+	    }
+	}
+    }
+
+    pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
+
+    pj_log_pop_indent();
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/94/940e32f044810ab0b6ac1e1058e2c9ae691da9d7.svn-base b/jni/pjproject-android/.svn/pristine/94/940e32f044810ab0b6ac1e1058e2c9ae691da9d7.svn-base
new file mode 100644
index 0000000..edbc42f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/940e32f044810ab0b6ac1e1058e2c9ae691da9d7.svn-base
@@ -0,0 +1 @@
+#include "../../../portaudio/src/hostapi/coreaudio/pa_mac_core_old.c"
diff --git a/jni/pjproject-android/.svn/pristine/94/943f5ca384931ecce84ed8c14f5eb174c4487c5d.svn-base b/jni/pjproject-android/.svn/pristine/94/943f5ca384931ecce84ed8c14f5eb174c4487c5d.svn-base
new file mode 100644
index 0000000..1e98332
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/943f5ca384931ecce84ed8c14f5eb174c4487c5d.svn-base
@@ -0,0 +1,818 @@
+/* $Id$
+ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJ_IOQUEUE_H__
+#define __PJ_IOQUEUE_H__
+
+/**
+ * @file ioqueue.h
+ * @brief I/O Dispatching Mechanism
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_IO Input/Output
+ * @brief Input/Output
+ * @ingroup PJ_OS
+ *
+ * This section contains API building blocks to perform network I/O and 
+ * communications. If provides:
+ *  - @ref PJ_SOCK
+ *\n
+ *    A highly portable socket abstraction, runs on all kind of
+ *    network APIs such as standard BSD socket, Windows socket, Linux
+ *    \b kernel socket, PalmOS networking API, etc.
+ *
+ *  - @ref pj_addr_resolve
+ *\n
+ *    Portable address resolution, which implements #pj_gethostbyname().
+ *
+ *  - @ref PJ_SOCK_SELECT
+ *\n
+ *    A portable \a select() like API (#pj_sock_select()) which can be
+ *    implemented with various back-ends.
+ *
+ *  - @ref PJ_IOQUEUE
+ *\n
+ *    Framework for dispatching network events.
+ *
+ * For more information see the modules below.
+ */
+
+/**
+ * @defgroup PJ_IOQUEUE IOQueue: I/O Event Dispatching with Proactor Pattern
+ * @ingroup PJ_IO
+ * @{
+ *
+ * I/O Queue provides API for performing asynchronous I/O operations. It
+ * conforms to proactor pattern, which allows application to submit an
+ * asynchronous operation and to be notified later when the operation has
+ * completed.
+ *
+ * The I/O Queue can work on both socket and file descriptors. For 
+ * asynchronous file operations however, one must make sure that the correct
+ * file I/O back-end is used, because not all file I/O back-end can be
+ * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.
+ *
+ * The framework works natively in platforms where asynchronous operation API
+ * exists, such as in Windows NT with IoCompletionPort/IOCP. In other 
+ * platforms, the I/O queue abstracts the operating system's event poll API
+ * to provide semantics similar to IoCompletionPort with minimal penalties
+ * (i.e. per ioqueue and per handle mutex protection).
+ *
+ * The I/O queue provides more than just unified abstraction. It also:
+ *  - makes sure that the operation uses the most effective way to utilize
+ *    the underlying mechanism, to achieve the maximum theoritical
+ *    throughput possible on a given platform.
+ *  - choose the most efficient mechanism for event polling on a given
+ *    platform.
+ *
+ * Currently, the I/O Queue is implemented using:
+ *  - <tt><b>select()</b></tt>, as the common denominator, but the least 
+ *    efficient. Also the number of descriptor is limited to 
+ *    \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).
+ *  - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), 
+ *    a much faster replacement for select() on Linux (and more importantly
+ *    doesn't have limitation on number of descriptors).
+ *  - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most 
+ *    efficient way to dispatch events in Windows NT based OSes, and most 
+ *    importantly, it doesn't have the limit on how many handles to monitor.
+ *    And it works with files (not only sockets) as well.
+ *
+ *
+ * \section pj_ioqueue_concurrency_sec Concurrency Rules
+ *
+ * The ioqueue has been fine tuned to allow multiple threads to poll the
+ * handles simultaneously, to maximize scalability when the application is
+ * running on multiprocessor systems. When more than one threads are polling
+ * the ioqueue and there are more than one handles are signaled, more than
+ * one threads will execute the callback simultaneously to serve the events.
+ * These parallel executions are completely safe when the events happen for
+ * two different handles.
+ *
+ * However, with multithreading, care must be taken when multiple events 
+ * happen on the same handle, or when event is happening on a handle (and 
+ * the callback is being executed) and application is performing 
+ * unregistration to the handle at the same time.
+ *
+ * The treatments of above scenario differ according to the concurrency
+ * setting that are applied to the handle.
+ *
+ * \subsection pj_ioq_concur_set Concurrency Settings for Handles
+ *
+ * Concurrency can be set on per handle (key) basis, by using
+ * #pj_ioqueue_set_concurrency() function. The default key concurrency value 
+ * for the handle is inherited from the key concurrency setting of the ioqueue, 
+ * and the key concurrency setting for the ioqueue can be changed by using
+ * #pj_ioqueue_set_default_concurrency(). The default key concurrency setting 
+ * for ioqueue itself is controlled by compile time setting
+ * PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY.
+ *
+ * Note that this key concurrency setting only controls whether multiple
+ * threads are allowed to operate <b>on the same key</b> at the same time. 
+ * The ioqueue itself always allows multiple threads to enter the ioqeuue at 
+ * the same time, and also simultaneous callback calls to <b>differrent 
+ * keys</b> is always allowed regardless to the key concurrency setting.
+ *
+ * \subsection pj_ioq_parallel Parallel Callback Executions for the Same Handle
+ *
+ * Note that when key concurrency is enabled (i.e. parallel callback calls on
+ * the same key is allowed; this is the default setting), the ioqueue will only
+ * perform simultaneous callback executions on the same key when the key has
+ * invoked multiple pending operations. This could be done for example by
+ * calling #pj_ioqueue_recvfrom() more than once on the same key, each with
+ * the same key but different operation key (pj_ioqueue_op_key_t). With this
+ * scenario, when multiple packets arrive on the key at the same time, more
+ * than one threads may execute the callback simultaneously, each with the
+ * same key but different operation key.
+ *
+ * When there is only one pending operation on the key (e.g. there is only one
+ * #pj_ioqueue_recvfrom() invoked on the key), then events occuring to the
+ * same key will be queued by the ioqueue, thus no simultaneous callback calls
+ * will be performed.
+ *
+ * \subsection pj_ioq_allow_concur Concurrency is Enabled (Default Value)
+ *
+ * The default setting for the ioqueue is to allow multiple threads to
+ * execute callbacks for the same handle/key. This setting is selected to
+ * promote good performance and scalability for application.
+ *
+ * However this setting has a major drawback with regard to synchronization,
+ * and application MUST carefully follow the following guidelines to ensure 
+ * that parallel access to the key does not cause problems:
+ *
+ *  - Always note that callback may be called simultaneously for the same
+ *    key.
+ *  - <b>Care must be taken when unregistering a key</b> from the
+ *    ioqueue. Application must take care that when one thread is issuing
+ *    an unregistration, other thread is not simultaneously invoking the
+ *    callback <b>to the same key</b>.
+ *\n
+ *    This happens because the ioqueue functions are working with a pointer
+ *    to the key, and there is a possible race condition where the pointer
+ *    has been rendered invalid by other threads before the ioqueue has a
+ *    chance to acquire mutex on it.
+ *
+ * \subsection pj_ioq_disallow_concur Concurrency is Disabled
+ *
+ * Alternatively, application may disable key concurrency to make 
+ * synchronization easier. As noted above, there are three ways to control
+ * key concurrency setting:
+ *  - by controlling on per handle/key basis, with #pj_ioqueue_set_concurrency().
+ *  - by changing default key concurrency setting on the ioqueue, with
+ *    #pj_ioqueue_set_default_concurrency().
+ *  - by changing the default concurrency on compile time, by declaring
+ *    PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY macro to zero in your config_site.h
+ *
+ * \section pj_ioqeuue_examples_sec Examples
+ *
+ * For some examples on how to use the I/O Queue, please see:
+ *
+ *  - \ref page_pjlib_ioqueue_tcp_test
+ *  - \ref page_pjlib_ioqueue_udp_test
+ *  - \ref page_pjlib_ioqueue_perf_test
+ */
+
+
+/**
+ * This structure describes operation specific key to be submitted to
+ * I/O Queue when performing the asynchronous operation. This key will
+ * be returned to the application when completion callback is called.
+ *
+ * Application normally wants to attach it's specific data in the
+ * \c user_data field so that it can keep track of which operation has
+ * completed when the callback is called. Alternatively, application can
+ * also extend this struct to include its data, because the pointer that
+ * is returned in the completion callback will be exactly the same as
+ * the pointer supplied when the asynchronous function is called.
+ */
+typedef struct pj_ioqueue_op_key_t
+{ 
+    void *internal__[32];           /**< Internal I/O Queue data.   */
+    void *activesock_data;	    /**< Active socket data.	    */
+    void *user_data;                /**< Application data.          */
+} pj_ioqueue_op_key_t;
+
+/**
+ * This structure describes the callbacks to be called when I/O operation
+ * completes.
+ */
+typedef struct pj_ioqueue_callback
+{
+    /**
+     * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom
+     * completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param bytes_read    >= 0 to indicate the amount of data read, 
+     *                      otherwise negative value containing the error
+     *                      code. To obtain the pj_status_t error code, use
+     *                      (pj_status_t code = -bytes_read).
+     */
+    void (*on_read_complete)(pj_ioqueue_key_t *key, 
+                             pj_ioqueue_op_key_t *op_key, 
+                             pj_ssize_t bytes_read);
+
+    /**
+     * This callback is called when #pj_ioqueue_send or #pj_ioqueue_sendto
+     * completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param bytes_sent    >= 0 to indicate the amount of data written, 
+     *                      otherwise negative value containing the error
+     *                      code. To obtain the pj_status_t error code, use
+     *                      (pj_status_t code = -bytes_sent).
+     */
+    void (*on_write_complete)(pj_ioqueue_key_t *key, 
+                              pj_ioqueue_op_key_t *op_key, 
+                              pj_ssize_t bytes_sent);
+
+    /**
+     * This callback is called when #pj_ioqueue_accept completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param sock          Newly connected socket.
+     * @param status	    Zero if the operation completes successfully.
+     */
+    void (*on_accept_complete)(pj_ioqueue_key_t *key, 
+                               pj_ioqueue_op_key_t *op_key, 
+                               pj_sock_t sock, 
+                               pj_status_t status);
+
+    /**
+     * This callback is called when #pj_ioqueue_connect completes.
+     *
+     * @param key	    The key.
+     * @param status	    PJ_SUCCESS if the operation completes successfully.
+     */
+    void (*on_connect_complete)(pj_ioqueue_key_t *key, 
+                                pj_status_t status);
+} pj_ioqueue_callback;
+
+
+/**
+ * Types of pending I/O Queue operation. This enumeration is only used
+ * internally within the ioqueue.
+ */
+typedef enum pj_ioqueue_operation_e
+{
+    PJ_IOQUEUE_OP_NONE		= 0,	/**< No operation.          */
+    PJ_IOQUEUE_OP_READ		= 1,	/**< read() operation.      */
+    PJ_IOQUEUE_OP_RECV          = 2,    /**< recv() operation.      */
+    PJ_IOQUEUE_OP_RECV_FROM	= 4,	/**< recvfrom() operation.  */
+    PJ_IOQUEUE_OP_WRITE		= 8,	/**< write() operation.     */
+    PJ_IOQUEUE_OP_SEND          = 16,   /**< send() operation.      */
+    PJ_IOQUEUE_OP_SEND_TO	= 32,	/**< sendto() operation.    */
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+    PJ_IOQUEUE_OP_ACCEPT	= 64,	/**< accept() operation.    */
+    PJ_IOQUEUE_OP_CONNECT	= 128	/**< connect() operation.   */
+#endif	/* PJ_HAS_TCP */
+} pj_ioqueue_operation_e;
+
+
+/**
+ * This macro specifies the maximum number of events that can be
+ * processed by the ioqueue on a single poll cycle, on implementation
+ * that supports it. The value is only meaningfull when specified
+ * during PJLIB build.
+ */
+#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL
+#   define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL     (16)
+#endif
+
+/**
+ * When this flag is specified in ioqueue's recv() or send() operations,
+ * the ioqueue will always mark the operation as asynchronous.
+ */
+#define PJ_IOQUEUE_ALWAYS_ASYNC	    ((pj_uint32_t)1 << (pj_uint32_t)31)
+
+/**
+ * Return the name of the ioqueue implementation.
+ *
+ * @return		Implementation name.
+ */
+PJ_DECL(const char*) pj_ioqueue_name(void);
+
+
+/**
+ * Create a new I/O Queue framework.
+ *
+ * @param pool		The pool to allocate the I/O queue structure. 
+ * @param max_fd	The maximum number of handles to be supported, which 
+ *			should not exceed PJ_IOQUEUE_MAX_HANDLES.
+ * @param ioqueue	Pointer to hold the newly created I/O Queue.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+					pj_size_t max_fd,
+					pj_ioqueue_t **ioqueue);
+
+/**
+ * Destroy the I/O queue.
+ *
+ * @param ioque	        The I/O Queue to be destroyed.
+ *
+ * @return              PJ_SUCCESS if success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );
+
+/**
+ * Set the lock object to be used by the I/O Queue. This function can only
+ * be called right after the I/O queue is created, before any handle is
+ * registered to the I/O queue.
+ *
+ * Initially the I/O queue is created with non-recursive mutex protection. 
+ * Applications can supply alternative lock to be used by calling this 
+ * function.
+ *
+ * @param ioque         The ioqueue instance.
+ * @param lock          The lock to be used by the ioqueue.
+ * @param auto_delete   In non-zero, the lock will be deleted by the ioqueue.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
+					  pj_lock_t *lock,
+					  pj_bool_t auto_delete );
+
+/**
+ * Set default concurrency policy for this ioqueue. If this function is not
+ * called, the default concurrency policy for the ioqueue is controlled by 
+ * compile time setting PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY.
+ *
+ * Note that changing the concurrency setting to the ioqueue will only affect
+ * subsequent key registrations. To modify the concurrency setting for
+ * individual key, use #pj_ioqueue_set_concurrency().
+ *
+ * @param ioqueue	The ioqueue instance.
+ * @param allow		Non-zero to allow concurrent callback calls, or
+ *			PJ_FALSE to disallow it.
+ *
+ * @return		PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_default_concurrency(pj_ioqueue_t *ioqueue,
+							pj_bool_t allow);
+
+/**
+ * Register a socket to the I/O queue framework. 
+ * When a socket is registered to the IOQueue, it may be modified to use
+ * non-blocking IO. If it is modified, there is no guarantee that this 
+ * modification will be restored after the socket is unregistered.
+ *
+ * @param pool	    To allocate the resource for the specified handle, 
+ *		    which must be valid until the handle/key is unregistered 
+ *		    from I/O Queue.
+ * @param ioque	    The I/O Queue.
+ * @param sock	    The socket.
+ * @param user_data User data to be associated with the key, which can be
+ *		    retrieved later.
+ * @param cb	    Callback to be called when I/O operation completes. 
+ * @param key       Pointer to receive the key to be associated with this
+ *                  socket. Subsequent I/O queue operation will need this
+ *                  key.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					       pj_ioqueue_t *ioque,
+					       pj_sock_t sock,
+					       void *user_data,
+					       const pj_ioqueue_callback *cb,
+                                               pj_ioqueue_key_t **key );
+
+/**
+ * Variant of pj_ioqueue_register_sock() with additional group lock parameter.
+ * If group lock is set for the key, the key will add the reference counter
+ * when the socket is registered and decrease it when it is destroyed.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_register_sock2(pj_pool_t *pool,
+					       pj_ioqueue_t *ioque,
+					       pj_sock_t sock,
+					       pj_grp_lock_t *grp_lock,
+					       void *user_data,
+					       const pj_ioqueue_callback *cb,
+                                               pj_ioqueue_key_t **key );
+
+/**
+ * Unregister from the I/O Queue framework. Caller must make sure that
+ * the key doesn't have any pending operations before calling this function,
+ * by calling #pj_ioqueue_is_pending() for all previously submitted
+ * operations except asynchronous connect, and if necessary call
+ * #pj_ioqueue_post_completion() to cancel the pending operations.
+ *
+ * Note that asynchronous connect operation will automatically be 
+ * cancelled during the unregistration.
+ *
+ * Also note that when I/O Completion Port backend is used, application
+ * MUST close the handle immediately after unregistering the key. This is
+ * because there is no unregistering API for IOCP. The only way to
+ * unregister the handle from IOCP is to close the handle.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return          PJ_SUCCESS on success or the error code.
+ *
+ * @see pj_ioqueue_is_pending
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
+
+
+/**
+ * Get user data associated with an ioqueue key.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return          The user data associated with the descriptor, or NULL 
+ *                  on error or if no data is associated with the key during
+ *                  registration.
+ */
+PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );
+
+/**
+ * Set or change the user data to be associated with the file descriptor or
+ * handle or socket descriptor.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ * @param user_data User data to be associated with the descriptor.
+ * @param old_data  Optional parameter to retrieve the old user data.
+ *
+ * @return          PJ_SUCCESS on success or the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+                                               void *user_data,
+                                               void **old_data);
+
+/**
+ * Configure whether the ioqueue is allowed to call the key's callback
+ * concurrently/in parallel. The default concurrency setting for the key
+ * is controlled by ioqueue's default concurrency value, which can be
+ * changed by calling #pj_ioqueue_set_default_concurrency().
+ *
+ * If concurrency is allowed for the key, it means that if there are more
+ * than one pending operations complete simultaneously, more than one
+ * threads may call the key's  callback at the same time. This generally
+ * would promote good scalability for application, at the expense of more
+ * complexity to manage the concurrent accesses in application's code.
+ *
+ * Alternatively application may disable the concurrent access by
+ * setting the \a allow flag to false. With concurrency disabled, only
+ * one thread can call the key's callback at one time.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ * @param allow	    Set this to non-zero to allow concurrent callback calls
+ *		    and zero (PJ_FALSE) to disallow it.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_concurrency(pj_ioqueue_key_t *key,
+						pj_bool_t allow);
+
+/**
+ * Acquire the key's mutex. When the key's concurrency is disabled, 
+ * application may call this function to synchronize its operation
+ * with the key's callback (i.e. this function will block until the
+ * key's callback returns).
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_lock_key(pj_ioqueue_key_t *key);
+
+/**
+ * Release the lock previously acquired with pj_ioqueue_lock_key().
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_unlock_key(pj_ioqueue_key_t *key);
+
+/**
+ * Initialize operation key.
+ *
+ * @param op_key    The operation key to be initialied.
+ * @param size	    The size of the operation key.
+ */
+PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
+				      pj_size_t size );
+
+/**
+ * Check if operation is pending on the specified operation key.
+ * The \c op_key must have been initialized with #pj_ioqueue_op_key_init() 
+ * or submitted as pending operation before, or otherwise the result 
+ * is undefined.
+ *
+ * @param key       The key.
+ * @param op_key    The operation key, previously submitted to any of
+ *                  the I/O functions and has returned PJ_EPENDING.
+ *
+ * @return          Non-zero if operation is still pending.
+ */
+PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+                                          pj_ioqueue_op_key_t *op_key );
+
+
+/**
+ * Post completion status to the specified operation key and call the
+ * appropriate callback. When the callback is called, the number of bytes 
+ * received in read/write callback or the status in accept/connect callback
+ * will be set from the \c bytes_status parameter.
+ *
+ * @param key           The key.
+ * @param op_key        Pending operation key.
+ * @param bytes_status  Number of bytes or status to be set. A good value
+ *                      to put here is -PJ_ECANCELLED.
+ *
+ * @return              PJ_SUCCESS if completion status has been successfully
+ *                      sent.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
+                                                 pj_ioqueue_op_key_t *op_key,
+                                                 pj_ssize_t bytes_status );
+
+
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+/**
+ * Instruct I/O Queue to accept incoming connection on the specified 
+ * listening socket. This function will return immediately (i.e. non-blocking)
+ * regardless whether a connection is immediately available. If the function
+ * can't complete immediately, the caller will be notified about the incoming
+ * connection when it calls pj_ioqueue_poll(). If a new connection is
+ * immediately available, the function returns PJ_SUCCESS with the new
+ * connection; in this case, the callback WILL NOT be called.
+ *
+ * @param key	    The key which registered to the server socket.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param new_sock  Argument which contain pointer to receive the new socket
+ *                  for the incoming connection.
+ * @param local	    Optional argument which contain pointer to variable to 
+ *                  receive local address.
+ * @param remote    Optional argument which contain pointer to variable to 
+ *                  receive the remote address.
+ * @param addrlen   On input, contains the length of the buffer for the
+ *		    address, and on output, contains the actual length of the
+ *		    address. This argument is optional.
+ * @return
+ *  - PJ_SUCCESS    When connection is available immediately, and the 
+ *                  parameters will be updated to contain information about 
+ *                  the new connection. In this case, a completion callback
+ *                  WILL NOT be called.
+ *  - PJ_EPENDING   If no connection is available immediately. When a new
+ *                  connection arrives, the callback will be called.
+ *  - non-zero      which indicates the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+                                        pj_ioqueue_op_key_t *op_key,
+					pj_sock_t *new_sock,
+					pj_sockaddr_t *local,
+					pj_sockaddr_t *remote,
+					int *addrlen );
+
+/**
+ * Initiate non-blocking socket connect. If the socket can NOT be connected
+ * immediately, asynchronous connect() will be scheduled and caller will be
+ * notified via completion callback when it calls pj_ioqueue_poll(). If
+ * socket is connected immediately, the function returns PJ_SUCCESS and
+ * completion callback WILL NOT be called.
+ *
+ * @param key	    The key associated with TCP socket
+ * @param addr	    The remote address.
+ * @param addrlen   The remote address length.
+ *
+ * @return
+ *  - PJ_SUCCESS    If socket is connected immediately. In this case, the
+ *                  completion callback WILL NOT be called.
+ *  - PJ_EPENDING   If operation is queued, or 
+ *  - non-zero      Indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+					 const pj_sockaddr_t *addr,
+					 int addrlen );
+
+#endif	/* PJ_HAS_TCP */
+
+/**
+ * Poll the I/O Queue for completed events.
+ *
+ * Note: polling the ioqueue is not necessary in Symbian. Please see
+ * @ref PJ_SYMBIAN_OS for more info.
+ *
+ * @param ioque		the I/O Queue.
+ * @param timeout	polling timeout, or NULL if the thread wishes to wait
+ *			indefinetely for the event.
+ *
+ * @return 
+ *  - zero if timed out (no event).
+ *  - (<0) if error occured during polling. Callback will NOT be called.
+ *  - (>1) to indicate numbers of events. Callbacks have been called.
+ */
+PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,
+			      const pj_time_val *timeout);
+
+
+/**
+ * Instruct the I/O Queue to read from the specified handle. This function
+ * returns immediately (i.e. non-blocking) regardless whether some data has 
+ * been transfered. If the operation can't complete immediately, caller will 
+ * be notified about the completion when it calls pj_ioqueue_poll(). If data
+ * is immediately available, the function will return PJ_SUCCESS and the
+ * callback WILL NOT be called.
+ *
+ * @param key	    The key that uniquely identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called. Caller must make sure that this key remains 
+ *                  valid until the function completes.
+ * @param buffer    The buffer to hold the read data. The caller MUST make sure
+ *		    that this buffer remain valid until the framework completes
+ *		    reading the handle.
+ * @param length    On input, it specifies the size of the buffer. If data is
+ *                  available to be read immediately, the function returns
+ *                  PJ_SUCCESS and this argument will be filled with the
+ *                  amount of data read. If the function is pending, caller
+ *                  will be notified about the amount of data read in the
+ *                  callback. This parameter can point to local variable in
+ *                  caller's stack and doesn't have to remain valid for the
+ *                  duration of pending operation.
+ * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ *
+ * @return
+ *  - PJ_SUCCESS    If immediate data has been received in the buffer. In this
+ *                  case, the callback WILL NOT be called.
+ *  - PJ_EPENDING   If the operation has been queued, and the callback will be
+ *                  called when data has been received.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      void *buffer,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags );
+
+/**
+ * This function behaves similarly as #pj_ioqueue_recv(), except that it is
+ * normally called for socket, and the remote address will also be returned
+ * along with the data. Caller MUST make sure that both buffer and addr
+ * remain valid until the framework completes reading the data.
+ *
+ * @param key	    The key that uniquely identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param buffer    The buffer to hold the read data. The caller MUST make sure
+ *		    that this buffer remain valid until the framework completes
+ *		    reading the handle.
+ * @param length    On input, it specifies the size of the buffer. If data is
+ *                  available to be read immediately, the function returns
+ *                  PJ_SUCCESS and this argument will be filled with the
+ *                  amount of data read. If the function is pending, caller
+ *                  will be notified about the amount of data read in the
+ *                  callback. This parameter can point to local variable in
+ *                  caller's stack and doesn't have to remain valid for the
+ *                  duration of pending operation.
+ * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ * @param addr      Optional Pointer to buffer to receive the address.
+ * @param addrlen   On input, specifies the length of the address buffer.
+ *                  On output, it will be filled with the actual length of
+ *                  the address. This argument can be NULL if \c addr is not
+ *                  specified.
+ *
+ * @return
+ *  - PJ_SUCCESS    If immediate data has been received. In this case, the 
+ *		    callback must have been called before this function 
+ *		    returns, and no pending operation is scheduled.
+ *  - PJ_EPENDING   If the operation has been queued.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+                                          pj_ioqueue_op_key_t *op_key,
+					  void *buffer,
+					  pj_ssize_t *length,
+                                          pj_uint32_t flags,
+					  pj_sockaddr_t *addr,
+					  int *addrlen);
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been 
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If 
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key	    The key that identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param data	    The data to send. Caller MUST make sure that this buffer 
+ *		    remains valid until the write operation completes.
+ * @param length    On input, it specifies the length of data to send. When
+ *                  data was sent immediately, this function returns PJ_SUCCESS
+ *                  and this parameter contains the length of data sent. If
+ *                  data can not be sent immediately, an asynchronous operation
+ *                  is scheduled and caller will be notified via callback the
+ *                  number of bytes sent. This parameter can point to local 
+ *                  variable on caller's stack and doesn't have to remain 
+ *                  valid until the operation has completed.
+ * @param flags     Send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ *
+ * @return
+ *  - PJ_SUCCESS    If data was immediately transfered. In this case, no
+ *                  pending operation has been scheduled and the callback
+ *                  WILL NOT be called.
+ *  - PJ_EPENDING   If the operation has been queued. Once data base been
+ *                  transfered, the callback will be called.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      const void *data,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags );
+
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been 
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If 
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key	    the key that identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param data	    the data to send. Caller MUST make sure that this buffer 
+ *		    remains valid until the write operation completes.
+ * @param length    On input, it specifies the length of data to send. When
+ *                  data was sent immediately, this function returns PJ_SUCCESS
+ *                  and this parameter contains the length of data sent. If
+ *                  data can not be sent immediately, an asynchronous operation
+ *                  is scheduled and caller will be notified via callback the
+ *                  number of bytes sent. This parameter can point to local 
+ *                  variable on caller's stack and doesn't have to remain 
+ *                  valid until the operation has completed.
+ * @param flags     send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ * @param addr      Optional remote address.
+ * @param addrlen   Remote address length, \c addr is specified.
+ *
+ * @return
+ *  - PJ_SUCCESS    If data was immediately written.
+ *  - PJ_EPENDING   If the operation has been queued.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+                                        pj_ioqueue_op_key_t *op_key,
+					const void *data,
+					pj_ssize_t *length,
+                                        pj_uint32_t flags,
+					const pj_sockaddr_t *addr,
+					int addrlen);
+
+
+/**
+ * !}
+ */
+
+PJ_END_DECL
+
+#endif	/* __PJ_IOQUEUE_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/94/94404a1eb9520fba6303b3eccfba8d304c8637c6.svn-base b/jni/pjproject-android/.svn/pristine/94/94404a1eb9520fba6303b3eccfba8d304c8637c6.svn-base
new file mode 100644
index 0000000..1675644
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/94404a1eb9520fba6303b3eccfba8d304c8637c6.svn-base
@@ -0,0 +1,62 @@
+/* $Id */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj++/file.hpp>
+#include <pj++/list.hpp>
+#include <pj++/lock.hpp>
+#include <pj++/hash.hpp>
+#include <pj++/os.hpp>
+#include <pj++/proactor.hpp>
+#include <pj++/sock.hpp>
+#include <pj++/string.hpp>
+#include <pj++/timer.hpp>
+#include <pj++/tree.hpp>
+
+class My_Async_Op : public Pj_Async_Op
+{
+};
+
+class My_Event_Handler : public Pj_Event_Handler
+{
+};
+
+int main()
+{
+    Pjlib lib;
+    Pj_Caching_Pool mem;
+    Pj_Pool the_pool;
+    Pj_Pool *pool = &the_pool;
+    
+    the_pool.attach(mem.create_pool(4000,4000));
+
+    Pj_Semaphore_Lock lsem(pool);
+    Pj_Semaphore_Lock *plsem;
+
+    plsem = new(pool) Pj_Semaphore_Lock(pool);
+    delete plsem;
+
+    Pj_Proactor proactor(pool, 100, 100);
+
+    My_Event_Handler *event_handler = new(the_pool) My_Event_Handler;
+    proactor.register_socket_handler(pool, event_handler);
+    proactor.unregister_handler(event_handler);
+
+    return 0;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/94/94426969e488a41da3917b09192bd8e6c280f417.svn-base b/jni/pjproject-android/.svn/pristine/94/94426969e488a41da3917b09192bd8e6c280f417.svn-base
new file mode 100644
index 0000000..1d5e645
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/94426969e488a41da3917b09192bd8e6c280f417.svn-base
@@ -0,0 +1,46 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Handling of incoming tel: URI.
+complete_msg = \
+"""INVITE tel:+2065551212 SIP/2.0
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;x-route-tag="tgrp:cococisco1";branch=z9hG4bK61E05
+From: <tel:12345>$FROM_TAG
+To: <tel:+2065551212>
+Date: Thu, 12 Feb 2009 18:32:33 GMT
+Call-ID: 58F8F7D6-F86A11DD-8013D591-5694EF79
+Supported: 100rel,timer,resource-priority
+Min-SE:  86400
+Cisco-Guid: 1492551325-4167700957-2148586897-1452601209
+User-Agent: Cisco-SIPGateway/IOS-12.x
+Allow: INVITE, OPTIONS, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY, INFO, REGISTER
+CSeq: 101 INVITE
+Max-Forwards: 70
+Timestamp: 1234463553
+Contact: <tel:+1234;ext=1>
+Contact: <sip:tester@$LOCAL_IP:$LOCAL_PORT>
+Record-Route: <sip:tester@$LOCAL_IP:$LOCAL_PORT;lr>
+Expires: 180
+Allow-Events: telephone-event
+Content-Type: application/sdp
+Content-Disposition: session;handling=required
+Content-Length: 265
+
+v=0
+o=CiscoSystemsSIP-GW-UserAgent 1296 9529 IN IP4 X.X.X.X
+s=SIP Call
+c=IN IP4 $LOCAL_IP
+t=0 0
+m=audio 18676 RTP/AVP 0 101 19
+c=IN IP4 $LOCAL_IP
+a=rtpmap:0 PCMU/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=rtpmap:19 CN/8000
+a=ptime:20
+"""
+
+sendto_cfg = sip.SendtoCfg( "tel: URI", "--null-audio --auto-answer 200", 
+			    "", 200, complete_msg=complete_msg)
+
diff --git a/jni/pjproject-android/.svn/pristine/94/945c28f16d7e46fe91415f8935b2c22d22bed69a.svn-base b/jni/pjproject-android/.svn/pristine/94/945c28f16d7e46fe91415f8935b2c22d22bed69a.svn-base
new file mode 100644
index 0000000..23f2f25
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/945c28f16d7e46fe91415f8935b2c22d22bed69a.svn-base
@@ -0,0 +1,377 @@
+/* $Id$ */
+/*
+ * Digital Audio Resampling Home Page located at
+ * http://www-ccrma.stanford.edu/~jos/resample/.
+ *
+ * SOFTWARE FOR SAMPLING-RATE CONVERSION AND FIR DIGITAL FILTER DESIGN
+ *
+ * Snippet from the resample.1 man page:
+ * 
+ * HISTORY
+ *
+ * The first version of this software was written by Julius O. Smith III
+ * <jos@ccrma.stanford.edu> at CCRMA <http://www-ccrma.stanford.edu> in
+ * 1981.  It was called SRCONV and was written in SAIL for PDP-10
+ * compatible machines.  The algorithm was first published in
+ * 
+ * Smith, Julius O. and Phil Gossett. ``A Flexible Sampling-Rate
+ * Conversion Method,'' Proceedings (2): 19.4.1-19.4.4, IEEE Conference
+ * on Acoustics, Speech, and Signal Processing, San Diego, March 1984.
+ * 
+ * An expanded tutorial based on this paper is available at the Digital
+ * Audio Resampling Home Page given above.
+ * 
+ * Circa 1988, the SRCONV program was translated from SAIL to C by
+ * Christopher Lee Fraley working with Roger Dannenberg at CMU.
+ * 
+ * Since then, the C version has been maintained by jos.
+ * 
+ * Sndlib support was added 6/99 by John Gibson <jgg9c@virginia.edu>.
+ * 
+ * The resample program is free software distributed in accordance
+ * with the Lesser GNU Public License (LGPL).  There is NO warranty; not
+ * even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* PJMEDIA modification:
+ *  - remove resample(), just use SrcUp, SrcUD, and SrcLinear directly.
+ *  - move FilterUp() and FilterUD() from filterkit.c
+ *  - move stddefs.h and resample.h to this file.
+ *  - const correctness.
+ */
+
+#include <resamplesubs.h>
+#include "config.h"
+#include "stddefs.h"
+#include "resample.h"
+
+
+#ifdef _MSC_VER
+#   pragma warning(push, 3)
+//#   pragma warning(disable: 4245)   // Conversion from uint to ushort
+#   pragma warning(disable: 4244)   // Conversion from double to uint
+#   pragma warning(disable: 4146)   // unary minus operator applied to unsigned type, result still unsigned
+#   pragma warning(disable: 4761)   // integral size mismatch in argument; conversion supplied
+#endif
+
+#if defined(RESAMPLE_HAS_SMALL_FILTER) && RESAMPLE_HAS_SMALL_FILTER!=0
+#   include "smallfilter.h"
+#else
+#   define SMALL_FILTER_NMULT	0
+#   define SMALL_FILTER_SCALE	0
+#   define SMALL_FILTER_NWING	0
+#   define SMALL_FILTER_IMP	NULL
+#   define SMALL_FILTER_IMPD	NULL
+#endif
+
+#if defined(RESAMPLE_HAS_LARGE_FILTER) && RESAMPLE_HAS_LARGE_FILTER!=0
+#   include "largefilter.h"
+#else
+#   define LARGE_FILTER_NMULT	0
+#   define LARGE_FILTER_SCALE	0
+#   define LARGE_FILTER_NWING	0
+#   define LARGE_FILTER_IMP	NULL
+#   define LARGE_FILTER_IMPD	NULL
+#endif
+
+
+#undef INLINE
+#define INLINE
+#define HAVE_FILTER 0    
+
+#ifndef NULL
+#   define NULL	0
+#endif
+
+
+static INLINE RES_HWORD WordToHword(RES_WORD v, int scl)
+{
+    RES_HWORD out;
+    RES_WORD llsb = (1<<(scl-1));
+    v += llsb;		/* round */
+    v >>= scl;
+    if (v>MAX_HWORD) {
+	v = MAX_HWORD;
+    } else if (v < MIN_HWORD) {
+	v = MIN_HWORD;
+    }	
+    out = (RES_HWORD) v;
+    return out;
+}
+
+/* Sampling rate conversion using linear interpolation for maximum speed.
+ */
+static int 
+  SrcLinear(const RES_HWORD X[], RES_HWORD Y[], double pFactor, RES_UHWORD nx)
+{
+    RES_HWORD iconst;
+    RES_UWORD time = 0;
+    const RES_HWORD *xp;
+    RES_HWORD *Ystart, *Yend;
+    RES_WORD v,x1,x2;
+    
+    double dt;                  /* Step through input signal */ 
+    RES_UWORD dtb;                  /* Fixed-point version of Dt */
+    RES_UWORD endTime;              /* When time reaches EndTime, return to user */
+    
+    dt = 1.0/pFactor;            /* Output sampling period */
+    dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
+    
+    Ystart = Y;
+    Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
+    endTime = time + (1<<Np)*(RES_WORD)nx;
+    
+    // Integer round down in dtb calculation may cause (endTime % dtb > 0), 
+    // so it may cause resample write pass the output buffer (Y >= Yend).
+    // while (time < endTime)
+    while (Y < Yend)
+    {
+	iconst = (time) & Pmask;
+	xp = &X[(time)>>Np];      /* Ptr to current input sample */
+	x1 = *xp++;
+	x2 = *xp;
+	x1 *= ((1<<Np)-iconst);
+	x2 *= iconst;
+	v = x1 + x2;
+	*Y++ = WordToHword(v,Np);   /* Deposit output */
+	time += dtb;		    /* Move to next sample by time increment */
+    }
+    return (Y - Ystart);            /* Return number of output samples */
+}
+
+static RES_WORD FilterUp(const RES_HWORD Imp[], const RES_HWORD ImpD[], 
+		     RES_UHWORD Nwing, RES_BOOL Interp,
+		     const RES_HWORD *Xp, RES_HWORD Ph, RES_HWORD Inc)
+{
+    const RES_HWORD *Hp;
+    const RES_HWORD *Hdp = NULL;
+    const RES_HWORD *End;
+    RES_HWORD a = 0;
+    RES_WORD v, t;
+    
+    v=0;
+    Hp = &Imp[Ph>>Na];
+    End = &Imp[Nwing];
+    if (Interp) {
+	Hdp = &ImpD[Ph>>Na];
+	a = Ph & Amask;
+    }
+    if (Inc == 1)		/* If doing right wing...              */
+    {				/* ...drop extra coeff, so when Ph is  */
+	End--;			/*    0.5, we don't do too many mult's */
+	if (Ph == 0)		/* If the phase is zero...           */
+	{			/* ...then we've already skipped the */
+	    Hp += Npc;		/*    first sample, so we must also  */
+	    Hdp += Npc;		/*    skip ahead in Imp[] and ImpD[] */
+	}
+    }
+    if (Interp)
+      while (Hp < End) {
+	  t = *Hp;		/* Get filter coeff */
+	  t += (((RES_WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
+	  Hdp += Npc;		/* Filter coeff differences step */
+	  t *= *Xp;		/* Mult coeff by input sample */
+	  if (t & (1<<(Nhxn-1)))  /* Round, if needed */
+	    t += (1<<(Nhxn-1));
+	  t >>= Nhxn;		/* Leave some guard bits, but come back some */
+	  v += t;			/* The filter output */
+	  Hp += Npc;		/* Filter coeff step */
+
+	  Xp += Inc;		/* Input signal step. NO CHECK ON BOUNDS */
+      } 
+    else 
+      while (Hp < End) {
+	  t = *Hp;		/* Get filter coeff */
+	  t *= *Xp;		/* Mult coeff by input sample */
+	  if (t & (1<<(Nhxn-1)))  /* Round, if needed */
+	    t += (1<<(Nhxn-1));
+	  t >>= Nhxn;		/* Leave some guard bits, but come back some */
+	  v += t;			/* The filter output */
+	  Hp += Npc;		/* Filter coeff step */
+	  Xp += Inc;		/* Input signal step. NO CHECK ON BOUNDS */
+      }
+    return(v);
+}
+
+
+static RES_WORD FilterUD(const RES_HWORD Imp[], const RES_HWORD ImpD[],
+		     RES_UHWORD Nwing, RES_BOOL Interp,
+		     const RES_HWORD *Xp, RES_HWORD Ph, RES_HWORD Inc, RES_UHWORD dhb)
+{
+    RES_HWORD a;
+    const RES_HWORD *Hp, *Hdp, *End;
+    RES_WORD v, t;
+    RES_UWORD Ho;
+    
+    v=0;
+    Ho = (Ph*(RES_UWORD)dhb)>>Np;
+    End = &Imp[Nwing];
+    if (Inc == 1)		/* If doing right wing...              */
+    {				/* ...drop extra coeff, so when Ph is  */
+	End--;			/*    0.5, we don't do too many mult's */
+	if (Ph == 0)		/* If the phase is zero...           */
+	  Ho += dhb;		/* ...then we've already skipped the */
+    }				/*    first sample, so we must also  */
+				/*    skip ahead in Imp[] and ImpD[] */
+    if (Interp)
+      while ((Hp = &Imp[Ho>>Na]) < End) {
+	  t = *Hp;		/* Get IR sample */
+	  Hdp = &ImpD[Ho>>Na];  /* get interp (lower Na) bits from diff table*/
+	  a = Ho & Amask;	/* a is logically between 0 and 1 */
+	  t += (((RES_WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
+	  t *= *Xp;		/* Mult coeff by input sample */
+	  if (t & 1<<(Nhxn-1))	/* Round, if needed */
+	    t += 1<<(Nhxn-1);
+	  t >>= Nhxn;		/* Leave some guard bits, but come back some */
+	  v += t;			/* The filter output */
+	  Ho += dhb;		/* IR step */
+	  Xp += Inc;		/* Input signal step. NO CHECK ON BOUNDS */
+      }
+    else 
+      while ((Hp = &Imp[Ho>>Na]) < End) {
+	  t = *Hp;		/* Get IR sample */
+	  t *= *Xp;		/* Mult coeff by input sample */
+	  if (t & 1<<(Nhxn-1))	/* Round, if needed */
+	    t += 1<<(Nhxn-1);
+	  t >>= Nhxn;		/* Leave some guard bits, but come back some */
+	  v += t;			/* The filter output */
+	  Ho += dhb;		/* IR step */
+	  Xp += Inc;		/* Input signal step. NO CHECK ON BOUNDS */
+      }
+    return(v);
+}
+
+/* Sampling rate up-conversion only subroutine;
+ * Slightly faster than down-conversion;
+ */
+static int SrcUp(const RES_HWORD X[], RES_HWORD Y[], double pFactor, 
+		 RES_UHWORD nx, RES_UHWORD pNwing, RES_UHWORD pLpScl,
+		 const RES_HWORD pImp[], const RES_HWORD pImpD[], RES_BOOL Interp)
+{
+    const RES_HWORD *xp;
+    RES_HWORD *Ystart, *Yend;
+    RES_WORD v;
+    
+    double dt;                  /* Step through input signal */ 
+    RES_UWORD dtb;                  /* Fixed-point version of Dt */
+    RES_UWORD time = 0;
+    RES_UWORD endTime;              /* When time reaches EndTime, return to user */
+    
+    dt = 1.0/pFactor;            /* Output sampling period */
+    dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
+    
+    Ystart = Y;
+    Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
+    endTime = time + (1<<Np)*(RES_WORD)nx;
+
+    // Integer round down in dtb calculation may cause (endTime % dtb > 0), 
+    // so it may cause resample write pass the output buffer (Y >= Yend).
+    // while (time < endTime)
+    while (Y < Yend)
+    {
+	xp = &X[time>>Np];      /* Ptr to current input sample */
+	/* Perform left-wing inner product */
+	v = 0;
+	v = FilterUp(pImp, pImpD, pNwing, Interp, xp, (RES_HWORD)(time&Pmask),-1);
+
+	/* Perform right-wing inner product */
+	v += FilterUp(pImp, pImpD, pNwing, Interp, xp+1,  (RES_HWORD)((-time)&Pmask),1);
+
+	v >>= Nhg;		/* Make guard bits */
+	v *= pLpScl;		/* Normalize for unity filter gain */
+	*Y++ = WordToHword(v,NLpScl);   /* strip guard bits, deposit output */
+	time += dtb;		/* Move to next sample by time increment */
+    }
+    return (Y - Ystart);        /* Return the number of output samples */
+}
+
+
+/* Sampling rate conversion subroutine */
+
+static int SrcUD(const RES_HWORD X[], RES_HWORD Y[], double pFactor, 
+		 RES_UHWORD nx, RES_UHWORD pNwing, RES_UHWORD pLpScl,
+		 const RES_HWORD pImp[], const RES_HWORD pImpD[], RES_BOOL Interp)
+{
+    const RES_HWORD *xp;
+    RES_HWORD *Ystart, *Yend;
+    RES_WORD v;
+    
+    double dh;                  /* Step through filter impulse response */
+    double dt;                  /* Step through input signal */
+    RES_UWORD time = 0;
+    RES_UWORD endTime;          /* When time reaches EndTime, return to user */
+    RES_UWORD dhb, dtb;         /* Fixed-point versions of Dh,Dt */
+    
+    dt = 1.0/pFactor;            /* Output sampling period */
+    dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
+    
+    dh = MIN(Npc, pFactor*Npc);  /* Filter sampling period */
+    dhb = dh*(1<<Na) + 0.5;     /* Fixed-point representation */
+    
+    Ystart = Y;
+    Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
+    endTime = time + (1<<Np)*(RES_WORD)nx;
+
+    // Integer round down in dtb calculation may cause (endTime % dtb > 0), 
+    // so it may cause resample write pass the output buffer (Y >= Yend).
+    // while (time < endTime)
+    while (Y < Yend)
+    {
+	xp = &X[time>>Np];	/* Ptr to current input sample */
+	v = FilterUD(pImp, pImpD, pNwing, Interp, xp, (RES_HWORD)(time&Pmask),
+		     -1, dhb);	/* Perform left-wing inner product */
+	v += FilterUD(pImp, pImpD, pNwing, Interp, xp+1, (RES_HWORD)((-time)&Pmask),
+		      1, dhb);	/* Perform right-wing inner product */
+	v >>= Nhg;		/* Make guard bits */
+	v *= pLpScl;		/* Normalize for unity filter gain */
+	*Y++ = WordToHword(v,NLpScl);   /* strip guard bits, deposit output */
+	time += dtb;		/* Move to next sample by time increment */
+    }
+    return (Y - Ystart);        /* Return the number of output samples */
+}
+
+
+DECL(int) res_SrcLinear(const RES_HWORD X[], RES_HWORD Y[], 
+		        double pFactor, RES_UHWORD nx)
+{
+    return SrcLinear(X, Y, pFactor, nx);
+}
+
+DECL(int) res_Resample(const RES_HWORD X[], RES_HWORD Y[], double pFactor, 
+		       RES_UHWORD nx, RES_BOOL LargeF, RES_BOOL Interp)
+{
+    if (pFactor >= 1) {
+
+	if (LargeF)
+	    return SrcUp(X, Y, pFactor, nx,
+			 LARGE_FILTER_NWING, LARGE_FILTER_SCALE,
+			 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp);
+	else
+	    return SrcUp(X, Y, pFactor, nx,
+			 SMALL_FILTER_NWING, SMALL_FILTER_SCALE,
+			 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp);
+
+    } else {
+
+	if (LargeF)
+	    return SrcUD(X, Y, pFactor, nx, 
+			 LARGE_FILTER_NWING, LARGE_FILTER_SCALE * pFactor + 0.5,
+			 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp);
+	else
+	    return SrcUD(X, Y, pFactor, nx, 
+			 SMALL_FILTER_NWING, SMALL_FILTER_SCALE * pFactor + 0.5,
+			 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp);
+
+    }
+}
+
+DECL(int) res_GetXOFF(double pFactor, RES_BOOL LargeF)
+{
+    if (LargeF)
+	return (LARGE_FILTER_NMULT + 1) / 2.0  *  
+	        MAX(1.0, 1.0/pFactor);
+    else
+	return (SMALL_FILTER_NMULT + 1) / 2.0  *  
+		MAX(1.0, 1.0/pFactor);
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/94/9473c2d060761a0aa28b8a90e845ec22f3d84cf6.svn-base b/jni/pjproject-android/.svn/pristine/94/9473c2d060761a0aa28b8a90e845ec22f3d84cf6.svn-base
new file mode 100644
index 0000000..425d503
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/9473c2d060761a0aa28b8a90e845ec22f3d84cf6.svn-base
@@ -0,0 +1,79 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/os.h>
+#include <linux/time.h>
+
+#if 0
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    ts->u32.hi = 0;
+    ts->u32.lo = jiffies;
+    return 0;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+    freq->u32.hi = 0;
+    freq->u32.lo = HZ;
+    return 0;
+}
+#elif 0
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    struct timespec tv;
+    
+    tv = CURRENT_TIME;
+
+    ts->u64 = tv.tv_sec;
+    ts->u64 *= NSEC_PER_SEC;
+    ts->u64 += tv.tv_nsec;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+    freq->u32.hi = 0;
+    freq->u32.lo = NSEC_PER_SEC;
+    return 0;
+}
+#else
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    struct timeval tv;
+    
+    do_gettimeofday(&tv);
+
+    ts->u64 = tv.tv_sec;
+    ts->u64 *= USEC_PER_SEC;
+    ts->u64 += tv.tv_usec;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+    freq->u32.hi = 0;
+    freq->u32.lo = USEC_PER_SEC;
+    return 0;
+}
+
+#endif
+
diff --git a/jni/pjproject-android/.svn/pristine/94/948ef702cb045d8bf1d224fbcee42f2359240570.svn-base b/jni/pjproject-android/.svn/pristine/94/948ef702cb045d8bf1d224fbcee42f2359240570.svn-base
new file mode 100644
index 0000000..d2b0bb1
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/948ef702cb045d8bf1d224fbcee42f2359240570.svn-base
@@ -0,0 +1,184 @@
+//------------------------------------------------------------------------------

+// File: RefClock.h

+//

+// Desc: DirectShow base classes - defines the IReferenceClock interface.

+//

+// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.

+//------------------------------------------------------------------------------

+

+

+#ifndef __BASEREFCLOCK__

+#define __BASEREFCLOCK__

+

+#include <Schedule.h>

+

+const UINT RESOLUTION = 1;                      /* High resolution timer */

+const INT ADVISE_CACHE = 4;                     /* Default cache size */

+const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF;   /* Maximum LONGLONG value */

+

+inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)

+{

+    /* This converts an arbitrary value representing a reference time

+       into a MILLISECONDS value for use in subsequent system calls */

+

+    return (RT / (UNITS / MILLISECONDS));

+}

+

+/* This class hierarchy will support an IReferenceClock interface so

+   that an audio card (or other externally driven clock) can update the

+   system wide clock that everyone uses.

+

+   The interface will be pretty thin with probably just one update method

+   This interface has not yet been defined.

+ */

+

+/* This abstract base class implements the IReferenceClock

+ * interface.  Classes that actually provide clock signals (from

+ * whatever source) have to be derived from this class.

+ *

+ * The abstract class provides implementations for:

+ *  CUnknown support

+ *      locking support (CCritSec)

+ *  client advise code (creates a thread)

+ *

+ * Question: what can we do about quality?  Change the timer

+ * resolution to lower the system load?  Up the priority of the

+ * timer thread to force more responsive signals?

+ *

+ * During class construction we create a worker thread that is destroyed during

+ * destuction.  This thread executes a series of WaitForSingleObject calls,

+ * waking up when a command is given to the thread or the next wake up point

+ * is reached.  The wakeup points are determined by clients making Advise

+ * calls.

+ *

+ * Each advise call defines a point in time when they wish to be notified.  A

+ * periodic advise is a series of these such events.  We maintain a list of

+ * advise links and calculate when the nearest event notification is due for.

+ * We then call WaitForSingleObject with a timeout equal to this time.  The

+ * handle we wait on is used by the class to signal that something has changed

+ * and that we must reschedule the next event.  This typically happens when

+ * someone comes in and asks for an advise link while we are waiting for an

+ * event to timeout.

+ *

+ * While we are modifying the list of advise requests we

+ * are protected from interference through a critical section.  Clients are NOT

+ * advised through callbacks.  One shot clients have an event set, while

+ * periodic clients have a semaphore released for each event notification.  A

+ * semaphore allows a client to be kept up to date with the number of events

+ * actually triggered and be assured that they can't miss multiple events being

+ * set.

+ *

+ * Keeping track of advises is taken care of by the CAMSchedule class.

+ */

+

+class CBaseReferenceClock

+: public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl 

+{

+protected:

+    virtual ~CBaseReferenceClock();     // Don't let me be created on the stack!

+public:

+    CBaseReferenceClock(__in_opt LPCTSTR pName, 

+                        __inout_opt LPUNKNOWN pUnk, 

+                        __inout HRESULT *phr, 

+                        __inout_opt CAMSchedule * pSched = 0 );

+

+    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);

+

+    DECLARE_IUNKNOWN

+

+    /* IReferenceClock methods */

+    // Derived classes must implement GetPrivateTime().  All our GetTime

+    // does is call GetPrivateTime and then check so that time does not

+    // go backwards.  A return code of S_FALSE implies that the internal

+    // clock has gone backwards and GetTime time has halted until internal

+    // time has caught up. (Don't know if this will be much use to folk,

+    // but it seems odd not to use the return code for something useful.)

+    STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime);

+    // When this is called, it sets m_rtLastGotTime to the time it returns.

+

+    /* Provide standard mechanisms for scheduling events */

+

+    /* Ask for an async notification that a time has elapsed */

+    STDMETHODIMP AdviseTime(

+        REFERENCE_TIME baseTime,        // base reference time

+        REFERENCE_TIME streamTime,      // stream offset time

+        HEVENT hEvent,                  // advise via this event

+        __out DWORD_PTR *pdwAdviseCookie// where your cookie goes

+    );

+

+    /* Ask for an asynchronous periodic notification that a time has elapsed */

+    STDMETHODIMP AdvisePeriodic(

+        REFERENCE_TIME StartTime,       // starting at this time

+        REFERENCE_TIME PeriodTime,      // time between notifications

+        HSEMAPHORE hSemaphore,          // advise via a semaphore

+        __out DWORD_PTR *pdwAdviseCookie// where your cookie goes

+    );

+

+    /* Cancel a request for notification(s) - if the notification was

+     * a one shot timer then this function doesn't need to be called

+     * as the advise is automatically cancelled, however it does no

+     * harm to explicitly cancel a one-shot advise.  It is REQUIRED that

+     * clients call Unadvise to clear a Periodic advise setting.

+     */

+

+    STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);

+

+    /* Methods for the benefit of derived classes or outer objects */

+

+    // GetPrivateTime() is the REAL clock.  GetTime is just a cover for

+    // it.  Derived classes will probably override this method but not

+    // GetTime() itself.

+    // The important point about GetPrivateTime() is it's allowed to go

+    // backwards.  Our GetTime() will keep returning the LastGotTime

+    // until GetPrivateTime() catches up.

+    virtual REFERENCE_TIME GetPrivateTime();

+

+    /* Provide a method for correcting drift */

+    STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );

+

+    CAMSchedule * GetSchedule() const { return m_pSchedule; }

+

+    // IReferenceClockTimerControl methods

+    //

+    // Setting a default of 0 disables the default of 1ms

+    STDMETHODIMP SetDefaultTimerResolution(

+        REFERENCE_TIME timerResolution // in 100ns

+    );

+    STDMETHODIMP GetDefaultTimerResolution(

+        __out REFERENCE_TIME* pTimerResolution // in 100ns

+    );

+

+private:

+    REFERENCE_TIME m_rtPrivateTime;     // Current best estimate of time

+    DWORD          m_dwPrevSystemTime;  // Last vaule we got from timeGetTime

+    REFERENCE_TIME m_rtLastGotTime;     // Last time returned by GetTime

+    REFERENCE_TIME m_rtNextAdvise;      // Time of next advise

+    UINT           m_TimerResolution;

+

+#ifdef PERF

+    int m_idGetSystemTime;

+#endif

+

+// Thread stuff

+public:

+    void TriggerThread()    // Wakes thread up.  Need to do this if

+    {                       // time to next advise needs reevaluating.

+        EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));

+    }

+

+

+private:

+    BOOL           m_bAbort;            // Flag used for thread shutdown

+    HANDLE         m_hThread;           // Thread handle

+

+    HRESULT AdviseThread();             // Method in which the advise thread runs

+    static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there

+

+protected:

+    CAMSchedule * m_pSchedule;

+

+    void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ;

+};

+

+#endif

+

diff --git a/jni/pjproject-android/.svn/pristine/94/949353fdda3d6e0916066ca854404b01eb1f6922.svn-base b/jni/pjproject-android/.svn/pristine/94/949353fdda3d6e0916066ca854404b01eb1f6922.svn-base
new file mode 100644
index 0000000..df56f5f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/949353fdda3d6e0916066ca854404b01eb1f6922.svn-base
@@ -0,0 +1,68 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+      
+   File: speex_buffer.h
+   This is a very simple ring buffer implementation. It is not thread-safe
+   so you need to do your own locking.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SPEEX_BUFFER_H
+#define SPEEX_BUFFER_H
+
+#include "speex/speex_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SpeexBuffer_;
+typedef struct SpeexBuffer_ SpeexBuffer;
+
+SpeexBuffer *speex_buffer_init(int size);
+
+void speex_buffer_destroy(SpeexBuffer *st);
+
+int speex_buffer_write(SpeexBuffer *st, void *data, int len);
+
+int speex_buffer_writezeros(SpeexBuffer *st, int len);
+
+int speex_buffer_read(SpeexBuffer *st, void *data, int len);
+
+int speex_buffer_get_available(SpeexBuffer *st);
+
+int speex_buffer_resize(SpeexBuffer *st, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
+
diff --git a/jni/pjproject-android/.svn/pristine/94/949b6e8c1268e99ef972ea1bd3c7a04560065e83.svn-base b/jni/pjproject-android/.svn/pristine/94/949b6e8c1268e99ef972ea1bd3c7a04560065e83.svn-base
new file mode 100644
index 0000000..b530f85
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/949b6e8c1268e99ef972ea1bd3c7a04560065e83.svn-base
@@ -0,0 +1,419 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file ltp_bfin.h
+   @author Jean-Marc Valin
+   @brief Long-Term Prediction functions (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_INNER_PROD
+spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
+{
+   spx_word32_t sum=0;
+   __asm__ __volatile__ (
+      "P0 = %3;\n\t"
+      "P1 = %1;\n\t"
+      "P2 = %2;\n\t"
+      "I0 = P1;\n\t"
+      "I1 = P2;\n\t"
+      "L0 = 0;\n\t"
+      "L1 = 0;\n\t"
+      "A0 = 0;\n\t"
+      "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+      "LOOP inner%= LC0 = P0;\n\t"
+      "LOOP_BEGIN inner%=;\n\t"
+         "A0 += R0.L*R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+      "LOOP_END inner%=;\n\t"
+      "A0 += R0.L*R1.L (IS);\n\t"
+      "A0 = A0 >>> 6;\n\t"
+      "R0 = A0;\n\t"
+      "%0 = R0;\n\t"
+   : "=m" (sum)
+   : "m" (x), "m" (y), "d" (len-1)
+   : "P0", "P1", "P2", "R0", "R1", "A0", "I0", "I1", "L0", "L1", "R3"
+   );
+   return sum;
+}
+
+#define OVERRIDE_PITCH_XCORR
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
+{
+   corr += nb_pitch - 1;
+   __asm__ __volatile__ (
+      "P2 = %0;\n\t"
+      "I0 = P2;\n\t" /* x in I0 */
+      "B0 = P2;\n\t" /* x in B0 */
+      "R0 = %3;\n\t" /* len in R0 */
+      "P3 = %3;\n\t"
+      "P3 += -2;\n\t" /* len in R0 */
+      "P4 = %4;\n\t" /* nb_pitch in R0 */
+      "R1 = R0 << 1;\n\t" /* number of bytes in x */
+      "L0 = R1;\n\t"
+      "P0 = %1;\n\t"
+
+      "P1 = %2;\n\t"
+      "B1 = P1;\n\t"
+      "L1 = 0;\n\t" /*Disable looping on I1*/
+
+      "r0 = [I0++];\n\t"
+      "LOOP pitch%= LC0 = P4 >> 1;\n\t"
+      "LOOP_BEGIN pitch%=;\n\t"
+         "I1 = P0;\n\t"
+         "A1 = A0 = 0;\n\t"
+         "R1 = [I1++];\n\t"
+         "LOOP inner_prod%= LC1 = P3 >> 1;\n\t"
+         "LOOP_BEGIN inner_prod%=;\n\t"
+            "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t"
+            "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t"
+         "LOOP_END inner_prod%=;\n\t"
+         "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t"
+         "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R0 = [I0++];\n\t"
+         "A0 = A0 >>> 6;\n\t"
+         "A1 = A1 >>> 6;\n\t"
+         "R2 = A0, R3 = A1;\n\t"
+         "[P1--] = r2;\n\t"
+         "[P1--] = r3;\n\t"
+         "P0 += 4;\n\t"
+      "LOOP_END pitch%=;\n\t"
+      "L0 = 0;\n\t"
+   : : "m" (_x), "m" (_y), "m" (corr), "m" (len), "m" (nb_pitch)
+   : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "I0", "I1", "L0", "L1", "B0", "B1", "memory"
+   );
+}
+
+#define OVERRIDE_COMPUTE_PITCH_ERROR
+static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control)
+{
+   spx_word32_t sum;
+   __asm__ __volatile__
+         (
+         "A0 = 0;\n\t"
+         
+         "R0 = W[%1++];\n\t"
+         "R1.L = %2.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %3.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %2.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+
+         "R1.L = %4.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%2.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %2.L*%2.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+
+         "R1.L = %3.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%4.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS);\n\t"
+         
+         "%0 = A0;\n\t"
+   : "=&D" (sum), "=a" (C)
+   : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C)
+   : "R0", "R1", "R2", "A0"
+         );
+   return sum;
+}
+
+#define OVERRIDE_OPEN_LOOP_NBEST_PITCH
+#ifdef OVERRIDE_OPEN_LOOP_NBEST_PITCH
+void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack)
+{
+   int i,j,k;
+   VARDECL(spx_word32_t *best_score);
+   VARDECL(spx_word32_t *best_ener);
+   spx_word32_t e0;
+   VARDECL(spx_word32_t *corr);
+   VARDECL(spx_word32_t *energy);
+
+   ALLOC(best_score, N, spx_word32_t);
+   ALLOC(best_ener, N, spx_word32_t);
+   ALLOC(corr, end-start+1, spx_word32_t);
+   ALLOC(energy, end-start+2, spx_word32_t);
+
+   for (i=0;i<N;i++)
+   {
+        best_score[i]=-1;
+        best_ener[i]=0;
+        pitch[i]=start;
+   }
+
+   energy[0]=inner_prod(sw-start, sw-start, len);
+   e0=inner_prod(sw, sw, len);
+
+   /* energy update -------------------------------------*/
+
+      __asm__ __volatile__
+      (
+"        P0 = %0;\n\t"
+"        I1 = %1;\n\t"
+"        L1 = 0;\n\t"
+"        I2 = %2;\n\t"
+"        L2 = 0;\n\t"
+"        R2 = [P0++];\n\t"
+"        R3 = 0;\n\t"
+"        LSETUP (eu1, eu2) LC1 = %3;\n\t"
+"eu1:      R1.L = W [I1--] || R0.L = W [I2--] ;\n\t"
+"          R1 = R1.L * R1.L (IS);\n\t"
+"          R0 = R0.L * R0.L (IS);\n\t"
+"          R1 >>>= 6;\n\t"
+"          R1 = R1 + R2;\n\t"
+"          R0 >>>= 6;\n\t"
+"          R1 = R1 - R0;\n\t"
+"          R2 = MAX(R1,R3);\n\t"
+"eu2:      [P0++] = R2;\n\t"
+       : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]),
+           "a" (end-start)  
+       : "P0", "I1", "I2", "R0", "R1", "R2", "R3"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+   pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
+
+   /* FIXME: Fixed-point and floating-point code should be merged */
+   {
+      VARDECL(spx_word16_t *corr16);
+      VARDECL(spx_word16_t *ener16);
+      ALLOC(corr16, end-start+1, spx_word16_t);
+      ALLOC(ener16, end-start+1, spx_word16_t);
+      /* Normalize to 180 so we can square it and it still fits in 16 bits */
+      normalize16(corr, corr16, 180, end-start+1);
+      normalize16(energy, ener16, 180, end-start+1);
+
+      if (N == 1) {
+	/* optimised asm to handle N==1 case */
+      __asm__ __volatile__
+      (
+"        I0 = %1;\n\t"                     /* I0: corr16[]    */
+"        L0 = 0;\n\t"
+"        I1 = %2;\n\t"                     /* I1: energy      */
+"        L1 = 0;\n\t"
+"        R2 = -1;\n\t"                     /* R2: best score  */
+"        R3 = 0;\n\t"                      /* R3: best energy */
+"        P0 = %4;\n\t"                     /* P0: best pitch  */
+"        P1 = %4;\n\t"                     /* P1: counter     */
+"        LSETUP (sl1, sl2) LC1 = %3;\n\t"
+"sl1:      R0.L = W [I0++] || R1.L = W [I1++];\n\t"         
+"          R0 = R0.L * R0.L (IS);\n\t"
+"          R1   += 1;\n\t"
+"          R4   = R0.L * R3.L;\n\t"
+"          R5   = R2.L * R1.L;\n\t"
+"          cc   = R5 < R4;\n\t"
+"          if cc R2 = R0;\n\t"
+"          if cc R3 = R1;\n\t"
+"          if cc P0 = P1;\n\t"
+"sl2:      P1 += 1;\n\t"
+"        %0 = P0;\n\t"
+       : "=&d" (pitch[0])
+       : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) 
+       : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+      }
+      else {
+	for (i=start;i<=end;i++)
+	  {
+	    spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
+	    /* Instead of dividing the tmp by the energy, we multiply on the other side */
+	    if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
+	      {
+		/* We can safely put it last and then check */
+		best_score[N-1]=tmp;
+		best_ener[N-1]=ener16[i-start]+1;
+		pitch[N-1]=i;
+		/* Check if it comes in front of others */
+		for (j=0;j<N-1;j++)
+		  {
+		    if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
+		      {
+			for (k=N-1;k>j;k--)
+			  {
+			    best_score[k]=best_score[k-1];
+			    best_ener[k]=best_ener[k-1];
+			    pitch[k]=pitch[k-1];
+			  }
+			best_score[j]=tmp;
+			best_ener[j]=ener16[i-start]+1;
+			pitch[j]=i;
+			break;
+		      }
+		  }
+	      }
+	  }
+      }
+   }
+
+   /* Compute open-loop gain */
+   if (gain)
+   {
+       for (j=0;j<N;j++)
+       {
+          spx_word16_t g;
+          i=pitch[j];
+          g = DIV32(corr[i-start], 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(energy[i-start])),6));
+          /* FIXME: g = max(g,corr/energy) */
+                   if (g<0)
+                   g = 0;
+             gain[j]=g;
+       }
+   }
+}
+#endif
+
+#define OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+#ifdef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+static int pitch_gain_search_3tap_vq(
+  const signed char *gain_cdbk,
+  int                gain_cdbk_size,
+  spx_word16_t      *C16,
+  spx_word16_t       max_gain
+)
+{
+  const signed char *ptr=gain_cdbk;
+  int                best_cdbk=0;
+  spx_word32_t       best_sum=-VERY_LARGE32;
+  spx_word32_t       sum=0;
+  spx_word16_t       g[3];
+  spx_word16_t       pitch_control=64;
+  spx_word16_t       gain_sum;
+  int                i;
+
+      /* fast asm version of VQ codebook search */
+
+      __asm__ __volatile__
+      (
+
+"        P0 = %2;\n\t"                     /* P0: ptr to gain_cdbk */
+"        L1 = 0;\n\t"                      /* no circ addr for L1  */
+"        %0 = 0;\n\t"                      /* %0: best_sum         */
+"        %1 = 0;\n\t"                      /* %1: best_cbdk        */
+"        P1 = 0;\n\t"                      /* P1: loop counter     */
+
+"        LSETUP (pgs1, pgs2) LC1 = %4;\n\t"
+"pgs1:     R2  = B [P0++] (X);\n\t"        /* R2: g[0]             */
+"          R3  = B [P0++] (X);\n\t"        /* R3: g[1]             */
+"          R4  = B [P0++] (X);\n\t"        /* R4: g[2]             */
+"          R2 += 32;\n\t"
+"          R3 += 32;\n\t"
+"          R4 += 32;\n\t"
+"          R4.H = 64;\n\t"                 /* R4.H: pitch_control    */
+
+"          R0  = B [P0++] (X);\n\t"              
+"          B0  = R0;\n\t"                  /* BO: gain_sum         */
+          
+           /* compute_pitch_error() -------------------------------*/
+
+"          I1 = %3;\n\t"                   /* I1: ptr to C         */
+"          A0 = 0;\n\t"
+         
+"          R0.L = W[I1++];\n\t"
+"          R1.L = R2.L*R4.H (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R3.L*R4.H (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R4.H (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R2.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+
+"          R1.L = R4.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R2.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R2.L*R2.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+
+"          R1.L = R3.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R4.L (IS);\n\t"
+"          R0 = (A0 -= R1.L*R0.L) (IS);\n\t"
+
+/*
+    Re-arrange the if-then to code efficiently on the Blackfin:
+
+      if (sum>best_sum && gain_sum<=max_gain)   ------ (1)
+
+      if (sum>best_sum && !(gain_sum>max_gain)) ------ (2)
+
+      if (max_gain<=gain_sum) {                 ------ (3)
+      sum = -VERY_LARGE32;
+      }
+      if (best_sum<=sum)
+
+    The blackin cc instructions are all of the form:
+
+      cc = x < y (or cc = x <= y)
+*/
+"          R1 = B0\n\t"
+"          R2 = %5\n\t"
+"          R3 = %6\n\t"
+"          cc = R2 <= R1;\n\t" 
+"          if cc R0 = R3;\n\t"
+"          cc = %0 <= R0;\n\t"
+"          if cc %0 = R0;\n\t"
+"          if cc %1 = P1;\n\t"
+
+"pgs2:     P1 += 1;\n\t"
+   
+       : "=&d" (best_sum), "=&d" (best_cdbk) 
+       : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain),
+         "b" (-VERY_LARGE32)
+       : "R0", "R1", "R2", "R3", "R4", "P0", 
+         "P1", "I1", "L1", "A0", "B0"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+  return best_cdbk;
+}
+#endif
+
diff --git a/jni/pjproject-android/.svn/pristine/94/94daadc48d598b5c06bb55c182302cf9f88e3e3f.svn-base b/jni/pjproject-android/.svn/pristine/94/94daadc48d598b5c06bb55c182302cf9f88e3e3f.svn-base
new file mode 100644
index 0000000..569193d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/94daadc48d598b5c06bb55c182302cf9f88e3e3f.svn-base
@@ -0,0 +1,45 @@
+EXPORTS
+	pjmedia_sdp_attr_add                     @ 1 NONAME
+	pjmedia_sdp_attr_clone                   @ 2 NONAME
+	pjmedia_sdp_attr_create                  @ 3 NONAME
+	pjmedia_sdp_attr_find                    @ 4 NONAME
+	pjmedia_sdp_attr_find2                   @ 5 NONAME
+	pjmedia_sdp_attr_get_fmtp                @ 6 NONAME
+	pjmedia_sdp_attr_get_rtcp                @ 7 NONAME
+	pjmedia_sdp_attr_get_rtpmap              @ 8 NONAME
+	pjmedia_sdp_attr_remove                  @ 9 NONAME
+	pjmedia_sdp_attr_remove_all              @ 10 NONAME
+	pjmedia_sdp_attr_to_rtpmap               @ 11 NONAME
+	pjmedia_sdp_conn_clone                   @ 12 NONAME
+	pjmedia_sdp_media_add_attr               @ 13 NONAME
+	pjmedia_sdp_media_clone                  @ 14 NONAME
+	pjmedia_sdp_media_cmp                    @ 15 NONAME
+	pjmedia_sdp_media_find_attr              @ 16 NONAME
+	pjmedia_sdp_media_find_attr2             @ 17 NONAME
+	pjmedia_sdp_media_remove_all_attr        @ 18 NONAME
+	pjmedia_sdp_media_remove_attr            @ 19 NONAME
+	pjmedia_sdp_neg_cancel_offer             @ 20 NONAME
+	pjmedia_sdp_neg_create_w_local_offer     @ 21 NONAME
+	pjmedia_sdp_neg_create_w_remote_offer    @ 22 NONAME
+	pjmedia_sdp_neg_get_active_local         @ 23 NONAME
+	pjmedia_sdp_neg_get_active_remote        @ 24 NONAME
+	pjmedia_sdp_neg_get_neg_local            @ 25 NONAME
+	pjmedia_sdp_neg_get_neg_remote           @ 26 NONAME
+	pjmedia_sdp_neg_get_state                @ 27 NONAME
+	pjmedia_sdp_neg_has_local_answer         @ 28 NONAME
+	pjmedia_sdp_neg_modify_local_offer       @ 29 NONAME
+	pjmedia_sdp_neg_negotiate                @ 30 NONAME
+	pjmedia_sdp_neg_send_local_offer         @ 31 NONAME
+	pjmedia_sdp_neg_set_local_answer         @ 32 NONAME
+	pjmedia_sdp_neg_set_prefer_remote_codec_order @ 33 NONAME
+	pjmedia_sdp_neg_set_remote_answer        @ 34 NONAME
+	pjmedia_sdp_neg_set_remote_offer         @ 35 NONAME
+	pjmedia_sdp_neg_state_str                @ 36 NONAME
+	pjmedia_sdp_neg_was_answer_remote        @ 37 NONAME
+	pjmedia_sdp_parse                        @ 38 NONAME
+	pjmedia_sdp_print                        @ 39 NONAME
+	pjmedia_sdp_rtpmap_to_attr               @ 40 NONAME
+	pjmedia_sdp_session_clone                @ 41 NONAME
+	pjmedia_sdp_session_cmp                  @ 42 NONAME
+	pjmedia_sdp_validate                     @ 43 NONAME
+	pjmedia_strerror                         @ 44 NONAME
diff --git a/jni/pjproject-android/.svn/pristine/94/94e286987adfd0edbbdafa926a887697d930bfe4.svn-base b/jni/pjproject-android/.svn/pristine/94/94e286987adfd0edbbdafa926a887697d930bfe4.svn-base
new file mode 100644
index 0000000..b0b6fa9
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/94/94e286987adfd0edbbdafa926a887697d930bfe4.svn-base
@@ -0,0 +1,224 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia/mem_port.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/pool.h>
+
+
+#define THIS_FILE	    "mem_player.c"
+
+#define SIGNATURE	    PJMEDIA_SIG_PORT_MEM_PLAYER
+#define BYTES_PER_SAMPLE    2
+
+struct mem_player
+{
+    pjmedia_port     base;
+
+    unsigned	     options;
+    pj_timestamp     timestamp;
+
+    char	    *buffer;
+    pj_size_t	     buf_size;
+    char	    *read_pos;
+
+    pj_bool_t	     eof;
+    void	    *user_data;
+    pj_status_t    (*cb)(pjmedia_port *port,
+			 void *user_data);
+
+};
+
+
+static pj_status_t mem_put_frame(pjmedia_port *this_port, 
+				 pjmedia_frame *frame);
+static pj_status_t mem_get_frame(pjmedia_port *this_port, 
+				  pjmedia_frame *frame);
+static pj_status_t mem_on_destroy(pjmedia_port *this_port);
+
+
+PJ_DEF(pj_status_t) pjmedia_mem_player_create( pj_pool_t *pool,
+					       const void *buffer,
+					       pj_size_t size,
+					       unsigned clock_rate,
+					       unsigned channel_count,
+					       unsigned samples_per_frame,
+					       unsigned bits_per_sample,
+					       unsigned options,
+					       pjmedia_port **p_port )
+{
+    struct mem_player *port;
+    pj_str_t name = pj_str("memplayer");
+
+    /* Sanity check */
+    PJ_ASSERT_RETURN(pool && buffer && size && clock_rate && channel_count &&
+		     samples_per_frame && bits_per_sample && p_port,
+		     PJ_EINVAL);
+
+    /* Can only support 16bit PCM */
+    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
+
+
+    port = PJ_POOL_ZALLOC_T(pool, struct mem_player);
+    PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);
+
+    /* Create the port */
+    pjmedia_port_info_init(&port->base.info, &name, SIGNATURE, clock_rate,
+			   channel_count, bits_per_sample, samples_per_frame);
+
+    port->base.put_frame = &mem_put_frame;
+    port->base.get_frame = &mem_get_frame;
+    port->base.on_destroy = &mem_on_destroy;
+
+
+    /* Save the buffer */
+    port->buffer = port->read_pos = (char*)buffer;
+    port->buf_size = size;
+
+    /* Options */
+    port->options = options;
+
+    *p_port = &port->base;
+
+    return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Register a callback to be called when the file reading has reached the
+ * end of buffer.
+ */
+PJ_DEF(pj_status_t) pjmedia_mem_player_set_eof_cb( pjmedia_port *port,
+			       void *user_data,
+			       pj_status_t (*cb)(pjmedia_port *port,
+						 void *usr_data))
+{
+    struct mem_player *player;
+
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
+		     PJ_EINVALIDOP);
+
+    player = (struct mem_player*) port;
+    player->user_data = user_data;
+    player->cb = cb;
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t mem_put_frame( pjmedia_port *this_port, 
+				  pjmedia_frame *frame)
+{
+    PJ_UNUSED_ARG(this_port);
+    PJ_UNUSED_ARG(frame);
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t mem_get_frame( pjmedia_port *this_port, 
+				  pjmedia_frame *frame)
+{
+    struct mem_player *player;
+    char *endpos;
+    pj_size_t size_needed, size_written;
+
+    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE,
+		     PJ_EINVALIDOP);
+
+    player = (struct mem_player*) this_port;
+
+    if (player->eof) {
+	pj_status_t status = PJ_SUCCESS;
+
+	/* Call callback, if any */
+	if (player->cb)
+	    status = (*player->cb)(this_port, player->user_data);
+
+	/* If callback returns non PJ_SUCCESS or 'no loop' is specified
+	 * return immediately (and don't try to access player port since
+	 * it might have been destroyed by the callback).
+	 */
+	if ((status != PJ_SUCCESS) || (player->options & PJMEDIA_MEM_NO_LOOP)) {
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    return PJ_EEOF;
+	}
+	
+	player->eof = PJ_FALSE;
+    }
+
+    size_needed = PJMEDIA_PIA_AVG_FSZ(&this_port->info);
+    size_written = 0;
+    endpos = player->buffer + player->buf_size;
+
+    while (size_written < size_needed) {
+	char *dst = ((char*)frame->buf) + size_written;
+	pj_size_t max;
+	
+	max = size_needed - size_written;
+	if (endpos - player->read_pos < (int)max)
+	    max = endpos - player->read_pos;
+
+	pj_memcpy(dst, player->read_pos, max);
+	size_written += max;
+	player->read_pos += max;
+
+	pj_assert(player->read_pos <= endpos);
+
+	if (player->read_pos == endpos) {
+	    /* Set EOF flag */
+	    player->eof = PJ_TRUE;
+	    /* Reset read pointer */
+	    player->read_pos = player->buffer;
+
+	    /* Pad with zeroes then return for no looped play */
+	    if (player->options & PJMEDIA_MEM_NO_LOOP) {
+		pj_size_t null_len;
+
+    		null_len = size_needed - size_written;
+		pj_bzero(dst + max, null_len);
+		break;
+	    }
+	}
+    }
+
+    frame->size = PJMEDIA_PIA_AVG_FSZ(&this_port->info);
+    frame->timestamp.u64 = player->timestamp.u64;
+    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+
+    player->timestamp.u64 += PJMEDIA_PIA_SPF(&this_port->info);
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t mem_on_destroy(pjmedia_port *this_port)
+{
+    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE,
+		     PJ_EINVALIDOP);
+
+    /* Destroy signature */
+    this_port->info.signature = 0;
+
+    return PJ_SUCCESS;
+}
+
+