* #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;
+}
+
+