* #39226: Switch back to pjsip rev 4710

Rev 4716 introduces errors when building for android (miltiple definitions)
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f0e39048149dcf76eb52da453ed4714d40f9c22.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f0e39048149dcf76eb52da453ed4714d40f9c22.svn-base
new file mode 100644
index 0000000..0870186
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f0e39048149dcf76eb52da453ed4714d40f9c22.svn-base
@@ -0,0 +1,732 @@
+/* $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_uri.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/print_util.h>
+#include <pjsip/sip_errno.h>
+#include <pjlib-util/string.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/assert.h>
+
+/*
+ * Generic parameter manipulation.
+ */
+PJ_DEF(pjsip_param*) pjsip_param_find(  const pjsip_param *param_list,
+					const pj_str_t *name )
+{
+    pjsip_param *p = (pjsip_param*)param_list->next;
+    while (p != param_list) {
+	if (pj_stricmp(&p->name, name)==0)
+	    return p;
+	p = p->next;
+    }
+    return NULL;
+}
+
+PJ_DEF(int) pjsip_param_cmp( const pjsip_param *param_list1,
+			     const pjsip_param *param_list2,
+			     pj_bool_t ig_nf)
+{
+    const pjsip_param *p1;
+
+    if ((ig_nf & 1)==0 && pj_list_size(param_list1)!=pj_list_size(param_list2))
+	return 1;
+
+    p1 = param_list1->next;
+    while (p1 != param_list1) {
+	const pjsip_param *p2;
+	p2 = pjsip_param_find(param_list2, &p1->name);
+	if (p2 ) {
+	    int rc = pj_stricmp(&p1->value, &p2->value);
+	    if (rc != 0)
+		return rc;
+	} else if ((ig_nf & 1)==0)
+	    return 1;
+
+	p1 = p1->next;
+    }
+
+    return 0;
+}
+
+PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list,
+				const pjsip_param *src_list)
+{
+    const pjsip_param *p = src_list->next;
+
+    pj_list_init(dst_list);
+    while (p && p != src_list) {
+	pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
+	pj_strdup(pool, &new_param->name, &p->name);
+	pj_strdup(pool, &new_param->value, &p->value);
+	pj_list_insert_before(dst_list, new_param);
+	p = p->next;
+    }
+}
+
+
+PJ_DEF(void) pjsip_param_shallow_clone( pj_pool_t *pool, 
+					pjsip_param *dst_list,
+					const pjsip_param *src_list)
+{
+    const pjsip_param *p = src_list->next;
+
+    pj_list_init(dst_list);
+    while (p != src_list) {
+	pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
+	new_param->name = p->name;
+	new_param->value = p->value;
+	pj_list_insert_before(dst_list, new_param);
+	p = p->next;
+    }
+}
+
+PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
+					 char *buf, pj_size_t size,
+					 const pj_cis_t *pname_spec,
+					 const pj_cis_t *pvalue_spec,
+					 int sep)
+{
+    const pjsip_param *p;
+    char *startbuf;
+    char *endbuf;
+    int printed;
+
+    p = param_list->next;
+    if (p == NULL || p == param_list)
+	return 0;
+
+    startbuf = buf;
+    endbuf = buf + size;
+
+    PJ_UNUSED_ARG(pname_spec);
+
+    do {
+	*buf++ = (char)sep;
+	copy_advance_escape(buf, p->name, (*pname_spec));
+	if (p->value.slen) {
+	    *buf++ = '=';
+	    if (*p->value.ptr == '"')
+		copy_advance(buf, p->value);
+	    else
+		copy_advance_escape(buf, p->value, (*pvalue_spec));
+	}
+	p = p->next;
+	if (sep == '?') sep = '&';
+    } while (p != param_list);
+
+    return buf-startbuf;
+}
+
+
+/*
+ * URI stuffs
+ */
+#define IS_SIPS(url)	((url)->vptr==&sips_url_vptr)
+
+static const pj_str_t *pjsip_url_get_scheme( const pjsip_sip_uri* );
+static const pj_str_t *pjsips_url_get_scheme( const pjsip_sip_uri* );
+static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
+static void *pjsip_get_uri( pjsip_uri *uri );
+static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
+
+static pj_str_t sip_str = { "sip", 3 };
+static pj_str_t sips_str = { "sips", 4 };
+
+static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 
+					       const pjsip_name_addr *rhs);
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+					const pjsip_name_addr *name, 
+					char *buf, pj_size_t size);
+static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
+				     const pjsip_name_addr *naddr1,
+				     const pjsip_name_addr *naddr2);
+static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
+				    const pjsip_sip_uri *url, 
+				    char *buf, pj_size_t size);
+static int pjsip_url_compare( pjsip_uri_context_e context,
+			      const pjsip_sip_uri *url1, 
+			      const pjsip_sip_uri *url2);
+static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, 
+				      const pjsip_sip_uri *rhs);
+
+typedef const pj_str_t* (*P_GET_SCHEME)(const void*);
+typedef void* 		(*P_GET_URI)(void*);
+typedef pj_ssize_t 	(*P_PRINT_URI)(pjsip_uri_context_e,const void *,
+				       char*,pj_size_t);
+typedef int 		(*P_CMP_URI)(pjsip_uri_context_e, const void*, 
+				     const void*);
+typedef void* 		(*P_CLONE)(pj_pool_t*, const void*);
+
+
+static pjsip_uri_vptr sip_url_vptr = 
+{
+    (P_GET_SCHEME)	&pjsip_url_get_scheme,
+    (P_GET_URI)		&pjsip_get_uri,
+    (P_PRINT_URI) 	&pjsip_url_print,
+    (P_CMP_URI) 	&pjsip_url_compare,
+    (P_CLONE) 		&pjsip_url_clone
+};
+
+static pjsip_uri_vptr sips_url_vptr = 
+{
+    (P_GET_SCHEME)	&pjsips_url_get_scheme,
+    (P_GET_URI)		&pjsip_get_uri,
+    (P_PRINT_URI) 	&pjsip_url_print,
+    (P_CMP_URI) 	&pjsip_url_compare,
+    (P_CLONE) 		&pjsip_url_clone
+};
+
+static pjsip_uri_vptr name_addr_vptr = 
+{
+    (P_GET_SCHEME)	&pjsip_name_addr_get_scheme,
+    (P_GET_URI)		&pjsip_name_addr_get_uri,
+    (P_PRINT_URI) 	&pjsip_name_addr_print,
+    (P_CMP_URI) 	&pjsip_name_addr_compare,
+    (P_CLONE) 		&pjsip_name_addr_clone
+};
+
+static const pj_str_t *pjsip_url_get_scheme(const pjsip_sip_uri *url)
+{
+    PJ_UNUSED_ARG(url);
+    return &sip_str;
+}
+
+static const pj_str_t *pjsips_url_get_scheme(const pjsip_sip_uri *url)
+{
+    PJ_UNUSED_ARG(url);
+    return &sips_str;
+}
+
+static void *pjsip_get_uri( pjsip_uri *uri )
+{
+    return uri;
+}
+
+static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
+{
+    return pjsip_uri_get_uri(name->uri);
+}
+
+PJ_DEF(void) pjsip_sip_uri_set_secure( pjsip_sip_uri *url, 
+				       pj_bool_t secure )
+{
+    url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
+}
+
+PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, pj_bool_t secure)
+{
+    pj_bzero(url, sizeof(*url));
+    url->ttl_param = -1;
+    pjsip_sip_uri_set_secure(url, secure);
+    pj_list_init(&url->other_param);
+    pj_list_init(&url->header_param);
+}
+
+PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, 
+					     pj_bool_t secure )
+{
+    pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
+    pjsip_sip_uri_init(url, secure);
+    return url;
+}
+
+static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
+				    const pjsip_sip_uri *url, 
+				    char *buf, pj_size_t size)
+{
+    int printed;
+    char *startbuf = buf;
+    char *endbuf = buf+size;
+    const pj_str_t *scheme;
+    const pjsip_parser_const_t *pc = pjsip_parser_const();
+
+    *buf = '\0';
+
+    /* Print scheme ("sip:" or "sips:") */
+    scheme = pjsip_uri_get_scheme(url);
+    copy_advance_check(buf, *scheme);
+    *buf++ = ':';
+
+    /* Print "user:password@", if any. */
+    if (url->user.slen) {
+	const pj_cis_t *spec = pjsip_cfg()->endpt.allow_tx_hash_in_uri ?
+				&pc->pjsip_USER_SPEC_LENIENT :
+				&pc->pjsip_USER_SPEC;
+	copy_advance_escape(buf, url->user, *spec);
+	if (url->passwd.slen) {
+	    *buf++ = ':';
+	    copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
+	}
+
+	*buf++ = '@';
+    }
+
+    /* Print host. */
+    pj_assert(url->host.slen != 0);
+    /* Detect IPv6 IP address */
+    if (pj_memchr(url->host.ptr, ':', url->host.slen)) {
+	copy_advance_pair_quote_cond(buf, "", 0, url->host, '[', ']');
+    } else {
+	copy_advance_check(buf, url->host);
+    }
+
+    /* Only print port if it is explicitly specified. 
+     * Port is not allowed in To and From header, see Table 1 in
+     * RFC 3261 Section 19.1.1
+     */
+    /* Note: ticket #1141 adds run-time setting to allow port number to
+     * appear in From/To header. Default is still false.
+     */
+    if (url->port &&
+	(context != PJSIP_URI_IN_FROMTO_HDR ||
+	 pjsip_cfg()->endpt.allow_port_in_fromto_hdr))
+    {
+	if (endbuf - buf < 10)
+	    return -1;
+
+	*buf++ = ':';
+	printed = pj_utoa(url->port, buf);
+	buf += printed;
+    }
+
+    /* User param is allowed in all contexes */
+    copy_advance_pair_check(buf, ";user=", 6, url->user_param);
+
+    /* Method param is only allowed in external/other context. */
+    if (context == PJSIP_URI_IN_OTHER) {
+	copy_advance_pair_escape(buf, ";method=", 8, url->method_param, 
+				 pc->pjsip_PARAM_CHAR_SPEC);
+    }
+
+    /* Transport is not allowed in From/To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
+				 pc->pjsip_PARAM_CHAR_SPEC);
+    }
+
+    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
+    if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
+	context != PJSIP_URI_IN_ROUTING_HDR) 
+    {
+	if (endbuf - buf < 15)
+	    return -1;
+	pj_memcpy(buf, ";ttl=", 5);
+	printed = pj_utoa(url->ttl_param, buf+5);
+	buf += printed + 5;
+    }
+
+    /* maddr param is not allowed in From and To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR && url->maddr_param.slen) {
+	/* Detect IPv6 IP address */
+	if (pj_memchr(url->maddr_param.ptr, ':', url->maddr_param.slen)) {
+	    copy_advance_pair_quote_cond(buf, ";maddr=", 7, url->maddr_param,
+				         '[', ']');
+	} else {
+	    copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
+				     pc->pjsip_PARAM_CHAR_SPEC);
+	}
+    }
+
+    /* lr param is not allowed in From, To, and Contact header. */
+    if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
+	context != PJSIP_URI_IN_CONTACT_HDR) 
+    {
+	pj_str_t lr = { ";lr", 3 };
+	if (endbuf - buf < 3)
+	    return -1;
+	copy_advance_check(buf, lr);
+    }
+
+    /* Other param. */
+    printed = (int)pjsip_param_print_on(&url->other_param, buf, endbuf-buf, 
+					&pc->pjsip_PARAM_CHAR_SPEC, 
+					&pc->pjsip_PARAM_CHAR_SPEC, ';');
+    if (printed < 0)
+	return -1;
+    buf += printed;
+
+    /* Header param. 
+     * Header param is only allowed in these contexts:
+     *	- PJSIP_URI_IN_CONTACT_HDR
+     *	- PJSIP_URI_IN_OTHER
+     */
+    if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
+	printed = (int)pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
+					    &pc->pjsip_HDR_CHAR_SPEC, 
+					    &pc->pjsip_HDR_CHAR_SPEC, '?');
+	if (printed < 0)
+	    return -1;
+	buf += printed;
+    }
+
+    *buf = '\0';
+    return buf-startbuf;
+}
+
+static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
+				      const pjsip_sip_uri *url1, 
+				      const pjsip_sip_uri *url2)
+{
+    const pjsip_param *p1;
+
+    /*
+     * Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
+     */
+
+    /* SIP and SIPS URI are never equivalent. 
+     * Note: just compare the vptr to avoid string comparison. 
+     *       Pretty neat huh!!
+     */
+    if (url1->vptr != url2->vptr)
+	return PJSIP_ECMPSCHEME;
+
+    /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. 
+     * This includes userinfo containing passwords or formatted as 
+     * telephone-subscribers.
+     */
+    if (pj_strcmp(&url1->user, &url2->user) != 0)
+	return PJSIP_ECMPUSER;
+    if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
+	return PJSIP_ECMPPASSWD;
+    
+    /* Comparison of all other components of the URI is
+     * case-insensitive unless explicitly defined otherwise.
+     */
+
+    /* The ordering of parameters and header fields is not significant 
+     * in comparing SIP and SIPS URIs.
+     */
+
+    /* Characters other than those in the reserved set (see RFC 2396 [5])
+     * are equivalent to their encoding.
+     */
+
+    /* An IP address that is the result of a DNS lookup of a host name 
+     * does not match that host name.
+     */
+    if (pj_stricmp(&url1->host, &url2->host) != 0)
+	return PJSIP_ECMPHOST;
+
+    /* A URI omitting any component with a default value will not match a URI
+     * explicitly containing that component with its default value. 
+     * For instance, a URI omitting the optional port component will not match
+     * a URI explicitly declaring port 5060. 
+     * The same is true for the transport-parameter, ttl-parameter, 
+     * user-parameter, and method components.
+     */
+
+    /* Port is not allowed in To and From header.
+     */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (url1->port != url2->port)
+	    return PJSIP_ECMPPORT;
+    }
+    /* Transport is not allowed in From/To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0)
+	    return PJSIP_ECMPTRANSPORTPRM;
+    }
+    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR &&
+	context != PJSIP_URI_IN_ROUTING_HDR)
+    {
+	if (url1->ttl_param != url2->ttl_param)
+	    return PJSIP_ECMPTTLPARAM;
+    }
+    /* User param is allowed in all contexes */
+    if (pj_stricmp(&url1->user_param, &url2->user_param) != 0)
+	return PJSIP_ECMPUSERPARAM;
+    /* Method param is only allowed in external/other context. */
+    if (context == PJSIP_URI_IN_OTHER) {
+	if (pj_stricmp(&url1->method_param, &url2->method_param) != 0)
+	    return PJSIP_ECMPMETHODPARAM;
+    }
+    /* maddr param is not allowed in From and To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0)
+	    return PJSIP_ECMPMADDRPARAM;
+    }
+
+    /* lr parameter is ignored (?) */
+    /* lr param is not allowed in From, To, and Contact header. */
+
+
+    /* All other uri-parameters appearing in only one URI are ignored when 
+     * comparing the URIs.
+     */
+    if (pjsip_param_cmp(&url1->other_param, &url2->other_param, 1)!=0)
+	return PJSIP_ECMPOTHERPARAM;
+
+    /* URI header components are never ignored. Any present header component
+     * MUST be present in both URIs and match for the URIs to match. 
+     * The matching rules are defined for each header field in Section 20.
+     */
+    p1 = url1->header_param.next;
+    while (p1 != &url1->header_param) {
+	const pjsip_param *p2;
+	p2 = pjsip_param_find(&url2->header_param, &p1->name);
+	if (p2) {
+	    /* It seems too much to compare two header params according to
+	     * the rule of each header. We'll just compare them string to
+	     * string..
+	     */
+	    if (pj_stricmp(&p1->value, &p2->value) != 0)
+		return PJSIP_ECMPHEADERPARAM;
+	} else {
+	    return PJSIP_ECMPHEADERPARAM;
+	}
+	p1 = p1->next;
+    }
+
+    /* Equal!! Pheuww.. */
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url, 
+				  const pjsip_sip_uri *rhs)
+{
+    pj_strdup( pool, &url->user, &rhs->user);
+    pj_strdup( pool, &url->passwd, &rhs->passwd);
+    pj_strdup( pool, &url->host, &rhs->host);
+    url->port = rhs->port;
+    pj_strdup( pool, &url->user_param, &rhs->user_param);
+    pj_strdup( pool, &url->method_param, &rhs->method_param);
+    pj_strdup( pool, &url->transport_param, &rhs->transport_param);
+    url->ttl_param = rhs->ttl_param;
+    pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
+    pjsip_param_clone(pool, &url->other_param, &rhs->other_param);
+    pjsip_param_clone(pool, &url->header_param, &rhs->header_param);
+    url->lr_param = rhs->lr_param;
+}
+
+static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, const pjsip_sip_uri *rhs)
+{
+    pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
+    if (!url)
+	return NULL;
+
+    pjsip_sip_uri_init(url, IS_SIPS(rhs));
+    pjsip_sip_uri_assign(pool, url, rhs);
+    return url;
+}
+
+static const pj_str_t *pjsip_name_addr_get_scheme(const pjsip_name_addr *name)
+{
+    pj_assert(name->uri != NULL);
+    return pjsip_uri_get_scheme(name->uri);
+}
+
+PJ_DEF(void) pjsip_name_addr_init(pjsip_name_addr *name)
+{
+    name->vptr = &name_addr_vptr;
+    name->uri = NULL;
+    name->display.slen = 0;
+    name->display.ptr = NULL;
+}
+
+PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
+{
+    pjsip_name_addr *name_addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
+    pjsip_name_addr_init(name_addr);
+    return name_addr;
+}
+
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+					const pjsip_name_addr *name, 
+					char *buf, pj_size_t size)
+{
+    int printed;
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+    pjsip_uri *uri;
+
+    uri = (pjsip_uri*) pjsip_uri_get_uri(name->uri);
+    pj_assert(uri != NULL);
+
+    if (context != PJSIP_URI_IN_REQ_URI) {
+	if (name->display.slen) {
+	    if (endbuf-buf < 8) return -1;
+	    *buf++ = '"';
+	    copy_advance(buf, name->display);
+	    *buf++ = '"';
+	    *buf++ = ' ';
+	}
+	*buf++ = '<';
+    }
+
+    printed = pjsip_uri_print(context,uri, buf, size-(buf-startbuf));
+    if (printed < 1)
+	return -1;
+    buf += printed;
+
+    if (context != PJSIP_URI_IN_REQ_URI) {
+	*buf++ = '>';
+    }
+
+    *buf = '\0';
+    return buf-startbuf;
+}
+
+PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
+				    const pjsip_name_addr *src)
+{
+    pj_strdup( pool, &dst->display, &src->display);
+    dst->uri = (pjsip_uri*) pjsip_uri_clone(pool, src->uri);
+}
+
+static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 
+					       const pjsip_name_addr *rhs)
+{
+    pjsip_name_addr *addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
+    if (!addr)
+	return NULL;
+
+    pjsip_name_addr_init(addr);
+    pjsip_name_addr_assign(pool, addr, rhs);
+    return addr;
+}
+
+static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
+				     const pjsip_name_addr *naddr1,
+				     const pjsip_name_addr *naddr2)
+{
+    int d;
+
+    /* Check that naddr2 is also a name_addr */
+    if (naddr1->vptr != naddr2->vptr)
+	return -1;
+
+    /* I'm not sure whether display name is included in the comparison. */
+    if (pj_strcmp(&naddr1->display, &naddr2->display) != 0) {
+	return -1;
+    }
+
+    pj_assert( naddr1->uri != NULL );
+    pj_assert( naddr2->uri != NULL );
+
+    /* Compare name-addr as URL */
+    d = pjsip_uri_cmp( context, naddr1->uri, naddr2->uri);
+    if (d)
+	return d;
+
+    return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri*);
+static void *other_uri_get_uri( pjsip_other_uri*);
+static pj_ssize_t other_uri_print( pjsip_uri_context_e context,
+				   const pjsip_other_uri *url, 
+				   char *buf, pj_size_t size);
+static int other_uri_cmp( pjsip_uri_context_e context,
+			  const pjsip_other_uri *url1, 
+			  const pjsip_other_uri *url2);
+static pjsip_other_uri* other_uri_clone( pj_pool_t *pool, 
+					 const pjsip_other_uri *rhs);
+
+static pjsip_uri_vptr other_uri_vptr = 
+{
+    (P_GET_SCHEME)  &other_uri_get_scheme,
+    (P_GET_URI)	    &other_uri_get_uri,
+    (P_PRINT_URI)   &other_uri_print,
+    (P_CMP_URI)	    &other_uri_cmp,
+    (P_CLONE) 	    &other_uri_clone
+};
+
+
+PJ_DEF(pjsip_other_uri*) pjsip_other_uri_create(pj_pool_t *pool) 
+{
+    pjsip_other_uri *uri = PJ_POOL_ZALLOC_T(pool, pjsip_other_uri);
+    uri->vptr = &other_uri_vptr;
+    return uri;
+}
+
+static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri *uri )
+{
+	return &uri->scheme;
+}
+
+static void *other_uri_get_uri( pjsip_other_uri *uri )
+{
+    return uri;
+}
+
+static pj_ssize_t other_uri_print(pjsip_uri_context_e context,
+				  const pjsip_other_uri *uri, 
+				  char *buf, pj_size_t size)
+{
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+    
+    PJ_UNUSED_ARG(context);
+    
+    if (uri->scheme.slen + uri->content.slen + 1 > (int)size)
+	return -1;
+
+    /* Print scheme. */
+    copy_advance(buf, uri->scheme);
+    *buf++ = ':';
+    
+    /* Print content. */
+    copy_advance(buf, uri->content);
+    
+    return (buf - startbuf);
+}
+
+static int other_uri_cmp(pjsip_uri_context_e context,
+			 const pjsip_other_uri *uri1,
+			 const pjsip_other_uri *uri2)
+{
+    PJ_UNUSED_ARG(context);
+
+    /* Check that uri2 is also an other_uri */
+    if (uri1->vptr != uri2->vptr)
+	return -1;
+    
+    /* Scheme must match. */
+    if (pj_stricmp(&uri1->scheme, &uri2->scheme) != 0) {
+	return PJSIP_ECMPSCHEME;
+    }
+    
+    /* Content must match. */
+    if(pj_stricmp(&uri1->content, &uri2->content) != 0) {
+	return -1;
+    }
+    
+    /* Equal. */
+    return 0;
+}
+
+/* Clone *: URI */
+static pjsip_other_uri* other_uri_clone(pj_pool_t *pool, 
+					const pjsip_other_uri *rhs) 
+{
+    pjsip_other_uri *uri = pjsip_other_uri_create(pool);
+    pj_strdup(pool, &uri->scheme, &rhs->scheme);
+    pj_strdup(pool, &uri->content, &rhs->content);
+
+    return uri;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f26afcb8ecadf3d94b934552b6e1f0fdb91c696.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f26afcb8ecadf3d94b934552b6e1f0fdb91c696.svn-base
new file mode 100644
index 0000000..ddfce33
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f26afcb8ecadf3d94b934552b6e1f0fdb91c696.svn-base
Binary files differ
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f26e002830a7dd36ac34af3267f2fefe1fa2061.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f26e002830a7dd36ac34af3267f2fefe1fa2061.svn-base
new file mode 100644
index 0000000..cd94316
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f26e002830a7dd36ac34af3267f2fefe1fa2061.svn-base
@@ -0,0 +1,227 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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 <pjsua2/persistent.hpp>
+
+using namespace pj;
+using namespace std;
+
+
+bool PersistentDocument::hasUnread() const
+{
+    return getRootContainer().hasUnread();
+}
+
+string PersistentDocument::unreadName() const throw(Error)
+{
+    return getRootContainer().unreadName();
+}
+
+int PersistentDocument::readInt(const string &name) const throw(Error)
+{
+    return (int)getRootContainer().readNumber(name);
+}
+
+float PersistentDocument::readNumber(const string &name) const throw(Error)
+{
+    return getRootContainer().readNumber(name);
+}
+
+bool PersistentDocument::readBool(const string &name) const throw(Error)
+{
+    return getRootContainer().readBool(name);
+}
+
+string PersistentDocument::readString(const string &name) const throw(Error)
+{
+    return getRootContainer().readString(name);
+}
+
+StringVector PersistentDocument::readStringVector(const string &name) const
+						  throw(Error)
+{
+    return getRootContainer().readStringVector(name);
+}
+
+void PersistentDocument::readObject(PersistentObject &obj) const throw(Error)
+{
+    getRootContainer().readObject(obj);
+}
+
+ContainerNode PersistentDocument::readContainer(const string &name) const
+					        throw(Error)
+{
+    return getRootContainer().readContainer(name);
+}
+
+ContainerNode PersistentDocument::readArray(const string &name) const
+					    throw(Error)
+{
+    return getRootContainer().readArray(name);
+}
+
+void PersistentDocument::writeNumber(const string &name,
+				     float num) throw(Error)
+{
+    getRootContainer().writeNumber(name, num);
+}
+
+void PersistentDocument::writeInt(const string &name,
+				  int num) throw(Error)
+{
+    getRootContainer().writeNumber(name, (float)num);
+}
+
+void PersistentDocument::writeBool(const string &name,
+				   bool value) throw(Error)
+{
+    getRootContainer().writeBool(name, value);
+}
+
+void PersistentDocument::writeString(const string &name,
+                                     const string &value) throw(Error)
+{
+    getRootContainer().writeString(name, value);
+}
+
+void PersistentDocument::writeStringVector(const string &name,
+                                           const StringVector &value)
+					   throw(Error)
+{
+    getRootContainer().writeStringVector(name, value);
+}
+
+void PersistentDocument::writeObject(const PersistentObject &obj) throw(Error)
+{
+    getRootContainer().writeObject(obj);
+}
+
+ContainerNode PersistentDocument::writeNewContainer(const string &name)
+						    throw(Error)
+{
+    return getRootContainer().writeNewContainer(name);
+}
+
+ContainerNode PersistentDocument::writeNewArray(const string &name)
+						    throw(Error)
+{
+    return getRootContainer().writeNewArray(name);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool ContainerNode::hasUnread() const
+{
+    return op->hasUnread(this);
+}
+
+string ContainerNode::unreadName() const throw(Error)
+{
+    return op->unreadName(this);
+}
+
+int ContainerNode::readInt(const string &name) const throw(Error)
+{
+    return (int)op->readNumber(this, name);
+}
+
+float ContainerNode::readNumber(const string &name) const throw(Error)
+{
+    return op->readNumber(this, name);
+}
+
+bool ContainerNode::readBool(const string &name) const throw(Error)
+{
+    return op->readBool(this, name);
+}
+
+string ContainerNode::readString(const string &name) const throw(Error)
+{
+    return op->readString(this, name);
+}
+
+StringVector ContainerNode::readStringVector(const string &name) const
+					     throw(Error)
+{
+    return op->readStringVector(this, name);
+}
+
+void ContainerNode::readObject(PersistentObject &obj) const throw(Error)
+{
+    obj.readObject(*this);
+}
+
+ContainerNode ContainerNode::readContainer(const string &name) const
+					   throw(Error)
+{
+    return op->readContainer(this, name);
+}
+
+ContainerNode ContainerNode::readArray(const string &name) const
+					   throw(Error)
+{
+    return op->readArray(this, name);
+}
+
+void ContainerNode::writeNumber(const string &name,
+				float num) throw(Error)
+{
+    return op->writeNumber(this, name, num);
+}
+
+void ContainerNode::writeInt(const string &name,
+			     int num) throw(Error)
+{
+    return op->writeNumber(this, name, (float)num);
+}
+
+void ContainerNode::writeBool(const string &name,
+			      bool value) throw(Error)
+{
+    return op->writeBool(this, name, value);
+}
+
+void ContainerNode::writeString(const string &name,
+				const string &value) throw(Error)
+{
+    return op->writeString(this, name, value);
+}
+
+void ContainerNode::writeStringVector(const string &name,
+				      const StringVector &value)
+				      throw(Error)
+{
+    return op->writeStringVector(this, name, value);
+}
+
+void ContainerNode::writeObject(const PersistentObject &obj) throw(Error)
+{
+    obj.writeObject(*this);
+}
+
+ContainerNode ContainerNode::writeNewContainer(const string &name)
+					       throw(Error)
+{
+    return op->writeNewContainer(this, name);
+}
+
+ContainerNode ContainerNode::writeNewArray(const string &name)
+					   throw(Error)
+{
+    return op->writeNewArray(this, name);
+}
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f294d7151cc98897e3723588440284d0041f3c3.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f294d7151cc98897e3723588440284d0041f3c3.svn-base
new file mode 100644
index 0000000..2c984be
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f294d7151cc98897e3723588440284d0041f3c3.svn-base
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="Basic UAS responder">
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 100 Trying
+      [last_Via:];received=1.1.1.1;rport=1111
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      WWW-Authenticate: digest realm="test"
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <pause milliseconds="2000"/>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 401 Unauthorized
+      [last_Via:];received=2.2.2.2;rport=2222
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      WWW-Authenticate: digest realm="test"
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 401 Unauthorized again
+      [last_Via:];received=3.3.3.3;rport=3333
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      WWW-Authenticate: digest realm="test", stale=true
+      Content-Length: 0
+    ]]>
+  </send>
+
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 200 OK
+      [last_Via:];received=4.4.4.4;rport=4444
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <!-- IP CHANGE FOR 200/OK -->
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 401 Unauthorized
+      [last_Via:];received=5.5.5.5;rport=5555
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      WWW-Authenticate: digest realm="test"
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 401 Nasty Unauthorized
+      [last_Via:];received=6.6.6.6;rport=6666
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      WWW-Authenticate: digest realm="test", stale=true
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 200 OK
+      [last_Via:];received=8.8.8.8;rport=8888
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <recv request="REGISTER" crlf="true">
+  </recv>
+
+  <send>
+    <![CDATA[
+      SIP/2.0 200 OK
+      [last_Via:];received=8.8.8.8;rport=8888
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      [last_Contact:]
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
+
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f2a884dad107b791794a7bbe9763df66b0cac05.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f2a884dad107b791794a7bbe9763df66b0cac05.svn-base
new file mode 100644
index 0000000..e0ef520
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f2a884dad107b791794a7bbe9763df66b0cac05.svn-base
@@ -0,0 +1,230 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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 __VIDEODEV_IMP_H__
+#define __VIDEODEV_IMP_H__
+
+#include <pjmedia-videodev/videodev.h>
+
+/**
+ * @defgroup s8_video_device_implementors_api Video Device Implementors API
+ * @ingroup video_device_api
+ * @brief API for video device implementors
+ * @{
+ */
+
+/**
+ * Video device factory operations.
+ */
+typedef struct pjmedia_vid_dev_factory_op
+{
+    /**
+     * Initialize the video device factory.
+     *
+     * @param f		The video device factory.
+     */
+    pj_status_t (*init)(pjmedia_vid_dev_factory *f);
+
+    /**
+     * Close this video device factory and release all resources back to the
+     * operating system.
+     *
+     * @param f		The video device factory.
+     */
+    pj_status_t (*destroy)(pjmedia_vid_dev_factory *f);
+
+    /**
+     * Get the number of video devices installed in the system.
+     *
+     * @param f		The video device factory.
+     */
+    unsigned (*get_dev_count)(pjmedia_vid_dev_factory *f);
+
+    /**
+     * Get the video device information and capabilities.
+     *
+     * @param f		The video device factory.
+     * @param index	Device index.
+     * @param info	The video device information structure which will be
+     *			initialized by this function once it returns 
+     *			successfully.
+     */
+    pj_status_t	(*get_dev_info)(pjmedia_vid_dev_factory *f, 
+				unsigned index,
+				pjmedia_vid_dev_info *info);
+
+    /**
+     * Initialize the specified video device parameter with the default
+     * values for the specified device.
+     *
+     * @param f		The video device factory.
+     * @param index	Device index.
+     * @param param	The video device parameter.
+     */
+    pj_status_t (*default_param)(pj_pool_t *pool,
+                                 pjmedia_vid_dev_factory *f,
+				 unsigned index,
+				 pjmedia_vid_dev_param *param);
+
+    /**
+     * Open the video device and create video stream. See
+     * #pjmedia_vid_dev_stream_create()
+     */
+    pj_status_t (*create_stream)(pjmedia_vid_dev_factory *f,
+				 pjmedia_vid_dev_param *param,
+				 const pjmedia_vid_dev_cb *cb,
+				 void *user_data,
+				 pjmedia_vid_dev_stream **p_vid_strm);
+
+    /**
+     * Refresh the list of video devices installed in the system.
+     *
+     * @param f		The video device factory.
+     */
+    pj_status_t (*refresh)(pjmedia_vid_dev_factory *f);
+
+} pjmedia_vid_dev_factory_op;
+
+
+/**
+ * This structure describes a video device factory. 
+ */
+struct pjmedia_vid_dev_factory
+{
+    /** Internal data to be initialized by video subsystem. */
+    struct {
+	/** Driver index */
+	unsigned drv_idx;
+    } sys;
+
+    /** Operations */
+    pjmedia_vid_dev_factory_op *op;
+};
+
+
+/**
+ * Video stream operations.
+ */
+typedef struct pjmedia_vid_dev_stream_op
+{
+    /**
+     * See #pjmedia_vid_dev_stream_get_param()
+     */
+    pj_status_t (*get_param)(pjmedia_vid_dev_stream *strm,
+			     pjmedia_vid_dev_param *param);
+
+    /**
+     * See #pjmedia_vid_dev_stream_get_cap()
+     */
+    pj_status_t (*get_cap)(pjmedia_vid_dev_stream *strm,
+			   pjmedia_vid_dev_cap cap,
+			   void *value);
+
+    /**
+     * See #pjmedia_vid_dev_stream_set_cap()
+     */
+    pj_status_t (*set_cap)(pjmedia_vid_dev_stream *strm,
+			   pjmedia_vid_dev_cap cap,
+			   const void *value);
+
+    /**
+     * See #pjmedia_vid_dev_stream_start()
+     */
+    pj_status_t (*start)(pjmedia_vid_dev_stream *strm);
+
+    /**
+     * See #pjmedia_vid_dev_stream_get_frame()
+     */
+    pj_status_t (*get_frame)(pjmedia_vid_dev_stream *strm,
+                             pjmedia_frame *frame);
+
+    /**
+     * See #pjmedia_vid_dev_stream_put_frame()
+     */
+    pj_status_t (*put_frame)(pjmedia_vid_dev_stream *strm,
+                             const pjmedia_frame *frame);
+
+    /**
+     * See #pjmedia_vid_dev_stream_stop().
+     */
+    pj_status_t (*stop)(pjmedia_vid_dev_stream *strm);
+
+    /**
+     * See #pjmedia_vid_dev_stream_destroy().
+     */
+    pj_status_t (*destroy)(pjmedia_vid_dev_stream *strm);
+
+} pjmedia_vid_dev_stream_op;
+
+
+/**
+ * This structure describes the video device stream.
+ */
+struct pjmedia_vid_dev_stream
+{
+    /** Internal data to be initialized by video subsystem */
+    struct {
+	/** Driver index */
+	unsigned drv_idx;
+
+	/** Has it been started? */
+	pj_bool_t is_running;
+    } sys;
+
+    /** Operations */
+    pjmedia_vid_dev_stream_op *op;
+};
+
+
+/**
+ * Internal API: return the factory instance and device index that's local
+ * to the factory for a given device ID.
+ *
+ * @param id		Device id.
+ * @param p_f		Out: factory instance
+ * @param p_local_index Out: device index within the factory
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_vid_dev_get_local_index(pjmedia_vid_dev_index id,
+                                pjmedia_vid_dev_factory **p_f,
+                                unsigned *p_local_index);
+
+/**
+ * Internal API: return the global device index given a factory instance and
+ * a local device index.
+ *
+ * @param f		Factory.
+ * @param local_idx	Local index.
+ * @param pid		Returned global index.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_vid_dev_get_global_index(const pjmedia_vid_dev_factory *f,
+                                 unsigned local_idx,
+                                 pjmedia_vid_dev_index *pid);
+
+/**
+ * @}
+ */
+
+
+
+#endif /* __VIDEODEV_IMP_H__ */
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f2b5a08de26a4570ddb37f574a762552c7cdd9d.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f2b5a08de26a4570ddb37f574a762552c7cdd9d.svn-base
new file mode 100644
index 0000000..ae816cc
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f2b5a08de26a4570ddb37f574a762552c7cdd9d.svn-base
@@ -0,0 +1,91 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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 
+ */
+#import "TestViewController.h"
+
+@implementation TestViewController
+@synthesize testDesc;
+@synthesize button1;
+@synthesize button2;
+@synthesize key;
+
+- (void)button1Pressed:(id)sender {
+    self.key = 1;
+    [self.button1 setHidden:true];
+    [self.button2 setHidden:true];
+}
+
+- (void)button2Pressed:(id)sender {
+    self.key = 2;
+    [self.button1 setHidden:true];
+    [self.button2 setHidden:true];
+}
+
+/*
+ // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
+ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
+    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
+    // Custom initialization
+ }
+ return self;
+ }
+ */
+
+/*
+ // Implement loadView to create a view hierarchy programmatically, without using a nib.
+ - (void)loadView {
+ }
+ */
+
+
+// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [button1 addTarget:self action:@selector(button1Pressed:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
+    [button2 addTarget:self action:@selector(button2Pressed:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
+    [testDesc setEditable:false];
+}
+
+/*
+ // Override to allow orientations other than the default portrait orientation.
+ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
+    // Return YES for supported orientations
+    return (interfaceOrientation == UIInterfaceOrientationPortrait);
+ }
+ */
+
+- (void)didReceiveMemoryWarning {
+    // Releases the view if it doesn't have a superview.
+    [super didReceiveMemoryWarning];
+    
+    // Release any cached data, images, etc that aren't in use.
+}
+
+- (void)viewDidUnload {
+    // Release any retained subviews of the main view.
+    // e.g. self.myOutlet = nil;
+}
+
+
+- (void)dealloc {
+    [super dealloc];
+}
+
+
+@end
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f349a6fb2988428fafcacc58939ab4b46166181.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f349a6fb2988428fafcacc58939ab4b46166181.svn-base
new file mode 100644
index 0000000..3f4e47b
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f349a6fb2988428fafcacc58939ab4b46166181.svn-base
@@ -0,0 +1,32 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJ_COMPAT_SIZE_T_H__
+#define __PJ_COMPAT_SIZE_T_H__
+
+/**
+ * @file size_t.h
+ * @brief Provides size_t type.
+ */
+#if PJ_HAS_STDDEF_H
+# include <stddef.h>
+#endif
+
+#endif	/* __PJ_COMPAT_SIZE_T_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/4f/4f92265026718986376118277aa4a6667de77deb.svn-base b/jni/pjproject-android/.svn/pristine/4f/4f92265026718986376118277aa4a6667de77deb.svn-base
new file mode 100644
index 0000000..d830e20
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4f92265026718986376118277aa4a6667de77deb.svn-base
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1996 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header*/
+
+/* Generate code to pack a bit array from a name:#bits description */
+
+#include	<stdio.h>
+#include	"taste.h"
+#include	"proto.h"
+#include	<limits.h>
+
+/* This module is the opposite of sour.   Sweet was already taken,
+ * that's why it's called ginger.  (Add one point if that reminds
+ * you of Gary Larson.)
+ */
+
+#define WORD_BITS	16	/* sizeof(uword) * CHAR_BIT on the 
+				 * target architecture---if this isn't 16,
+				 * you're in trouble with this library anyway.
+				 */
+
+#define BYTE_BITS	 8	/* CHAR_BIT on the target architecture---
+				 * if this isn't 8, you're in *deep* trouble.
+				 */
+
+void write_code P2((s_spex, n_spex), struct spex * s_spex, int n_spex)
+{
+	struct spex	* sp = s_spex;
+	int		  n_in = 0;
+
+	printf("uword sr = 0;\n");
+
+	for (; n_spex > 0; n_spex--, sp++) {
+
+		while (n_in < sp->varsize) {
+			if (n_in) printf("sr |= (uword)*c++ << %d;\n", n_in);
+			else printf("sr = *c++;\n");
+			n_in += BYTE_BITS;
+		}
+
+		printf("%s = sr & %#x;  sr >>= %d;\n",
+			sp->var, ~(~0U << sp->varsize), sp->varsize);
+
+		n_in -= sp->varsize;
+	}
+
+	if (n_in > 0) {
+		fprintf(stderr, "%d bits left over\n", n_in);
+	}
+}
diff --git a/jni/pjproject-android/.svn/pristine/4f/4fe9dc1ec8029447ea558074645558bfb94c7010.svn-base b/jni/pjproject-android/.svn/pristine/4f/4fe9dc1ec8029447ea558074645558bfb94c7010.svn-base
new file mode 100644
index 0000000..0f37fae
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4fe9dc1ec8029447ea558074645558bfb94c7010.svn-base
@@ -0,0 +1,343 @@
+/* $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_msg.h>
+#include <pjsip/sip_auth_parser.h>
+#include <pjsip/sip_parser.h>
+#include <pj/pool.h>
+#include <pj/list.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pjsip/print_util.h>
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Authorization and Proxy-Authorization header.
+ */
+static pjsip_authorization_hdr* pjsip_authorization_hdr_clone( pj_pool_t *pool,
+							       const pjsip_authorization_hdr *hdr);
+static pjsip_authorization_hdr* pjsip_authorization_hdr_shallow_clone( pj_pool_t *pool,
+								       const pjsip_authorization_hdr *hdr);
+static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,
+					  char *buf, pj_size_t size);
+
+static pjsip_hdr_vptr authorization_hdr_vptr = 
+{
+    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_clone,
+    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_shallow_clone,
+    (pjsip_hdr_print_fptr) &pjsip_authorization_hdr_print,
+};
+
+
+PJ_DEF(pjsip_authorization_hdr*) pjsip_authorization_hdr_create(pj_pool_t *pool)
+{
+    pjsip_authorization_hdr *hdr;
+    hdr = PJ_POOL_ZALLOC_T(pool, pjsip_authorization_hdr);
+    init_hdr(hdr, PJSIP_H_AUTHORIZATION, &authorization_hdr_vptr);
+    pj_list_init(&hdr->credential.common.other_param);
+    return hdr;
+}
+
+PJ_DEF(pjsip_proxy_authorization_hdr*) pjsip_proxy_authorization_hdr_create(pj_pool_t *pool)
+{
+    pjsip_proxy_authorization_hdr *hdr;
+    hdr = PJ_POOL_ZALLOC_T(pool, pjsip_proxy_authorization_hdr);
+    init_hdr(hdr, PJSIP_H_PROXY_AUTHORIZATION, &authorization_hdr_vptr);
+    pj_list_init(&hdr->credential.common.other_param);
+    return hdr;
+}
+
+static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_size_t size)
+{
+    pj_ssize_t printed;
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+    const pjsip_parser_const_t *pc = pjsip_parser_const();
+    
+    copy_advance_pair_quote_cond(buf, "username=", 9, cred->username, '"', '"');
+    copy_advance_pair_quote_cond(buf, ", realm=", 8, cred->realm, '"', '"');
+    copy_advance_pair_quote(buf, ", nonce=", 8, cred->nonce, '"', '"');
+    copy_advance_pair_quote_cond(buf, ", uri=", 6, cred->uri, '"', '"');
+    copy_advance_pair_quote(buf, ", response=", 11, cred->response, '"', '"');
+    copy_advance_pair(buf, ", algorithm=", 12, cred->algorithm);
+    copy_advance_pair_quote_cond(buf, ", cnonce=", 9, cred->cnonce, '"', '"');
+    copy_advance_pair_quote_cond(buf, ", opaque=", 9, cred->opaque, '"', '"');
+    //Note: there's no dbl-quote in qop in Authorization header 
+    // (unlike WWW-Authenticate)
+    //copy_advance_pair_quote_cond(buf, ", qop=", 6, cred->qop, '"', '"');
+    copy_advance_pair(buf, ", qop=", 6, cred->qop);
+    copy_advance_pair(buf, ", nc=", 5, cred->nc);
+    
+    printed = pjsip_param_print_on(&cred->other_param, buf, endbuf-buf, 
+				   &pc->pjsip_TOKEN_SPEC, 
+				   &pc->pjsip_TOKEN_SPEC, ',');
+    if (printed < 0)
+	return -1;
+    buf += printed;
+
+    return (int) (buf-startbuf);
+}
+
+static int print_pgp_credential(pjsip_pgp_credential *cred, char *buf, pj_size_t size)
+{
+    PJ_UNUSED_ARG(cred);
+    PJ_UNUSED_ARG(buf);
+    PJ_UNUSED_ARG(size);
+    return -1;
+}
+
+static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,
+					  char *buf, pj_size_t size)
+{
+    int printed;
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+
+    copy_advance(buf, hdr->name);
+    *buf++ = ':';
+    *buf++ = ' ';
+
+    copy_advance(buf, hdr->scheme);
+    *buf++ = ' ';
+
+    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0)
+    {
+	printed = print_digest_credential(&hdr->credential.digest, buf, endbuf - buf);
+    } 
+    else if (pj_stricmp(&hdr->scheme, &pjsip_PGP_STR) == 0)
+    {
+	printed = print_pgp_credential(&hdr->credential.pgp, buf, endbuf - buf);
+    } 
+    else {
+	pj_assert(0);
+	return -1;
+    }
+
+    if (printed == -1)
+	return -1;
+
+    buf += printed;
+    *buf = '\0';
+    return (int)(buf-startbuf);
+}
+
+static pjsip_authorization_hdr* pjsip_authorization_hdr_clone(  pj_pool_t *pool,
+								const pjsip_authorization_hdr *rhs)
+{
+    /* This function also serves Proxy-Authorization header. */
+    pjsip_authorization_hdr *hdr;
+    if (rhs->type == PJSIP_H_AUTHORIZATION)
+	hdr = pjsip_authorization_hdr_create(pool);
+    else
+	hdr = pjsip_proxy_authorization_hdr_create(pool);
+
+    pj_strdup(pool, &hdr->scheme, &rhs->scheme);
+
+    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {
+	pj_strdup(pool, &hdr->credential.digest.username, &rhs->credential.digest.username);
+	pj_strdup(pool, &hdr->credential.digest.realm, &rhs->credential.digest.realm);
+	pj_strdup(pool, &hdr->credential.digest.nonce, &rhs->credential.digest.nonce);
+	pj_strdup(pool, &hdr->credential.digest.uri, &rhs->credential.digest.uri);
+	pj_strdup(pool, &hdr->credential.digest.response, &rhs->credential.digest.response);
+	pj_strdup(pool, &hdr->credential.digest.algorithm, &rhs->credential.digest.algorithm);
+	pj_strdup(pool, &hdr->credential.digest.cnonce, &rhs->credential.digest.cnonce);
+	pj_strdup(pool, &hdr->credential.digest.opaque, &rhs->credential.digest.opaque);
+	pj_strdup(pool, &hdr->credential.digest.qop, &rhs->credential.digest.qop);
+	pj_strdup(pool, &hdr->credential.digest.nc, &rhs->credential.digest.nc);
+	pjsip_param_clone(pool, &hdr->credential.digest.other_param, &rhs->credential.digest.other_param);
+    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {
+	pj_assert(0);
+	return NULL;
+    } else {
+	pj_assert(0);
+	return NULL;
+    }
+
+    return hdr;
+}
+
+static pjsip_authorization_hdr* 
+pjsip_authorization_hdr_shallow_clone(  pj_pool_t *pool,
+					const pjsip_authorization_hdr *rhs)
+{
+    /* This function also serves Proxy-Authorization header. */
+    pjsip_authorization_hdr *hdr;
+    hdr = PJ_POOL_ALLOC_T(pool, pjsip_authorization_hdr);
+    pj_memcpy(hdr, rhs, sizeof(*hdr));
+    pjsip_param_shallow_clone(pool, &hdr->credential.common.other_param, 
+			      &rhs->credential.common.other_param);
+    return hdr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Proxy-Authenticate and WWW-Authenticate header.
+ */
+static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,
+					     char *buf, pj_size_t size);
+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,
+								     const pjsip_www_authenticate_hdr *hdr);
+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,
+									     const pjsip_www_authenticate_hdr *hdr);
+
+static pjsip_hdr_vptr www_authenticate_hdr_vptr = 
+{
+    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_clone,
+    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_shallow_clone,
+    (pjsip_hdr_print_fptr) &pjsip_www_authenticate_hdr_print,
+};
+
+
+PJ_DEF(pjsip_www_authenticate_hdr*) pjsip_www_authenticate_hdr_create(pj_pool_t *pool)
+{
+    pjsip_www_authenticate_hdr *hdr;
+    hdr = PJ_POOL_ZALLOC_T(pool, pjsip_www_authenticate_hdr);
+    init_hdr(hdr, PJSIP_H_WWW_AUTHENTICATE, &www_authenticate_hdr_vptr);
+    pj_list_init(&hdr->challenge.common.other_param);
+    return hdr;
+}
+
+
+PJ_DEF(pjsip_proxy_authenticate_hdr*) pjsip_proxy_authenticate_hdr_create(pj_pool_t *pool)
+{
+    pjsip_proxy_authenticate_hdr *hdr;
+    hdr = PJ_POOL_ZALLOC_T(pool, pjsip_proxy_authenticate_hdr);
+    init_hdr(hdr, PJSIP_H_PROXY_AUTHENTICATE, &www_authenticate_hdr_vptr);
+    pj_list_init(&hdr->challenge.common.other_param);
+    return hdr;
+}
+
+static int print_digest_challenge( pjsip_digest_challenge *chal,
+				   char *buf, pj_size_t size)
+{
+    pj_ssize_t printed;
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+    const pjsip_parser_const_t *pc = pjsip_parser_const();
+
+    /* Allow empty realm, see http://trac.pjsip.org/repos/ticket/1061 */
+    copy_advance_pair_quote(buf, " realm=", 7, chal->realm, '"', '"');
+    copy_advance_pair_quote_cond(buf, ",domain=", 8, chal->domain, '"', '"');
+    copy_advance_pair_quote_cond(buf, ",nonce=", 7, chal->nonce, '"', '"');
+    copy_advance_pair_quote_cond(buf, ",opaque=", 8, chal->opaque, '"', '"');
+    if (chal->stale) {
+	pj_str_t true_str = { "true", 4 };
+	copy_advance_pair(buf, ",stale=", 7, true_str);
+    }
+    copy_advance_pair(buf, ",algorithm=", 11, chal->algorithm);
+    copy_advance_pair_quote_cond(buf, ",qop=", 5, chal->qop, '"', '"');
+    
+    printed = pjsip_param_print_on(&chal->other_param, buf, endbuf-buf, 
+				   &pc->pjsip_TOKEN_SPEC, 
+				   &pc->pjsip_TOKEN_SPEC, ',');
+    if (printed < 0)
+	return -1;
+    buf += printed;
+
+    return (int)(buf-startbuf);
+}
+
+static int print_pgp_challenge( pjsip_pgp_challenge *chal,
+			        char *buf, pj_size_t size)
+{
+    PJ_UNUSED_ARG(chal);
+    PJ_UNUSED_ARG(buf);
+    PJ_UNUSED_ARG(size);
+    return -1;
+}
+
+static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,
+					     char *buf, pj_size_t size)
+{
+    int printed;
+    char *startbuf = buf;
+    char *endbuf = buf + size;
+
+    copy_advance(buf, hdr->name);
+    *buf++ = ':';
+    *buf++ = ' ';
+
+    copy_advance(buf, hdr->scheme);
+    *buf++ = ' ';
+
+    if (pj_stricmp2(&hdr->scheme, "digest") == 0)
+	printed = print_digest_challenge(&hdr->challenge.digest, buf, endbuf - buf);
+    else if (pj_stricmp2(&hdr->scheme, "pgp") == 0)
+	printed = print_pgp_challenge(&hdr->challenge.pgp, buf, endbuf - buf);
+    else {
+	pj_assert(0);
+	return -1;
+    }
+
+    if (printed == -1)
+	return -1;
+
+    buf += printed;
+    *buf = '\0';
+    return (int)(buf-startbuf);
+}
+
+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,
+								     const pjsip_www_authenticate_hdr *rhs)
+{
+    /* This function also serves Proxy-Authenticate header. */
+    pjsip_www_authenticate_hdr *hdr;
+    if (rhs->type == PJSIP_H_WWW_AUTHENTICATE)
+	hdr = pjsip_www_authenticate_hdr_create(pool);
+    else
+	hdr = pjsip_proxy_authenticate_hdr_create(pool);
+
+    pj_strdup(pool, &hdr->scheme, &rhs->scheme);
+
+    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {
+	pj_strdup(pool, &hdr->challenge.digest.realm, &rhs->challenge.digest.realm);
+	pj_strdup(pool, &hdr->challenge.digest.domain, &rhs->challenge.digest.domain);
+	pj_strdup(pool, &hdr->challenge.digest.nonce, &rhs->challenge.digest.nonce);
+	pj_strdup(pool, &hdr->challenge.digest.opaque, &rhs->challenge.digest.opaque);
+	hdr->challenge.digest.stale = rhs->challenge.digest.stale;
+	pj_strdup(pool, &hdr->challenge.digest.algorithm, &rhs->challenge.digest.algorithm);
+	pj_strdup(pool, &hdr->challenge.digest.qop, &rhs->challenge.digest.qop);
+	pjsip_param_clone(pool, &hdr->challenge.digest.other_param, 
+			  &rhs->challenge.digest.other_param);
+    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {
+	pj_assert(0);
+	return NULL;
+    } else {
+	pj_assert(0);
+	return NULL;
+    }
+
+    return hdr;
+
+}
+
+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,
+									     const pjsip_www_authenticate_hdr *rhs)
+{
+    /* This function also serves Proxy-Authenticate header. */
+    pjsip_www_authenticate_hdr *hdr;
+    hdr = PJ_POOL_ALLOC_T(pool, pjsip_www_authenticate_hdr);
+    pj_memcpy(hdr, rhs, sizeof(*hdr));
+    pjsip_param_shallow_clone(pool, &hdr->challenge.common.other_param, 
+			      &rhs->challenge.common.other_param);
+    return hdr;
+}
+
+
diff --git a/jni/pjproject-android/.svn/pristine/4f/4fef6b17a805627ce0362c57fc587323c03601a4.svn-base b/jni/pjproject-android/.svn/pristine/4f/4fef6b17a805627ce0362c57fc587323c03601a4.svn-base
new file mode 100644
index 0000000..ea7c7bf
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/4f/4fef6b17a805627ce0362c57fc587323c03601a4.svn-base
@@ -0,0 +1,898 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia/tonegen.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/silencedet.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+
+/* amplitude */
+#define AMP	PJMEDIA_TONEGEN_VOLUME
+
+#ifndef M_PI
+#   define M_PI  ((DATA)3.141592653589793238462643383279)
+#endif
+
+#if PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_SINE
+    #include <math.h>
+    #define DATA	double
+
+    /*
+     * This is the good old tone generator using sin().
+     * Speed = 1347 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
+     *         approx. 10.91 MIPS
+     *
+     *         506,535 usec/100.29 MIPS on ARM926EJ-S.
+     */
+    struct gen
+    {
+	DATA add;
+	DATA c;
+	DATA vol;
+    };
+
+    #define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A
+    #define GEN_SAMP(val,var)   val = (short)(sin(var.c * 2 * M_PI) * \
+					      var.vol); \
+			        var.c += var.add
+
+#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FLOATING_POINT
+    #include <math.h>
+    #define DATA	float
+
+    /*
+     * Default floating-point based tone generation using sine wave 
+     * generation from:
+     *   http://www.musicdsp.org/showone.php?id=10.
+     * This produces good quality tone in relatively faster time than
+     * the normal sin() generator.
+     * Speed = 350 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
+     *         approx. 2.84 MIPS
+     *
+     *         18,037 usec/3.57 MIPS on ARM926EJ-S.
+     */
+    struct gen
+    {
+	DATA a, s0, s1;
+    };
+
+    #define GEN_INIT(var,R,F,A) var.a = (DATA) (2.0 * sin(M_PI * F / R)); \
+			        var.s0 = 0; \
+			        var.s1 = (DATA)(0 - (int)A)
+    #define GEN_SAMP(val,var)   var.s0 = var.s0 - var.a * var.s1; \
+			        var.s1 = var.s1 + var.a * var.s0; \
+			        val = (short) var.s0
+
+#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FIXED_POINT_CORDIC
+    /* Cordic algorithm with 28 bit size, from:
+     * http://www.dcs.gla.ac.uk/~jhw/cordic/
+     * Speed = 742 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
+     *         (PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP=7)
+     *         approx. 6.01 MIPS
+     *
+     *         ARM926EJ-S results:
+     *	        loop=7:   8,943 usec/1.77 MIPS
+     *		loop=8:   9,872 usec/1.95 MIPS
+     *          loop=10: 11,662 usec/2.31 MIPS
+     *          loop=12: 13,561 usec/2.69 MIPS
+     */
+    #define CORDIC_1K		0x026DD3B6
+    #define CORDIC_HALF_PI	0x06487ED5
+    #define CORDIC_PI		(CORDIC_HALF_PI * 2)
+    #define CORDIC_MUL_BITS	26
+    #define CORDIC_MUL		(1 << CORDIC_MUL_BITS)
+    #define CORDIC_NTAB		28
+    #define CORDIC_LOOP		PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP
+
+    static int cordic_ctab [] = 
+    {
+	0x03243F6A, 0x01DAC670, 0x00FADBAF, 0x007F56EA, 0x003FEAB7, 
+	0x001FFD55, 0x000FFFAA, 0x0007FFF5, 0x0003FFFE, 0x0001FFFF, 
+	0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF, 
+	0x000007FF, 0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F, 
+	0x0000003F, 0x0000001F, 0x0000000F, 0x00000007, 0x00000003, 
+	0x00000001, 0x00000000, 0x00000000 
+    };
+
+    static pj_int32_t cordic(pj_int32_t theta, unsigned n)
+    {
+	unsigned k;
+	int d;
+	pj_int32_t tx;
+	pj_int32_t x = CORDIC_1K, y = 0, z = theta;
+
+	for (k=0; k<n; ++k) {
+	    #if 0
+	    d = (z>=0) ? 0 : -1;
+	    #else
+	    /* Only slightly (~2.5%) faster, but not portable? */
+	     d = z>>27;
+	    #endif
+	    tx = x - (((y>>k) ^ d) - d);
+	    y = y + (((x>>k) ^ d) - d);
+	    z = z - ((cordic_ctab[k] ^ d) - d);
+	    x = tx;
+	}  
+	return y;
+    }
+
+    /* Note: theta must be uint32 here */
+    static pj_int32_t cordic_sin(pj_uint32_t theta, unsigned n)
+    {
+	if (theta < CORDIC_HALF_PI)
+	    return cordic(theta, n);
+	else if (theta < CORDIC_PI)
+	    return cordic(CORDIC_HALF_PI-(theta-CORDIC_HALF_PI), n);
+	else if (theta < CORDIC_PI + CORDIC_HALF_PI)
+	    return -cordic(theta - CORDIC_PI, n);
+	else if (theta < 2 * CORDIC_PI)
+	    return -cordic(CORDIC_HALF_PI-(theta-3*CORDIC_HALF_PI), n);
+	else {
+	    pj_assert(!"Invalid cordic_sin() value");
+	    return 0;
+	}
+    }
+
+    struct gen
+    {
+	unsigned    add;
+	pj_uint32_t c;
+	unsigned    vol;
+    };
+
+    #define VOL(var,v)		(((v) * var.vol) >> 15)
+    #define GEN_INIT(var,R,F,A)	gen_init(&var, R, F, A)
+    #define GEN_SAMP(val,var)	val = gen_samp(&var)
+
+    static void gen_init(struct gen *var, unsigned R, unsigned F, unsigned A)
+    {
+	var->add = 2*CORDIC_PI/R * F;
+	var->c = 0;
+	var->vol = A;
+    }
+
+    PJ_INLINE(short) gen_samp(struct gen *var)
+    {
+	pj_int32_t val;
+	val = cordic_sin(var->c, CORDIC_LOOP);
+	/*val = (val * 32767) / CORDIC_MUL;
+	 *val = VOL((*var), val);
+	 */
+	val = ((val >> 10) * var->vol) >> 16;
+	var->c += var->add;
+	if (var->c > 2*CORDIC_PI)
+	    var->c -= (2 * CORDIC_PI);
+	return (short) val;
+    }
+
+#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FAST_FIXED_POINT
+
+    /* 
+     * Fallback algorithm when floating point is disabled.
+     * This is a very fast fixed point tone generation using sine wave
+     * approximation from
+     *    http://www.audiomulch.com/~rossb/code/sinusoids/ 
+     * Quality wise not so good, but it's blazing fast!
+     * Speed = 117 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
+     *         approx. 0.95 MIPS
+     *
+     *         1,449 usec/0.29 MIPS on ARM926EJ-S.
+     */
+    PJ_INLINE(int) approximate_sin3(unsigned x)
+    {	
+	    unsigned s=-(int)(x>>31);
+	    x+=x;
+	    x=x>>16;
+	    x*=x^0xffff;            // x=x*(2-x)
+	    x+=x;                   // optional
+	    return x^s;
+    }
+    struct gen
+    {
+	unsigned add;
+	unsigned c;
+	unsigned vol;
+    };
+
+    #define MAXI		((unsigned)0xFFFFFFFF)
+    #define SIN			approximate_sin3
+    #define VOL(var,v)		(((v) * var.vol) >> 15)
+    #define GEN_INIT(var,R,F,A)	var.add = MAXI/R * F, var.c=0, var.vol=A
+    #define GEN_SAMP(val,var)	val = (short) VOL(var,SIN(var.c)>>16); \
+				var.c += var.add
+
+#else
+    #error "PJMEDIA_TONEGEN_ALG is not set correctly"
+#endif
+
+struct gen_state
+{
+    struct gen tone1;
+    struct gen tone2;
+    pj_bool_t  has_tone2;
+};
+
+
+static void init_generate_single_tone(struct gen_state *state,
+				      unsigned clock_rate, 
+				      unsigned freq,
+				      unsigned vol)
+{
+    GEN_INIT(state->tone1,clock_rate,freq,vol);
+    state->has_tone2 = PJ_FALSE;
+}
+
+static void generate_single_tone(struct gen_state *state,
+				 unsigned channel_count,
+				 unsigned samples,
+				 short buf[]) 
+{
+    short *end = buf + samples;
+
+    if (channel_count==1) {
+
+	while (buf < end) {
+	    GEN_SAMP(*buf++, state->tone1);
+	}
+
+    } else if (channel_count == 2) {
+
+	while (buf < end) {
+	    GEN_SAMP(*buf, state->tone1);
+	    *(buf+1) = *buf;
+	    buf += 2;
+	}
+    }
+}
+
+
+static void init_generate_dual_tone(struct gen_state *state,
+				    unsigned clock_rate, 
+				    unsigned freq1,
+				    unsigned freq2,
+				    unsigned vol)
+{
+    GEN_INIT(state->tone1,clock_rate,freq1,vol);
+    GEN_INIT(state->tone2,clock_rate,freq2,vol);
+    state->has_tone2 = PJ_TRUE;
+}
+
+
+static void generate_dual_tone(struct gen_state *state,
+			       unsigned channel_count,
+			       unsigned samples,
+			       short buf[]) 
+{
+    short *end = buf + samples;
+
+    if (channel_count==1) {
+	int val, val2;
+	while (buf < end) {
+	    GEN_SAMP(val, state->tone1);
+	    GEN_SAMP(val2, state->tone2);
+	    *buf++ = (short)((val+val2) >> 1);
+	}
+    } else if (channel_count == 2) {
+	int val, val2;
+	while (buf < end) {
+
+	    GEN_SAMP(val, state->tone1);
+	    GEN_SAMP(val2, state->tone2);
+	    val = (val + val2) >> 1;
+
+	    *buf++ = (short)val;
+	    *buf++ = (short)val;
+	}
+    }
+}
+
+
+static void init_generate_tone(struct gen_state *state,
+			       unsigned clock_rate, 
+			       unsigned freq1,
+			       unsigned freq2,
+			       unsigned vol)
+{
+    if (freq2)
+	init_generate_dual_tone(state, clock_rate, freq1, freq2 ,vol);
+    else
+	init_generate_single_tone(state, clock_rate, freq1,vol);
+}
+
+
+static void generate_tone(struct gen_state *state,
+			  unsigned channel_count,
+			  unsigned samples,
+			  short buf[])
+{
+    if (!state->has_tone2)
+	generate_single_tone(state, channel_count, samples, buf);
+    else
+	generate_dual_tone(state, channel_count, samples, buf);
+}
+
+
+/****************************************************************************/
+
+#define SIGNATURE   PJMEDIA_SIG_PORT_TONEGEN
+#define THIS_FILE   "tonegen.c"
+
+#if 0
+#   define TRACE_(expr)	PJ_LOG(4,expr)
+#else
+#   define TRACE_(expr)
+#endif
+
+enum flags
+{
+    PJMEDIA_TONE_INITIALIZED	= 1,
+    PJMEDIA_TONE_ENABLE_FADE	= 2
+};
+
+struct tonegen
+{
+    pjmedia_port	base;
+
+    /* options */
+    unsigned		options;
+    unsigned		playback_options;
+    unsigned		fade_in_len;	/* fade in for this # of samples */
+    unsigned		fade_out_len;	/* fade out for this # of samples*/
+
+    /* lock */
+    pj_lock_t	       *lock;
+
+    /* Digit map */
+    pjmedia_tone_digit_map  *digit_map;
+
+    /* Tone generation state */
+    struct gen_state	state;
+
+    /* Currently played digits: */
+    unsigned		count;		    /* # of digits		*/
+    unsigned		cur_digit;	    /* currently played		*/
+    unsigned		dig_samples;	    /* sample pos in cur digit	*/
+    pjmedia_tone_desc	digits[PJMEDIA_TONEGEN_MAX_DIGITS];/* array of digits*/
+};
+
+
+/* Default digit map is DTMF */
+static pjmedia_tone_digit_map digit_map = 
+{
+    16,
+    {
+	{ '0', 941,  1336 },
+	{ '1', 697,  1209 },
+	{ '2', 697,  1336 },
+	{ '3', 697,  1477 },
+	{ '4', 770,  1209 },
+	{ '5', 770,  1336 },
+	{ '6', 770,  1477 },
+	{ '7', 852,  1209 },
+	{ '8', 852,  1336 },
+	{ '9', 852,  1477 },
+	{ 'a', 697,  1633 },
+	{ 'b', 770,  1633 },
+	{ 'c', 852,  1633 },
+	{ 'd', 941,  1633 },
+	{ '*', 941,  1209 },
+	{ '#', 941,  1477 },
+    }
+};
+
+
+static pj_status_t tonegen_get_frame(pjmedia_port *this_port, 
+				     pjmedia_frame *frame);
+static pj_status_t tonegen_destroy(pjmedia_port *this_port);
+
+/*
+ * Create an instance of tone generator with the specified parameters.
+ * When the tone generator is first created, it will be loaded with the
+ * default digit map.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_create2(pj_pool_t *pool,
+					    const pj_str_t *name,
+					    unsigned clock_rate,
+					    unsigned channel_count,
+					    unsigned samples_per_frame,
+					    unsigned bits_per_sample,
+					    unsigned options,
+					    pjmedia_port **p_port)
+{
+    const pj_str_t STR_TONE_GEN = pj_str("tonegen");
+    struct tonegen  *tonegen;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(pool && clock_rate && channel_count && 
+		     samples_per_frame && bits_per_sample == 16 && 
+		     p_port != NULL, PJ_EINVAL);
+
+    /* Only support mono and stereo */
+    PJ_ASSERT_RETURN(channel_count==1 || channel_count==2, PJ_EINVAL);
+
+    /* Create and initialize port */
+    tonegen = PJ_POOL_ZALLOC_T(pool, struct tonegen);
+    if (name == NULL || name->slen == 0) name = &STR_TONE_GEN;
+    status = pjmedia_port_info_init(&tonegen->base.info, name, 
+				    SIGNATURE, clock_rate, channel_count, 
+				    bits_per_sample, samples_per_frame);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    tonegen->options = options;
+    tonegen->base.get_frame = &tonegen_get_frame;
+    tonegen->base.on_destroy = &tonegen_destroy;
+    tonegen->digit_map = &digit_map;
+
+    tonegen->fade_in_len = PJMEDIA_TONEGEN_FADE_IN_TIME * clock_rate / 1000;
+    tonegen->fade_out_len = PJMEDIA_TONEGEN_FADE_OUT_TIME * clock_rate / 1000;
+
+    /* Lock */
+    if (options & PJMEDIA_TONEGEN_NO_LOCK) {
+	status = pj_lock_create_null_mutex(pool, "tonegen", &tonegen->lock);
+    } else {
+	status = pj_lock_create_simple_mutex(pool, "tonegen", &tonegen->lock);
+    }
+
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
+
+    TRACE_((THIS_FILE, "Tonegen created: %u/%u/%u/%u", clock_rate, 
+	    channel_count, samples_per_frame, bits_per_sample));
+
+    /* Done */
+    *p_port = &tonegen->base;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool,
+					    unsigned clock_rate,
+					    unsigned channel_count,
+					    unsigned samples_per_frame,
+					    unsigned bits_per_sample,
+					    unsigned options,
+					    pjmedia_port **p_port)
+{
+    return pjmedia_tonegen_create2(pool, NULL, clock_rate, channel_count,
+				   samples_per_frame, bits_per_sample, 
+				   options, p_port);
+}
+
+
+/*
+ * Check if the tone generator is still busy producing some tones.
+ */
+PJ_DEF(pj_bool_t) pjmedia_tonegen_is_busy(pjmedia_port *port)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_TRUE);
+    return tonegen->count != 0;
+}
+
+
+/*
+ * Instruct the tone generator to stop current processing.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_stop(pjmedia_port *port)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    TRACE_((THIS_FILE, "tonegen_stop()"));
+
+    pj_lock_acquire(tonegen->lock);
+    tonegen->count = 0;
+    tonegen->cur_digit = 0;
+    tonegen->dig_samples = 0;
+    pj_lock_release(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Instruct the tone generator to stop current processing.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_rewind(pjmedia_port *port)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    TRACE_((THIS_FILE, "tonegen_rewind()"));
+
+    /* Reset back to the first tone */
+    pj_lock_acquire(tonegen->lock);
+    tonegen->cur_digit = 0;
+    tonegen->dig_samples = 0;
+    pj_lock_release(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Callback to destroy tonegen
+ */
+static pj_status_t tonegen_destroy(pjmedia_port *port)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    TRACE_((THIS_FILE, "tonegen_destroy()"));
+
+    pj_lock_acquire(tonegen->lock);
+    pj_lock_release(tonegen->lock);
+
+    pj_lock_destroy(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Fill a frame with tones.
+ */
+static pj_status_t tonegen_get_frame(pjmedia_port *port, 
+				     pjmedia_frame *frame)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    short *dst, *end;
+    unsigned clock_rate = PJMEDIA_PIA_SRATE(&tonegen->base.info);
+
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    pj_lock_acquire(tonegen->lock);
+
+    if (tonegen->count == 0) {
+	/* We don't have digits to play */
+	frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	goto on_return;
+    }
+
+    if (tonegen->cur_digit > tonegen->count) {
+	/* We have played all the digits */
+	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
+	{
+	    /* Reset back to the first tone */
+	    tonegen->cur_digit = 0;
+	    tonegen->dig_samples = 0;
+
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
+	} else {
+	    tonegen->count = 0;
+	    tonegen->cur_digit = 0;
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	    goto on_return;
+	}
+    }
+
+    if (tonegen->dig_samples>=(tonegen->digits[tonegen->cur_digit].on_msec+
+			       tonegen->digits[tonegen->cur_digit].off_msec)*
+			       clock_rate / 1000)
+    {
+	/* We have finished with current digit */
+	tonegen->cur_digit++;
+	tonegen->dig_samples = 0;
+
+	TRACE_((THIS_FILE, "tonegen_get_frame(): next digit"));
+    }
+
+    if (tonegen->cur_digit >= tonegen->count) {
+	/* After we're finished with the last digit, we have played all 
+	 * the digits 
+	 */
+	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
+	{
+	    /* Reset back to the first tone */
+	    tonegen->cur_digit = 0;
+	    tonegen->dig_samples = 0;
+
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
+	} else {
+	    tonegen->count = 0;
+	    tonegen->cur_digit = 0;
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	    goto on_return;
+	}
+    }
+    
+    dst = (short*) frame->buf;
+    end = dst + PJMEDIA_PIA_SPF(&port->info);
+
+    while (dst < end) {
+	pjmedia_tone_desc *dig = &tonegen->digits[tonegen->cur_digit];
+	unsigned required, cnt, on_samp, off_samp;
+
+	required = (unsigned)(end - dst);
+	on_samp = dig->on_msec * clock_rate / 1000;
+	off_samp = dig->off_msec * clock_rate / 1000;
+
+	/* Init tonegen */
+	if (tonegen->dig_samples == 0 && 
+	    (tonegen->count!=1 || !(dig->flags & PJMEDIA_TONE_INITIALIZED)))
+	{
+	    init_generate_tone(&tonegen->state,
+		               PJMEDIA_PIA_SRATE(&port->info),
+			       dig->freq1, dig->freq2, dig->volume);
+	    dig->flags |= PJMEDIA_TONE_INITIALIZED;
+	    if (tonegen->cur_digit > 0) {
+		/* Clear initialized flag of previous digit */
+		tonegen->digits[tonegen->cur_digit-1].flags &= 
+						(~PJMEDIA_TONE_INITIALIZED);
+	    }
+	}
+
+	/* Add tone signal */
+	if (tonegen->dig_samples < on_samp) {
+	    cnt = on_samp - tonegen->dig_samples;
+	    if (cnt > required)
+		cnt = required;
+	    generate_tone(&tonegen->state,
+			  PJMEDIA_PIA_CCNT(&port->info),
+			  cnt, dst);
+
+	    dst += cnt;
+	    tonegen->dig_samples += cnt;
+	    required -= cnt;
+
+	    if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) && 
+		tonegen->dig_samples == cnt) 
+	    {
+		/* Fade in */
+		short *samp = (dst - cnt);
+		short *end;
+
+		if (cnt > tonegen->fade_in_len)
+		    cnt = tonegen->fade_in_len;
+		end = samp + cnt;
+		if (cnt) {
+		    const unsigned step = 0xFFFF / cnt;
+		    unsigned scale = 0;
+
+		    for (; samp < end; ++samp) {
+			(*samp) = (short)(((*samp) * scale) >> 16);
+			scale += step;
+		    }
+		}
+	    } else if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
+			tonegen->dig_samples==on_samp) 
+	    {
+		/* Fade out */
+		if (cnt > tonegen->fade_out_len)
+		    cnt = tonegen->fade_out_len;
+		if (cnt) {
+		    short *samp = (dst - cnt);
+		    const unsigned step = 0xFFFF / cnt;
+		    unsigned scale = 0xFFFF - step;
+
+		    for (; samp < dst; ++samp) {
+			(*samp) = (short)(((*samp) * scale) >> 16);
+			scale -= step;
+		    }
+		}
+	    }
+
+	    if (dst == end)
+		break;
+	}
+
+	/* Add silence signal */
+	cnt = off_samp + on_samp - tonegen->dig_samples;
+	if (cnt > required)
+	    cnt = required;
+	pjmedia_zero_samples(dst, cnt);
+	dst += cnt;
+	tonegen->dig_samples += cnt;
+
+	/* Move to next digit if we're finished with this tone */
+	if (tonegen->dig_samples >= on_samp + off_samp) {
+	    tonegen->cur_digit++;
+	    tonegen->dig_samples = 0;
+
+	    if (tonegen->cur_digit >= tonegen->count) {
+		/* All digits have been played */
+		if ((tonegen->options & PJMEDIA_TONEGEN_LOOP) ||
+		    (tonegen->playback_options & PJMEDIA_TONEGEN_LOOP))
+		{
+		    tonegen->cur_digit = 0;
+		} else {
+		    break;
+		}
+	    }
+	}
+    }
+
+    if (dst < end)
+	pjmedia_zero_samples(dst, (unsigned)(end-dst));
+
+    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    frame->size = PJMEDIA_PIA_AVG_FSZ(&port->info);
+
+    TRACE_((THIS_FILE, "tonegen_get_frame(): frame created, level=%u",
+	    pjmedia_calc_avg_signal((pj_int16_t*)frame->buf, frame->size/2)));
+
+    if (tonegen->cur_digit >= tonegen->count) {
+	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
+	{
+	    /* Reset back to the first tone */
+	    tonegen->cur_digit = 0;
+	    tonegen->dig_samples = 0;
+
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
+	} else {
+	    tonegen->count = 0;
+	    tonegen->cur_digit = 0;
+
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	}
+    }
+
+on_return:
+    pj_lock_release(tonegen->lock);
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Play tones.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_play( pjmedia_port *port,
+					  unsigned count,
+					  const pjmedia_tone_desc tones[],
+					  unsigned options)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
+		     count && tones, PJ_EINVAL);
+
+    /* Don't put more than available buffer */
+    PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
+		     PJ_ETOOMANY);
+
+    pj_lock_acquire(tonegen->lock);
+
+    /* Set playback options */
+    tonegen->playback_options = options;
+    
+    /* Copy digits */
+    pj_memcpy(tonegen->digits + tonegen->count,
+	      tones, count * sizeof(pjmedia_tone_desc));
+    
+    /* Normalize volume, and check if we need to disable fading.
+     * Disable fading if tone off time is zero. Application probably
+     * wants to play this tone continuously (e.g. dial tone).
+     */
+    for (i=0; i<count; ++i) {
+	pjmedia_tone_desc *t = &tonegen->digits[i+tonegen->count];
+	if (t->volume == 0)
+	    t->volume = AMP;
+	else if (t->volume < 0)
+	    t->volume = (short) -t->volume;
+	/* Reset flags */
+	t->flags = 0;
+	if (t->off_msec != 0)
+	    t->flags |= PJMEDIA_TONE_ENABLE_FADE;
+    }
+
+    tonegen->count += count;
+
+    pj_lock_release(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Play digits.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_play_digits( pjmedia_port *port,
+						 unsigned count,
+						 const pjmedia_tone_digit digits[],
+						 unsigned options)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
+    const pjmedia_tone_digit_map *map;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
+		     count && digits, PJ_EINVAL);
+    PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);
+
+    pj_lock_acquire(tonegen->lock);
+
+    map = tonegen->digit_map;
+
+    for (i=0; i<count; ++i) {
+	int d = pj_tolower(digits[i].digit);
+	unsigned j;
+
+	/* Translate ASCII digits with digitmap */
+	for (j=0; j<map->count; ++j) {
+	    if (d == map->digits[j].digit)
+		break;
+	}
+	if (j == map->count) {
+	    pj_lock_release(tonegen->lock);
+	    return PJMEDIA_RTP_EINDTMF;
+	}
+
+	tones[i].freq1 = map->digits[j].freq1;
+	tones[i].freq2 = map->digits[j].freq2;
+	tones[i].on_msec = digits[i].on_msec;
+	tones[i].off_msec = digits[i].off_msec;
+	tones[i].volume = digits[i].volume;
+    }
+
+    pj_lock_release(tonegen->lock);
+
+    return pjmedia_tonegen_play(port, count, tones, options);
+}
+
+
+/*
+ * Get the digit-map currently used by this tone generator.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_get_digit_map(pjmedia_port *port,
+						  const pjmedia_tone_digit_map **m)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
+
+    *m = tonegen->digit_map;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set digit map to be used by the tone generator.
+ */
+PJ_DEF(pj_status_t) pjmedia_tonegen_set_digit_map(pjmedia_port *port,
+						  pjmedia_tone_digit_map *m)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
+
+    pj_lock_acquire(tonegen->lock);
+
+    tonegen->digit_map = m;
+
+    pj_lock_release(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
+
+