* #27232: jni: added pjproject checkout as regular git content
We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6224bf475da0ff744684b3626008b86c7ca956e.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6224bf475da0ff744684b3626008b86c7ca956e.svn-base
new file mode 100644
index 0000000..82efbaf
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6224bf475da0ff744684b3626008b86c7ca956e.svn-base
@@ -0,0 +1,204 @@
+/* $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 <pjsip/sip_auth_aka.h>
+#include <pjsip/sip_errno.h>
+#include <pjlib-util/base64.h>
+#include <pjlib-util/md5.h>
+#include <pjlib-util/hmac_md5.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+#if PJSIP_HAS_DIGEST_AKA_AUTH
+
+#include "../../third_party/milenage/milenage.h"
+
+/*
+ * Create MD5-AKA1 digest response.
+ */
+PJ_DEF(pj_status_t) pjsip_auth_create_aka_response(
+ pj_pool_t *pool,
+ const pjsip_digest_challenge*chal,
+ const pjsip_cred_info *cred,
+ const pj_str_t *method,
+ pjsip_digest_credential *auth)
+{
+ pj_str_t nonce_bin;
+ int aka_version;
+ const pj_str_t pjsip_AKAv1_MD5 = { "AKAv1-MD5", 9 };
+ const pj_str_t pjsip_AKAv2_MD5 = { "AKAv2-MD5", 9 };
+ pj_uint8_t *chal_rand, *chal_sqnxoraka, *chal_mac;
+ pj_uint8_t k[PJSIP_AKA_KLEN];
+ pj_uint8_t op[PJSIP_AKA_OPLEN];
+ pj_uint8_t amf[PJSIP_AKA_AMFLEN];
+ pj_uint8_t res[PJSIP_AKA_RESLEN];
+ pj_uint8_t ck[PJSIP_AKA_CKLEN];
+ pj_uint8_t ik[PJSIP_AKA_IKLEN];
+ pj_uint8_t ak[PJSIP_AKA_AKLEN];
+ pj_uint8_t sqn[PJSIP_AKA_SQNLEN];
+ pj_uint8_t xmac[PJSIP_AKA_MACLEN];
+ pjsip_cred_info aka_cred;
+ int i, len;
+ pj_status_t status;
+
+ /* Check the algorithm is supported. */
+ if (chal->algorithm.slen==0 || pj_stricmp2(&chal->algorithm, "md5") == 0) {
+ /*
+ * A normal MD5 authentication is requested. Fallbackt to the usual
+ * MD5 digest creation.
+ */
+ pjsip_auth_create_digest(&auth->response, &auth->nonce, &auth->nc,
+ &auth->cnonce, &auth->qop, &auth->uri,
+ &auth->realm, cred, method);
+ return PJ_SUCCESS;
+
+ } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv1_MD5) == 0) {
+ /*
+ * AKA version 1 is requested.
+ */
+ aka_version = 1;
+
+ } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv2_MD5) == 0) {
+ /*
+ * AKA version 2 is requested.
+ */
+ aka_version = 2;
+
+ } else {
+ /* Unsupported algorithm */
+ return PJSIP_EINVALIDALGORITHM;
+ }
+
+ /* Decode nonce */
+ nonce_bin.slen = len = PJ_BASE64_TO_BASE256_LEN(chal->nonce.slen);
+ nonce_bin.ptr = pj_pool_alloc(pool, nonce_bin.slen + 1);
+ status = pj_base64_decode(&chal->nonce, (pj_uint8_t*)nonce_bin.ptr, &len);
+ nonce_bin.slen = len;
+ if (status != PJ_SUCCESS)
+ return PJSIP_EAUTHINNONCE;
+
+ if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN)
+ return PJSIP_EAUTHINNONCE;
+
+ /* Get RAND, AUTN, and MAC */
+ chal_rand = (pj_uint8_t*)(nonce_bin.ptr + 0);
+ chal_sqnxoraka = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN);
+ chal_mac = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN +
+ PJSIP_AKA_SQNLEN + PJSIP_AKA_AMFLEN);
+
+ /* Copy k. op, and amf */
+ pj_bzero(k, sizeof(k));
+ pj_bzero(op, sizeof(op));
+ pj_bzero(amf, sizeof(amf));
+
+ if (cred->ext.aka.k.slen)
+ pj_memcpy(k, cred->ext.aka.k.ptr, cred->ext.aka.k.slen);
+ if (cred->ext.aka.op.slen)
+ pj_memcpy(op, cred->ext.aka.op.ptr, cred->ext.aka.op.slen);
+ if (cred->ext.aka.amf.slen)
+ pj_memcpy(amf, cred->ext.aka.amf.ptr, cred->ext.aka.amf.slen);
+
+ /* Given key K and random challenge RAND, compute response RES,
+ * confidentiality key CK, integrity key IK and anonymity key AK.
+ */
+ f2345(k, chal_rand, res, ck, ik, ak, op);
+
+ /* Compute sequence number SQN */
+ for (i=0; i<PJSIP_AKA_SQNLEN; ++i)
+ sqn[i] = (pj_uint8_t) (chal_sqnxoraka[i] ^ ak[i]);
+
+ /* Verify MAC in the challenge */
+ /* Compute XMAC */
+ f1(k, chal_rand, sqn, amf, xmac, op);
+
+ if (pj_memcmp(chal_mac, xmac, PJSIP_AKA_MACLEN) != 0) {
+ return PJSIP_EAUTHINNONCE;
+ }
+
+ /* Build a temporary credential info to create MD5 digest, using
+ * "res" as the password.
+ */
+ pj_memcpy(&aka_cred, cred, sizeof(aka_cred));
+ aka_cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+
+ /* Create a response */
+ if (aka_version == 1) {
+ /*
+ * For AKAv1, the password is RES
+ */
+ aka_cred.data.ptr = (char*)res;
+ aka_cred.data.slen = PJSIP_AKA_RESLEN;
+
+ pjsip_auth_create_digest(&auth->response, &chal->nonce,
+ &auth->nc, &auth->cnonce, &auth->qop,
+ &auth->uri, &chal->realm, &aka_cred, method);
+
+ } else if (aka_version == 2) {
+
+ /*
+ * For AKAv2, password is base64 encoded [1] parameters:
+ * PRF(RES||IK||CK,"http-digest-akav2-password")
+ *
+ * The pseudo-random function (PRF) is HMAC-MD5 in this case.
+ */
+
+ pj_str_t resikck;
+ const pj_str_t AKAv2_Passwd = { "http-digest-akav2-password", 26 };
+ pj_uint8_t hmac_digest[16];
+ char tmp_buf[48];
+ int hmac64_len;
+
+ resikck.slen = PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN + PJSIP_AKA_CKLEN;
+ pj_assert(resikck.slen <= PJ_ARRAY_SIZE(tmp_buf));
+ resikck.ptr = tmp_buf;
+ pj_memcpy(resikck.ptr + 0, res, PJSIP_AKA_RESLEN);
+ pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN, ik, PJSIP_AKA_IKLEN);
+ pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN,
+ ck, PJSIP_AKA_CKLEN);
+
+ pj_hmac_md5((const pj_uint8_t*)AKAv2_Passwd.ptr, AKAv2_Passwd.slen,
+ (const pj_uint8_t*)resikck.ptr, resikck.slen,
+ hmac_digest);
+
+ aka_cred.data.slen = hmac64_len =
+ PJ_BASE256_TO_BASE64_LEN(PJ_ARRAY_SIZE(hmac_digest));
+ pj_assert(aka_cred.data.slen+1 <= PJ_ARRAY_SIZE(tmp_buf));
+ aka_cred.data.ptr = tmp_buf;
+ pj_base64_encode(hmac_digest, PJ_ARRAY_SIZE(hmac_digest),
+ aka_cred.data.ptr, &len);
+ aka_cred.data.slen = hmac64_len;
+
+ pjsip_auth_create_digest(&auth->response, &chal->nonce,
+ &auth->nc, &auth->cnonce, &auth->qop,
+ &auth->uri, &chal->realm, &aka_cred, method);
+
+ } else {
+ pj_assert(!"Bug!");
+ return PJ_EBUG;
+ }
+
+ /* Done */
+ return PJ_SUCCESS;
+}
+
+
+#endif /* PJSIP_HAS_DIGEST_AKA_AUTH */
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b630599ff4c8933b92a0b6ca035e3fe56e82b1a2.svn-base b/jni/pjproject-android/.svn/pristine/b6/b630599ff4c8933b92a0b6ca035e3fe56e82b1a2.svn-base
new file mode 100644
index 0000000..5ccdd3f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b630599ff4c8933b92a0b6ca035e3fe56e82b1a2.svn-base
@@ -0,0 +1,1336 @@
+/* $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
+ */
+
+/*
+ * ioqueue_common_abs.c
+ *
+ * This contains common functionalities to emulate proactor pattern with
+ * various event dispatching mechanisms (e.g. select, epoll).
+ *
+ * This file will be included by the appropriate ioqueue implementation.
+ * This file is NOT supposed to be compiled as stand-alone source.
+ */
+
+#define PENDING_RETRY 2
+
+static void ioqueue_init( pj_ioqueue_t *ioqueue )
+{
+ ioqueue->lock = NULL;
+ ioqueue->auto_delete_lock = 0;
+ ioqueue->default_concurrency = PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY;
+}
+
+static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+ if (ioqueue->auto_delete_lock && ioqueue->lock ) {
+ pj_lock_release(ioqueue->lock);
+ return pj_lock_destroy(ioqueue->lock);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_set_lock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue,
+ pj_lock_t *lock,
+ pj_bool_t auto_delete )
+{
+ PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
+
+ if (ioqueue->auto_delete_lock && ioqueue->lock) {
+ pj_lock_destroy(ioqueue->lock);
+ }
+
+ ioqueue->lock = lock;
+ ioqueue->auto_delete_lock = auto_delete;
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t ioqueue_init_key( pj_pool_t *pool,
+ pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ pj_sock_t sock,
+ pj_grp_lock_t *grp_lock,
+ void *user_data,
+ const pj_ioqueue_callback *cb)
+{
+ pj_status_t rc;
+ int optlen;
+
+ PJ_UNUSED_ARG(pool);
+
+ key->ioqueue = ioqueue;
+ key->fd = sock;
+ key->user_data = user_data;
+ pj_list_init(&key->read_list);
+ pj_list_init(&key->write_list);
+#if PJ_HAS_TCP
+ pj_list_init(&key->accept_list);
+ key->connecting = 0;
+#endif
+
+ /* Save callback. */
+ pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));
+
+#if PJ_IOQUEUE_HAS_SAFE_UNREG
+ /* Set initial reference count to 1 */
+ pj_assert(key->ref_count == 0);
+ ++key->ref_count;
+
+ key->closing = 0;
+#endif
+
+ rc = pj_ioqueue_set_concurrency(key, ioqueue->default_concurrency);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Get socket type. When socket type is datagram, some optimization
+ * will be performed during send to allow parallel send operations.
+ */
+ optlen = sizeof(key->fd_type);
+ rc = pj_sock_getsockopt(sock, pj_SOL_SOCKET(), pj_SO_TYPE(),
+ &key->fd_type, &optlen);
+ if (rc != PJ_SUCCESS)
+ key->fd_type = pj_SOCK_STREAM();
+
+ /* Create mutex for the key. */
+#if !PJ_IOQUEUE_HAS_SAFE_UNREG
+ rc = pj_lock_create_simple_mutex(poll, NULL, &key->lock);
+#endif
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Group lock */
+ key->grp_lock = grp_lock;
+ if (key->grp_lock) {
+ pj_grp_lock_add_ref_dbg(key->grp_lock, "ioqueue", 0);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_get_user_data()
+ *
+ * Obtain value associated with a key.
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+ PJ_ASSERT_RETURN(key != NULL, NULL);
+ return key->user_data;
+}
+
+/*
+ * pj_ioqueue_set_user_data()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+ void *user_data,
+ void **old_data)
+{
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+ if (old_data)
+ *old_data = key->user_data;
+ key->user_data = user_data;
+
+ return PJ_SUCCESS;
+}
+
+PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)
+{
+ return !pj_list_empty(&key->write_list);
+}
+
+PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)
+{
+ return !pj_list_empty(&key->read_list);
+}
+
+PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)
+{
+#if PJ_HAS_TCP
+ return !pj_list_empty(&key->accept_list);
+#else
+ PJ_UNUSED_ARG(key);
+ return 0;
+#endif
+}
+
+PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)
+{
+ return key->connecting;
+}
+
+
+#if PJ_IOQUEUE_HAS_SAFE_UNREG
+# define IS_CLOSING(key) (key->closing)
+#else
+# define IS_CLOSING(key) (0)
+#endif
+
+
+/*
+ * ioqueue_dispatch_event()
+ *
+ * Report occurence of an event in the key to be processed by the
+ * framework.
+ */
+void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
+{
+ /* Lock the key. */
+ pj_ioqueue_lock_key(h);
+
+ if (IS_CLOSING(h)) {
+ pj_ioqueue_unlock_key(h);
+ return;
+ }
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
+ if (h->connecting) {
+ /* Completion of connect() operation */
+ pj_status_t status;
+ pj_bool_t has_lock;
+
+ /* Clear operation. */
+ h->connecting = 0;
+
+ ioqueue_remove_from_set(ioqueue, h, WRITEABLE_EVENT);
+ ioqueue_remove_from_set(ioqueue, h, EXCEPTION_EVENT);
+
+
+#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
+ /* from connect(2):
+ * On Linux, use getsockopt to read the SO_ERROR option at
+ * level SOL_SOCKET to determine whether connect() completed
+ * successfully (if SO_ERROR is zero).
+ */
+ {
+ int value;
+ int vallen = sizeof(value);
+ int gs_rc = pj_sock_getsockopt(h->fd, SOL_SOCKET, SO_ERROR,
+ &value, &vallen);
+ if (gs_rc != 0) {
+ /* Argh!! What to do now???
+ * Just indicate that the socket is connected. The
+ * application will get error as soon as it tries to use
+ * the socket to send/receive.
+ */
+ status = PJ_SUCCESS;
+ } else {
+ status = PJ_STATUS_FROM_OS(value);
+ }
+ }
+#elif (defined(PJ_WIN32) && PJ_WIN32!=0) || (defined(PJ_WIN64) && PJ_WIN64!=0)
+ status = PJ_SUCCESS; /* success */
+#else
+ /* Excellent information in D.J. Bernstein page:
+ * http://cr.yp.to/docs/connect.html
+ *
+ * Seems like the most portable way of detecting connect()
+ * failure is to call getpeername(). If socket is connected,
+ * getpeername() will return 0. If the socket is not connected,
+ * it will return ENOTCONN, and read(fd, &ch, 1) will produce
+ * the right errno through error slippage. This is a combination
+ * of suggestions from Douglas C. Schmidt and Ken Keys.
+ */
+ {
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ status = pj_sock_getpeername(h->fd, (struct sockaddr*)&addr,
+ &addrlen);
+ }
+#endif
+
+ /* Unlock; from this point we don't need to hold key's mutex
+ * (unless concurrency is disabled, which in this case we should
+ * hold the mutex while calling the callback) */
+ if (h->allow_concurrent) {
+ /* concurrency may be changed while we're in the callback, so
+ * save it to a flag.
+ */
+ has_lock = PJ_FALSE;
+ pj_ioqueue_unlock_key(h);
+ } else {
+ has_lock = PJ_TRUE;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_connect_complete && !IS_CLOSING(h))
+ (*h->cb.on_connect_complete)(h, status);
+
+ /* Unlock if we still hold the lock */
+ if (has_lock) {
+ pj_ioqueue_unlock_key(h);
+ }
+
+ /* Done. */
+
+ } else
+#endif /* PJ_HAS_TCP */
+ if (key_has_pending_write(h)) {
+ /* Socket is writable. */
+ struct write_operation *write_op;
+ pj_ssize_t sent;
+ pj_status_t send_rc = PJ_SUCCESS;
+
+ /* Get the first in the queue. */
+ write_op = h->write_list.next;
+
+ /* For datagrams, we can remove the write_op from the list
+ * so that send() can work in parallel.
+ */
+ if (h->fd_type == pj_SOCK_DGRAM()) {
+ pj_list_erase(write_op);
+
+ if (pj_list_empty(&h->write_list))
+ ioqueue_remove_from_set(ioqueue, h, WRITEABLE_EVENT);
+
+ }
+
+ /* Send the data.
+ * Unfortunately we must do this while holding key's mutex, thus
+ * preventing parallel write on a single key.. :-((
+ */
+ sent = write_op->size - write_op->written;
+ if (write_op->op == PJ_IOQUEUE_OP_SEND) {
+ send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,
+ &sent, write_op->flags);
+ /* Can't do this. We only clear "op" after we're finished sending
+ * the whole buffer.
+ */
+ //write_op->op = 0;
+ } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
+ int retry = 2;
+ while (--retry >= 0) {
+ send_rc = pj_sock_sendto(h->fd,
+ write_op->buf+write_op->written,
+ &sent, write_op->flags,
+ &write_op->rmt_addr,
+ write_op->rmt_addrlen);
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+ /* Special treatment for dead UDP sockets here, see ticket #1107 */
+ if (send_rc==PJ_STATUS_FROM_OS(EPIPE) && !IS_CLOSING(h) &&
+ h->fd_type==pj_SOCK_DGRAM())
+ {
+ PJ_PERROR(4,(THIS_FILE, send_rc,
+ "Send error for socket %d, retrying",
+ h->fd));
+ replace_udp_sock(h);
+ continue;
+ }
+#endif
+ break;
+ }
+
+ /* Can't do this. We only clear "op" after we're finished sending
+ * the whole buffer.
+ */
+ //write_op->op = 0;
+ } else {
+ pj_assert(!"Invalid operation type!");
+ write_op->op = PJ_IOQUEUE_OP_NONE;
+ send_rc = PJ_EBUG;
+ }
+
+ if (send_rc == PJ_SUCCESS) {
+ write_op->written += sent;
+ } else {
+ pj_assert(send_rc > 0);
+ write_op->written = -send_rc;
+ }
+
+ /* Are we finished with this buffer? */
+ if (send_rc!=PJ_SUCCESS ||
+ write_op->written == (pj_ssize_t)write_op->size ||
+ h->fd_type == pj_SOCK_DGRAM())
+ {
+ pj_bool_t has_lock;
+
+ write_op->op = PJ_IOQUEUE_OP_NONE;
+
+ if (h->fd_type != pj_SOCK_DGRAM()) {
+ /* Write completion of the whole stream. */
+ pj_list_erase(write_op);
+
+ /* Clear operation if there's no more data to send. */
+ if (pj_list_empty(&h->write_list))
+ ioqueue_remove_from_set(ioqueue, h, WRITEABLE_EVENT);
+
+ }
+
+ /* Unlock; from this point we don't need to hold key's mutex
+ * (unless concurrency is disabled, which in this case we should
+ * hold the mutex while calling the callback) */
+ if (h->allow_concurrent) {
+ /* concurrency may be changed while we're in the callback, so
+ * save it to a flag.
+ */
+ has_lock = PJ_FALSE;
+ pj_ioqueue_unlock_key(h);
+ PJ_RACE_ME(5);
+ } else {
+ has_lock = PJ_TRUE;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_write_complete && !IS_CLOSING(h)) {
+ (*h->cb.on_write_complete)(h,
+ (pj_ioqueue_op_key_t*)write_op,
+ write_op->written);
+ }
+
+ if (has_lock) {
+ pj_ioqueue_unlock_key(h);
+ }
+
+ } else {
+ pj_ioqueue_unlock_key(h);
+ }
+
+ /* Done. */
+ } else {
+ /*
+ * This is normal; execution may fall here when multiple threads
+ * are signalled for the same event, but only one thread eventually
+ * able to process the event.
+ */
+ pj_ioqueue_unlock_key(h);
+ }
+}
+
+void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
+{
+ pj_status_t rc;
+
+ /* Lock the key. */
+ pj_ioqueue_lock_key(h);
+
+ if (IS_CLOSING(h)) {
+ pj_ioqueue_unlock_key(h);
+ return;
+ }
+
+# if PJ_HAS_TCP
+ if (!pj_list_empty(&h->accept_list)) {
+
+ struct accept_operation *accept_op;
+ pj_bool_t has_lock;
+
+ /* Get one accept operation from the list. */
+ accept_op = h->accept_list.next;
+ pj_list_erase(accept_op);
+ accept_op->op = PJ_IOQUEUE_OP_NONE;
+
+ /* Clear bit in fdset if there is no more pending accept */
+ if (pj_list_empty(&h->accept_list))
+ ioqueue_remove_from_set(ioqueue, h, READABLE_EVENT);
+
+ rc=pj_sock_accept(h->fd, accept_op->accept_fd,
+ accept_op->rmt_addr, accept_op->addrlen);
+ if (rc==PJ_SUCCESS && accept_op->local_addr) {
+ rc = pj_sock_getsockname(*accept_op->accept_fd,
+ accept_op->local_addr,
+ accept_op->addrlen);
+ }
+
+ /* Unlock; from this point we don't need to hold key's mutex
+ * (unless concurrency is disabled, which in this case we should
+ * hold the mutex while calling the callback) */
+ if (h->allow_concurrent) {
+ /* concurrency may be changed while we're in the callback, so
+ * save it to a flag.
+ */
+ has_lock = PJ_FALSE;
+ pj_ioqueue_unlock_key(h);
+ PJ_RACE_ME(5);
+ } else {
+ has_lock = PJ_TRUE;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_accept_complete && !IS_CLOSING(h)) {
+ (*h->cb.on_accept_complete)(h,
+ (pj_ioqueue_op_key_t*)accept_op,
+ *accept_op->accept_fd, rc);
+ }
+
+ if (has_lock) {
+ pj_ioqueue_unlock_key(h);
+ }
+ }
+ else
+# endif
+ if (key_has_pending_read(h)) {
+ struct read_operation *read_op;
+ pj_ssize_t bytes_read;
+ pj_bool_t has_lock;
+
+ /* Get one pending read operation from the list. */
+ read_op = h->read_list.next;
+ pj_list_erase(read_op);
+
+ /* Clear fdset if there is no pending read. */
+ if (pj_list_empty(&h->read_list))
+ ioqueue_remove_from_set(ioqueue, h, READABLE_EVENT);
+
+ bytes_read = read_op->size;
+
+ if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
+ read_op->op = PJ_IOQUEUE_OP_NONE;
+ rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read,
+ read_op->flags,
+ read_op->rmt_addr,
+ read_op->rmt_addrlen);
+ } else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
+ read_op->op = PJ_IOQUEUE_OP_NONE;
+ rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read,
+ read_op->flags);
+ } else {
+ pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
+ read_op->op = PJ_IOQUEUE_OP_NONE;
+ /*
+ * User has specified pj_ioqueue_read().
+ * On Win32, we should do ReadFile(). But because we got
+ * here because of select() anyway, user must have put a
+ * socket descriptor on h->fd, which in this case we can
+ * just call pj_sock_recv() instead of ReadFile().
+ * On Unix, user may put a file in h->fd, so we'll have
+ * to call read() here.
+ * This may not compile on systems which doesn't have
+ * read(). That's why we only specify PJ_LINUX here so
+ * that error is easier to catch.
+ */
+# if defined(PJ_WIN32) && PJ_WIN32 != 0 || \
+ defined(PJ_WIN64) && PJ_WIN64 != 0 || \
+ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE != 0
+ rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read,
+ read_op->flags);
+ //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
+ // &bytes_read, NULL);
+# elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
+ bytes_read = read(h->fd, read_op->buf, bytes_read);
+ rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
+# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
+ bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
+ rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
+# else
+# error "Implement read() for this platform!"
+# endif
+ }
+
+ if (rc != PJ_SUCCESS) {
+# if (defined(PJ_WIN32) && PJ_WIN32 != 0) || \
+ (defined(PJ_WIN64) && PJ_WIN64 != 0)
+ /* On Win32, for UDP, WSAECONNRESET on the receive side
+ * indicates that previous sending has triggered ICMP Port
+ * Unreachable message.
+ * But we wouldn't know at this point which one of previous
+ * key that has triggered the error, since UDP socket can
+ * be shared!
+ * So we'll just ignore it!
+ */
+
+ if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
+ //PJ_LOG(4,(THIS_FILE,
+ // "Ignored ICMP port unreach. on key=%p", h));
+ }
+# endif
+
+ /* In any case we would report this to caller. */
+ bytes_read = -rc;
+
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+ /* Special treatment for dead UDP sockets here, see ticket #1107 */
+ if (rc == PJ_STATUS_FROM_OS(ENOTCONN) && !IS_CLOSING(h) &&
+ h->fd_type==pj_SOCK_DGRAM())
+ {
+ replace_udp_sock(h);
+ }
+#endif
+ }
+
+ /* Unlock; from this point we don't need to hold key's mutex
+ * (unless concurrency is disabled, which in this case we should
+ * hold the mutex while calling the callback) */
+ if (h->allow_concurrent) {
+ /* concurrency may be changed while we're in the callback, so
+ * save it to a flag.
+ */
+ has_lock = PJ_FALSE;
+ pj_ioqueue_unlock_key(h);
+ PJ_RACE_ME(5);
+ } else {
+ has_lock = PJ_TRUE;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_read_complete && !IS_CLOSING(h)) {
+ (*h->cb.on_read_complete)(h,
+ (pj_ioqueue_op_key_t*)read_op,
+ bytes_read);
+ }
+
+ if (has_lock) {
+ pj_ioqueue_unlock_key(h);
+ }
+
+ } else {
+ /*
+ * This is normal; execution may fall here when multiple threads
+ * are signalled for the same event, but only one thread eventually
+ * able to process the event.
+ */
+ pj_ioqueue_unlock_key(h);
+ }
+}
+
+
+void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *h )
+{
+ pj_bool_t has_lock;
+
+ pj_ioqueue_lock_key(h);
+
+ if (!h->connecting) {
+ /* It is possible that more than one thread was woken up, thus
+ * the remaining thread will see h->connecting as zero because
+ * it has been processed by other thread.
+ */
+ pj_ioqueue_unlock_key(h);
+ return;
+ }
+
+ if (IS_CLOSING(h)) {
+ pj_ioqueue_unlock_key(h);
+ return;
+ }
+
+ /* Clear operation. */
+ h->connecting = 0;
+
+ ioqueue_remove_from_set(ioqueue, h, WRITEABLE_EVENT);
+ ioqueue_remove_from_set(ioqueue, h, EXCEPTION_EVENT);
+
+ /* Unlock; from this point we don't need to hold key's mutex
+ * (unless concurrency is disabled, which in this case we should
+ * hold the mutex while calling the callback) */
+ if (h->allow_concurrent) {
+ /* concurrency may be changed while we're in the callback, so
+ * save it to a flag.
+ */
+ has_lock = PJ_FALSE;
+ pj_ioqueue_unlock_key(h);
+ PJ_RACE_ME(5);
+ } else {
+ has_lock = PJ_TRUE;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_connect_complete && !IS_CLOSING(h)) {
+ pj_status_t status = -1;
+#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
+ int value;
+ int vallen = sizeof(value);
+ int gs_rc = pj_sock_getsockopt(h->fd, SOL_SOCKET, SO_ERROR,
+ &value, &vallen);
+ if (gs_rc == 0) {
+ status = PJ_RETURN_OS_ERROR(value);
+ }
+#endif
+
+ (*h->cb.on_connect_complete)(h, status);
+ }
+
+ if (has_lock) {
+ pj_ioqueue_unlock_key(h);
+ }
+}
+
+/*
+ * pj_ioqueue_recv()
+ *
+ * Start asynchronous recv() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags )
+{
+ struct read_operation *read_op;
+
+ PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
+
+ /* Check if key is closing (need to do this first before accessing
+ * other variables, since they might have been destroyed. See ticket
+ * #469).
+ */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ read_op = (struct read_operation*)op_key;
+ read_op->op = PJ_IOQUEUE_OP_NONE;
+
+ /* Try to see if there's data immediately available.
+ */
+ if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+ pj_status_t status;
+ pj_ssize_t size;
+
+ size = *length;
+ status = pj_sock_recv(key->fd, buffer, &size, flags);
+ if (status == PJ_SUCCESS) {
+ /* Yes! Data is available! */
+ *length = size;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+ return status;
+ }
+ }
+
+ flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+ /*
+ * No data is immediately available.
+ * Must schedule asynchronous operation to the ioqueue.
+ */
+ read_op->op = PJ_IOQUEUE_OP_RECV;
+ read_op->buf = buffer;
+ read_op->size = *length;
+ read_op->flags = flags;
+
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous check
+ * in multithreaded app. If we add bad handle to the set it will
+ * corrupt the ioqueue set. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ pj_list_insert_before(&key->read_list, read_op);
+ ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_recvfrom()
+ *
+ * Start asynchronous recvfrom() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ struct read_operation *read_op;
+
+ PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
+
+ /* Check if key is closing. */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ read_op = (struct read_operation*)op_key;
+ read_op->op = PJ_IOQUEUE_OP_NONE;
+
+ /* Try to see if there's data immediately available.
+ */
+ if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+ pj_status_t status;
+ pj_ssize_t size;
+
+ size = *length;
+ status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
+ addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Yes! Data is available! */
+ *length = size;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+ return status;
+ }
+ }
+
+ flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+ /*
+ * No data is immediately available.
+ * Must schedule asynchronous operation to the ioqueue.
+ */
+ read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
+ read_op->buf = buffer;
+ read_op->size = *length;
+ read_op->flags = flags;
+ read_op->rmt_addr = addr;
+ read_op->rmt_addrlen = addrlen;
+
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous check
+ * in multithreaded app. If we add bad handle to the set it will
+ * corrupt the ioqueue set. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ pj_list_insert_before(&key->read_list, read_op);
+ ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_send()
+ *
+ * Start asynchronous send() to the descriptor.
+ */
+PJ_DEF(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,
+ unsigned flags)
+{
+ struct write_operation *write_op;
+ pj_status_t status;
+ unsigned retry;
+ pj_ssize_t sent;
+
+ PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
+
+ /* Check if key is closing. */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write. */
+ flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+ /* Fast track:
+ * Try to send data immediately, only if there's no pending write!
+ * Note:
+ * We are speculating that the list is empty here without properly
+ * acquiring ioqueue's mutex first. This is intentional, to maximize
+ * performance via parallelism.
+ *
+ * This should be safe, because:
+ * - by convention, we require caller to make sure that the
+ * key is not unregistered while other threads are invoking
+ * an operation on the same key.
+ * - pj_list_empty() is safe to be invoked by multiple threads,
+ * even when other threads are modifying the list.
+ */
+ if (pj_list_empty(&key->write_list)) {
+ /*
+ * See if data can be sent immediately.
+ */
+ sent = *length;
+ status = pj_sock_send(key->fd, data, &sent, flags);
+ if (status == PJ_SUCCESS) {
+ /* Success! */
+ *length = sent;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+ return status;
+ }
+ }
+ }
+
+ /*
+ * Schedule asynchronous send.
+ */
+ write_op = (struct write_operation*)op_key;
+
+ /* Spin if write_op has pending operation */
+ for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry)
+ pj_thread_sleep(0);
+
+ /* Last chance */
+ if (write_op->op) {
+ /* Unable to send packet because there is already pending write in the
+ * write_op. We could not put the operation into the write_op
+ * because write_op already contains a pending operation! And
+ * we could not send the packet directly with send() either,
+ * because that will break the order of the packet. So we can
+ * only return error here.
+ *
+ * This could happen for example in multithreads program,
+ * where polling is done by one thread, while other threads are doing
+ * the sending only. If the polling thread runs on lower priority
+ * than the sending thread, then it's possible that the pending
+ * write flag is not cleared in-time because clearing is only done
+ * during polling.
+ *
+ * Aplication should specify multiple write operation keys on
+ * situation like this.
+ */
+ //pj_assert(!"ioqueue: there is pending operation on this key!");
+ return PJ_EBUSY;
+ }
+
+ write_op->op = PJ_IOQUEUE_OP_SEND;
+ write_op->buf = (char*)data;
+ write_op->size = *length;
+ write_op->written = 0;
+ write_op->flags = flags;
+
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous check
+ * in multithreaded app. If we add bad handle to the set it will
+ * corrupt the ioqueue set. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ pj_list_insert_before(&key->write_list, write_op);
+ ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EPENDING;
+}
+
+
+/*
+ * pj_ioqueue_sendto()
+ *
+ * Start asynchronous write() to the descriptor.
+ */
+PJ_DEF(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)
+{
+ struct write_operation *write_op;
+ unsigned retry;
+ pj_bool_t restart_retry = PJ_FALSE;
+ pj_status_t status;
+ pj_ssize_t sent;
+
+ PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
+
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+retry_on_restart:
+#else
+ PJ_UNUSED_ARG(restart_retry);
+#endif
+ /* Check if key is closing. */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */
+ flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+ /* Fast track:
+ * Try to send data immediately, only if there's no pending write!
+ * Note:
+ * We are speculating that the list is empty here without properly
+ * acquiring ioqueue's mutex first. This is intentional, to maximize
+ * performance via parallelism.
+ *
+ * This should be safe, because:
+ * - by convention, we require caller to make sure that the
+ * key is not unregistered while other threads are invoking
+ * an operation on the same key.
+ * - pj_list_empty() is safe to be invoked by multiple threads,
+ * even when other threads are modifying the list.
+ */
+ if (pj_list_empty(&key->write_list)) {
+ /*
+ * See if data can be sent immediately.
+ */
+ sent = *length;
+ status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Success! */
+ *length = sent;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+ /* Special treatment for dead UDP sockets here, see ticket #1107 */
+ if (status==PJ_STATUS_FROM_OS(EPIPE) && !IS_CLOSING(key) &&
+ key->fd_type==pj_SOCK_DGRAM() && !restart_retry)
+ {
+ PJ_PERROR(4,(THIS_FILE, status,
+ "Send error for socket %d, retrying",
+ key->fd));
+ replace_udp_sock(key);
+ restart_retry = PJ_TRUE;
+ goto retry_on_restart;
+ }
+#endif
+
+ return status;
+ }
+ status = status;
+ }
+ }
+
+ /*
+ * Check that address storage can hold the address parameter.
+ */
+ PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG);
+
+ /*
+ * Schedule asynchronous send.
+ */
+ write_op = (struct write_operation*)op_key;
+
+ /* Spin if write_op has pending operation */
+ for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry)
+ pj_thread_sleep(0);
+
+ /* Last chance */
+ if (write_op->op) {
+ /* Unable to send packet because there is already pending write on the
+ * write_op. We could not put the operation into the write_op
+ * because write_op already contains a pending operation! And
+ * we could not send the packet directly with sendto() either,
+ * because that will break the order of the packet. So we can
+ * only return error here.
+ *
+ * This could happen for example in multithreads program,
+ * where polling is done by one thread, while other threads are doing
+ * the sending only. If the polling thread runs on lower priority
+ * than the sending thread, then it's possible that the pending
+ * write flag is not cleared in-time because clearing is only done
+ * during polling.
+ *
+ * Aplication should specify multiple write operation keys on
+ * situation like this.
+ */
+ //pj_assert(!"ioqueue: there is pending operation on this key!");
+ return PJ_EBUSY;
+ }
+
+ write_op->op = PJ_IOQUEUE_OP_SEND_TO;
+ write_op->buf = (char*)data;
+ write_op->size = *length;
+ write_op->written = 0;
+ write_op->flags = flags;
+ pj_memcpy(&write_op->rmt_addr, addr, addrlen);
+ write_op->rmt_addrlen = addrlen;
+
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous check
+ * in multithreaded app. If we add bad handle to the set it will
+ * corrupt the ioqueue set. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ pj_list_insert_before(&key->write_list, write_op);
+ ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EPENDING;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(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)
+{
+ struct accept_operation *accept_op;
+ pj_status_t status;
+
+ /* check parameters. All must be specified! */
+ PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+
+ /* Check if key is closing. */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ accept_op = (struct accept_operation*)op_key;
+ accept_op->op = PJ_IOQUEUE_OP_NONE;
+
+ /* Fast track:
+ * See if there's new connection available immediately.
+ */
+ if (pj_list_empty(&key->accept_list)) {
+ status = pj_sock_accept(key->fd, new_sock, remote, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Yes! New connection is available! */
+ if (local && addrlen) {
+ status = pj_sock_getsockname(*new_sock, local, addrlen);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(*new_sock);
+ *new_sock = PJ_INVALID_SOCKET;
+ return status;
+ }
+ }
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+ return status;
+ }
+ }
+ }
+
+ /*
+ * No connection is available immediately.
+ * Schedule accept() operation to be completed when there is incoming
+ * connection available.
+ */
+ accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
+ accept_op->accept_fd = new_sock;
+ accept_op->rmt_addr = remote;
+ accept_op->addrlen= addrlen;
+ accept_op->local_addr = local;
+
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous check
+ * in multithreaded app. If we add bad handle to the set it will
+ * corrupt the ioqueue set. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ pj_list_insert_before(&key->accept_list, accept_op);
+ ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen )
+{
+ pj_status_t status;
+
+ /* check parameters. All must be specified! */
+ PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
+
+ /* Check if key is closing. */
+ if (IS_CLOSING(key))
+ return PJ_ECANCELLED;
+
+ /* Check if socket has not been marked for connecting */
+ if (key->connecting != 0)
+ return PJ_EPENDING;
+
+ status = pj_sock_connect(key->fd, addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Connected! */
+ return PJ_SUCCESS;
+ } else {
+ if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
+ /* Pending! */
+ pj_ioqueue_lock_key(key);
+ /* Check again. Handle may have been closed after the previous
+ * check in multithreaded app. See #913
+ */
+ if (IS_CLOSING(key)) {
+ pj_ioqueue_unlock_key(key);
+ return PJ_ECANCELLED;
+ }
+ key->connecting = PJ_TRUE;
+ ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
+ ioqueue_add_to_set(key->ioqueue, key, EXCEPTION_EVENT);
+ pj_ioqueue_unlock_key(key);
+ return PJ_EPENDING;
+ } else {
+ /* Error! */
+ return status;
+ }
+ }
+}
+#endif /* PJ_HAS_TCP */
+
+
+PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
+ pj_size_t size )
+{
+ pj_bzero(op_key, size);
+}
+
+
+/*
+ * pj_ioqueue_is_pending()
+ */
+PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key )
+{
+ struct generic_operation *op_rec;
+
+ PJ_UNUSED_ARG(key);
+
+ op_rec = (struct generic_operation*)op_key;
+ return op_rec->op != 0;
+}
+
+
+/*
+ * pj_ioqueue_post_completion()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_status )
+{
+ struct generic_operation *op_rec;
+
+ /*
+ * Find the operation key in all pending operation list to
+ * really make sure that it's still there; then call the callback.
+ */
+ pj_ioqueue_lock_key(key);
+
+ /* Find the operation in the pending read list. */
+ op_rec = (struct generic_operation*)key->read_list.next;
+ while (op_rec != (void*)&key->read_list) {
+ if (op_rec == (void*)op_key) {
+ pj_list_erase(op_rec);
+ op_rec->op = PJ_IOQUEUE_OP_NONE;
+ pj_ioqueue_unlock_key(key);
+
+ (*key->cb.on_read_complete)(key, op_key, bytes_status);
+ return PJ_SUCCESS;
+ }
+ op_rec = op_rec->next;
+ }
+
+ /* Find the operation in the pending write list. */
+ op_rec = (struct generic_operation*)key->write_list.next;
+ while (op_rec != (void*)&key->write_list) {
+ if (op_rec == (void*)op_key) {
+ pj_list_erase(op_rec);
+ op_rec->op = PJ_IOQUEUE_OP_NONE;
+ pj_ioqueue_unlock_key(key);
+
+ (*key->cb.on_write_complete)(key, op_key, bytes_status);
+ return PJ_SUCCESS;
+ }
+ op_rec = op_rec->next;
+ }
+
+ /* Find the operation in the pending accept list. */
+ op_rec = (struct generic_operation*)key->accept_list.next;
+ while (op_rec != (void*)&key->accept_list) {
+ if (op_rec == (void*)op_key) {
+ pj_list_erase(op_rec);
+ op_rec->op = PJ_IOQUEUE_OP_NONE;
+ pj_ioqueue_unlock_key(key);
+
+ (*key->cb.on_accept_complete)(key, op_key,
+ PJ_INVALID_SOCKET,
+ (pj_status_t)bytes_status);
+ return PJ_SUCCESS;
+ }
+ op_rec = op_rec->next;
+ }
+
+ pj_ioqueue_unlock_key(key);
+
+ return PJ_EINVALIDOP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_set_default_concurrency( pj_ioqueue_t *ioqueue,
+ pj_bool_t allow)
+{
+ PJ_ASSERT_RETURN(ioqueue != NULL, PJ_EINVAL);
+ ioqueue->default_concurrency = allow;
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ioqueue_set_concurrency(pj_ioqueue_key_t *key,
+ pj_bool_t allow)
+{
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+ /* PJ_IOQUEUE_HAS_SAFE_UNREG must be enabled if concurrency is
+ * disabled.
+ */
+ PJ_ASSERT_RETURN(allow || PJ_IOQUEUE_HAS_SAFE_UNREG, PJ_EINVAL);
+
+ key->allow_concurrent = allow;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_lock_key(pj_ioqueue_key_t *key)
+{
+ if (key->grp_lock)
+ return pj_grp_lock_acquire(key->grp_lock);
+ else
+ return pj_lock_acquire(key->lock);
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_unlock_key(pj_ioqueue_key_t *key)
+{
+ if (key->grp_lock)
+ return pj_grp_lock_release(key->grp_lock);
+ else
+ return pj_lock_release(key->lock);
+}
+
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b64255f01b27b9199de687caf095503d2922ebaf.svn-base b/jni/pjproject-android/.svn/pristine/b6/b64255f01b27b9199de687caf095503d2922ebaf.svn-base
new file mode 100644
index 0000000..8865b89
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b64255f01b27b9199de687caf095503d2922ebaf.svn-base
@@ -0,0 +1,24 @@
+
+ /******************************************************************
+
+ iLBC Speech Coder ANSI-C Source Code
+
+ syntFilter.h
+
+ Copyright (C) The Internet Society (2004).
+ All Rights Reserved.
+
+ ******************************************************************/
+
+ #ifndef __iLBC_SYNTFILTER_H
+ #define __iLBC_SYNTFILTER_H
+
+ void syntFilter(
+ float *Out, /* (i/o) Signal to be filtered */
+ float *a, /* (i) LP parameters */
+ int len, /* (i) Length of signal */
+ float *mem /* (i/o) Filter state */
+ );
+
+ #endif
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6425b8c0d2001a90dadcac7d8887581c4cb8919.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6425b8c0d2001a90dadcac7d8887581c4cb8919.svn-base
new file mode 100644
index 0000000..feac113
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6425b8c0d2001a90dadcac7d8887581c4cb8919.svn-base
@@ -0,0 +1,10 @@
+# $Id$
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "subscription state is TERMINATED", ""]
+ ]
diff --git a/jni/pjproject-android/.svn/pristine/b6/b69a7e2508b678266484f051493f3d5247aabaee.svn-base b/jni/pjproject-android/.svn/pristine/b6/b69a7e2508b678266484f051493f3d5247aabaee.svn-base
new file mode 100644
index 0000000..c1047c3
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b69a7e2508b678266484f051493f3d5247aabaee.svn-base
@@ -0,0 +1,255 @@
+/* $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
+ */
+#define THIS_FILE "stateless_proxy.c"
+
+/* Common proxy functions */
+#define STATEFUL 0
+#include "proxy.h"
+
+
+/* Callback to be called to handle incoming requests. */
+static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
+
+/* Callback to be called to handle incoming response. */
+static pj_bool_t on_rx_response( pjsip_rx_data *rdata );
+
+
+static pj_status_t init_stateless_proxy(void)
+{
+ static pjsip_module mod_stateless_proxy =
+ {
+ NULL, NULL, /* prev, next. */
+ { "mod-stateless-proxy", 19 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &on_rx_request, /* on_rx_request() */
+ &on_rx_response, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+ };
+
+ pj_status_t status;
+
+ /* Register our module to receive incoming requests. */
+ status = pjsip_endpt_register_module( global.endpt, &mod_stateless_proxy);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ return PJ_SUCCESS;
+}
+
+
+/* Callback to be called to handle incoming requests. */
+static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
+{
+ pjsip_tx_data *tdata;
+ pj_status_t status;
+
+
+ /* Verify incoming request */
+ status = proxy_verify_request(rdata);
+ if (status != PJ_SUCCESS) {
+ app_perror("RX invalid request", status);
+ return PJ_TRUE;
+ }
+
+ /*
+ * Request looks sane, next clone the request to create transmit data.
+ */
+ status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL,
+ NULL, 0, &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsip_endpt_respond_stateless(global.endpt, rdata,
+ PJSIP_SC_INTERNAL_SERVER_ERROR, NULL,
+ NULL, NULL);
+ return PJ_TRUE;
+ }
+
+
+ /* Process routing */
+ status = proxy_process_routing(tdata);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error processing route", status);
+ return PJ_TRUE;
+ }
+
+ /* Calculate target */
+ status = proxy_calculate_target(rdata, tdata);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error calculating target", status);
+ return PJ_TRUE;
+ }
+
+ /* Target is set, forward the request */
+ status = pjsip_endpt_send_request_stateless(global.endpt, tdata,
+ NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error forwarding request", status);
+ return PJ_TRUE;
+ }
+
+ return PJ_TRUE;
+}
+
+
+/* Callback to be called to handle incoming response. */
+static pj_bool_t on_rx_response( pjsip_rx_data *rdata )
+{
+ pjsip_tx_data *tdata;
+ pjsip_response_addr res_addr;
+ pjsip_via_hdr *hvia;
+ pj_status_t status;
+
+ /* Create response to be forwarded upstream (Via will be stripped here) */
+ status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, &tdata);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error creating response", status);
+ return PJ_TRUE;
+ }
+
+ /* Get topmost Via header */
+ hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
+ if (hvia == NULL) {
+ /* Invalid response! Just drop it */
+ pjsip_tx_data_dec_ref(tdata);
+ return PJ_TRUE;
+ }
+
+ /* Calculate the address to forward the response */
+ pj_bzero(&res_addr, sizeof(res_addr));
+ res_addr.dst_host.type = PJSIP_TRANSPORT_UDP;
+ res_addr.dst_host.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
+
+ /* Destination address is Via's received param */
+ res_addr.dst_host.addr.host = hvia->recvd_param;
+ if (res_addr.dst_host.addr.host.slen == 0) {
+ /* Someone has messed up our Via header! */
+ res_addr.dst_host.addr.host = hvia->sent_by.host;
+ }
+
+ /* Destination port is the rpot */
+ if (hvia->rport_param != 0 && hvia->rport_param != -1)
+ res_addr.dst_host.addr.port = hvia->rport_param;
+
+ if (res_addr.dst_host.addr.port == 0) {
+ /* Ugh, original sender didn't put rport!
+ * At best, can only send the response to the port in Via.
+ */
+ res_addr.dst_host.addr.port = hvia->sent_by.port;
+ }
+
+ /* Forward response */
+ status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata,
+ NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error forwarding response", status);
+ return PJ_TRUE;
+ }
+
+ return PJ_TRUE;
+}
+
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+ pj_status_t status;
+
+ global.port = 5060;
+ pj_log_set_level(4);
+
+ status = init_options(argc, argv);
+ if (status != PJ_SUCCESS)
+ return 1;
+
+ status = init_stack();
+ if (status != PJ_SUCCESS) {
+ app_perror("Error initializing stack", status);
+ return 1;
+ }
+
+ status = init_proxy();
+ if (status != PJ_SUCCESS) {
+ app_perror("Error initializing proxy", status);
+ return 1;
+ }
+
+ status = init_stateless_proxy();
+ if (status != PJ_SUCCESS) {
+ app_perror("Error initializing stateless proxy", status);
+ return 1;
+ }
+
+#if PJ_HAS_THREADS
+ status = pj_thread_create(global.pool, "sproxy", &worker_thread,
+ NULL, 0, 0, &global.thread);
+ if (status != PJ_SUCCESS) {
+ app_perror("Error creating thread", status);
+ return 1;
+ }
+
+ while (!global.quit_flag) {
+ char line[10];
+
+ puts("\n"
+ "Menu:\n"
+ " q quit\n"
+ " d dump status\n"
+ " dd dump detailed status\n"
+ "");
+
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ puts("EOF while reading stdin, will quit now..");
+ global.quit_flag = PJ_TRUE;
+ break;
+ }
+
+ if (line[0] == 'q') {
+ global.quit_flag = PJ_TRUE;
+ } else if (line[0] == 'd') {
+ pj_bool_t detail = (line[1] == 'd');
+ pjsip_endpt_dump(global.endpt, detail);
+#if STATEFUL
+ pjsip_tsx_layer_dump(detail);
+#endif
+ }
+ }
+
+ pj_thread_join(global.thread);
+
+#else
+ puts("\nPress Ctrl-C to quit\n");
+ for (;;) {
+ pj_time_val delay = {0, 0};
+ pjsip_endpt_handle_events(global.endpt, &delay);
+ }
+#endif
+
+ destroy_stack();
+
+ return 0;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6a2f58cbbbd2e28f1cd3f93986b55dde58b0c88.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6a2f58cbbbd2e28f1cd3f93986b55dde58b0c88.svn-base
new file mode 100644
index 0000000..f186652
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6a2f58cbbbd2e28f1cd3f93986b55dde58b0c88.svn-base
@@ -0,0 +1,237 @@
+/*
+ * datatypes_driver.c
+ *
+ * a test driver for crypto/math datatypes
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+
+/*
+ *
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ *
+ * 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 Cisco Systems, Inc. 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ */
+
+
+#include <stdio.h> /* for printf() */
+#include <string.h> /* for strlen() */
+#include "datatypes.h"
+
+void
+byte_order(void);
+
+void
+test_hex_string_funcs(void);
+
+void
+print_string(char *s);
+
+void
+test_bswap(void);
+
+int
+main (void) {
+
+ /*
+ * this program includes various and sundry tests for fundamental
+ * datatypes. it's a grab-bag of throwaway code, retained only in
+ * case of future problems
+ */
+
+ int i, j;
+ v128_t x;
+ char *r =
+ "The Moving Finger writes; and, having writ,\n"
+ "Moves on: nor all thy Piety nor Wit\n"
+ "Shall lure it back to cancel half a Line,\n"
+ "Nor all thy Tears wash out a Word of it.";
+ char *s = "incomplet";
+
+ print_string(r);
+ print_string(s);
+
+ byte_order();
+ test_hex_string_funcs();
+
+ for (j=0; j < 128; j++) {
+ v128_set_to_zero(&x);
+ /* x.v32[0] = (1 << j); */
+ v128_set_bit(&x, j);
+ printf("%s\n", v128_bit_string(&x));
+ v128_clear_bit(&x, j);
+ printf("%s\n", v128_bit_string(&x));
+
+ }
+
+ printf("----------------------------------------------\n");
+ v128_set_to_zero(&x);
+ for (i=0; i < 128; i++) {
+ v128_set_bit(&x, i);
+ }
+ printf("%s\n", v128_bit_string(&x));
+
+ printf("----------------------------------------------\n");
+ v128_set_to_zero(&x);
+ v128_set_bit(&x, 0);
+ for (i=0; i < 128; i++) {
+ printf("%s\n", v128_bit_string(&x));
+ v128_right_shift(&x, 1);
+ }
+ printf("----------------------------------------------\n");
+ v128_set_to_zero(&x);
+ v128_set_bit(&x, 127);
+ for (i=0; i < 128; i++) {
+ printf("%s\n", v128_bit_string(&x));
+ v128_left_shift(&x, 1);
+ }
+ printf("----------------------------------------------\n");
+ for (i=0; i < 128; i++) {
+ v128_set_to_zero(&x);
+ v128_set_bit(&x, 127);
+ v128_left_shift(&x, i);
+ printf("%s\n", v128_bit_string(&x));
+ }
+ printf("----------------------------------------------\n");
+ v128_set_to_zero(&x);
+ for (i=0; i < 128; i+=2) {
+ v128_set_bit(&x, i);
+ }
+ printf("bit_string: { %s }\n", v128_bit_string(&x));
+ printf("get_bit: { ");
+ for (i=0; i < 128; i++) {
+ if (v128_get_bit(&x, i) == 1)
+ printf("1");
+ else
+ printf("0");
+ }
+ printf(" } \n");
+
+ test_bswap();
+
+ return 0;
+}
+
+
+/* byte_order() prints out byte ordering of datatypes */
+
+void
+byte_order(void) {
+ int i;
+ v128_t e;
+#if 0
+ v16_t b;
+ v32_t c;
+ v64_t d;
+
+ for (i=0; i < sizeof(b); i++)
+ b.octet[i] = i;
+ for (i=0; i < sizeof(c); i++)
+ c.octet[i] = i;
+ for (i=0; i < sizeof(d); i++)
+ d.octet[i] = i;
+
+ printf("v128_t:\t%s\n", v128_hex_string(&e));
+ printf("v64_t:\t%s\n", v64_hex_string(&d));
+ printf("v32_t:\t%s\n", v32_hex_string(c));
+ printf("v16_t:\t%s\n", v16_hex_string(b));
+
+ c.value = 0x01020304;
+ printf("v32_t:\t%s\n", v32_hex_string(c));
+ b.value = 0x0102;
+ printf("v16_t:\t%s\n", v16_hex_string(b));
+
+ printf("uint16_t ordering:\n");
+
+ c.value = 0x00010002;
+ printf("v32_t:\t%x%x\n", c.v16[0], c.v16[1]);
+#endif
+
+ printf("byte ordering of crypto/math datatypes:\n");
+ for (i=0; i < sizeof(e); i++)
+ e.v8[i] = i;
+ printf("v128_t: %s\n", v128_hex_string(&e));
+
+}
+
+void
+test_hex_string_funcs(void) {
+ char hex1[] = "abadcafe";
+ char hex2[] = "0123456789abcdefqqqqq";
+ char raw[10];
+ int len;
+
+ len = hex_string_to_octet_string(raw, hex1, strlen(hex1));
+ printf("computed length: %d\tstring: %s\n", len,
+ octet_string_hex_string(raw, len/2));
+ printf("expected length: %u\tstring: %s\n", (unsigned)strlen(hex1), hex1);
+
+ len = hex_string_to_octet_string(raw, hex2, strlen(hex2));
+ printf("computed length: %d\tstring: %s\n", len,
+ octet_string_hex_string(raw, len/2));
+ printf("expected length: %d\tstring: %s\n", 16, "0123456789abcdef");
+
+}
+
+void
+print_string(char *s) {
+ int i;
+ printf("%s\n", s);
+ printf("strlen(s) = %u\n", (unsigned)strlen(s));
+ printf("{ ");
+ for (i=0; i < strlen(s); i++) {
+ printf("0x%x, ", s[i]);
+ if (((i+1) % 8) == 0)
+ printf("\n ");
+ }
+ printf("}\n");
+}
+
+void
+test_bswap(void) {
+ uint32_t x = 0x11223344;
+ uint64_t y = 0x1122334455667788LL;
+
+ printf("before: %0x\nafter: %0x\n", x, be32_to_cpu(x));
+ printf("before: %0llx\nafter: %0llx\n", (unsigned long long)y,
+ (unsigned long long)be64_to_cpu(y));
+
+ y = 1234;
+
+ printf("1234: %0llx\n", (unsigned long long)y);
+ printf("as octet string: %s\n",
+ octet_string_hex_string((uint8_t *) &y, 8));
+ y = be64_to_cpu(y);
+ printf("bswapped octet string: %s\n",
+ octet_string_hex_string((uint8_t *) &y, 8));
+}
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6a95ceefe0823f5df4575955199ea155b16fcfb.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6a95ceefe0823f5df4575955199ea155b16fcfb.svn-base
new file mode 100644
index 0000000..10ed2fb
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6a95ceefe0823f5df4575955199ea155b16fcfb.svn-base
@@ -0,0 +1,6 @@
+all:
+ python setup.py install
+
+clean:
+ python setup.py clean
+ rm -rf ./build
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6b926ae6e81a219ad2d7d4c41590a9877f68d9a.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6b926ae6e81a219ad2d7d4c41590a9877f68d9a.svn-base
new file mode 100644
index 0000000..d170b66
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6b926ae6e81a219ad2d7d4c41590a9877f68d9a.svn-base
@@ -0,0 +1,3016 @@
+/* $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 <pjsua-lib/pjsua.h>
+#include <pjsua-lib/pjsua_internal.h>
+
+
+#define THIS_FILE "pjsua_core.c"
+
+
+/* Internal prototypes */
+static void resolve_stun_entry(pjsua_stun_resolve *sess);
+
+
+/* PJSUA application instance. */
+struct pjsua_data pjsua_var;
+
+
+PJ_DEF(struct pjsua_data*) pjsua_get_var(void)
+{
+ return &pjsua_var;
+}
+
+
+/* Display error */
+PJ_DEF(void) pjsua_perror( const char *sender, const char *title,
+ pj_status_t status)
+{
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(1,(sender, "%s: %s [status=%d]", title, errmsg, status));
+}
+
+
+static void init_data()
+{
+ unsigned i;
+
+ pj_bzero(&pjsua_var, sizeof(pjsua_var));
+
+ for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i)
+ pjsua_var.acc[i].index = i;
+
+ for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i)
+ pjsua_var.tpdata[i].index = i;
+
+ pjsua_var.stun_status = PJ_EUNKNOWN;
+ pjsua_var.nat_status = PJ_EPENDING;
+ pj_list_init(&pjsua_var.stun_res);
+ pj_list_init(&pjsua_var.outbound_proxy);
+
+ pjsua_config_default(&pjsua_var.ua_cfg);
+
+ for (i=0; i<PJSUA_MAX_VID_WINS; ++i) {
+ pjsua_vid_win_reset(i);
+ }
+}
+
+
+PJ_DEF(void) pjsua_logging_config_default(pjsua_logging_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+
+ cfg->msg_logging = PJ_TRUE;
+ cfg->level = 5;
+ cfg->console_level = 4;
+ cfg->decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |
+ PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE |
+ PJ_LOG_HAS_SPACE | PJ_LOG_HAS_THREAD_SWC |
+ PJ_LOG_HAS_INDENT;
+#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
+ cfg->decor |= PJ_LOG_HAS_COLOR;
+#endif
+}
+
+PJ_DEF(void) pjsua_logging_config_dup(pj_pool_t *pool,
+ pjsua_logging_config *dst,
+ const pjsua_logging_config *src)
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename);
+}
+
+PJ_DEF(void) pjsua_config_default(pjsua_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+
+ cfg->max_calls = ((PJSUA_MAX_CALLS) < 4) ? (PJSUA_MAX_CALLS) : 4;
+ cfg->thread_cnt = 1;
+ cfg->nat_type_in_sdp = 1;
+ cfg->stun_ignore_failure = PJ_TRUE;
+ cfg->force_lr = PJ_TRUE;
+ cfg->enable_unsolicited_mwi = PJ_TRUE;
+ cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP;
+ cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING;
+ cfg->hangup_forked_call = PJ_TRUE;
+
+ cfg->use_timer = PJSUA_SIP_TIMER_OPTIONAL;
+ pjsip_timer_setting_default(&cfg->timer_setting);
+}
+
+PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool,
+ pjsua_config *dst,
+ const pjsua_config *src)
+{
+ unsigned i;
+
+ pj_memcpy(dst, src, sizeof(*src));
+
+ for (i=0; i<src->outbound_proxy_cnt; ++i) {
+ pj_strdup_with_null(pool, &dst->outbound_proxy[i],
+ &src->outbound_proxy[i]);
+ }
+
+ for (i=0; i<src->cred_count; ++i) {
+ pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
+ }
+
+ pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
+ pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain);
+ pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host);
+
+ for (i=0; i<src->stun_srv_cnt; ++i) {
+ pj_strdup_with_null(pool, &dst->stun_srv[i], &src->stun_srv[i]);
+ }
+}
+
+PJ_DEF(void) pjsua_msg_data_init(pjsua_msg_data *msg_data)
+{
+ pj_bzero(msg_data, sizeof(*msg_data));
+ pj_list_init(&msg_data->hdr_list);
+ pjsip_media_type_init(&msg_data->multipart_ctype, NULL, NULL);
+ pj_list_init(&msg_data->multipart_parts);
+}
+
+PJ_DEF(pjsua_msg_data*) pjsua_msg_data_clone(pj_pool_t *pool,
+ const pjsua_msg_data *rhs)
+{
+ pjsua_msg_data *msg_data;
+ const pjsip_hdr *hdr;
+ const pjsip_multipart_part *mpart;
+
+ PJ_ASSERT_RETURN(pool && rhs, NULL);
+
+ msg_data = PJ_POOL_ZALLOC_T(pool, pjsua_msg_data);
+ PJ_ASSERT_RETURN(msg_data != NULL, NULL);
+
+ pj_strdup(pool, &msg_data->target_uri, &rhs->target_uri);
+
+ pj_list_init(&msg_data->hdr_list);
+ hdr = rhs->hdr_list.next;
+ while (hdr != &rhs->hdr_list) {
+ pj_list_push_back(&msg_data->hdr_list, pjsip_hdr_clone(pool, hdr));
+ hdr = hdr->next;
+ }
+
+ pj_strdup(pool, &msg_data->content_type, &rhs->content_type);
+ pj_strdup(pool, &msg_data->msg_body, &rhs->msg_body);
+
+ pjsip_media_type_cp(pool, &msg_data->multipart_ctype,
+ &rhs->multipart_ctype);
+
+ pj_list_init(&msg_data->multipart_parts);
+ mpart = rhs->multipart_parts.next;
+ while (mpart != &rhs->multipart_parts) {
+ pj_list_push_back(&msg_data->multipart_parts,
+ pjsip_multipart_clone_part(pool, mpart));
+ mpart = mpart->next;
+ }
+
+ return msg_data;
+}
+
+PJ_DEF(void) pjsua_transport_config_default(pjsua_transport_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+ pjsip_tls_setting_default(&cfg->tls_setting);
+}
+
+PJ_DEF(void) pjsua_transport_config_dup(pj_pool_t *pool,
+ pjsua_transport_config *dst,
+ const pjsua_transport_config *src)
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ pj_strdup(pool, &dst->public_addr, &src->public_addr);
+ pj_strdup(pool, &dst->bound_addr, &src->bound_addr);
+}
+
+PJ_DEF(void) pjsua_ice_config_from_media_config( pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_media_config *src)
+{
+ PJ_UNUSED_ARG(pool);
+
+ dst->enable_ice = src->enable_ice;
+ dst->ice_max_host_cands = src->ice_max_host_cands;
+ dst->ice_opt = src->ice_opt;
+ dst->ice_no_rtcp = src->ice_no_rtcp;
+ dst->ice_always_update = src->ice_always_update;
+}
+
+PJ_DEF(void) pjsua_ice_config_dup( pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_ice_config *src)
+{
+ PJ_UNUSED_ARG(pool);
+ pj_memcpy(dst, src, sizeof(*src));
+}
+
+PJ_DEF(void) pjsua_turn_config_from_media_config(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_media_config *src)
+{
+ dst->enable_turn = src->enable_turn;
+ dst->turn_conn_type = src->turn_conn_type;
+ if (pool == NULL) {
+ dst->turn_server = src->turn_server;
+ dst->turn_auth_cred = src->turn_auth_cred;
+ } else {
+ if (pj_stricmp(&dst->turn_server, &src->turn_server))
+ pj_strdup(pool, &dst->turn_server, &src->turn_server);
+ pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
+ &src->turn_auth_cred);
+ }
+}
+
+PJ_DEF(void) pjsua_turn_config_dup(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_turn_config *src)
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ if (pool) {
+ pj_strdup(pool, &dst->turn_server, &src->turn_server);
+ pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
+ &src->turn_auth_cred);
+ }
+}
+
+PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
+{
+ pjsua_media_config med_cfg;
+
+ pj_bzero(cfg, sizeof(*cfg));
+
+ cfg->reg_timeout = PJSUA_REG_INTERVAL;
+ cfg->reg_delay_before_refresh = PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH;
+ cfg->unreg_timeout = PJSUA_UNREG_TIMEOUT;
+ pjsip_publishc_opt_default(&cfg->publish_opt);
+ cfg->unpublish_max_wait_time_msec = PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC;
+ cfg->transport_id = PJSUA_INVALID_ID;
+ cfg->allow_contact_rewrite = PJ_TRUE;
+ cfg->allow_via_rewrite = PJ_TRUE;
+ cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
+ cfg->use_timer = pjsua_var.ua_cfg.use_timer;
+ cfg->timer_setting = pjsua_var.ua_cfg.timer_setting;
+ cfg->lock_codec = 1;
+ cfg->ka_interval = 15;
+ cfg->ka_data = pj_str("\r\n");
+ cfg->vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+ cfg->vid_rend_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+#if PJMEDIA_HAS_VIDEO
+ pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg);
+#endif
+ pjsua_transport_config_default(&cfg->rtp_cfg);
+
+ pjsua_media_config_default(&med_cfg);
+ pjsua_ice_config_from_media_config(NULL, &cfg->ice_cfg, &med_cfg);
+ pjsua_turn_config_from_media_config(NULL, &cfg->turn_cfg, &med_cfg);
+
+ cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
+ cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
+ cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer;
+ cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
+ cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD;
+ cfg->use_rfc5626 = PJ_TRUE;
+ cfg->reg_use_proxy = PJSUA_REG_USE_OUTBOUND_PROXY |
+ PJSUA_REG_USE_ACC_PROXY;
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
+ cfg->use_stream_ka = (PJMEDIA_STREAM_ENABLE_KA != 0);
+#endif
+ pj_list_init(&cfg->reg_hdr_list);
+ pj_list_init(&cfg->sub_hdr_list);
+ cfg->call_hold_type = PJSUA_CALL_HOLD_TYPE_DEFAULT;
+ cfg->register_on_acc_add = PJ_TRUE;
+ cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES;
+}
+
+PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+}
+
+PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+
+ cfg->clock_rate = PJSUA_DEFAULT_CLOCK_RATE;
+ cfg->snd_clock_rate = 0;
+ cfg->channel_count = 1;
+ cfg->audio_frame_ptime = PJSUA_DEFAULT_AUDIO_FRAME_PTIME;
+ cfg->max_media_ports = PJSUA_MAX_CONF_PORTS;
+ cfg->has_ioqueue = PJ_TRUE;
+ cfg->thread_cnt = 1;
+ cfg->quality = PJSUA_DEFAULT_CODEC_QUALITY;
+ cfg->ilbc_mode = PJSUA_DEFAULT_ILBC_MODE;
+ cfg->ec_tail_len = PJSUA_DEFAULT_EC_TAIL_LEN;
+ cfg->snd_rec_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY;
+ cfg->snd_play_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
+ cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1;
+ cfg->snd_auto_close_time = 1;
+
+ cfg->ice_max_host_cands = -1;
+ cfg->ice_always_update = PJ_TRUE;
+ pj_ice_sess_options_default(&cfg->ice_opt);
+
+ cfg->turn_conn_type = PJ_TURN_TP_UDP;
+ cfg->vid_preview_enable_native = PJ_TRUE;
+}
+
+/*****************************************************************************
+ * This is a very simple PJSIP module, whose sole purpose is to display
+ * incoming and outgoing messages to log. This module will have priority
+ * higher than transport layer, which means:
+ *
+ * - incoming messages will come to this module first before reaching
+ * transaction layer.
+ *
+ * - outgoing messages will come to this module last, after the message
+ * has been 'printed' to contiguous buffer by transport layer and
+ * appropriate transport instance has been decided for this message.
+ *
+ */
+
+/* Notification on incoming messages */
+static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
+{
+ PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
+ "%.*s\n"
+ "--end msg--",
+ rdata->msg_info.len,
+ pjsip_rx_data_get_info(rdata),
+ rdata->tp_info.transport->type_name,
+ rdata->pkt_info.src_name,
+ rdata->pkt_info.src_port,
+ (int)rdata->msg_info.len,
+ rdata->msg_info.msg_buf));
+
+ /* Always return false, otherwise messages will not get processed! */
+ return PJ_FALSE;
+}
+
+/* Notification on outgoing messages */
+static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
+{
+
+ /* Important note:
+ * tp_info field is only valid after outgoing messages has passed
+ * transport layer. So don't try to access tp_info when the module
+ * has lower priority than transport layer.
+ */
+
+ PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
+ "%.*s\n"
+ "--end msg--",
+ (tdata->buf.cur - tdata->buf.start),
+ pjsip_tx_data_get_info(tdata),
+ tdata->tp_info.transport->type_name,
+ tdata->tp_info.dst_name,
+ tdata->tp_info.dst_port,
+ (int)(tdata->buf.cur - tdata->buf.start),
+ tdata->buf.start));
+
+ /* Always return success, otherwise message will not get sent! */
+ return PJ_SUCCESS;
+}
+
+/* The module instance. */
+static pjsip_module pjsua_msg_logger =
+{
+ NULL, NULL, /* prev, next. */
+ { "mod-pjsua-log", 13 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &logging_on_rx_msg, /* on_rx_request() */
+ &logging_on_rx_msg, /* on_rx_response() */
+ &logging_on_tx_msg, /* on_tx_request. */
+ &logging_on_tx_msg, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+
+};
+
+
+/*****************************************************************************
+ * Another simple module to handle incoming OPTIONS request
+ */
+
+/* Notification on incoming request */
+static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
+{
+ pjsip_tx_data *tdata;
+ pjsip_response_addr res_addr;
+ const pjsip_hdr *cap_hdr;
+ pj_status_t status;
+
+ /* Only want to handle OPTIONS requests */
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
+ pjsip_get_options_method()) != 0)
+ {
+ return PJ_FALSE;
+ }
+
+ /* Don't want to handle if shutdown is in progress */
+ if (pjsua_var.thread_quit_flag) {
+ pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,
+ PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL,
+ NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Create basic response. */
+ status = pjsip_endpt_create_response(pjsua_var.endpt, rdata, 200, NULL,
+ &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create OPTIONS response", status);
+ return PJ_TRUE;
+ }
+
+ /* Add Allow header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ALLOW, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg,
+ (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Accept header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ACCEPT, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg,
+ (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Supported header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_SUPPORTED, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg,
+ (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Allow-Events header from the evsub module */
+ cap_hdr = pjsip_evsub_get_allow_events_hdr(NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg,
+ (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add User-Agent header */
+ if (pjsua_var.ua_cfg.user_agent.slen) {
+ const pj_str_t USER_AGENT = { "User-Agent", 10};
+ pjsip_hdr *h;
+
+ h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
+ &USER_AGENT,
+ &pjsua_var.ua_cfg.user_agent);
+ pjsip_msg_add_hdr(tdata->msg, h);
+ }
+
+ /* Get media socket info, make sure transport is ready */
+#if DISABLED_FOR_TICKET_1185
+ if (pjsua_var.calls[0].med_tp) {
+ pjmedia_transport_info tpinfo;
+ pjmedia_sdp_session *sdp;
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(pjsua_var.calls[0].med_tp, &tpinfo);
+
+ /* Add SDP body, using call0's RTP address */
+ status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, tdata->pool, 1,
+ &tpinfo.sock_info, &sdp);
+ if (status == PJ_SUCCESS) {
+ pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);
+ }
+ }
+#endif
+
+ /* Send response */
+ pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+ status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);
+ if (status != PJ_SUCCESS)
+ pjsip_tx_data_dec_ref(tdata);
+
+ return PJ_TRUE;
+}
+
+
+/* The module instance. */
+static pjsip_module pjsua_options_handler =
+{
+ NULL, NULL, /* prev, next. */
+ { "mod-pjsua-options", 17 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &options_on_rx_request, /* on_rx_request() */
+ NULL, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+
+};
+
+
+/*****************************************************************************
+ * These two functions are the main callbacks registered to PJSIP stack
+ * to receive SIP request and response messages that are outside any
+ * dialogs and any transactions.
+ */
+
+/*
+ * Handler for receiving incoming requests.
+ *
+ * This handler serves multiple purposes:
+ * - it receives requests outside dialogs.
+ * - it receives requests inside dialogs, when the requests are
+ * unhandled by other dialog usages. Example of these
+ * requests are: MESSAGE.
+ */
+static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
+{
+ pj_bool_t processed = PJ_FALSE;
+
+ PJSUA_LOCK();
+
+ if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {
+
+ processed = pjsua_call_on_incoming(rdata);
+ }
+
+ PJSUA_UNLOCK();
+
+ return processed;
+}
+
+
+/*
+ * Handler for receiving incoming responses.
+ *
+ * This handler serves multiple purposes:
+ * - it receives strayed responses (i.e. outside any dialog and
+ * outside any transactions).
+ * - it receives responses coming to a transaction, when pjsua
+ * module is set as transaction user for the transaction.
+ * - it receives responses inside a dialog, when these responses
+ * are unhandled by other dialog usages.
+ */
+static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata)
+{
+ PJ_UNUSED_ARG(rdata);
+ return PJ_FALSE;
+}
+
+
+/*****************************************************************************
+ * Logging.
+ */
+
+/* Log callback */
+static void log_writer(int level, const char *buffer, int len)
+{
+ /* Write to file, stdout or application callback. */
+
+ if (pjsua_var.log_file) {
+ pj_ssize_t size = len;
+ pj_file_write(pjsua_var.log_file, buffer, &size);
+ /* This will slow things down considerably! Don't do it!
+ pj_file_flush(pjsua_var.log_file);
+ */
+ }
+
+ if (level <= (int)pjsua_var.log_cfg.console_level) {
+ if (pjsua_var.log_cfg.cb)
+ (*pjsua_var.log_cfg.cb)(level, buffer, len);
+ else
+ pj_log_write(level, buffer, len);
+ }
+}
+
+
+/*
+ * Application can call this function at any time (after pjsua_create(), of
+ * course) to change logging settings.
+ */
+PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg)
+{
+ pj_status_t status;
+
+ /* Save config. */
+ pjsua_logging_config_dup(pjsua_var.pool, &pjsua_var.log_cfg, cfg);
+
+ /* Redirect log function to ours */
+ pj_log_set_log_func( &log_writer );
+
+ /* Set decor */
+ pj_log_set_decor(pjsua_var.log_cfg.decor);
+
+ /* Set log level */
+ pj_log_set_level(pjsua_var.log_cfg.level);
+
+ /* Close existing file, if any */
+ if (pjsua_var.log_file) {
+ pj_file_close(pjsua_var.log_file);
+ pjsua_var.log_file = NULL;
+ }
+
+ /* If output log file is desired, create the file: */
+ if (pjsua_var.log_cfg.log_filename.slen) {
+ unsigned flags = PJ_O_WRONLY;
+ flags |= pjsua_var.log_cfg.log_file_flags;
+ status = pj_file_open(pjsua_var.pool,
+ pjsua_var.log_cfg.log_filename.ptr,
+ flags,
+ &pjsua_var.log_file);
+
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating log file", status);
+ return status;
+ }
+ }
+
+ /* Unregister msg logging if it's previously registered */
+ if (pjsua_msg_logger.id >= 0) {
+ pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger);
+ pjsua_msg_logger.id = -1;
+ }
+
+ /* Enable SIP message logging */
+ if (pjsua_var.log_cfg.msg_logging)
+ pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger);
+
+ return PJ_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * PJSUA Base API.
+ */
+
+/* Worker thread function. */
+static int worker_thread(void *arg)
+{
+ enum { TIMEOUT = 10 };
+
+ PJ_UNUSED_ARG(arg);
+
+ while (!pjsua_var.thread_quit_flag) {
+ int count;
+
+ count = pjsua_handle_events(TIMEOUT);
+ if (count < 0)
+ pj_thread_sleep(TIMEOUT);
+ }
+
+ return 0;
+}
+
+
+/* Init random seed */
+static void init_random_seed(void)
+{
+ pj_sockaddr addr;
+ const pj_str_t *hostname;
+ pj_uint32_t pid;
+ pj_time_val t;
+ unsigned seed=0;
+
+ /* Add hostname */
+ hostname = pj_gethostname();
+ seed = pj_hash_calc(seed, hostname->ptr, (int)hostname->slen);
+
+ /* Add primary IP address */
+ if (pj_gethostip(pj_AF_INET(), &addr)==PJ_SUCCESS)
+ seed = pj_hash_calc(seed, &addr.ipv4.sin_addr, 4);
+
+ /* Get timeofday */
+ pj_gettimeofday(&t);
+ seed = pj_hash_calc(seed, &t, sizeof(t));
+
+ /* Add PID */
+ pid = pj_getpid();
+ seed = pj_hash_calc(seed, &pid, sizeof(pid));
+
+ /* Init random seed */
+ pj_srand(seed);
+}
+
+/*
+ * Instantiate pjsua application.
+ */
+PJ_DEF(pj_status_t) pjsua_create(void)
+{
+ pj_status_t status;
+
+ /* Init pjsua data */
+ init_data();
+
+ /* Set default logging settings */
+ pjsua_logging_config_default(&pjsua_var.log_cfg);
+
+ /* Init PJLIB: */
+ status = pj_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ pj_log_push_indent();
+
+ /* Init random seed */
+ init_random_seed();
+
+ /* Init PJLIB-UTIL: */
+ status = pjlib_util_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Init PJNATH */
+ status = pjnath_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Set default sound device ID */
+ pjsua_var.cap_dev = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
+ pjsua_var.play_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
+
+ /* Set default video device ID */
+ pjsua_var.vcap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+ pjsua_var.vrdr_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+
+ /* Init caching pool. */
+ pj_caching_pool_init(&pjsua_var.cp, NULL, 0);
+
+ /* Create memory pool for application. */
+ pjsua_var.pool = pjsua_pool_create("pjsua", 1000, 1000);
+
+ PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM);
+
+ /* Create mutex */
+ status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua",
+ &pjsua_var.mutex);
+ if (status != PJ_SUCCESS) {
+ pj_log_pop_indent();
+ pjsua_perror(THIS_FILE, "Unable to create mutex", status);
+ return status;
+ }
+
+ /* Must create SIP endpoint to initialize SIP parser. The parser
+ * is needed for example when application needs to call pjsua_verify_url().
+ */
+ status = pjsip_endpt_create(&pjsua_var.cp.factory,
+ pj_gethostname()->ptr,
+ &pjsua_var.endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Init timer entry list */
+ pj_list_init(&pjsua_var.timer_list);
+
+ /* Create timer mutex */
+ status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua_timer",
+ &pjsua_var.timer_mutex);
+ if (status != PJ_SUCCESS) {
+ pj_log_pop_indent();
+ pjsua_perror(THIS_FILE, "Unable to create mutex", status);
+ return status;
+ }
+
+ pjsua_set_state(PJSUA_STATE_CREATED);
+ pj_log_pop_indent();
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize pjsua with the specified settings. All the settings are
+ * optional, and the default values will be used when the config is not
+ * specified.
+ */
+PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
+ const pjsua_logging_config *log_cfg,
+ const pjsua_media_config *media_cfg)
+{
+ pjsua_config default_cfg;
+ pjsua_media_config default_media_cfg;
+ const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
+ pjsip_ua_init_param ua_init_param;
+ unsigned i;
+ pj_status_t status;
+
+ pj_log_push_indent();
+
+ /* Create default configurations when the config is not supplied */
+
+ if (ua_cfg == NULL) {
+ pjsua_config_default(&default_cfg);
+ ua_cfg = &default_cfg;
+ }
+
+ if (media_cfg == NULL) {
+ pjsua_media_config_default(&default_media_cfg);
+ media_cfg = &default_media_cfg;
+ }
+
+ /* Initialize logging first so that info/errors can be captured */
+ if (log_cfg) {
+ status = pjsua_reconfigure_logging(log_cfg);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT != 0
+ if (!(pj_get_sys_info()->flags & PJ_SYS_HAS_IOS_BG)) {
+ PJ_LOG(5, (THIS_FILE, "Device does not support "
+ "background mode"));
+ pj_activesock_enable_iphone_os_bg(PJ_FALSE);
+ }
+#endif
+
+ /* If nameserver is configured, create DNS resolver instance and
+ * set it to be used by SIP resolver.
+ */
+ if (ua_cfg->nameserver_count) {
+#if PJSIP_HAS_RESOLVER
+ unsigned i;
+
+ /* Create DNS resolver */
+ status = pjsip_endpt_create_resolver(pjsua_var.endpt,
+ &pjsua_var.resolver);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating resolver", status);
+ goto on_error;
+ }
+
+ /* Configure nameserver for the DNS resolver */
+ status = pj_dns_resolver_set_ns(pjsua_var.resolver,
+ ua_cfg->nameserver_count,
+ ua_cfg->nameserver, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error setting nameserver", status);
+ goto on_error;
+ }
+
+ /* Set this DNS resolver to be used by the SIP resolver */
+ status = pjsip_endpt_set_resolver(pjsua_var.endpt, pjsua_var.resolver);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error setting DNS resolver", status);
+ goto on_error;
+ }
+
+ /* Print nameservers */
+ for (i=0; i<ua_cfg->nameserver_count; ++i) {
+ PJ_LOG(4,(THIS_FILE, "Nameserver %.*s added",
+ (int)ua_cfg->nameserver[i].slen,
+ ua_cfg->nameserver[i].ptr));
+ }
+#else
+ PJ_LOG(2,(THIS_FILE,
+ "DNS resolver is disabled (PJSIP_HAS_RESOLVER==0)"));
+#endif
+ }
+
+ /* Init SIP UA: */
+
+ /* Initialize transaction layer: */
+ status = pjsip_tsx_layer_init_module(pjsua_var.endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+
+ /* Initialize UA layer module: */
+ pj_bzero(&ua_init_param, sizeof(ua_init_param));
+ if (ua_cfg->hangup_forked_call) {
+ ua_init_param.on_dlg_forked = &on_dlg_forked;
+ }
+ status = pjsip_ua_init_module( pjsua_var.endpt, &ua_init_param);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+
+ /* Initialize Replaces support. */
+ status = pjsip_replaces_init_module( pjsua_var.endpt );
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Initialize 100rel support */
+ status = pjsip_100rel_init_module(pjsua_var.endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Initialize session timer support */
+ status = pjsip_timer_init_module(pjsua_var.endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Initialize and register PJSUA application module. */
+ {
+ const pjsip_module mod_initializer =
+ {
+ NULL, NULL, /* prev, next. */
+ { "mod-pjsua", 9 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &mod_pjsua_on_rx_request, /* on_rx_request() */
+ &mod_pjsua_on_rx_response, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+ };
+
+ pjsua_var.mod = mod_initializer;
+
+ status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+ }
+
+ /* Parse outbound proxies */
+ for (i=0; i<ua_cfg->outbound_proxy_cnt; ++i) {
+ pj_str_t tmp;
+ pj_str_t hname = { "Route", 5};
+ pjsip_route_hdr *r;
+
+ pj_strdup_with_null(pjsua_var.pool, &tmp, &ua_cfg->outbound_proxy[i]);
+
+ r = (pjsip_route_hdr*)
+ pjsip_parse_hdr(pjsua_var.pool, &hname, tmp.ptr,
+ (unsigned)tmp.slen, NULL);
+ if (r == NULL) {
+ pjsua_perror(THIS_FILE, "Invalid outbound proxy URI",
+ PJSIP_EINVALIDURI);
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ if (pjsua_var.ua_cfg.force_lr) {
+ pjsip_sip_uri *sip_url;
+ if (!PJSIP_URI_SCHEME_IS_SIP(r->name_addr.uri) &&
+ !PJSIP_URI_SCHEME_IS_SIPS(r->name_addr.uri))
+ {
+ status = PJSIP_EINVALIDSCHEME;
+ goto on_error;
+ }
+ sip_url = (pjsip_sip_uri*)r->name_addr.uri;
+ sip_url->lr_param = 1;
+ }
+
+ pj_list_push_back(&pjsua_var.outbound_proxy, r);
+ }
+
+
+ /* Initialize PJSUA call subsystem: */
+ status = pjsua_call_subsys_init(ua_cfg);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Convert deprecated STUN settings */
+ if (pjsua_var.ua_cfg.stun_srv_cnt==0) {
+ if (pjsua_var.ua_cfg.stun_domain.slen) {
+ pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =
+ pjsua_var.ua_cfg.stun_domain;
+ }
+ if (pjsua_var.ua_cfg.stun_host.slen) {
+ pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =
+ pjsua_var.ua_cfg.stun_host;
+ }
+ }
+
+ /* Start resolving STUN server */
+ status = resolve_stun_server(PJ_FALSE);
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
+ goto on_error;
+ }
+
+ /* Initialize PJSUA media subsystem */
+ status = pjsua_media_subsys_init(media_cfg);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Init core SIMPLE module : */
+ status = pjsip_evsub_init_module(pjsua_var.endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+
+ /* Init presence module: */
+ status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance());
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Initialize MWI support */
+ status = pjsip_mwi_init_module(pjsua_var.endpt, pjsip_evsub_instance());
+
+ /* Init PUBLISH module */
+ pjsip_publishc_init_module(pjsua_var.endpt);
+
+ /* Init xfer/REFER module */
+ status = pjsip_xfer_init_module( pjsua_var.endpt );
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Init pjsua presence handler: */
+ status = pjsua_pres_init();
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Init out-of-dialog MESSAGE request handler. */
+ status = pjsua_im_init();
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register OPTIONS handler */
+ pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler);
+
+ /* Add OPTIONS in Allow header */
+ pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_ALLOW,
+ NULL, 1, &STR_OPTIONS);
+
+ /* Start worker thread if needed. */
+ if (pjsua_var.ua_cfg.thread_cnt) {
+ unsigned i;
+
+ if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread))
+ pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread);
+
+ for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) {
+ status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread,
+ NULL, 0, 0, &pjsua_var.thread[i]);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+ PJ_LOG(4,(THIS_FILE, "%d SIP worker threads created",
+ pjsua_var.ua_cfg.thread_cnt));
+ } else {
+ PJ_LOG(4,(THIS_FILE, "No SIP worker threads created"));
+ }
+
+ /* Done! */
+
+ PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized",
+ pj_get_version(), pj_get_sys_info()->info.ptr));
+
+ pjsua_set_state(PJSUA_STATE_INIT);
+ pj_log_pop_indent();
+ return PJ_SUCCESS;
+
+on_error:
+ pjsua_destroy();
+ pj_log_pop_indent();
+ return status;
+}
+
+
+/* Sleep with polling */
+static void busy_sleep(unsigned msec)
+{
+ pj_time_val timeout, now;
+
+ pj_gettickcount(&timeout);
+ timeout.msec += msec;
+ pj_time_val_normalize(&timeout);
+
+ do {
+ int i;
+ i = msec / 10;
+ while (pjsua_handle_events(10) > 0 && i > 0)
+ --i;
+ pj_gettickcount(&now);
+ } while (PJ_TIME_VAL_LT(now, timeout));
+}
+
+static void stun_resolve_add_ref(pjsua_stun_resolve *sess)
+{
+ ++sess->ref_cnt;
+}
+
+static void destroy_stun_resolve(pjsua_stun_resolve *sess)
+{
+ sess->destroy_flag = PJ_TRUE;
+ if (sess->ref_cnt > 0)
+ return;
+
+ PJSUA_LOCK();
+ pj_list_erase(sess);
+ PJSUA_UNLOCK();
+
+ pj_assert(sess->stun_sock==NULL);
+ pj_pool_release(sess->pool);
+}
+
+static void stun_resolve_dec_ref(pjsua_stun_resolve *sess)
+{
+ --sess->ref_cnt;
+ if (sess->ref_cnt <= 0 && sess->destroy_flag)
+ destroy_stun_resolve(sess);
+}
+
+
+/* This is the internal function to be called when STUN resolution
+ * session (pj_stun_resolve) has completed.
+ */
+static void stun_resolve_complete(pjsua_stun_resolve *sess)
+{
+ pj_stun_resolve_result result;
+
+ if (sess->has_result)
+ goto on_return;
+
+ pj_bzero(&result, sizeof(result));
+ result.token = sess->token;
+ result.status = sess->status;
+ result.name = sess->srv[sess->idx];
+ pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr));
+ sess->has_result = PJ_TRUE;
+
+ if (result.status == PJ_SUCCESS) {
+ char addr[PJ_INET6_ADDRSTRLEN+10];
+ pj_sockaddr_print(&result.addr, addr, sizeof(addr), 3);
+ PJ_LOG(4,(THIS_FILE,
+ "STUN resolution success, using %.*s, address is %s",
+ (int)sess->srv[sess->idx].slen,
+ sess->srv[sess->idx].ptr,
+ addr));
+ } else {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(result.status, errmsg, sizeof(errmsg));
+ PJ_LOG(1,(THIS_FILE, "STUN resolution failed: %s", errmsg));
+ }
+
+ stun_resolve_add_ref(sess);
+ sess->cb(&result);
+ stun_resolve_dec_ref(sess);
+
+on_return:
+ if (!sess->blocking) {
+ destroy_stun_resolve(sess);
+ }
+}
+
+/* This is the callback called by the STUN socket (pj_stun_sock)
+ * to report it's state. We use this as part of testing the
+ * STUN server.
+ */
+static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,
+ pj_stun_sock_op op,
+ pj_status_t status)
+{
+ pjsua_stun_resolve *sess;
+
+ sess = (pjsua_stun_resolve*) pj_stun_sock_get_user_data(stun_sock);
+ pj_assert(stun_sock == sess->stun_sock);
+
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(status, errmsg, sizeof(errmsg));
+
+ PJ_LOG(4,(THIS_FILE, "STUN resolution for %.*s failed: %s",
+ (int)sess->srv[sess->idx].slen,
+ sess->srv[sess->idx].ptr, errmsg));
+
+ sess->status = status;
+
+ pj_stun_sock_destroy(stun_sock);
+ sess->stun_sock = NULL;
+
+ ++sess->idx;
+ resolve_stun_entry(sess);
+
+ return PJ_FALSE;
+
+ } else if (op == PJ_STUN_SOCK_BINDING_OP) {
+ pj_stun_sock_info ssi;
+
+ pj_stun_sock_get_info(stun_sock, &ssi);
+ pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr));
+
+ sess->status = PJ_SUCCESS;
+ pj_stun_sock_destroy(stun_sock);
+ sess->stun_sock = NULL;
+
+ stun_resolve_complete(sess);
+
+ return PJ_FALSE;
+
+ } else
+ return PJ_TRUE;
+
+}
+
+/* This is an internal function to resolve and test current
+ * server entry in pj_stun_resolve session. It is called by
+ * pjsua_resolve_stun_servers() and test_stun_on_status() above
+ */
+static void resolve_stun_entry(pjsua_stun_resolve *sess)
+{
+ stun_resolve_add_ref(sess);
+
+ /* Loop while we have entry to try */
+ for (; sess->idx < sess->count; ++sess->idx) {
+ const int af = pj_AF_INET();
+ char target[64];
+ pj_str_t hostpart;
+ pj_uint16_t port;
+ pj_stun_sock_cb stun_sock_cb;
+
+ pj_assert(sess->idx < sess->count);
+
+ pj_ansi_snprintf(target, sizeof(target), "%.*s",
+ (int)sess->srv[sess->idx].slen,
+ sess->srv[sess->idx].ptr);
+
+ /* Parse the server entry into host:port */
+ sess->status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx],
+ &hostpart, &port, NULL);
+ if (sess->status != PJ_SUCCESS) {
+ PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target));
+ continue;
+ }
+
+ /* Use default port if not specified */
+ if (port == 0)
+ port = PJ_STUN_PORT;
+
+ pj_assert(sess->stun_sock == NULL);
+
+ PJ_LOG(4,(THIS_FILE, "Trying STUN server %s (%d of %d)..",
+ target, sess->idx+1, sess->count));
+
+ /* Use STUN_sock to test this entry */
+ pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
+ stun_sock_cb.on_status = &test_stun_on_status;
+ sess->status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve",
+ pj_AF_INET(), &stun_sock_cb,
+ NULL, sess, &sess->stun_sock);
+ if (sess->status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(sess->status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(THIS_FILE,
+ "Error creating STUN socket for %s: %s",
+ target, errmsg));
+
+ continue;
+ }
+
+ sess->status = pj_stun_sock_start(sess->stun_sock, &hostpart,
+ port, pjsua_var.resolver);
+ if (sess->status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(sess->status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(THIS_FILE,
+ "Error starting STUN socket for %s: %s",
+ target, errmsg));
+
+ if (sess->stun_sock) {
+ pj_stun_sock_destroy(sess->stun_sock);
+ sess->stun_sock = NULL;
+ }
+ continue;
+ }
+
+ /* Done for now, testing will resume/complete asynchronously in
+ * stun_sock_cb()
+ */
+ goto on_return;
+ }
+
+ if (sess->idx >= sess->count) {
+ /* No more entries to try */
+ PJ_ASSERT_ON_FAIL(sess->status != PJ_SUCCESS,
+ sess->status = PJ_EUNKNOWN);
+ stun_resolve_complete(sess);
+ }
+
+on_return:
+ stun_resolve_dec_ref(sess);
+}
+
+
+/*
+ * Resolve STUN server.
+ */
+PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
+ pj_str_t srv[],
+ pj_bool_t wait,
+ void *token,
+ pj_stun_resolve_cb cb)
+{
+ pj_pool_t *pool;
+ pjsua_stun_resolve *sess;
+ pj_status_t status;
+ unsigned i;
+
+ PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL);
+
+ pool = pjsua_pool_create("stunres", 256, 256);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve);
+ sess->pool = pool;
+ sess->token = token;
+ sess->cb = cb;
+ sess->count = count;
+ sess->blocking = wait;
+ sess->status = PJ_EPENDING;
+ sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
+ for (i=0; i<count; ++i) {
+ pj_strdup(pool, &sess->srv[i], &srv[i]);
+ }
+
+ PJSUA_LOCK();
+ pj_list_push_back(&pjsua_var.stun_res, sess);
+ PJSUA_UNLOCK();
+
+ resolve_stun_entry(sess);
+
+ if (!wait)
+ return PJ_SUCCESS;
+
+ while (sess->status == PJ_EPENDING) {
+ pjsua_handle_events(50);
+ }
+
+ status = sess->status;
+ destroy_stun_resolve(sess);
+
+ return status;
+}
+
+/*
+ * Cancel pending STUN resolution.
+ */
+PJ_DEF(pj_status_t) pjsua_cancel_stun_resolution( void *token,
+ pj_bool_t notify_cb)
+{
+ pjsua_stun_resolve *sess;
+ unsigned cancelled_count = 0;
+
+ PJSUA_LOCK();
+ sess = pjsua_var.stun_res.next;
+ while (sess != &pjsua_var.stun_res) {
+ pjsua_stun_resolve *next = sess->next;
+
+ if (sess->token == token) {
+ if (notify_cb) {
+ pj_stun_resolve_result result;
+
+ pj_bzero(&result, sizeof(result));
+ result.token = token;
+ result.status = PJ_ECANCELLED;
+
+ sess->cb(&result);
+ }
+
+ destroy_stun_resolve(sess);
+ ++cancelled_count;
+ }
+
+ sess = next;
+ }
+ PJSUA_UNLOCK();
+
+ return cancelled_count ? PJ_SUCCESS : PJ_ENOTFOUND;
+}
+
+static void internal_stun_resolve_cb(const pj_stun_resolve_result *result)
+{
+ pjsua_var.stun_status = result->status;
+ if (result->status == PJ_SUCCESS) {
+ pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr));
+ }
+}
+
+/*
+ * Resolve STUN server.
+ */
+pj_status_t resolve_stun_server(pj_bool_t wait)
+{
+ if (pjsua_var.stun_status == PJ_EUNKNOWN) {
+ pj_status_t status;
+
+ /* Initialize STUN configuration */
+ pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0,
+ pjsip_endpt_get_ioqueue(pjsua_var.endpt),
+ pjsip_endpt_get_timer_heap(pjsua_var.endpt));
+
+ /* Start STUN server resolution */
+ if (pjsua_var.ua_cfg.stun_srv_cnt) {
+ pjsua_var.stun_status = PJ_EPENDING;
+ status = pjsua_resolve_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt,
+ pjsua_var.ua_cfg.stun_srv,
+ wait, NULL,
+ &internal_stun_resolve_cb);
+ if (wait || status != PJ_SUCCESS) {
+ pjsua_var.stun_status = status;
+ }
+ } else {
+ pjsua_var.stun_status = PJ_SUCCESS;
+ }
+
+ } else if (pjsua_var.stun_status == PJ_EPENDING) {
+ /* STUN server resolution has been started, wait for the
+ * result.
+ */
+ if (wait) {
+ while (pjsua_var.stun_status == PJ_EPENDING) {
+ if (pjsua_var.thread[0] == NULL)
+ pjsua_handle_events(10);
+ else
+ pj_thread_sleep(10);
+ }
+ }
+ }
+
+ if (pjsua_var.stun_status != PJ_EPENDING &&
+ pjsua_var.stun_status != PJ_SUCCESS &&
+ pjsua_var.ua_cfg.stun_ignore_failure)
+ {
+ PJ_LOG(2,(THIS_FILE,
+ "Ignoring STUN resolution failure (by setting)"));
+ pjsua_var.stun_status = PJ_SUCCESS;
+ }
+
+ return pjsua_var.stun_status;
+}
+
+/*
+ * Destroy pjsua.
+ */
+PJ_DEF(pj_status_t) pjsua_destroy2(unsigned flags)
+{
+ int i; /* Must be signed */
+
+ if (pjsua_var.endpt) {
+ PJ_LOG(4,(THIS_FILE, "Shutting down, flags=%d...", flags));
+ }
+
+ if (pjsua_var.state > PJSUA_STATE_NULL &&
+ pjsua_var.state < PJSUA_STATE_CLOSING)
+ {
+ pjsua_set_state(PJSUA_STATE_CLOSING);
+ }
+
+ /* Signal threads to quit: */
+ pjsua_var.thread_quit_flag = 1;
+
+ /* Wait worker threads to quit: */
+ for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) {
+ if (pjsua_var.thread[i]) {
+ pj_status_t status;
+ status = pj_thread_join(pjsua_var.thread[i]);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(THIS_FILE, status, "Error joining worker thread"));
+ pj_thread_sleep(1000);
+ }
+ pj_thread_destroy(pjsua_var.thread[i]);
+ pjsua_var.thread[i] = NULL;
+ }
+ }
+
+ if (pjsua_var.endpt) {
+ unsigned max_wait;
+
+ pj_log_push_indent();
+
+ /* Terminate all calls. */
+ if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
+ pjsua_call_hangup_all();
+ }
+
+ /* Set all accounts to offline */
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (!pjsua_var.acc[i].valid)
+ continue;
+ pjsua_var.acc[i].online_status = PJ_FALSE;
+ pj_bzero(&pjsua_var.acc[i].rpid, sizeof(pjrpid_element));
+ }
+
+ /* Terminate all presence subscriptions. */
+ pjsua_pres_shutdown(flags);
+
+ /* Destroy media (to shutdown media transports etc) */
+ pjsua_media_subsys_destroy(flags);
+
+ /* Wait for sometime until all publish client sessions are done
+ * (ticket #364)
+ */
+ /* First stage, get the maximum wait time */
+ max_wait = 100;
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (!pjsua_var.acc[i].valid)
+ continue;
+ if (pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec > max_wait)
+ max_wait = pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec;
+ }
+
+ /* No waiting if RX is disabled */
+ if (flags & PJSUA_DESTROY_NO_RX_MSG) {
+ max_wait = 0;
+ }
+
+ /* Second stage, wait for unpublications to complete */
+ for (i=0; i<(int)(max_wait/50); ++i) {
+ unsigned j;
+ for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+ if (!pjsua_var.acc[j].valid)
+ continue;
+
+ if (pjsua_var.acc[j].publish_sess)
+ break;
+ }
+ if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
+ busy_sleep(50);
+ else
+ break;
+ }
+
+ /* Third stage, forcefully destroy unfinished unpublications */
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (pjsua_var.acc[i].publish_sess) {
+ pjsip_publishc_destroy(pjsua_var.acc[i].publish_sess);
+ pjsua_var.acc[i].publish_sess = NULL;
+ }
+ }
+
+ /* Unregister all accounts */
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (!pjsua_var.acc[i].valid)
+ continue;
+
+ if (pjsua_var.acc[i].regc && (flags & PJSUA_DESTROY_NO_TX_MSG)==0)
+ {
+ pjsua_acc_set_registration(i, PJ_FALSE);
+ }
+ }
+
+ /* Terminate any pending STUN resolution */
+ if (!pj_list_empty(&pjsua_var.stun_res)) {
+ pjsua_stun_resolve *sess = pjsua_var.stun_res.next;
+ while (sess != &pjsua_var.stun_res) {
+ pjsua_stun_resolve *next = sess->next;
+ destroy_stun_resolve(sess);
+ sess = next;
+ }
+ }
+
+ /* Wait until all unregistrations are done (ticket #364) */
+ /* First stage, get the maximum wait time */
+ max_wait = 100;
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (!pjsua_var.acc[i].valid)
+ continue;
+ if (pjsua_var.acc[i].cfg.unreg_timeout > max_wait)
+ max_wait = pjsua_var.acc[i].cfg.unreg_timeout;
+ }
+
+ /* No waiting if RX is disabled */
+ if (flags & PJSUA_DESTROY_NO_RX_MSG) {
+ max_wait = 0;
+ }
+
+ /* Second stage, wait for unregistrations to complete */
+ for (i=0; i<(int)(max_wait/50); ++i) {
+ unsigned j;
+ for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+ if (!pjsua_var.acc[j].valid)
+ continue;
+
+ if (pjsua_var.acc[j].regc)
+ break;
+ }
+ if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
+ busy_sleep(50);
+ else
+ break;
+ }
+ /* Note variable 'i' is used below */
+
+ /* Wait for some time to allow unregistration and ICE/TURN
+ * transports shutdown to complete:
+ */
+ if (i < 20 && (flags & PJSUA_DESTROY_NO_RX_MSG) == 0) {
+ busy_sleep(1000 - i*50);
+ }
+
+ PJ_LOG(4,(THIS_FILE, "Destroying..."));
+
+ /* Must destroy endpoint first before destroying pools in
+ * buddies or accounts, since shutting down transaction layer
+ * may emit events which trigger some buddy or account callbacks
+ * to be called.
+ */
+ pjsip_endpt_destroy(pjsua_var.endpt);
+ pjsua_var.endpt = NULL;
+
+ /* Destroy pool in the buddy object */
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
+ if (pjsua_var.buddy[i].pool) {
+ pj_pool_release(pjsua_var.buddy[i].pool);
+ pjsua_var.buddy[i].pool = NULL;
+ }
+ }
+
+ /* Destroy accounts */
+ for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (pjsua_var.acc[i].pool) {
+ pj_pool_release(pjsua_var.acc[i].pool);
+ pjsua_var.acc[i].pool = NULL;
+ }
+ }
+ }
+
+ /* Destroy mutex */
+ if (pjsua_var.mutex) {
+ pj_mutex_destroy(pjsua_var.mutex);
+ pjsua_var.mutex = NULL;
+ }
+
+ if (pjsua_var.timer_mutex) {
+ pj_mutex_destroy(pjsua_var.timer_mutex);
+ pjsua_var.timer_mutex = NULL;
+ }
+
+ /* Destroy pool and pool factory. */
+ if (pjsua_var.pool) {
+ pj_pool_release(pjsua_var.pool);
+ pjsua_var.pool = NULL;
+ pj_caching_pool_destroy(&pjsua_var.cp);
+
+ pjsua_set_state(PJSUA_STATE_NULL);
+
+ PJ_LOG(4,(THIS_FILE, "PJSUA destroyed..."));
+
+ /* End logging */
+ if (pjsua_var.log_file) {
+ pj_file_close(pjsua_var.log_file);
+ pjsua_var.log_file = NULL;
+ }
+
+ pj_log_pop_indent();
+
+ /* Shutdown PJLIB */
+ pj_shutdown();
+ }
+
+ /* Clear pjsua_var */
+ pj_bzero(&pjsua_var, sizeof(pjsua_var));
+
+ /* Done. */
+ return PJ_SUCCESS;
+}
+
+void pjsua_set_state(pjsua_state new_state)
+{
+ const char *state_name[] = {
+ "NULL",
+ "CREATED",
+ "INIT",
+ "STARTING",
+ "RUNNING",
+ "CLOSING"
+ };
+ pjsua_state old_state = pjsua_var.state;
+
+ pjsua_var.state = new_state;
+ PJ_LOG(4,(THIS_FILE, "PJSUA state changed: %s --> %s",
+ state_name[old_state], state_name[new_state]));
+}
+
+/* Get state */
+PJ_DEF(pjsua_state) pjsua_get_state(void)
+{
+ return pjsua_var.state;
+}
+
+PJ_DEF(pj_status_t) pjsua_destroy(void)
+{
+ return pjsua_destroy2(0);
+}
+
+
+/**
+ * Application is recommended to call this function after all initialization
+ * is done, so that the library can do additional checking set up
+ * additional
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DEF(pj_status_t) pjsua_start(void)
+{
+ pj_status_t status;
+
+ pjsua_set_state(PJSUA_STATE_STARTING);
+ pj_log_push_indent();
+
+ status = pjsua_call_subsys_start();
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ status = pjsua_media_subsys_start();
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ status = pjsua_pres_start();
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ pjsua_set_state(PJSUA_STATE_RUNNING);
+
+on_return:
+ pj_log_pop_indent();
+ return status;
+}
+
+
+/**
+ * Poll pjsua for events, and if necessary block the caller thread for
+ * the specified maximum interval (in miliseconds).
+ */
+PJ_DEF(int) pjsua_handle_events(unsigned msec_timeout)
+{
+#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0
+
+ return pj_symbianos_poll(-1, msec_timeout);
+
+#else
+
+ unsigned count = 0;
+ pj_time_val tv;
+ pj_status_t status;
+
+ tv.sec = 0;
+ tv.msec = msec_timeout;
+ pj_time_val_normalize(&tv);
+
+ status = pjsip_endpt_handle_events2(pjsua_var.endpt, &tv, &count);
+
+ if (status != PJ_SUCCESS)
+ return -status;
+
+ return count;
+
+#endif
+}
+
+
+/*
+ * Create memory pool.
+ */
+PJ_DEF(pj_pool_t*) pjsua_pool_create( const char *name, pj_size_t init_size,
+ pj_size_t increment)
+{
+ /* Pool factory is thread safe, no need to lock */
+ return pj_pool_create(&pjsua_var.cp.factory, name, init_size, increment,
+ NULL);
+}
+
+
+/*
+ * Internal function to get SIP endpoint instance of pjsua, which is
+ * needed for example to register module, create transports, etc.
+ * Probably is only valid after #pjsua_init() is called.
+ */
+PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void)
+{
+ return pjsua_var.endpt;
+}
+
+/*
+ * Internal function to get media endpoint instance.
+ * Only valid after #pjsua_init() is called.
+ */
+PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void)
+{
+ return pjsua_var.med_endpt;
+}
+
+/*
+ * Internal function to get PJSUA pool factory.
+ */
+PJ_DEF(pj_pool_factory*) pjsua_get_pool_factory(void)
+{
+ return &pjsua_var.cp.factory;
+}
+
+/*****************************************************************************
+ * PJSUA SIP Transport API.
+ */
+
+/*
+ * Tools to get address string.
+ */
+static const char *addr_string(const pj_sockaddr_t *addr)
+{
+ static char str[128];
+ str[0] = '\0';
+ pj_inet_ntop(((const pj_sockaddr*)addr)->addr.sa_family,
+ pj_sockaddr_get_addr(addr),
+ str, sizeof(str));
+ return str;
+}
+
+void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info);
+
+/* Callback to receive transport state notifications */
+static void on_tp_state_callback(pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info)
+{
+ if (pjsua_var.ua_cfg.cb.on_transport_state) {
+ (*pjsua_var.ua_cfg.cb.on_transport_state)(tp, state, info);
+ }
+ if (pjsua_var.old_tp_cb) {
+ (*pjsua_var.old_tp_cb)(tp, state, info);
+ }
+ pjsua_acc_on_tp_state_changed(tp, state, info);
+}
+
+/*
+ * Create and initialize SIP socket (and possibly resolve public
+ * address via STUN, depending on config).
+ */
+static pj_status_t create_sip_udp_sock(int af,
+ const pjsua_transport_config *cfg,
+ pj_sock_t *p_sock,
+ pj_sockaddr *p_pub_addr)
+{
+ char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
+ unsigned port = cfg->port;
+ pj_str_t stun_srv;
+ pj_sock_t sock;
+ pj_sockaddr bind_addr;
+ pj_status_t status;
+
+ /* Make sure STUN server resolution has completed */
+ status = resolve_stun_server(PJ_TRUE);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
+ return status;
+ }
+
+ /* Initialize bound address */
+ if (cfg->bound_addr.slen) {
+ status = pj_sockaddr_init(af, &bind_addr, &cfg->bound_addr,
+ (pj_uint16_t)port);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to resolve transport bound address",
+ status);
+ return status;
+ }
+ } else {
+ pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
+ }
+
+ /* Create socket */
+ status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "socket() error", status);
+ return status;
+ }
+
+ /* Apply QoS, if specified */
+ status = pj_sock_apply_qos2(sock, cfg->qos_type,
+ &cfg->qos_params,
+ 2, THIS_FILE, "SIP UDP socket");
+
+ /* Bind socket */
+ status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "bind() error", status);
+ pj_sock_close(sock);
+ return status;
+ }
+
+ /* If port is zero, get the bound port */
+ if (port == 0) {
+ pj_sockaddr bound_addr;
+ int namelen = sizeof(bound_addr);
+ status = pj_sock_getsockname(sock, &bound_addr, &namelen);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "getsockname() error", status);
+ pj_sock_close(sock);
+ return status;
+ }
+
+ port = pj_sockaddr_get_port(&bound_addr);
+ }
+
+ if (pjsua_var.stun_srv.addr.sa_family != 0) {
+ pj_ansi_strcpy(stun_ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
+ stun_srv = pj_str(stun_ip_addr);
+ } else {
+ stun_srv.slen = 0;
+ }
+
+ /* Get the published address, either by STUN or by resolving
+ * the name of local host.
+ */
+ if (pj_sockaddr_has_addr(p_pub_addr)) {
+ /*
+ * Public address is already specified, no need to resolve the
+ * address, only set the port.
+ */
+ if (pj_sockaddr_get_port(p_pub_addr) == 0)
+ pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
+
+ } else if (stun_srv.slen) {
+ pjstun_setting stun_opt;
+
+ /*
+ * STUN is specified, resolve the address with STUN.
+ */
+ if (af != pj_AF_INET()) {
+ pjsua_perror(THIS_FILE, "Cannot use STUN", PJ_EAFNOTSUP);
+ pj_sock_close(sock);
+ return PJ_EAFNOTSUP;
+ }
+
+ pj_bzero(&stun_opt, sizeof(stun_opt));
+ stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
+ stun_opt.srv1 = stun_opt.srv2 = stun_srv;
+ stun_opt.port1 = stun_opt.port2 =
+ pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
+ 1, &sock, &p_pub_addr->ipv4);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
+ pj_sock_close(sock);
+ return status;
+ }
+
+ } else {
+ pj_bzero(p_pub_addr, sizeof(pj_sockaddr));
+
+ if (pj_sockaddr_has_addr(&bind_addr)) {
+ pj_sockaddr_copy_addr(p_pub_addr, &bind_addr);
+ } else {
+ status = pj_gethostip(af, p_pub_addr);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
+ pj_sock_close(sock);
+ return status;
+ }
+ }
+
+ p_pub_addr->addr.sa_family = (pj_uint16_t)af;
+ pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
+ }
+
+ *p_sock = sock;
+
+ PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
+ addr_string(p_pub_addr),
+ (int)pj_sockaddr_get_port(p_pub_addr)));
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Create SIP transport.
+ */
+PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
+ const pjsua_transport_config *cfg,
+ pjsua_transport_id *p_id)
+{
+ pjsip_transport *tp;
+ unsigned id;
+ pj_status_t status;
+
+ PJSUA_LOCK();
+
+ /* Find empty transport slot */
+ for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) {
+ if (pjsua_var.tpdata[id].data.ptr == NULL)
+ break;
+ }
+
+ if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) {
+ status = PJ_ETOOMANY;
+ pjsua_perror(THIS_FILE, "Error creating transport", status);
+ goto on_return;
+ }
+
+ /* Create the transport */
+ if (type==PJSIP_TRANSPORT_UDP || type==PJSIP_TRANSPORT_UDP6) {
+ /*
+ * Create UDP transport (IPv4 or IPv6).
+ */
+ pjsua_transport_config config;
+ char hostbuf[PJ_INET6_ADDRSTRLEN];
+ pj_sock_t sock = PJ_INVALID_SOCKET;
+ pj_sockaddr pub_addr;
+ pjsip_host_port addr_name;
+
+ /* Supply default config if it's not specified */
+ if (cfg == NULL) {
+ pjsua_transport_config_default(&config);
+ cfg = &config;
+ }
+
+ /* Initialize the public address from the config, if any */
+ pj_sockaddr_init(pjsip_transport_type_get_af(type), &pub_addr,
+ NULL, (pj_uint16_t)cfg->port);
+ if (cfg->public_addr.slen) {
+ status = pj_sockaddr_set_str_addr(pjsip_transport_type_get_af(type),
+ &pub_addr, &cfg->public_addr);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to resolve transport public address",
+ status);
+ goto on_return;
+ }
+ }
+
+ /* Create the socket and possibly resolve the address with STUN
+ * (only when public address is not specified).
+ */
+ status = create_sip_udp_sock(pjsip_transport_type_get_af(type),
+ cfg, &sock, &pub_addr);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ pj_ansi_strcpy(hostbuf, addr_string(&pub_addr));
+ addr_name.host = pj_str(hostbuf);
+ addr_name.port = pj_sockaddr_get_port(&pub_addr);
+
+ /* Create UDP transport */
+ status = pjsip_udp_transport_attach2(pjsua_var.endpt, type, sock,
+ &addr_name, 1, &tp);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating SIP UDP transport",
+ status);
+ pj_sock_close(sock);
+ goto on_return;
+ }
+
+
+ /* Save the transport */
+ pjsua_var.tpdata[id].type = type;
+ pjsua_var.tpdata[id].local_name = tp->local_name;
+ pjsua_var.tpdata[id].data.tp = tp;
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
+
+ } else if (type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_TCP6) {
+ /*
+ * Create TCP transport.
+ */
+ pjsua_transport_config config;
+ pjsip_tpfactory *tcp;
+ pjsip_tcp_transport_cfg tcp_cfg;
+ int af;
+
+ af = (type==PJSIP_TRANSPORT_TCP6) ? pj_AF_INET6() : pj_AF_INET();
+ pjsip_tcp_transport_cfg_default(&tcp_cfg, af);
+
+ /* Supply default config if it's not specified */
+ if (cfg == NULL) {
+ pjsua_transport_config_default(&config);
+ cfg = &config;
+ }
+
+ /* Configure bind address */
+ if (cfg->port)
+ pj_sockaddr_set_port(&tcp_cfg.bind_addr, (pj_uint16_t)cfg->port);
+
+ if (cfg->bound_addr.slen) {
+ status = pj_sockaddr_set_str_addr(tcp_cfg.af,
+ &tcp_cfg.bind_addr,
+ &cfg->bound_addr);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to resolve transport bound address",
+ status);
+ goto on_return;
+ }
+ }
+
+ /* Set published name */
+ if (cfg->public_addr.slen)
+ tcp_cfg.addr_name.host = cfg->public_addr;
+
+ /* Copy the QoS settings */
+ tcp_cfg.qos_type = cfg->qos_type;
+ pj_memcpy(&tcp_cfg.qos_params, &cfg->qos_params,
+ sizeof(cfg->qos_params));
+
+ /* Create the TCP transport */
+ status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp);
+
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating SIP TCP listener",
+ status);
+ goto on_return;
+ }
+
+ /* Save the transport */
+ pjsua_var.tpdata[id].type = type;
+ pjsua_var.tpdata[id].local_name = tcp->addr_name;
+ pjsua_var.tpdata[id].data.factory = tcp;
+
+#endif /* PJ_HAS_TCP */
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+ } else if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_TLS6) {
+ /*
+ * Create TLS transport.
+ */
+ pjsua_transport_config config;
+ pjsip_host_port a_name;
+ pjsip_tpfactory *tls;
+ pj_sockaddr local_addr;
+ int af;
+
+ /* Supply default config if it's not specified */
+ if (cfg == NULL) {
+ pjsua_transport_config_default(&config);
+ config.port = 5061;
+ cfg = &config;
+ }
+
+ /* Init local address */
+ af = (type==PJSIP_TRANSPORT_TLS) ? pj_AF_INET() : pj_AF_INET6();
+ pj_sockaddr_init(af, &local_addr, NULL, 0);
+
+ if (cfg->port)
+ pj_sockaddr_set_port(&local_addr, (pj_uint16_t)cfg->port);
+
+ if (cfg->bound_addr.slen) {
+ status = pj_sockaddr_set_str_addr(af, &local_addr,
+ &cfg->bound_addr);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to resolve transport bound address",
+ status);
+ goto on_return;
+ }
+ }
+
+ /* Init published name */
+ pj_bzero(&a_name, sizeof(pjsip_host_port));
+ if (cfg->public_addr.slen)
+ a_name.host = cfg->public_addr;
+
+ status = pjsip_tls_transport_start2(pjsua_var.endpt,
+ &cfg->tls_setting,
+ &local_addr, &a_name, 1, &tls);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
+ status);
+ goto on_return;
+ }
+
+ /* Save the transport */
+ pjsua_var.tpdata[id].type = type;
+ pjsua_var.tpdata[id].local_name = tls->addr_name;
+ pjsua_var.tpdata[id].data.factory = tls;
+#endif
+
+ } else {
+ status = PJSIP_EUNSUPTRANSPORT;
+ pjsua_perror(THIS_FILE, "Error creating transport", status);
+ goto on_return;
+ }
+
+ /* Set transport state callback */
+ {
+ pjsip_tp_state_callback tpcb;
+ pjsip_tpmgr *tpmgr;
+
+ tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
+ tpcb = pjsip_tpmgr_get_state_cb(tpmgr);
+
+ if (tpcb != &on_tp_state_callback) {
+ pjsua_var.old_tp_cb = tpcb;
+ pjsip_tpmgr_set_state_cb(tpmgr, &on_tp_state_callback);
+ }
+ }
+
+ /* Return the ID */
+ if (p_id) *p_id = id;
+
+ status = PJ_SUCCESS;
+
+on_return:
+
+ PJSUA_UNLOCK();
+
+ return status;
+}
+
+
+/*
+ * Register transport that has been created by application.
+ */
+PJ_DEF(pj_status_t) pjsua_transport_register( pjsip_transport *tp,
+ pjsua_transport_id *p_id)
+{
+ unsigned id;
+
+ PJSUA_LOCK();
+
+ /* Find empty transport slot */
+ for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) {
+ if (pjsua_var.tpdata[id].data.ptr == NULL)
+ break;
+ }
+
+ if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) {
+ pjsua_perror(THIS_FILE, "Error creating transport", PJ_ETOOMANY);
+ PJSUA_UNLOCK();
+ return PJ_ETOOMANY;
+ }
+
+ /* Save the transport */
+ pjsua_var.tpdata[id].type = (pjsip_transport_type_e) tp->key.type;
+ pjsua_var.tpdata[id].local_name = tp->local_name;
+ pjsua_var.tpdata[id].data.tp = tp;
+
+ /* Return the ID */
+ if (p_id) *p_id = id;
+
+ PJSUA_UNLOCK();
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Enumerate all transports currently created in the system.
+ */
+PJ_DEF(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[],
+ unsigned *p_count )
+{
+ unsigned i, count;
+
+ PJSUA_LOCK();
+
+ for (i=0, count=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata) && count<*p_count;
+ ++i)
+ {
+ if (!pjsua_var.tpdata[i].data.ptr)
+ continue;
+
+ id[count++] = i;
+ }
+
+ *p_count = count;
+
+ PJSUA_UNLOCK();
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Get information about transports.
+ */
+PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
+ pjsua_transport_info *info)
+{
+ pjsua_transport_data *t = &pjsua_var.tpdata[id];
+ pj_status_t status;
+
+ pj_bzero(info, sizeof(*info));
+
+ /* Make sure id is in range. */
+ PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
+ PJ_EINVAL);
+
+ /* Make sure that transport exists */
+ PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
+
+ PJSUA_LOCK();
+
+ if (t->type == PJSIP_TRANSPORT_UDP) {
+
+ pjsip_transport *tp = t->data.tp;
+
+ if (tp == NULL) {
+ PJSUA_UNLOCK();
+ return PJ_EINVALIDOP;
+ }
+
+ info->id = id;
+ info->type = (pjsip_transport_type_e) tp->key.type;
+ info->type_name = pj_str(tp->type_name);
+ info->info = pj_str(tp->info);
+ info->flag = tp->flag;
+ info->addr_len = tp->addr_len;
+ info->local_addr = tp->local_addr;
+ info->local_name = tp->local_name;
+ info->usage_count = pj_atomic_get(tp->ref_cnt);
+
+ status = PJ_SUCCESS;
+
+ } else if (t->type == PJSIP_TRANSPORT_TCP ||
+ t->type == PJSIP_TRANSPORT_TLS)
+ {
+
+ pjsip_tpfactory *factory = t->data.factory;
+
+ if (factory == NULL) {
+ PJSUA_UNLOCK();
+ return PJ_EINVALIDOP;
+ }
+
+ info->id = id;
+ info->type = t->type;
+ info->type_name = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP"):
+ pj_str("TLS");
+ info->info = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP transport"):
+ pj_str("TLS transport");
+ info->flag = factory->flag;
+ info->addr_len = sizeof(factory->local_addr);
+ info->local_addr = factory->local_addr;
+ info->local_name = factory->addr_name;
+ info->usage_count = 0;
+
+ status = PJ_SUCCESS;
+
+ } else {
+ pj_assert(!"Unsupported transport");
+ status = PJ_EINVALIDOP;
+ }
+
+
+ PJSUA_UNLOCK();
+
+ return status;
+}
+
+
+/*
+ * Disable a transport or re-enable it.
+ */
+PJ_DEF(pj_status_t) pjsua_transport_set_enable( pjsua_transport_id id,
+ pj_bool_t enabled)
+{
+ /* Make sure id is in range. */
+ PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
+ PJ_EINVAL);
+
+ /* Make sure that transport exists */
+ PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
+
+
+ /* To be done!! */
+ PJ_TODO(pjsua_transport_set_enable);
+ PJ_UNUSED_ARG(enabled);
+
+ return PJ_EINVALIDOP;
+}
+
+
+/*
+ * Close the transport.
+ */
+PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
+ pj_bool_t force )
+{
+ pj_status_t status;
+
+ /* Make sure id is in range. */
+ PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
+ PJ_EINVAL);
+
+ /* Make sure that transport exists */
+ PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
+
+ /* Note: destroy() may not work if there are objects still referencing
+ * the transport.
+ */
+ if (force) {
+ switch (pjsua_var.tpdata[id].type) {
+ case PJSIP_TRANSPORT_UDP:
+ status = pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
+ if (status != PJ_SUCCESS)
+ return status;
+ status = pjsip_transport_destroy(pjsua_var.tpdata[id].data.tp);
+ if (status != PJ_SUCCESS)
+ return status;
+ break;
+
+ case PJSIP_TRANSPORT_TLS:
+ case PJSIP_TRANSPORT_TCP:
+ /* This will close the TCP listener, but existing TCP/TLS
+ * connections (if any) will still linger
+ */
+ status = (*pjsua_var.tpdata[id].data.factory->destroy)
+ (pjsua_var.tpdata[id].data.factory);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ break;
+
+ default:
+ return PJ_EINVAL;
+ }
+
+ } else {
+ /* If force is not specified, transports will be closed at their
+ * convenient time. However this will leak PJSUA-API transport
+ * descriptors as PJSUA-API wouldn't know when exactly the
+ * transport is closed thus it can't cleanup PJSUA transport
+ * descriptor.
+ */
+ switch (pjsua_var.tpdata[id].type) {
+ case PJSIP_TRANSPORT_UDP:
+ return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
+ case PJSIP_TRANSPORT_TLS:
+ case PJSIP_TRANSPORT_TCP:
+ return (*pjsua_var.tpdata[id].data.factory->destroy)
+ (pjsua_var.tpdata[id].data.factory);
+ default:
+ return PJ_EINVAL;
+ }
+ }
+
+ /* Cleanup pjsua data when force is applied */
+ if (force) {
+ pjsua_var.tpdata[id].type = PJSIP_TRANSPORT_UNSPECIFIED;
+ pjsua_var.tpdata[id].data.ptr = NULL;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Add additional headers etc in msg_data specified by application
+ * when sending requests.
+ */
+void pjsua_process_msg_data(pjsip_tx_data *tdata,
+ const pjsua_msg_data *msg_data)
+{
+ pj_bool_t allow_body;
+ const pjsip_hdr *hdr;
+
+ /* Always add User-Agent */
+ if (pjsua_var.ua_cfg.user_agent.slen &&
+ tdata->msg->type == PJSIP_REQUEST_MSG)
+ {
+ const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
+ pjsip_hdr *h;
+ h = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool,
+ &STR_USER_AGENT,
+ &pjsua_var.ua_cfg.user_agent);
+ pjsip_msg_add_hdr(tdata->msg, h);
+ }
+
+ if (!msg_data)
+ return;
+
+ hdr = msg_data->hdr_list.next;
+ while (hdr && hdr != &msg_data->hdr_list) {
+ pjsip_hdr *new_hdr;
+
+ new_hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr);
+ pjsip_msg_add_hdr(tdata->msg, new_hdr);
+
+ hdr = hdr->next;
+ }
+
+ allow_body = (tdata->msg->body == NULL);
+
+ if (allow_body && msg_data->content_type.slen && msg_data->msg_body.slen) {
+ pjsip_media_type ctype;
+ pjsip_msg_body *body;
+
+ pjsua_parse_media_type(tdata->pool, &msg_data->content_type, &ctype);
+ body = pjsip_msg_body_create(tdata->pool, &ctype.type, &ctype.subtype,
+ &msg_data->msg_body);
+ tdata->msg->body = body;
+ }
+
+ /* Multipart */
+ if (!pj_list_empty(&msg_data->multipart_parts) &&
+ msg_data->multipart_ctype.type.slen)
+ {
+ pjsip_msg_body *bodies;
+ pjsip_multipart_part *part;
+ pj_str_t *boundary = NULL;
+
+ bodies = pjsip_multipart_create(tdata->pool,
+ &msg_data->multipart_ctype,
+ boundary);
+ part = msg_data->multipart_parts.next;
+ while (part != &msg_data->multipart_parts) {
+ pjsip_multipart_part *part_copy;
+
+ part_copy = pjsip_multipart_clone_part(tdata->pool, part);
+ pjsip_multipart_add_part(tdata->pool, bodies, part_copy);
+ part = part->next;
+ }
+
+ if (tdata->msg->body) {
+ part = pjsip_multipart_create_part(tdata->pool);
+ part->body = tdata->msg->body;
+ pjsip_multipart_add_part(tdata->pool, bodies, part);
+
+ tdata->msg->body = NULL;
+ }
+
+ tdata->msg->body = bodies;
+ }
+}
+
+
+/*
+ * Add route_set to outgoing requests
+ */
+void pjsua_set_msg_route_set( pjsip_tx_data *tdata,
+ const pjsip_route_hdr *route_set )
+{
+ const pjsip_route_hdr *r;
+
+ r = route_set->next;
+ while (r != route_set) {
+ pjsip_route_hdr *new_r;
+
+ new_r = (pjsip_route_hdr*) pjsip_hdr_clone(tdata->pool, r);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)new_r);
+
+ r = r->next;
+ }
+}
+
+
+/*
+ * Simple version of MIME type parsing (it doesn't support parameters)
+ */
+void pjsua_parse_media_type( pj_pool_t *pool,
+ const pj_str_t *mime,
+ pjsip_media_type *media_type)
+{
+ pj_str_t tmp;
+ char *pos;
+
+ pj_bzero(media_type, sizeof(*media_type));
+
+ pj_strdup_with_null(pool, &tmp, mime);
+
+ pos = pj_strchr(&tmp, '/');
+ if (pos) {
+ media_type->type.ptr = tmp.ptr;
+ media_type->type.slen = (pos-tmp.ptr);
+ media_type->subtype.ptr = pos+1;
+ media_type->subtype.slen = tmp.ptr+tmp.slen-pos-1;
+ } else {
+ media_type->type = tmp;
+ }
+}
+
+
+/*
+ * Internal function to init transport selector from transport id.
+ */
+void pjsua_init_tpselector(pjsua_transport_id tp_id,
+ pjsip_tpselector *sel)
+{
+ pjsua_transport_data *tpdata;
+ unsigned flag;
+
+ pj_bzero(sel, sizeof(*sel));
+ if (tp_id == PJSUA_INVALID_ID)
+ return;
+
+ pj_assert(tp_id >= 0 && tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata));
+ tpdata = &pjsua_var.tpdata[tp_id];
+
+ flag = pjsip_transport_get_flag_from_type(tpdata->type);
+
+ if (flag & PJSIP_TRANSPORT_DATAGRAM) {
+ sel->type = PJSIP_TPSELECTOR_TRANSPORT;
+ sel->u.transport = tpdata->data.tp;
+ } else {
+ sel->type = PJSIP_TPSELECTOR_LISTENER;
+ sel->u.listener = tpdata->data.factory;
+ }
+}
+
+
+/* Callback upon NAT detection completion */
+static void nat_detect_cb(void *user_data,
+ const pj_stun_nat_detect_result *res)
+{
+ PJ_UNUSED_ARG(user_data);
+
+ pjsua_var.nat_in_progress = PJ_FALSE;
+ pjsua_var.nat_status = res->status;
+ pjsua_var.nat_type = res->nat_type;
+
+ if (pjsua_var.ua_cfg.cb.on_nat_detect) {
+ (*pjsua_var.ua_cfg.cb.on_nat_detect)(res);
+ }
+}
+
+
+/*
+ * Detect NAT type.
+ */
+PJ_DEF(pj_status_t) pjsua_detect_nat_type()
+{
+ pj_status_t status;
+
+ if (pjsua_var.nat_in_progress)
+ return PJ_SUCCESS;
+
+ /* Make sure STUN server resolution has completed */
+ status = resolve_stun_server(PJ_TRUE);
+ if (status != PJ_SUCCESS) {
+ pjsua_var.nat_status = status;
+ pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
+ return status;
+ }
+
+ /* Make sure we have STUN */
+ if (pjsua_var.stun_srv.ipv4.sin_family == 0) {
+ pjsua_var.nat_status = PJNATH_ESTUNINSERVER;
+ return PJNATH_ESTUNINSERVER;
+ }
+
+ status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4,
+ &pjsua_var.stun_cfg,
+ NULL, &nat_detect_cb);
+
+ if (status != PJ_SUCCESS) {
+ pjsua_var.nat_status = status;
+ pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
+ return status;
+ }
+
+ pjsua_var.nat_in_progress = PJ_TRUE;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Get NAT type.
+ */
+PJ_DEF(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type)
+{
+ *type = pjsua_var.nat_type;
+ return pjsua_var.nat_status;
+}
+
+/*
+ * Verify that valid url is given.
+ */
+PJ_DEF(pj_status_t) pjsua_verify_url(const char *c_url)
+{
+ pjsip_uri *p;
+ pj_pool_t *pool;
+ char *url;
+ pj_size_t len = (c_url ? pj_ansi_strlen(c_url) : 0);
+
+ if (!len) return PJSIP_EINVALIDURI;
+
+ pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
+ if (!pool) return PJ_ENOMEM;
+
+ url = (char*) pj_pool_alloc(pool, len+1);
+ pj_ansi_strcpy(url, c_url);
+
+ p = pjsip_parse_uri(pool, url, len, 0);
+
+ pj_pool_release(pool);
+ return p ? 0 : PJSIP_EINVALIDURI;
+}
+
+/*
+ * Verify that valid SIP url is given.
+ */
+PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url)
+{
+ pjsip_uri *p;
+ pj_pool_t *pool;
+ char *url;
+ pj_size_t len = (c_url ? pj_ansi_strlen(c_url) : 0);
+
+ if (!len) return PJSIP_EINVALIDURI;
+
+ pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
+ if (!pool) return PJ_ENOMEM;
+
+ url = (char*) pj_pool_alloc(pool, len+1);
+ pj_ansi_strcpy(url, c_url);
+
+ p = pjsip_parse_uri(pool, url, len, 0);
+ if (!p || (pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0 &&
+ pj_stricmp2(pjsip_uri_get_scheme(p), "sips") != 0))
+ {
+ p = NULL;
+ }
+
+ pj_pool_release(pool);
+ return p ? 0 : PJSIP_EINVALIDURI;
+}
+
+/*
+ * Schedule a timer entry.
+ */
+#if PJ_TIMER_DEBUG
+PJ_DEF(pj_status_t) pjsua_schedule_timer_dbg( pj_timer_entry *entry,
+ const pj_time_val *delay,
+ const char *src_file,
+ int src_line)
+{
+ return pjsip_endpt_schedule_timer_dbg(pjsua_var.endpt, entry, delay,
+ src_file, src_line);
+}
+#else
+PJ_DEF(pj_status_t) pjsua_schedule_timer( pj_timer_entry *entry,
+ const pj_time_val *delay)
+{
+ return pjsip_endpt_schedule_timer(pjsua_var.endpt, entry, delay);
+}
+#endif
+
+/* Timer callback */
+static void timer_cb( pj_timer_heap_t *th,
+ pj_timer_entry *entry)
+{
+ pjsua_timer_list *tmr = (pjsua_timer_list *)entry->user_data;
+ void (*cb)(void *user_data) = tmr->cb;
+ void *user_data = tmr->user_data;
+
+ PJ_UNUSED_ARG(th);
+
+ pj_mutex_lock(pjsua_var.timer_mutex);
+ pj_list_push_back(&pjsua_var.timer_list, tmr);
+ pj_mutex_unlock(pjsua_var.timer_mutex);
+
+ if (cb)
+ (*cb)(user_data);
+}
+
+/*
+ * Schedule a timer callback.
+ */
+#if PJ_TIMER_DEBUG
+PJ_DEF(pj_status_t) pjsua_schedule_timer2_dbg( void (*cb)(void *user_data),
+ void *user_data,
+ unsigned msec_delay,
+ const char *src_file,
+ int src_line)
+#else
+PJ_DEF(pj_status_t) pjsua_schedule_timer2( void (*cb)(void *user_data),
+ void *user_data,
+ unsigned msec_delay)
+#endif
+{
+ pjsua_timer_list *tmr = NULL;
+ pj_status_t status;
+ pj_time_val delay;
+
+ pj_mutex_lock(pjsua_var.timer_mutex);
+
+ if (pj_list_empty(&pjsua_var.timer_list)) {
+ tmr = PJ_POOL_ALLOC_T(pjsua_var.pool, pjsua_timer_list);
+ } else {
+ tmr = pjsua_var.timer_list.next;
+ pj_list_erase(tmr);
+ }
+ pj_timer_entry_init(&tmr->entry, 0, tmr, timer_cb);
+ tmr->cb = cb;
+ tmr->user_data = user_data;
+ delay.sec = 0;
+ delay.msec = msec_delay;
+
+#if PJ_TIMER_DEBUG
+ status = pjsip_endpt_schedule_timer_dbg(pjsua_var.endpt, &tmr->entry,
+ &delay, src_file, src_line);
+#else
+ status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &tmr->entry, &delay);
+#endif
+ if (status != PJ_SUCCESS) {
+ pj_list_push_back(&pjsua_var.timer_list, tmr);
+ }
+
+ pj_mutex_unlock(pjsua_var.timer_mutex);
+
+ return status;
+}
+
+/*
+ * Cancel the previously scheduled timer.
+ *
+ */
+PJ_DEF(void) pjsua_cancel_timer(pj_timer_entry *entry)
+{
+ pjsip_endpt_cancel_timer(pjsua_var.endpt, entry);
+}
+
+/**
+ * Normalize route URI (check for ";lr" and append one if it doesn't
+ * exist and pjsua_config.force_lr is set.
+ */
+pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri)
+{
+ pj_str_t tmp_uri;
+ pj_pool_t *tmp_pool;
+ pjsip_uri *uri_obj;
+ pjsip_sip_uri *sip_uri;
+
+ tmp_pool = pjsua_pool_create("tmplr%p", 512, 512);
+ if (!tmp_pool)
+ return PJ_ENOMEM;
+
+ pj_strdup_with_null(tmp_pool, &tmp_uri, uri);
+
+ uri_obj = pjsip_parse_uri(tmp_pool, tmp_uri.ptr, tmp_uri.slen, 0);
+ if (!uri_obj) {
+ PJ_LOG(1,(THIS_FILE, "Invalid route URI: %.*s",
+ (int)uri->slen, uri->ptr));
+ pj_pool_release(tmp_pool);
+ return PJSIP_EINVALIDURI;
+ }
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(uri_obj) &&
+ !PJSIP_URI_SCHEME_IS_SIPS(uri_obj))
+ {
+ PJ_LOG(1,(THIS_FILE, "Route URI must be SIP URI: %.*s",
+ (int)uri->slen, uri->ptr));
+ pj_pool_release(tmp_pool);
+ return PJSIP_EINVALIDSCHEME;
+ }
+
+ sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri_obj);
+
+ /* Done if force_lr is disabled or if lr parameter is present */
+ if (!pjsua_var.ua_cfg.force_lr || sip_uri->lr_param) {
+ pj_pool_release(tmp_pool);
+ return PJ_SUCCESS;
+ }
+
+ /* Set lr param */
+ sip_uri->lr_param = 1;
+
+ /* Print the URI */
+ tmp_uri.ptr = (char*) pj_pool_alloc(tmp_pool, PJSIP_MAX_URL_SIZE);
+ tmp_uri.slen = pjsip_uri_print(PJSIP_URI_IN_ROUTING_HDR, uri_obj,
+ tmp_uri.ptr, PJSIP_MAX_URL_SIZE);
+ if (tmp_uri.slen < 1) {
+ PJ_LOG(1,(THIS_FILE, "Route URI is too long: %.*s",
+ (int)uri->slen, uri->ptr));
+ pj_pool_release(tmp_pool);
+ return PJSIP_EURITOOLONG;
+ }
+
+ /* Clone the URI */
+ pj_strdup_with_null(pool, uri, &tmp_uri);
+
+ pj_pool_release(tmp_pool);
+ return PJ_SUCCESS;
+}
+
+/*
+ * This is a utility function to dump the stack states to log, using
+ * verbosity level 3.
+ */
+PJ_DEF(void) pjsua_dump(pj_bool_t detail)
+{
+ unsigned old_decor;
+ unsigned i;
+
+ PJ_LOG(3,(THIS_FILE, "Start dumping application states:"));
+
+ old_decor = pj_log_get_decor();
+ pj_log_set_decor(old_decor & (PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
+
+ if (detail)
+ pj_dump_config();
+
+ pjsip_endpt_dump(pjsua_get_pjsip_endpt(), detail);
+
+ pjmedia_endpt_dump(pjsua_get_pjmedia_endpt());
+
+ PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
+ for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
+ pjsua_call *call = &pjsua_var.calls[i];
+ pjsua_acc_config *acc_cfg;
+ pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2];
+ unsigned tp_cnt = 0;
+ unsigned j;
+
+ /* Collect media transports in this call */
+ for (j = 0; j < call->med_cnt; ++j) {
+ if (call->media[j].tp != NULL)
+ tp[tp_cnt++] = call->media[j].tp;
+ }
+ for (j = 0; j < call->med_prov_cnt; ++j) {
+ pjmedia_transport *med_tp = call->media_prov[j].tp;
+ if (med_tp) {
+ unsigned k;
+ pj_bool_t used = PJ_FALSE;
+ for (k = 0; k < tp_cnt; ++k) {
+ if (med_tp == tp[k]) {
+ used = PJ_TRUE;
+ break;
+ }
+ }
+ if (!used)
+ tp[tp_cnt++] = med_tp;
+ }
+ }
+
+ acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
+
+ /* Dump the media transports in this call */
+ for (j = 0; j < tp_cnt; ++j) {
+ pjmedia_transport_info tpinfo;
+ char addr_buf[80];
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(tp[j], &tpinfo);
+ PJ_LOG(3,(THIS_FILE, " %s: %s",
+ (acc_cfg->ice_cfg.enable_ice ? "ICE" : "UDP"),
+ pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name,
+ addr_buf,
+ sizeof(addr_buf), 3)));
+ }
+ }
+
+ pjsip_tsx_layer_dump(detail);
+ pjsip_ua_dump(detail);
+
+// Dumping complete call states may require a 'large' buffer
+// (about 3KB per call session, including RTCP XR).
+#if 0
+ /* Dump all invite sessions: */
+ PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:"));
+
+ if (pjsua_call_get_count() == 0) {
+
+ PJ_LOG(3,(THIS_FILE, " - no sessions -"));
+
+ } else {
+ unsigned i;
+
+ for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
+ if (pjsua_call_is_active(i)) {
+ /* Tricky logging, since call states log string tends to be
+ * longer than PJ_LOG_MAX_SIZE.
+ */
+ char buf[1024 * 3];
+ unsigned call_dump_len;
+ unsigned part_len;
+ unsigned part_idx;
+ unsigned log_decor;
+
+ pjsua_call_dump(i, detail, buf, sizeof(buf), " ");
+ call_dump_len = strlen(buf);
+
+ log_decor = pj_log_get_decor();
+ pj_log_set_decor(log_decor & ~(PJ_LOG_HAS_NEWLINE |
+ PJ_LOG_HAS_CR));
+ PJ_LOG(3,(THIS_FILE, "\n"));
+ pj_log_set_decor(0);
+
+ part_idx = 0;
+ part_len = PJ_LOG_MAX_SIZE-80;
+ while (part_idx < call_dump_len) {
+ char p_orig, *p;
+
+ p = &buf[part_idx];
+ if (part_idx + part_len > call_dump_len)
+ part_len = call_dump_len - part_idx;
+ p_orig = p[part_len];
+ p[part_len] = '\0';
+ PJ_LOG(3,(THIS_FILE, "%s", p));
+ p[part_len] = p_orig;
+ part_idx += part_len;
+ }
+ pj_log_set_decor(log_decor);
+ }
+ }
+ }
+#endif
+
+ /* Dump presence status */
+ pjsua_pres_dump(detail);
+
+ pj_log_set_decor(old_decor);
+ PJ_LOG(3,(THIS_FILE, "Dump complete"));
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6dd2e93a644095b999cae06820663b2de1ed4f2.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6dd2e93a644095b999cae06820663b2de1ed4f2.svn-base
new file mode 100644
index 0000000..b4fe0ed
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6dd2e93a644095b999cae06820663b2de1ed4f2.svn-base
@@ -0,0 +1,283 @@
+
+ /******************************************************************
+
+ iLBC Speech Coder ANSI-C Source Code
+
+ lsf.c
+
+ Copyright (C) The Internet Society (2004).
+ All Rights Reserved.
+
+ ******************************************************************/
+
+ #include <string.h>
+
+
+
+
+
+ #include <math.h>
+
+ #include "iLBC_define.h"
+
+ /*----------------------------------------------------------------*
+ * conversion from lpc coefficients to lsf coefficients
+ *---------------------------------------------------------------*/
+
+ void a2lsf(
+ float *freq,/* (o) lsf coefficients */
+ float *a /* (i) lpc coefficients */
+ ){
+ float steps[LSF_NUMBER_OF_STEPS] =
+ {(float)0.00635, (float)0.003175, (float)0.0015875,
+ (float)0.00079375};
+ float step;
+ int step_idx;
+ int lsp_index;
+ float p[LPC_HALFORDER];
+ float q[LPC_HALFORDER];
+ float p_pre[LPC_HALFORDER];
+ float q_pre[LPC_HALFORDER];
+ float old_p, old_q, *old;
+ float *pq_coef;
+ float omega, old_omega;
+ int i;
+ float hlp, hlp1, hlp2, hlp3, hlp4, hlp5;
+
+ for (i=0; i<LPC_HALFORDER; i++) {
+ p[i] = (float)-1.0 * (a[i + 1] + a[LPC_FILTERORDER - i]);
+ q[i] = a[LPC_FILTERORDER - i] - a[i + 1];
+ }
+
+ p_pre[0] = (float)-1.0 - p[0];
+ p_pre[1] = - p_pre[0] - p[1];
+ p_pre[2] = - p_pre[1] - p[2];
+ p_pre[3] = - p_pre[2] - p[3];
+ p_pre[4] = - p_pre[3] - p[4];
+ p_pre[4] = p_pre[4] / 2;
+
+ q_pre[0] = (float)1.0 - q[0];
+ q_pre[1] = q_pre[0] - q[1];
+ q_pre[2] = q_pre[1] - q[2];
+ q_pre[3] = q_pre[2] - q[3];
+ q_pre[4] = q_pre[3] - q[4];
+ q_pre[4] = q_pre[4] / 2;
+
+ omega = 0.0;
+
+
+
+
+
+ old_omega = 0.0;
+
+ old_p = FLOAT_MAX;
+ old_q = FLOAT_MAX;
+
+ /* Here we loop through lsp_index to find all the
+ LPC_FILTERORDER roots for omega. */
+
+ for (lsp_index = 0; lsp_index<LPC_FILTERORDER; lsp_index++) {
+
+ /* Depending on lsp_index being even or odd, we
+ alternatively solve the roots for the two LSP equations. */
+
+
+ if ((lsp_index & 0x1) == 0) {
+ pq_coef = p_pre;
+ old = &old_p;
+ } else {
+ pq_coef = q_pre;
+ old = &old_q;
+ }
+
+ /* Start with low resolution grid */
+
+ for (step_idx = 0, step = steps[step_idx];
+ step_idx < LSF_NUMBER_OF_STEPS;){
+
+ /* cos(10piw) + pq(0)cos(8piw) + pq(1)cos(6piw) +
+ pq(2)cos(4piw) + pq(3)cod(2piw) + pq(4) */
+
+ hlp = (float)cos(omega * TWO_PI);
+ hlp1 = (float)2.0 * hlp + pq_coef[0];
+ hlp2 = (float)2.0 * hlp * hlp1 - (float)1.0 +
+ pq_coef[1];
+ hlp3 = (float)2.0 * hlp * hlp2 - hlp1 + pq_coef[2];
+ hlp4 = (float)2.0 * hlp * hlp3 - hlp2 + pq_coef[3];
+ hlp5 = hlp * hlp4 - hlp3 + pq_coef[4];
+
+
+ if (((hlp5 * (*old)) <= 0.0) || (omega >= 0.5)){
+
+ if (step_idx == (LSF_NUMBER_OF_STEPS - 1)){
+
+ if (fabs(hlp5) >= fabs(*old)) {
+ freq[lsp_index] = omega - step;
+ } else {
+ freq[lsp_index] = omega;
+ }
+
+
+
+
+
+
+
+ if ((*old) >= 0.0){
+ *old = (float)-1.0 * FLOAT_MAX;
+ } else {
+ *old = FLOAT_MAX;
+ }
+
+ omega = old_omega;
+ step_idx = 0;
+
+ step_idx = LSF_NUMBER_OF_STEPS;
+ } else {
+
+ if (step_idx == 0) {
+ old_omega = omega;
+ }
+
+ step_idx++;
+ omega -= steps[step_idx];
+
+ /* Go back one grid step */
+
+ step = steps[step_idx];
+ }
+ } else {
+
+ /* increment omega until they are of different sign,
+ and we know there is at least one root between omega
+ and old_omega */
+ *old = hlp5;
+ omega += step;
+ }
+ }
+ }
+
+ for (i = 0; i<LPC_FILTERORDER; i++) {
+ freq[i] = freq[i] * TWO_PI;
+ }
+ }
+
+ /*----------------------------------------------------------------*
+ * conversion from lsf coefficients to lpc coefficients
+ *---------------------------------------------------------------*/
+
+ void lsf2a(
+ float *a_coef, /* (o) lpc coefficients */
+ float *freq /* (i) lsf coefficients */
+
+
+
+
+
+ ){
+ int i, j;
+ float hlp;
+ float p[LPC_HALFORDER], q[LPC_HALFORDER];
+ float a[LPC_HALFORDER + 1], a1[LPC_HALFORDER],
+ a2[LPC_HALFORDER];
+ float b[LPC_HALFORDER + 1], b1[LPC_HALFORDER],
+ b2[LPC_HALFORDER];
+
+ for (i=0; i<LPC_FILTERORDER; i++) {
+ freq[i] = freq[i] * PI2;
+ }
+
+ /* Check input for ill-conditioned cases. This part is not
+ found in the TIA standard. It involves the following 2 IF
+ blocks. If "freq" is judged ill-conditioned, then we first
+ modify freq[0] and freq[LPC_HALFORDER-1] (normally
+ LPC_HALFORDER = 10 for LPC applications), then we adjust
+ the other "freq" values slightly */
+
+
+ if ((freq[0] <= 0.0) || (freq[LPC_FILTERORDER - 1] >= 0.5)){
+
+
+ if (freq[0] <= 0.0) {
+ freq[0] = (float)0.022;
+ }
+
+
+ if (freq[LPC_FILTERORDER - 1] >= 0.5) {
+ freq[LPC_FILTERORDER - 1] = (float)0.499;
+ }
+
+ hlp = (freq[LPC_FILTERORDER - 1] - freq[0]) /
+ (float) (LPC_FILTERORDER - 1);
+
+ for (i=1; i<LPC_FILTERORDER; i++) {
+ freq[i] = freq[i - 1] + hlp;
+ }
+ }
+
+ memset(a1, 0, LPC_HALFORDER*sizeof(float));
+ memset(a2, 0, LPC_HALFORDER*sizeof(float));
+ memset(b1, 0, LPC_HALFORDER*sizeof(float));
+ memset(b2, 0, LPC_HALFORDER*sizeof(float));
+ memset(a, 0, (LPC_HALFORDER+1)*sizeof(float));
+ memset(b, 0, (LPC_HALFORDER+1)*sizeof(float));
+
+
+
+
+
+
+ /* p[i] and q[i] compute cos(2*pi*omega_{2j}) and
+ cos(2*pi*omega_{2j-1} in eqs. 4.2.2.2-1 and 4.2.2.2-2.
+ Note that for this code p[i] specifies the coefficients
+ used in .Q_A(z) while q[i] specifies the coefficients used
+ in .P_A(z) */
+
+ for (i=0; i<LPC_HALFORDER; i++) {
+ p[i] = (float)cos(TWO_PI * freq[2 * i]);
+ q[i] = (float)cos(TWO_PI * freq[2 * i + 1]);
+ }
+
+ a[0] = 0.25;
+ b[0] = 0.25;
+
+ for (i= 0; i<LPC_HALFORDER; i++) {
+ a[i + 1] = a[i] - 2 * p[i] * a1[i] + a2[i];
+ b[i + 1] = b[i] - 2 * q[i] * b1[i] + b2[i];
+ a2[i] = a1[i];
+ a1[i] = a[i];
+ b2[i] = b1[i];
+ b1[i] = b[i];
+ }
+
+ for (j=0; j<LPC_FILTERORDER; j++) {
+
+ if (j == 0) {
+ a[0] = 0.25;
+ b[0] = -0.25;
+ } else {
+ a[0] = b[0] = 0.0;
+ }
+
+ for (i=0; i<LPC_HALFORDER; i++) {
+ a[i + 1] = a[i] - 2 * p[i] * a1[i] + a2[i];
+ b[i + 1] = b[i] - 2 * q[i] * b1[i] + b2[i];
+ a2[i] = a1[i];
+ a1[i] = a[i];
+ b2[i] = b1[i];
+ b1[i] = b[i];
+ }
+
+ a_coef[j + 1] = 2 * (a[LPC_HALFORDER] + b[LPC_HALFORDER]);
+ }
+
+ a_coef[0] = 1.0;
+ }
+
+
+
+
+
+
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6e6f492c4014cb3c334cfb2fef7a2f0db538453.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6e6f492c4014cb3c334cfb2fef7a2f0db538453.svn-base
new file mode 100644
index 0000000..cc63179
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6e6f492c4014cb3c334cfb2fef7a2f0db538453.svn-base
@@ -0,0 +1,28 @@
+#
+# This file is used by get-footprint.py script to build samples/footprint.c
+# to get the footprint report for PJSIP/PJMEDIA.
+#
+include ../../build.mak
+include ../../build/common.mak
+
+
+###############################################################################
+# Gather all flags.
+#
+export _CFLAGS := $(APP_CFLAGS) $(CFLAGS)
+export _CXXFLAGS:= $(_CFLAGS)
+
+export _LDFLAGS := $(APP_LDFLAGS) $(APP_LDLIBS) $(LDFLAGS)
+
+EXE := footprint.exe
+
+all:
+ $(APP_CC) -o $(EXE) ../src/samples/footprint.c $(FCFLAGS) $(_CFLAGS) $(_LDFLAGS)
+ $(CROSS_COMPILE)strip --strip-all $(EXE)
+
+clean:
+ rm -f $(EXE)
+
+print_name:
+ @echo $(MACHINE_NAME) $(OS_NAME) $(CROSS_COMPILE)$(CC_NAME) `$(CROSS_COMPILE)$(CC_NAME) -dumpversion`
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6f1001ee2a49feefb4f5d32117829436b5e1afd.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6f1001ee2a49feefb4f5d32117829436b5e1afd.svn-base
new file mode 100644
index 0000000..a3b4807
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6f1001ee2a49feefb4f5d32117829436b5e1afd.svn-base
@@ -0,0 +1,22 @@
+export CC = $(CROSS_COMPILE)gcc -c
+export AR = $(CROSS_COMPILE)ar rv
+export LD = $(CROSS_COMPILE)gcc
+export LDOUT = -o
+export RANLIB = $(CROSS_COMPILE)ranlib
+
+export OBJEXT := .o
+export LIBEXT := .a
+export LIBEXT2 :=
+
+export CC_OUT := -o
+export CC_INC := -I
+export CC_DEF := -D
+export CC_OPTIMIZE := -O2
+export CC_LIB := -l
+
+export CC_SOURCES :=
+export CC_CFLAGS := -Wall
+#export CC_CFLAGS += -Wdeclaration-after-statement
+#export CC_CXXFLAGS := -Wdeclaration-after-statement
+export CC_LDFLAGS :=
+
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6f3096483e511c930c7120dbb35e7aa048e0ca1.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6f3096483e511c930c7120dbb35e7aa048e0ca1.svn-base
new file mode 100644
index 0000000..5850304
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6f3096483e511c930c7120dbb35e7aa048e0ca1.svn-base
@@ -0,0 +1,99 @@
+How to get started:
+
+ Edit the Makefile.
+
+ You should configure a few machine-dependencies and what
+ compiler you want to use.
+
+ The code works both with ANSI and K&R-C. Use
+ -DNeedFunctionPrototypes to compile with, or
+ -UNeedFunctionPrototypes to compile without, function
+ prototypes in the header files.
+
+ Make addtst
+
+ The "add" program that will be compiled and run checks whether
+ the basic math functions of the gsm library work with your
+ compiler. If it prints anything to stderr, complain (to us).
+
+ Edit inc/config.h.
+
+ Make
+
+ Local versions of the gsm library and the "compress"-like filters
+ toast, untoast and tcat will be generated.
+
+ If the compilation aborts because of a missing function,
+ declaration, or header file, see if there's something in
+ inc/config.h to work around it. If not, complain.
+
+ Try it
+
+ Grab an audio file from somewhere (raw u-law or Sun .au is fine,
+ linear 16-bit in host byte order will do), copy it, toast it,
+ untoast it, and listen to the result.
+
+ The GSM-encoded and -decoded audio should have the quality
+ of a good phone line. If the resulting audio is noisier than
+ your original, or if you hear compression artifacts, complain;
+ that's a bug in our software, not a bug in the GSM encoding
+ standard itself.
+
+Installation
+
+ You can install the gsm library interface, or the toast binaries,
+ or both.
+
+ Edit the Makefile
+
+ Fill in the directories where you want to install the
+ library, header files, manual pages, and binaries.
+
+ Turn off the installation of one half of the distribution
+ (i.e., gsm library or toast binaries) by not setting the
+ corresponding directory root Makefile macro.
+
+ make install
+
+ will install the programs "toast" with two links named
+ "tcat" and "untoast", and the gsm library "libgsm.a" with
+ a "gsm.h" header file, and their respective manual pages.
+
+
+Optimizing
+
+ This code was developed on a machine without an integer
+ multiplication instruction, where we obtained the fastest result by
+ replacing some of the integer multiplications with floating point
+ multiplications.
+
+ If your machine does multiply integers fast enough,
+ leave USE_FLOAT_MUL undefined. The results should be the
+ same in both cases.
+
+ On machines with fast floating point arithmetic, defining
+ both USE_FLOAT_MUL and FAST makes a run-time library
+ option available that will (in a few crucial places) use
+ ``native'' floating point operations rather than the bit-by-bit
+ defined ones of the GSM standard. If you use this fast
+ option, the outcome will not be bitwise identical to the
+ results prescribed by the standard, but it is compatible with
+ the standard encoding, and a user is unlikely to notice a
+ difference.
+
+
+Bug Reports
+
+ Please direct bug reports, questions, and comments to
+ jutta@cs.tu-berlin.de and cabo@informatik.uni-bremen.de.
+
+
+Good luck,
+
+ Jutta Degener,
+ Carsten Bormann
+
+--
+Copyright 1992, 1993, 1994, by Jutta Degener and Carsten Bormann,
+Technische Universitaet Berlin. See the accompanying file "COPYRIGHT"
+for details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
diff --git a/jni/pjproject-android/.svn/pristine/b6/b6fa867f941e71ebfc56ade6e64c556c97c96b06.svn-base b/jni/pjproject-android/.svn/pristine/b6/b6fa867f941e71ebfc56ade6e64c556c97c96b06.svn-base
new file mode 100644
index 0000000..fc63eb4
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/b6/b6fa867f941e71ebfc56ade6e64c556c97c96b06.svn-base
@@ -0,0 +1,1228 @@
+/* $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 __PJMEDIA_CODECS_AMR_HELPER_H__
+#define __PJMEDIA_CODECS_AMR_HELPER_H__
+
+/**
+ * @file pjmedia-codec/amr_helper.h
+ * @brief Common tables and helper functions for AMR codec (NB & WB).
+ */
+
+
+#ifdef _MSC_VER
+# pragma warning(disable:4214) // bit field types other than int
+#endif
+
+/**
+ * @defgroup PJMED_AMR_CODEC_HELPER AMR Codec Helper
+ * @ingroup PJMEDIA_CODEC_CODECS
+ * @brief AMR common tables and helper functions.
+ * @{
+ *
+ * This sections describes common AMR constants tables (e.g: bits sensitivity
+ * order map, frame lengths, bitrates) and helper functions (e.g: pack AMR
+ * payload in octet-aligned mode or bandwidth-efficient mode, payload parser,
+ * reorder AMR bitstream).
+ */
+
+PJ_BEGIN_DECL
+
+
+/* AMR bits sensitivity order maps */
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap122[244] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 23, 15, 16, 17, 18,
+ 19, 20, 21, 22, 24, 25, 26, 27, 28, 38,
+ 141, 39, 142, 40, 143, 41, 144, 42, 145, 43,
+ 146, 44, 147, 45, 148, 46, 149, 47, 97, 150,
+ 200, 48, 98, 151, 201, 49, 99, 152, 202, 86,
+ 136, 189, 239, 87, 137, 190, 240, 88, 138, 191,
+ 241, 91, 194, 92, 195, 93, 196, 94, 197, 95,
+ 198, 29, 30, 31, 32, 33, 34, 35, 50, 100,
+ 153, 203, 89, 139, 192, 242, 51, 101, 154, 204,
+ 55, 105, 158, 208, 90, 140, 193, 243, 59, 109,
+ 162, 212, 63, 113, 166, 216, 67, 117, 170, 220,
+ 36, 37, 54, 53, 52, 58, 57, 56, 62, 61,
+ 60, 66, 65, 64, 70, 69, 68, 104, 103, 102,
+ 108, 107, 106, 112, 111, 110, 116, 115, 114, 120,
+ 119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
+ 163, 169, 168, 167, 173, 172, 171, 207, 206, 205,
+ 211, 210, 209, 215, 214, 213, 219, 218, 217, 223,
+ 222, 221, 73, 72, 71, 76, 75, 74, 79, 78,
+ 77, 82, 81, 80, 85, 84, 83, 123, 122, 121,
+ 126, 125, 124, 129, 128, 127, 132, 131, 130, 135,
+ 134, 133, 176, 175, 174, 179, 178, 177, 182, 181,
+ 180, 185, 184, 183, 188, 187, 186, 226, 225, 224,
+ 229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
+ 237, 236, 96, 199
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap102[204] =
+{
+ 7, 6, 5, 4, 3, 2, 1, 0, 16, 15,
+ 14, 13, 12, 11, 10, 9, 8, 26, 27, 28,
+ 29, 30, 31, 115, 116, 117, 118, 119, 120, 72,
+ 73, 161, 162, 65, 68, 69, 108, 111, 112, 154,
+ 157, 158, 197, 200, 201, 32, 33, 121, 122, 74,
+ 75, 163, 164, 66, 109, 155, 198, 19, 23, 21,
+ 22, 18, 17, 20, 24, 25, 37, 36, 35, 34,
+ 80, 79, 78, 77, 126, 125, 124, 123, 169, 168,
+ 167, 166, 70, 67, 71, 113, 110, 114, 159, 156,
+ 160, 202, 199, 203, 76, 165, 81, 82, 92, 91,
+ 93, 83, 95, 85, 84, 94, 101, 102, 96, 104,
+ 86, 103, 87, 97, 127, 128, 138, 137, 139, 129,
+ 141, 131, 130, 140, 147, 148, 142, 150, 132, 149,
+ 133, 143, 170, 171, 181, 180, 182, 172, 184, 174,
+ 173, 183, 190, 191, 185, 193, 175, 192, 176, 186,
+ 38, 39, 49, 48, 50, 40, 52, 42, 41, 51,
+ 58, 59, 53, 61, 43, 60, 44, 54, 194, 179,
+ 189, 196, 177, 195, 178, 187, 188, 151, 136, 146,
+ 153, 134, 152, 135, 144, 145, 105, 90, 100, 107,
+ 88, 106, 89, 98, 99, 62, 47, 57, 64, 45,
+ 63, 46, 55, 56
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap795[159] =
+{
+ 8, 7, 6, 5, 4, 3, 2, 14, 16, 9,
+ 10, 12, 13, 15, 11, 17, 20, 22, 24, 23,
+ 19, 18, 21, 56, 88, 122, 154, 57, 89, 123,
+ 155, 58, 90, 124, 156, 52, 84, 118, 150, 53,
+ 85, 119, 151, 27, 93, 28, 94, 29, 95, 30,
+ 96, 31, 97, 61, 127, 62, 128, 63, 129, 59,
+ 91, 125, 157, 32, 98, 64, 130, 1, 0, 25,
+ 26, 33, 99, 34, 100, 65, 131, 66, 132, 54,
+ 86, 120, 152, 60, 92, 126, 158, 55, 87, 121,
+ 153, 117, 116, 115, 46, 78, 112, 144, 43, 75,
+ 109, 141, 40, 72, 106, 138, 36, 68, 102, 134,
+ 114, 149, 148, 147, 146, 83, 82, 81, 80, 51,
+ 50, 49, 48, 47, 45, 44, 42, 39, 35, 79,
+ 77, 76, 74, 71, 67, 113, 111, 110, 108, 105,
+ 101, 145, 143, 142, 140, 137, 133, 41, 73, 107,
+ 139, 37, 69, 103, 135, 38, 70, 104, 136
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap74[148] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 26, 87, 27,
+ 88, 28, 89, 29, 90, 30, 91, 51, 80, 112,
+ 141, 52, 81, 113, 142, 54, 83, 115, 144, 55,
+ 84, 116, 145, 58, 119, 59, 120, 21, 22, 23,
+ 17, 18, 19, 31, 60, 92, 121, 56, 85, 117,
+ 146, 20, 24, 25, 50, 79, 111, 140, 57, 86,
+ 118, 147, 49, 78, 110, 139, 48, 77, 53, 82,
+ 114, 143, 109, 138, 47, 76, 108, 137, 32, 33,
+ 61, 62, 93, 94, 122, 123, 41, 42, 43, 44,
+ 45, 46, 70, 71, 72, 73, 74, 75, 102, 103,
+ 104, 105, 106, 107, 131, 132, 133, 134, 135, 136,
+ 34, 63, 95, 124, 35, 64, 96, 125, 36, 65,
+ 97, 126, 37, 66, 98, 127, 38, 67, 99, 128,
+ 39, 68, 100, 129, 40, 69, 101, 130
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap67[134] =
+{
+ 0, 1, 4, 3, 5, 6, 13, 7, 2, 8,
+ 9, 11, 15, 12, 14, 10, 28, 82, 29, 83,
+ 27, 81, 26, 80, 30, 84, 16, 55, 109, 56,
+ 110, 31, 85, 57, 111, 48, 73, 102, 127, 32,
+ 86, 51, 76, 105, 130, 52, 77, 106, 131, 58,
+ 112, 33, 87, 19, 23, 53, 78, 107, 132, 21,
+ 22, 18, 17, 20, 24, 25, 50, 75, 104, 129,
+ 47, 72, 101, 126, 54, 79, 108, 133, 46, 71,
+ 100, 125, 128, 103, 74, 49, 45, 70, 99, 124,
+ 42, 67, 96, 121, 39, 64, 93, 118, 38, 63,
+ 92, 117, 35, 60, 89, 114, 34, 59, 88, 113,
+ 44, 69, 98, 123, 43, 68, 97, 122, 41, 66,
+ 95, 120, 40, 65, 94, 119, 37, 62, 91, 116,
+ 36, 61, 90, 115
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap59[118] =
+{
+ 0, 1, 4, 5, 3, 6, 7, 2, 13, 15,
+ 8, 9, 11, 12, 14, 10, 16, 28, 74, 29,
+ 75, 27, 73, 26, 72, 30, 76, 51, 97, 50,
+ 71, 96, 117, 31, 77, 52, 98, 49, 70, 95,
+ 116, 53, 99, 32, 78, 33, 79, 48, 69, 94,
+ 115, 47, 68, 93, 114, 46, 67, 92, 113, 19,
+ 21, 23, 22, 18, 17, 20, 24, 111, 43, 89,
+ 110, 64, 65, 44, 90, 25, 45, 66, 91, 112,
+ 54, 100, 40, 61, 86, 107, 39, 60, 85, 106,
+ 36, 57, 82, 103, 35, 56, 81, 102, 34, 55,
+ 80, 101, 42, 63, 88, 109, 41, 62, 87, 108,
+ 38, 59, 84, 105, 37, 58, 83, 104
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap515[103] =
+{
+ 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
+ 13, 12, 11, 10, 9, 8, 23, 24, 25, 26,
+ 27, 46, 65, 84, 45, 44, 43, 64, 63, 62,
+ 83, 82, 81, 102, 101, 100, 42, 61, 80, 99,
+ 28, 47, 66, 85, 18, 41, 60, 79, 98, 29,
+ 48, 67, 17, 20, 22, 40, 59, 78, 97, 21,
+ 30, 49, 68, 86, 19, 16, 87, 39, 38, 58,
+ 57, 77, 35, 54, 73, 92, 76, 96, 95, 36,
+ 55, 74, 93, 32, 51, 33, 52, 70, 71, 89,
+ 90, 31, 50, 69, 88, 37, 56, 75, 94, 34,
+ 53, 72, 91
+};
+
+const pj_int16_t pjmedia_codec_amrnb_ordermap475[95] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 23, 24, 25, 26,
+ 27, 28, 48, 49, 61, 62, 82, 83, 47, 46,
+ 45, 44, 81, 80, 79, 78, 17, 18, 20, 22,
+ 77, 76, 75, 74, 29, 30, 43, 42, 41, 40,
+ 38, 39, 16, 19, 21, 50, 51, 59, 60, 63,
+ 64, 72, 73, 84, 85, 93, 94, 32, 33, 35,
+ 36, 53, 54, 56, 57, 66, 67, 69, 70, 87,
+ 88, 90, 91, 34, 55, 68, 89, 37, 58, 71,
+ 92, 31, 52, 65, 86
+};
+
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_660[] =
+{
+ 0, 5, 6, 7, 61, 84, 107, 130, 62, 85,
+ 8, 4, 37, 38, 39, 40, 58, 81, 104, 127,
+ 60, 83, 106, 129, 108, 131, 128, 41, 42, 80,
+ 126, 1, 3, 57, 103, 82, 105, 59, 2, 63,
+ 109, 110, 86, 19, 22, 23, 64, 87, 18, 20,
+ 21, 17, 13, 88, 43, 89, 65, 111, 14, 24,
+ 25, 26, 27, 28, 15, 16, 44, 90, 66, 112,
+ 9, 11, 10, 12, 67, 113, 29, 30, 31, 32,
+ 34, 33, 35, 36, 45, 51, 68, 74, 91, 97,
+ 114, 120, 46, 69, 92, 115, 52, 75, 98, 121,
+ 47, 70, 93, 116, 53, 76, 99, 122, 48, 71,
+ 94, 117, 54, 77, 100, 123, 49, 72, 95, 118,
+ 55, 78, 101, 124, 50, 73, 96, 119, 56, 79,
+ 102, 125
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_885[] =
+{
+ 0, 4, 6, 7, 5, 3, 47, 48, 49, 112,
+ 113, 114, 75, 106, 140, 171, 80, 111, 145, 176,
+ 77, 108, 142, 173, 78, 109, 143, 174, 79, 110,
+ 144, 175, 76, 107, 141, 172, 50, 115, 51, 2,
+ 1, 81, 116, 146, 19, 21, 12, 17, 18, 20,
+ 16, 25, 13, 10, 14, 24, 23, 22, 26, 8,
+ 15, 52, 117, 31, 82, 147, 9, 33, 11, 83,
+ 148, 53, 118, 28, 27, 84, 149, 34, 35, 29,
+ 46, 32, 30, 54, 119, 37, 36, 39, 38, 40,
+ 85, 150, 41, 42, 43, 44, 45, 55, 60, 65,
+ 70, 86, 91, 96, 101, 120, 125, 130, 135, 151,
+ 156, 161, 166, 56, 87, 121, 152, 61, 92, 126,
+ 157, 66, 97, 131, 162, 71, 102, 136, 167, 57,
+ 88, 122, 153, 62, 93, 127, 158, 67, 98, 132,
+ 163, 72, 103, 137, 168, 58, 89, 123, 154, 63,
+ 94, 128, 159, 68, 99, 133, 164, 73, 104, 138,
+ 169, 59, 90, 124, 155, 64, 95, 129, 160, 69,
+ 100, 134, 165, 74, 105, 139, 170
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_1265[] =
+{
+ 0, 4, 6, 93, 143, 196, 246, 7, 5, 3,
+ 47, 48, 49, 50, 51, 150, 151, 152, 153, 154,
+ 94, 144, 197, 247, 99, 149, 202, 252, 96, 146,
+ 199, 249, 97, 147, 200, 250, 100, 203, 98, 148,
+ 201, 251, 95, 145, 198, 248, 52, 2, 1, 101,
+ 204, 155, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 156, 31, 102, 205, 9, 33, 11, 103, 206, 54,
+ 157, 28, 27, 104, 207, 34, 35, 29, 46, 32,
+ 30, 55, 158, 37, 36, 39, 38, 40, 105, 208,
+ 41, 42, 43, 44, 45, 56, 106, 159, 209, 57,
+ 66, 75, 84, 107, 116, 125, 134, 160, 169, 178,
+ 187, 210, 219, 228, 237, 58, 108, 161, 211, 62,
+ 112, 165, 215, 67, 117, 170, 220, 71, 121, 174,
+ 224, 76, 126, 179, 229, 80, 130, 183, 233, 85,
+ 135, 188, 238, 89, 139, 192, 242, 59, 109, 162,
+ 212, 63, 113, 166, 216, 68, 118, 171, 221, 72,
+ 122, 175, 225, 77, 127, 180, 230, 81, 131, 184,
+ 234, 86, 136, 189, 239, 90, 140, 193, 243, 60,
+ 110, 163, 213, 64, 114, 167, 217, 69, 119, 172,
+ 222, 73, 123, 176, 226, 78, 128, 181, 231, 82,
+ 132, 185, 235, 87, 137, 190, 240, 91, 141, 194,
+ 244, 61, 111, 164, 214, 65, 115, 168, 218, 70,
+ 120, 173, 223, 74, 124, 177, 227, 79, 129, 182,
+ 232, 83, 133, 186, 236, 88, 138, 191, 241, 92,
+ 142, 195, 245
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_1425[] =
+{
+ 0, 4, 6, 101, 159, 220, 278, 7, 5, 3,
+ 47, 48, 49, 50, 51, 166, 167, 168, 169, 170,
+ 102, 160, 221, 279, 107, 165, 226, 284, 104, 162,
+ 223, 281, 105, 163, 224, 282, 108, 227, 106, 164,
+ 225, 283, 103, 161, 222, 280, 52, 2, 1, 109,
+ 228, 171, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 172, 31, 110, 229, 9, 33, 11, 111, 230, 54,
+ 173, 28, 27, 112, 231, 34, 35, 29, 46, 32,
+ 30, 55, 174, 37, 36, 39, 38, 40, 113, 232,
+ 41, 42, 43, 44, 45, 56, 114, 175, 233, 62,
+ 120, 181, 239, 75, 133, 194, 252, 57, 115, 176,
+ 234, 63, 121, 182, 240, 70, 128, 189, 247, 76,
+ 134, 195, 253, 83, 141, 202, 260, 92, 150, 211,
+ 269, 84, 142, 203, 261, 93, 151, 212, 270, 85,
+ 143, 204, 262, 94, 152, 213, 271, 86, 144, 205,
+ 263, 95, 153, 214, 272, 64, 122, 183, 241, 77,
+ 135, 196, 254, 65, 123, 184, 242, 78, 136, 197,
+ 255, 87, 145, 206, 264, 96, 154, 215, 273, 58,
+ 116, 177, 235, 66, 124, 185, 243, 71, 129, 190,
+ 248, 79, 137, 198, 256, 88, 146, 207, 265, 97,
+ 155, 216, 274, 59, 117, 178, 236, 67, 125, 186,
+ 244, 72, 130, 191, 249, 80, 138, 199, 257, 89,
+ 147, 208, 266, 98, 156, 217, 275, 60, 118, 179,
+ 237, 68, 126, 187, 245, 73, 131, 192, 250, 81,
+ 139, 200, 258, 90, 148, 209, 267, 99, 157, 218,
+ 276, 61, 119, 180, 238, 69, 127, 188, 246, 74,
+ 132, 193, 251, 82, 140, 201, 259, 91, 149, 210,
+ 268, 100, 158, 219, 277
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_1585[] =
+{
+ 0, 4, 6, 109, 175, 244, 310, 7, 5, 3,
+ 47, 48, 49, 50, 51, 182, 183, 184, 185, 186,
+ 110, 176, 245, 311, 115, 181, 250, 316, 112, 178,
+ 247, 313, 113, 179, 248, 314, 116, 251, 114, 180,
+ 249, 315, 111, 177, 246, 312, 52, 2, 1, 117,
+ 252, 187, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 188, 31, 118, 253, 9, 33, 11, 119, 254, 54,
+ 189, 28, 27, 120, 255, 34, 35, 29, 46, 32,
+ 30, 55, 190, 37, 36, 39, 38, 40, 121, 256,
+ 41, 42, 43, 44, 45, 56, 122, 191, 257, 63,
+ 129, 198, 264, 76, 142, 211, 277, 89, 155, 224,
+ 290, 102, 168, 237, 303, 57, 123, 192, 258, 70,
+ 136, 205, 271, 83, 149, 218, 284, 96, 162, 231,
+ 297, 62, 128, 197, 263, 75, 141, 210, 276, 88,
+ 154, 223, 289, 101, 167, 236, 302, 58, 124, 193,
+ 259, 71, 137, 206, 272, 84, 150, 219, 285, 97,
+ 163, 232, 298, 59, 125, 194, 260, 64, 130, 199,
+ 265, 67, 133, 202, 268, 72, 138, 207, 273, 77,
+ 143, 212, 278, 80, 146, 215, 281, 85, 151, 220,
+ 286, 90, 156, 225, 291, 93, 159, 228, 294, 98,
+ 164, 233, 299, 103, 169, 238, 304, 106, 172, 241,
+ 307, 60, 126, 195, 261, 65, 131, 200, 266, 68,
+ 134, 203, 269, 73, 139, 208, 274, 78, 144, 213,
+ 279, 81, 147, 216, 282, 86, 152, 221, 287, 91,
+ 157, 226, 292, 94, 160, 229, 295, 99, 165, 234,
+ 300, 104, 170, 239, 305, 107, 173, 242, 308, 61,
+ 127, 196, 262, 66, 132, 201, 267, 69, 135, 204,
+ 270, 74, 140, 209, 275, 79, 145, 214, 280, 82,
+ 148, 217, 283, 87, 153, 222, 288, 92, 158, 227,
+ 293, 95, 161, 230, 296, 100, 166, 235, 301, 105,
+ 171, 240, 306, 108, 174, 243, 309
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_1825[] =
+{
+ 0, 4, 6, 121, 199, 280, 358, 7, 5, 3,
+ 47, 48, 49, 50, 51, 206, 207, 208, 209, 210,
+ 122, 200, 281, 359, 127, 205, 286, 364, 124, 202,
+ 283, 361, 125, 203, 284, 362, 128, 287, 126, 204,
+ 285, 363, 123, 201, 282, 360, 52, 2, 1, 129,
+ 288, 211, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 212, 31, 130, 289, 9, 33, 11, 131, 290, 54,
+ 213, 28, 27, 132, 291, 34, 35, 29, 46, 32,
+ 30, 55, 214, 37, 36, 39, 38, 40, 133, 292,
+ 41, 42, 43, 44, 45, 56, 134, 215, 293, 198,
+ 299, 136, 120, 138, 60, 279, 58, 62, 357, 139,
+ 140, 295, 156, 57, 219, 297, 63, 217, 137, 170,
+ 300, 222, 64, 106, 61, 78, 294, 92, 142, 141,
+ 135, 221, 296, 301, 343, 59, 298, 184, 329, 315,
+ 220, 216, 265, 251, 218, 237, 352, 223, 157, 86,
+ 171, 87, 164, 351, 111, 302, 65, 178, 115, 323,
+ 72, 192, 101, 179, 93, 73, 193, 151, 337, 309,
+ 143, 274, 69, 324, 165, 150, 97, 338, 110, 310,
+ 330, 273, 68, 107, 175, 245, 114, 79, 113, 189,
+ 246, 259, 174, 71, 185, 96, 344, 100, 322, 83,
+ 334, 316, 333, 252, 161, 348, 147, 82, 269, 232,
+ 260, 308, 353, 347, 163, 231, 306, 320, 188, 270,
+ 146, 177, 266, 350, 256, 85, 149, 116, 191, 160,
+ 238, 258, 336, 305, 255, 88, 224, 99, 339, 230,
+ 228, 227, 272, 242, 241, 319, 233, 311, 102, 74,
+ 180, 275, 66, 194, 152, 325, 172, 247, 244, 261,
+ 117, 158, 166, 354, 75, 144, 108, 312, 94, 186,
+ 303, 80, 234, 89, 195, 112, 340, 181, 345, 317,
+ 326, 276, 239, 167, 118, 313, 70, 355, 327, 253,
+ 190, 176, 271, 104, 98, 153, 103, 90, 76, 267,
+ 277, 248, 225, 262, 182, 84, 154, 235, 335, 168,
+ 331, 196, 341, 249, 162, 307, 148, 349, 263, 321,
+ 257, 243, 229, 356, 159, 119, 67, 187, 173, 145,
+ 240, 77, 304, 332, 314, 342, 109, 254, 81, 278,
+ 105, 91, 346, 318, 183, 250, 197, 328, 95, 155,
+ 169, 268, 226, 236, 264
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_1985[] =
+{
+ 0, 4, 6, 129, 215, 304, 390, 7, 5, 3,
+ 47, 48, 49, 50, 51, 222, 223, 224, 225, 226,
+ 130, 216, 305, 391, 135, 221, 310, 396, 132, 218,
+ 307, 393, 133, 219, 308, 394, 136, 311, 134, 220,
+ 309, 395, 131, 217, 306, 392, 52, 2, 1, 137,
+ 312, 227, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 228, 31, 138, 313, 9, 33, 11, 139, 314, 54,
+ 229, 28, 27, 140, 315, 34, 35, 29, 46, 32,
+ 30, 55, 230, 37, 36, 39, 38, 40, 141, 316,
+ 41, 42, 43, 44, 45, 56, 142, 231, 317, 63,
+ 73, 92, 340, 82, 324, 149, 353, 159, 334, 165,
+ 338, 178, 163, 254, 77, 168, 257, 153, 343, 57,
+ 248, 238, 79, 252, 166, 67, 80, 201, 101, 267,
+ 143, 164, 341, 255, 339, 187, 376, 318, 78, 328,
+ 362, 115, 232, 242, 253, 290, 276, 62, 58, 158,
+ 68, 93, 179, 319, 148, 169, 154, 72, 385, 329,
+ 333, 344, 102, 83, 144, 233, 323, 124, 243, 192,
+ 354, 237, 64, 247, 202, 209, 150, 116, 335, 268,
+ 239, 299, 188, 196, 298, 94, 195, 258, 123, 363,
+ 384, 109, 325, 371, 170, 370, 84, 110, 295, 180,
+ 74, 210, 191, 106, 291, 205, 367, 381, 377, 206,
+ 355, 122, 119, 120, 383, 160, 105, 108, 277, 380,
+ 294, 284, 285, 345, 208, 269, 249, 366, 386, 300,
+ 297, 259, 125, 369, 197, 97, 194, 286, 211, 281,
+ 280, 183, 372, 87, 155, 283, 59, 348, 327, 184,
+ 76, 111, 330, 203, 349, 69, 98, 152, 145, 189,
+ 66, 320, 337, 173, 358, 251, 198, 174, 263, 262,
+ 126, 241, 193, 88, 388, 117, 95, 387, 112, 359,
+ 287, 244, 103, 272, 301, 171, 162, 234, 273, 127,
+ 373, 181, 292, 85, 378, 302, 121, 107, 364, 346,
+ 356, 212, 278, 213, 65, 382, 288, 207, 113, 175,
+ 99, 296, 374, 368, 199, 260, 185, 336, 331, 161,
+ 270, 264, 250, 240, 75, 350, 151, 60, 89, 321,
+ 156, 274, 360, 326, 70, 282, 167, 146, 352, 81,
+ 91, 389, 266, 245, 177, 235, 190, 256, 204, 342,
+ 128, 118, 303, 104, 379, 182, 114, 375, 200, 96,
+ 293, 172, 214, 365, 279, 86, 289, 351, 347, 357,
+ 261, 186, 176, 271, 90, 100, 147, 322, 275, 361,
+ 71, 332, 61, 265, 157, 246, 236
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_2305[] =
+{
+ 0, 4, 6, 145, 247, 352, 454, 7, 5, 3,
+ 47, 48, 49, 50, 51, 254, 255, 256, 257, 258,
+ 146, 248, 353, 455, 151, 253, 358, 460, 148, 250,
+ 355, 457, 149, 251, 356, 458, 152, 359, 150, 252,
+ 357, 459, 147, 249, 354, 456, 52, 2, 1, 153,
+ 360, 259, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 260, 31, 154, 361, 9, 33, 11, 155, 362, 54,
+ 261, 28, 27, 156, 363, 34, 35, 29, 46, 32,
+ 30, 55, 262, 37, 36, 39, 38, 40, 157, 364,
+ 41, 42, 43, 44, 45, 56, 158, 263, 365, 181,
+ 192, 170, 79, 57, 399, 90, 159, 297, 377, 366,
+ 275, 68, 183, 388, 286, 194, 299, 92, 70, 182,
+ 401, 172, 59, 91, 58, 400, 368, 161, 81, 160,
+ 264, 171, 80, 389, 390, 378, 379, 193, 298, 69,
+ 266, 265, 367, 277, 288, 276, 287, 184, 60, 195,
+ 82, 93, 71, 369, 402, 173, 162, 444, 300, 391,
+ 98, 76, 278, 61, 267, 374, 135, 411, 167, 102,
+ 380, 200, 87, 178, 65, 94, 204, 124, 72, 342,
+ 189, 305, 381, 396, 433, 301, 226, 407, 289, 237,
+ 113, 215, 185, 128, 309, 403, 116, 320, 196, 331,
+ 370, 422, 174, 64, 392, 83, 425, 219, 134, 188,
+ 432, 112, 427, 139, 279, 163, 436, 208, 447, 218,
+ 236, 229, 97, 294, 385, 230, 166, 268, 177, 443,
+ 225, 426, 101, 272, 138, 127, 290, 117, 347, 199,
+ 414, 95, 140, 240, 410, 395, 209, 129, 283, 346,
+ 105, 241, 437, 86, 308, 448, 203, 345, 186, 107,
+ 220, 415, 334, 319, 106, 313, 118, 123, 73, 207,
+ 421, 214, 384, 373, 438, 62, 371, 341, 75, 449,
+ 168, 323, 164, 242, 416, 324, 304, 197, 335, 404,
+ 271, 63, 191, 325, 96, 169, 231, 280, 312, 187,
+ 406, 84, 201, 100, 67, 382, 175, 336, 202, 330,
+ 269, 393, 376, 383, 293, 307, 409, 179, 285, 314,
+ 302, 372, 398, 190, 180, 89, 99, 103, 232, 78,
+ 88, 77, 136, 387, 165, 198, 394, 125, 176, 428,
+ 74, 375, 238, 227, 66, 273, 282, 141, 306, 412,
+ 114, 85, 130, 348, 119, 291, 296, 386, 233, 397,
+ 303, 405, 284, 445, 423, 221, 210, 205, 450, 108,
+ 274, 434, 216, 343, 337, 142, 243, 321, 408, 451,
+ 310, 292, 120, 109, 281, 439, 270, 429, 332, 295,
+ 418, 211, 315, 222, 326, 131, 430, 244, 327, 349,
+ 417, 316, 143, 338, 440, 234, 110, 212, 452, 245,
+ 121, 419, 350, 223, 132, 441, 328, 413, 317, 339,
+ 126, 104, 137, 446, 344, 239, 435, 115, 333, 206,
+ 322, 217, 228, 424, 453, 311, 351, 111, 442, 224,
+ 213, 122, 431, 340, 235, 246, 133, 144, 420, 329,
+ 318
+};
+
+const pj_int16_t pjmedia_codec_amrwb_ordermap_2385[] =
+{
+ 0, 4, 6, 145, 251, 360, 466, 7, 5, 3,
+ 47, 48, 49, 50, 51, 262, 263, 264, 265, 266,
+ 146, 252, 361, 467, 151, 257, 366, 472, 148, 254,
+ 363, 469, 149, 255, 364, 470, 156, 371, 150, 256,
+ 365, 471, 147, 253, 362, 468, 52, 2, 1, 157,
+ 372, 267, 19, 21, 12, 17, 18, 20, 16, 25,
+ 13, 10, 14, 24, 23, 22, 26, 8, 15, 53,
+ 268, 31, 152, 153, 154, 155, 258, 259, 260, 261,
+ 367, 368, 369, 370, 473, 474, 475, 476, 158, 373,
+ 9, 33, 11, 159, 374, 54, 269, 28, 27, 160,
+ 375, 34, 35, 29, 46, 32, 30, 55, 270, 37,
+ 36, 39, 38, 40, 161, 376, 41, 42, 43, 44,
+ 45, 56, 162, 271, 377, 185, 196, 174, 79, 57,
+ 411, 90, 163, 305, 389, 378, 283, 68, 187, 400,
+ 294, 198, 307, 92, 70, 186, 413, 176, 59, 91,
+ 58, 412, 380, 165, 81, 164, 272, 175, 80, 401,
+ 402, 390, 391, 197, 306, 69, 274, 273, 379, 285,
+ 296, 284, 295, 188, 60, 199, 82, 93, 71, 381,
+ 414, 177, 166, 456, 308, 403, 98, 76, 286, 61,
+ 275, 386, 135, 423, 171, 102, 392, 204, 87, 182,
+ 65, 94, 208, 124, 72, 350, 193, 313, 393, 408,
+ 445, 309, 230, 419, 297, 241, 113, 219, 189, 128,
+ 317, 415, 116, 328, 200, 339, 382, 434, 178, 64,
+ 404, 83, 437, 223, 134, 192, 444, 112, 439, 139,
+ 287, 167, 448, 212, 459, 222, 240, 233, 97, 302,
+ 397, 234, 170, 276, 181, 455, 229, 438, 101, 280,
+ 138, 127, 298, 117, 355, 203, 426, 95, 140, 244,
+ 422, 407, 213, 129, 291, 354, 105, 245, 449, 86,
+ 316, 460, 207, 353, 190, 107, 224, 427, 342, 327,
+ 106, 321, 118, 123, 73, 211, 433, 218, 396, 385,
+ 450, 62, 383, 349, 75, 461, 172, 331, 168, 246,
+ 428, 332, 312, 201, 343, 416, 279, 63, 195, 333,
+ 96, 173, 235, 288, 320, 191, 418, 84, 205, 100,
+ 67, 394, 179, 344, 206, 338, 277, 405, 388, 395,
+ 301, 315, 421, 183, 293, 322, 310, 384, 410, 194,
+ 184, 89, 99, 103, 236, 78, 88, 77, 136, 399,
+ 169, 202, 406, 125, 180, 440, 74, 387, 242, 231,
+ 66, 281, 290, 141, 314, 424, 114, 85, 130, 356,
+ 119, 299, 304, 398, 237, 409, 311, 417, 292, 457,
+ 435, 225, 214, 209, 462, 108, 282, 446, 220, 351,
+ 345, 142, 247, 329, 420, 463, 318, 300, 120, 109,
+ 289, 451, 278, 441, 340, 303, 430, 215, 323, 226,
+ 334, 131, 442, 248, 335, 357, 429, 324, 143, 346,
+ 452, 238, 110, 216, 464, 249, 121, 431, 358, 227,
+ 132, 453, 336, 425, 325, 347, 126, 104, 137, 458,
+ 352, 243, 447, 115, 341, 210, 330, 221, 232, 436,
+ 465, 319, 359, 111, 454, 228, 217, 122, 443, 348,
+ 239, 250, 133, 144, 432, 337, 326
+};
+
+/**
+ * AMR-NB bitstream sensitivity order maps.
+ */
+const pj_int16_t* const pjmedia_codec_amrnb_ordermaps[8] =
+{
+ pjmedia_codec_amrnb_ordermap475,
+ pjmedia_codec_amrnb_ordermap515,
+ pjmedia_codec_amrnb_ordermap59,
+ pjmedia_codec_amrnb_ordermap67,
+ pjmedia_codec_amrnb_ordermap74,
+ pjmedia_codec_amrnb_ordermap795,
+ pjmedia_codec_amrnb_ordermap102,
+ pjmedia_codec_amrnb_ordermap122
+};
+
+/**
+ * AMR-WB bitstream sensitivity order maps.
+ */
+const pj_int16_t* const pjmedia_codec_amrwb_ordermaps[9] =
+{
+ pjmedia_codec_amrwb_ordermap_660,
+ pjmedia_codec_amrwb_ordermap_885,
+ pjmedia_codec_amrwb_ordermap_1265,
+ pjmedia_codec_amrwb_ordermap_1425,
+ pjmedia_codec_amrwb_ordermap_1585,
+ pjmedia_codec_amrwb_ordermap_1825,
+ pjmedia_codec_amrwb_ordermap_1985,
+ pjmedia_codec_amrwb_ordermap_2305,
+ pjmedia_codec_amrwb_ordermap_2385
+};
+
+/**
+ * Constant of AMR-NB frame lengths in bytes.
+ */
+const pj_uint8_t pjmedia_codec_amrnb_framelen[16] =
+ {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
+/**
+ * Constant of AMR-NB frame lengths in bits.
+ */
+const pj_uint16_t pjmedia_codec_amrnb_framelenbits[9] =
+ {95, 103, 118, 134, 148, 159, 204, 244, 39};
+/**
+ * Constant of AMR-NB bitrates.
+ */
+const pj_uint16_t pjmedia_codec_amrnb_bitrates[8] =
+ {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200};
+
+/**
+ * Constant of AMR-WB frame lengths in bytes.
+ */
+const pj_uint8_t pjmedia_codec_amrwb_framelen[16] =
+ {17, 23, 32, 37, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 0, 0};
+/**
+ * Constant of AMR-WB frame lengths in bits.
+ */
+const pj_uint16_t pjmedia_codec_amrwb_framelenbits[10] =
+ {132, 177, 253, 285, 317, 365, 397, 461, 477, 40};
+/**
+ * Constant of AMR-WB bitrates.
+ */
+const pj_uint16_t pjmedia_codec_amrwb_bitrates[9] =
+ {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850};
+
+
+/**
+ * This structure describes AMR frame info, to be fitted into #pjmedia_frame
+ * bit info.
+ */
+#pragma pack(1)
+typedef struct pjmedia_codec_amr_bit_info {
+ pj_uint8_t frame_type; /**< AMR frame type. */
+ pj_int8_t mode; /**< AMR mode. */
+ pj_uint8_t start_bit; /**< Frame start bit. */
+ pj_uint8_t good_quality:1; /**< Flag if frame is good/degraded. */
+ pj_uint8_t STI:1; /**< STI mode (first/update). */
+} pjmedia_codec_amr_bit_info;
+#pragma pack()
+
+
+/**
+ * This structure describes AMR settings.
+ */
+typedef struct pjmedia_codec_amr_pack_setting {
+ pj_uint8_t amr_nb:1; /**< Set 1 for AMR-NB, 0 for AMR-WB. */
+ pj_uint8_t reorder:1; /**< Reorder bitstream into descending
+ sensitivity order or vice versa. */
+ pj_uint8_t octet_aligned:1; /**< TRUE if payload is in octet-aligned mode,
+ FALSE if payload is in bandwidth
+ efficient mode. */
+ pj_uint8_t cmr:4; /**< Change Mode Request for remote
+ encoder. */
+} pjmedia_codec_amr_pack_setting;
+
+
+/**
+ * Get AMR mode based on bitrate.
+ *
+ * @param bitrate AMR bitrate.
+ *
+ * @return AMR mode.
+ */
+PJ_INLINE(pj_int8_t) pjmedia_codec_amr_get_mode(unsigned bitrate)
+{
+ pj_int8_t mode = -1;
+
+ if(bitrate==4750){
+ mode = 0;
+ } else if(bitrate==5150){
+ mode = 1;
+ } else if(bitrate==5900){
+ mode = 2;
+ } else if(bitrate==6700){
+ mode = 3;
+ } else if(bitrate==7400){
+ mode = 4;
+ } else if(bitrate==7950){
+ mode = 5;
+ } else if(bitrate==10200){
+ mode = 6;
+ } else if(bitrate==12200){
+ mode = 7;
+
+ /* AMRWB */
+ } else if(bitrate==6600){
+ mode = 0;
+ } else if(bitrate==8850){
+ mode = 1;
+ } else if(bitrate==12650){
+ mode = 2;
+ } else if(bitrate==14250){
+ mode = 3;
+ } else if(bitrate==15850){
+ mode = 4;
+ } else if(bitrate==18250){
+ mode = 5;
+ } else if(bitrate==19850){
+ mode = 6;
+ } else if(bitrate==23050){
+ mode = 7;
+ } else if(bitrate==23850){
+ mode = 8;
+ }
+ return mode;
+}
+
+/**
+ * Get AMR mode based on frame length.
+ *
+ * @param amrnb Set to PJ_TRUE for AMR-NB domain or PJ_FALSE for AMR-WB.
+ * @param frame_len The frame length.
+ *
+ * @return AMR mode.
+ */
+
+PJ_INLINE(pj_int8_t) pjmedia_codec_amr_get_mode2(pj_bool_t amrnb,
+ unsigned frame_len)
+{
+ int i;
+
+ if (amrnb) {
+ for (i = 0; i < 9; ++i)
+ if (frame_len == pjmedia_codec_amrnb_framelen[i])
+ return (pj_int8_t)i;
+ } else {
+ for (i = 0; i < 10; ++i) {
+ if (frame_len == pjmedia_codec_amrwb_framelen[i])
+ return (pj_int8_t)i;
+ }
+ }
+
+ pj_assert(!"Invalid AMR frame length");
+ return -1;
+}
+
+/**
+ * Prepare a frame before pass it to decoder. This function will do:
+ * - reorder AMR bitstream from descending sensitivity order into
+ * encoder bits order. This can be enabled/disabled via param
+ * 'setting' by setting/resetting field 'reorder'.
+ * - align left the start bit (make the start_bit to be 0).
+ *
+ * @param in Input frame.
+ * @param setting Settings, see #pjmedia_codec_amr_pack_setting.
+ * @param out Output frame.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_INLINE(pj_status_t) pjmedia_codec_amr_predecode(
+ const pjmedia_frame *in,
+ const pjmedia_codec_amr_pack_setting *setting,
+ pjmedia_frame *out)
+{
+ pj_int8_t amr_bits[477 + 7] = {0};
+ pj_int8_t *p_amr_bits = &amr_bits[0];
+
+ pj_uint8_t *r = (pj_uint8_t*) in->buf; /* read cursor */
+ pj_uint8_t *w = (pj_uint8_t*) out->buf; /* write cursor */
+
+ /* env vars for AMR or AMRWB */
+ pj_uint8_t SID_FT;
+ const pj_uint8_t *framelen_tbl;
+ const pj_uint16_t *framelenbit_tbl;
+ const pj_uint16_t *bitrate_tbl;
+ const pj_int16_t* const *order_maps;
+
+ pjmedia_codec_amr_bit_info *in_info =
+ (pjmedia_codec_amr_bit_info*) &in->bit_info;
+ pjmedia_codec_amr_bit_info *out_info =
+ (pjmedia_codec_amr_bit_info*) &out->bit_info;
+
+ unsigned i;
+
+ *out_info = *in_info;
+
+ if (setting->amr_nb) {
+ SID_FT = 8;
+ framelen_tbl = pjmedia_codec_amrnb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrnb_framelenbits;
+ bitrate_tbl = pjmedia_codec_amrnb_bitrates;
+ order_maps = pjmedia_codec_amrnb_ordermaps;
+ } else {
+ SID_FT = 9;
+ framelen_tbl = pjmedia_codec_amrwb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrwb_framelenbits;
+ bitrate_tbl = pjmedia_codec_amrwb_bitrates;
+ order_maps = pjmedia_codec_amrwb_ordermaps;
+ }
+
+ /* unpack AMR bitstream if there is any data */
+ if (in_info->frame_type <= SID_FT) {
+ i = 0;
+ if (in_info->start_bit) {
+ for (; i < (unsigned)(8-in_info->start_bit); ++i)
+ *p_amr_bits++ = (pj_uint8_t)
+ ((*r >> (7-in_info->start_bit-i)) & 1);
+ ++r;
+ }
+ for(; i < framelenbit_tbl[in_info->frame_type]; i += 8, ++r) {
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 7) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 6) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 5) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 4) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 3) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 2) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 1) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r ) & 1);
+ }
+ }
+
+ if (in_info->frame_type < SID_FT) {
+
+ /* Speech */
+ out_info->mode = in_info->frame_type;
+ out->size = framelen_tbl[out_info->mode];
+
+ pj_bzero(out->buf, out->size);
+
+ if (setting->reorder) {
+ const pj_int16_t *order_map;
+
+ order_map = order_maps[out_info->mode];
+ for(i = 0; i < framelenbit_tbl[out_info->mode]; ++i) {
+ if (amr_bits[i]) {
+ pj_uint16_t bitpos;
+ bitpos = order_map[i];
+ w[bitpos>>3] |= 1 << (7 - (bitpos % 8));
+ }
+ }
+ } else {
+ for(i = 0; i < framelenbit_tbl[out_info->mode]; ++i) {
+ if (amr_bits[i])
+ w[i >> 3] |= 1 << (7 - (i % 8));
+ }
+ }
+
+ } else if (in_info->frame_type == SID_FT) {
+
+ /* SID */
+ pj_uint8_t w_bitptr = 0;
+ pj_uint8_t FT_;
+
+ if (setting->amr_nb)
+ FT_ = (pj_uint8_t)((amr_bits[36] << 2) | (amr_bits[37] << 1) |
+ amr_bits[38]);
+ else
+ FT_ = (pj_uint8_t)((amr_bits[36] << 3) | (amr_bits[37] << 2) |
+ (amr_bits[38] << 1) | amr_bits[39]);
+
+ out_info->mode = FT_;
+ out->size = 5;
+
+ pj_bzero(out->buf, out->size);
+ for(i = 0; i < framelenbit_tbl[SID_FT]; ++i) {
+ if (amr_bits[i])
+ *w |= (1 << (7-w_bitptr));
+
+ if (++w_bitptr == 8) {
+ ++w;
+ w_bitptr = 0;
+ }
+ }
+
+ } else {
+
+ /* NO DATA */
+ out->size = 0;
+ out_info->mode = -1;
+ }
+
+ out_info->start_bit = 0;
+
+ return PJ_SUCCESS;
+}
+
+
+/**
+ * Pack encoded AMR frame(s) into an RTP payload.
+ *
+ * @param frames AMR frames to be packed.
+ * @param nframes Number of frames to be packed.
+ * @param setting Settings, see #pjmedia_codec_amr_pack_setting.
+ * @param pkt Payload.
+ * @param pkt_size Payload size, as input this specifies payload maximum size,
+ * as output this specifies payload packed size.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_INLINE (pj_status_t) pjmedia_codec_amr_pack(
+ const pjmedia_frame frames[],
+ unsigned nframes,
+ const pjmedia_codec_amr_pack_setting *setting,
+ void *pkt,
+ pj_size_t *pkt_size)
+{
+ /* Write cursor */
+ pj_uint8_t *w = (pj_uint8_t*)pkt;
+ pj_uint8_t w_bitptr = 0;
+
+ /* Read cursor */
+ pj_uint8_t *r;
+
+ /* env vars for AMR or AMRWB */
+ pj_uint8_t SID_FT;
+ const pj_uint8_t *framelen_tbl;
+ const pj_uint16_t *framelenbit_tbl;
+ const pj_uint16_t *bitrate_tbl;
+ const pj_int16_t* const *order_maps;
+
+ /* frame info */
+ pjmedia_codec_amr_bit_info *info;
+
+ unsigned i, max_pkt_size;
+
+ max_pkt_size = *pkt_size;
+
+ if (setting->amr_nb) {
+ SID_FT = 8;
+ framelen_tbl = pjmedia_codec_amrnb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrnb_framelenbits;
+ bitrate_tbl = pjmedia_codec_amrnb_bitrates;
+ order_maps = pjmedia_codec_amrnb_ordermaps;
+ } else {
+ SID_FT = 9;
+ framelen_tbl = pjmedia_codec_amrwb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrwb_framelenbits;
+ bitrate_tbl = pjmedia_codec_amrwb_bitrates;
+ order_maps = pjmedia_codec_amrwb_ordermaps;
+ }
+
+ /* Code Mode Request, 4 bits */
+ *w = (pj_uint8_t)(setting->cmr << 4);
+ w_bitptr = 4;
+ if (setting->octet_aligned) {
+ ++w;
+ w_bitptr = 0;
+ }
+
+ /* Table Of Contents, 6 bits each */
+ for (i = 0; i < nframes; ++i) {
+ pj_uint8_t TOC, FT, Q;
+ pj_bool_t F;
+
+ info = (pjmedia_codec_amr_bit_info*)&frames[i].bit_info;
+
+ F = (i != nframes-1);
+ FT = info->frame_type;
+ Q = (pj_uint8_t)(info->good_quality == 1);
+ pj_assert(FT <= SID_FT || FT == 14 || FT == 15);
+
+ /* Check buffer availability */
+ *pkt_size = w - (pj_uint8_t*)pkt + 1;
+ PJ_ASSERT_RETURN(*pkt_size <= max_pkt_size, PJ_ETOOSMALL);
+
+ TOC = (pj_uint8_t)((F<<5) | (FT<<1) | Q);
+ if (w_bitptr == 0) {
+ *w = (pj_uint8_t)(TOC<<2);
+ w_bitptr = 6;
+ } else if (w_bitptr == 2) {
+ *w++ |= TOC;
+ w_bitptr = 0;
+ } else if (w_bitptr == 4) {
+ *w++ |= TOC>>2;
+ *w = (pj_uint8_t)(TOC<<6);
+ w_bitptr = 2;
+ } else if (w_bitptr == 6) {
+ *w++ |= TOC>>4;
+ *w = (pj_uint8_t)(TOC<<4);
+ w_bitptr = 4;
+ }
+ if (setting->octet_aligned) {
+ ++w;
+ w_bitptr = 0;
+ }
+ }
+
+ /* Encoded data */
+ for (i = 0; i < nframes; ++i) {
+ pj_int8_t amr_bits[477 + 7] = {0};
+ pj_int8_t *p_amr_bits = &amr_bits[0];
+ unsigned j;
+
+ info = (pjmedia_codec_amr_bit_info*)&frames[i].bit_info;
+
+ /* Check buffer availability */
+ *pkt_size = w - (pj_uint8_t*)pkt;
+ if (info->frame_type <= SID_FT)
+ *pkt_size += framelen_tbl[info->frame_type] + 1;
+ PJ_ASSERT_RETURN(*pkt_size <= max_pkt_size, PJ_ETOOSMALL);
+
+ /* Skip if there is no data */
+ if (info->frame_type > SID_FT)
+ continue;
+
+ /* Unpack bits */
+ r = (pj_uint8_t*) frames[i].buf;
+ j = 0;
+ if (info->start_bit) {
+ for (; j < (unsigned)(8-info->start_bit); ++j)
+ *p_amr_bits++ = (pj_uint8_t)
+ ((*r >> (7-info->start_bit-j)) & 1);
+ ++r;
+ }
+ for(; j < framelenbit_tbl[info->frame_type]; j+=8, ++r) {
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 7) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 6) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 5) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 4) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 3) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 2) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r >> 1) & 1);
+ *p_amr_bits++ = (pj_uint8_t)((*r ) & 1);
+ }
+
+ if (info->frame_type < SID_FT) {
+
+ /* Speech */
+ if (w_bitptr == 0) *w = 0;
+
+ if (setting->reorder) {
+ const pj_int16_t *order_map;
+
+ /* Put bits in the packet, sensitivity descending ordered */
+ order_map = order_maps[info->frame_type];
+ for(j = 0; j < framelenbit_tbl[info->frame_type]; ++j) {
+ if (amr_bits[order_map[j]])
+ *w |= (1 << (7-w_bitptr));
+
+ if (++w_bitptr == 8) {
+ w_bitptr = 0;
+ ++w;
+ *w = 0;
+ }
+ }
+ } else {
+ for(j = 0; j < framelenbit_tbl[info->frame_type]; ++j) {
+ if (amr_bits[j])
+ *w |= (1 << (7-w_bitptr));
+
+ if (++w_bitptr == 8) {
+ w_bitptr = 0;
+ ++w;
+ *w = 0;
+ }
+ }
+ }
+
+ } else if (info->frame_type == SID_FT) {
+
+ /* SID */
+ amr_bits[35] |= info->STI;
+
+ if (setting->amr_nb) {
+ amr_bits[36] = (pj_uint8_t)((info->mode >> 2) & 1);
+ amr_bits[37] = (pj_uint8_t)((info->mode >> 1) & 1);
+ amr_bits[38] = (pj_uint8_t)((info->mode) & 1);
+ } else {
+ amr_bits[36] = (pj_uint8_t)((info->mode >> 3) & 1);
+ amr_bits[37] = (pj_uint8_t)((info->mode >> 2) & 1);
+ amr_bits[38] = (pj_uint8_t)((info->mode >> 1) & 1);
+ amr_bits[39] = (pj_uint8_t)((info->mode) & 1);
+ }
+
+ if (w_bitptr == 0) *w = 0;
+ for(j = 0; j < framelenbit_tbl[info->frame_type]; ++j) {
+ if (amr_bits[j])
+ *w |= (1 << (7-w_bitptr));
+
+ if (++w_bitptr == 8) {
+ w_bitptr = 0;
+ ++w;
+ *w = 0;
+ }
+ }
+ }
+
+ if (setting->octet_aligned) {
+ ++w;
+ w_bitptr = 0;
+ }
+ }
+
+ *pkt_size = w - (pj_uint8_t*)pkt;
+ if (w_bitptr)
+ *pkt_size += 1;
+
+ return PJ_SUCCESS;
+}
+
+
+/**
+ * Parse AMR payload into frames.
+ *
+ * @param pkt Payload.
+ * @param pkt_size Payload size.
+ * @param ts Base timestamp.
+ * @param setting Settings, see #pjmedia_codec_amr_pack_setting.
+ * @param frames Frames parsed.
+ * @param nframes Number of frames parsed.
+ * @param cmr Change Mode Request message for local encoder.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_INLINE(pj_status_t) pjmedia_codec_amr_parse(
+ void *pkt,
+ pj_size_t pkt_size,
+ const pj_timestamp *ts,
+ const pjmedia_codec_amr_pack_setting* setting,
+ pjmedia_frame frames[],
+ unsigned *nframes,
+ pj_uint8_t *cmr)
+{
+ unsigned cnt = 0;
+ pj_timestamp ts_ = *ts;
+
+ /* Read cursor */
+ pj_uint8_t r_bitptr = 0;
+ pj_uint8_t *r = (pj_uint8_t*)pkt;
+
+ /* env vars for AMR or AMRWB */
+ pj_uint8_t SID_FT;
+ const pj_uint8_t *framelen_tbl;
+ const pj_uint16_t *framelenbit_tbl;
+ const pj_int16_t* const *order_maps;
+
+ /* frame info */
+ pjmedia_codec_amr_bit_info *info;
+
+ if (setting->amr_nb) {
+ SID_FT = 8;
+ framelen_tbl = pjmedia_codec_amrnb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrnb_framelenbits;
+ order_maps = pjmedia_codec_amrnb_ordermaps;
+ } else {
+ SID_FT = 9;
+ framelen_tbl = pjmedia_codec_amrwb_framelen;
+ framelenbit_tbl = pjmedia_codec_amrwb_framelenbits;
+ order_maps = pjmedia_codec_amrwb_ordermaps;
+ }
+
+ PJ_UNUSED_ARG(pkt_size);
+
+ /* Code Mode Request, 4 bits */
+ *cmr = (pj_uint8_t)((*r >> 4) & 0x0F);
+ r_bitptr = 4;
+ if (setting->octet_aligned) {
+ ++r;
+ r_bitptr = 0;
+ }
+
+ /* Table Of Contents, 6 bits each */
+ for (;;) {
+ pj_uint8_t TOC = 0;
+ pj_uint8_t F, FT, Q;
+
+ if (r_bitptr == 0) {
+ TOC = (pj_uint8_t)(*r >> 2);
+ r_bitptr = 6;
+ } else if (r_bitptr == 2) {
+ TOC = (pj_uint8_t)(*r++ & 0x3F);
+ r_bitptr = 0;
+ } else if (r_bitptr == 4) {
+ TOC = (pj_uint8_t)((*r++ & 0x0f) << 2);
+ TOC |= *r >> 6;
+ r_bitptr = 2;
+ } else if (r_bitptr == 6) {
+ TOC = (pj_uint8_t)((*r++ & 0x03) << 4);
+ TOC |= *r >> 4;
+ r_bitptr = 4;
+ }
+
+ F = (pj_uint8_t)(TOC >> 5);
+ FT = (pj_uint8_t)((TOC >> 1) & 0x0F);
+ Q = (pj_uint8_t)(TOC & 1);
+
+ if (FT > SID_FT && FT < 14) {
+ pj_assert(!"Invalid AMR frametype, stream may be corrupted!");
+ break;
+ }
+
+ if (setting->octet_aligned) {
+ ++r;
+ r_bitptr = 0;
+ }
+
+ /* Set frame attributes */
+ info = (pjmedia_codec_amr_bit_info*) &frames[cnt].bit_info;
+ info->frame_type = FT;
+ info->mode = (pj_int8_t)((FT < SID_FT)? FT : -1);
+ info->good_quality = (pj_uint8_t)(Q == 1);
+ info->start_bit = 0;
+ info->STI = 0;
+ frames[cnt].timestamp = ts_;
+ frames[cnt].type = PJMEDIA_FRAME_TYPE_AUDIO;
+
+ /* AMR frame length is 20ms */
+ ts_.u64 += setting->amr_nb? 160 : 320;
+
+ if (++cnt == *nframes || !F)
+ break;
+ }
+ *nframes = cnt;
+
+ cnt = 0;
+
+ /* Speech frames */
+ while (cnt < *nframes) {
+ pj_uint8_t FT;
+
+ info = (pjmedia_codec_amr_bit_info*) &frames[cnt].bit_info;
+ FT = info->frame_type;
+
+ frames[cnt].buf = r;
+ info->start_bit = r_bitptr;
+
+ if (FT == SID_FT) {
+ unsigned sti_bitptr;
+ sti_bitptr = r_bitptr + 35;
+ info->STI = (pj_uint8_t)
+ (r[sti_bitptr >> 3] >> (7 - (sti_bitptr % 8))) & 1;
+ }
+
+ if (setting->octet_aligned) {
+ r += framelen_tbl[FT];
+ frames[cnt].size = framelen_tbl[FT];
+ } else {
+ if (FT == 14 || FT == 15) {
+ /* NO DATA */
+ frames[cnt].size = 0;
+ } else {
+ unsigned adv_bit;
+
+ adv_bit = framelenbit_tbl[FT] + r_bitptr;
+ r += adv_bit >> 3;
+ r_bitptr = (pj_uint8_t)(adv_bit % 8);
+
+ frames[cnt].size = adv_bit >> 3;
+ if (r_bitptr)
+ ++frames[cnt].size;
+ }
+ }
+ ++cnt;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+#endif /* __PJMEDIA_CODECS_AMR_HELPER_H__ */