* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/d1/d130731c0885ba91c8535c26a2ad78c66bc8b681.svn-base b/jni/pjproject-android/.svn/pristine/d1/d130731c0885ba91c8535c26a2ad78c66bc8b681.svn-base
new file mode 100644
index 0000000..ad6df03
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d130731c0885ba91c8535c26a2ad78c66bc8b681.svn-base
@@ -0,0 +1,63 @@
+#
+# Include host/target/compiler selection.
+# This will export CC_NAME, MACHINE_NAME, OS_NAME, and HOST_NAME variables.
+#
+include $(PJDIR)/build.mak
+
+#
+# Include global compiler specific definitions
+#
+include $(PJDIR)/build/cc-$(CC_NAME).mak
+
+#
+# (Optionally) Include compiler specific configuration that is
+# specific to this project. This configuration file is
+# located in this directory.
+#
+-include cc-$(CC_NAME).mak
+
+#
+# Include auto configured compiler specification.
+# This will override the compiler settings above.
+# Currently this is made OPTIONAL, to prevent people
+# from getting errors because they don't re-run ./configure
+# after downloading new PJSIP.
+#
+-include $(PJDIR)/build/cc-auto.mak
+
+#
+# Include global machine specific definitions
+#
+include $(PJDIR)/build/m-$(MACHINE_NAME).mak
+-include m-$(MACHINE_NAME).mak
+
+#
+# Include target OS specific definitions
+#
+include $(PJDIR)/build/os-$(OS_NAME).mak
+
+#
+# (Optionally) Include target OS specific configuration that is
+# specific to this project. This configuration file is
+# located in this directory.
+#
+-include os-$(OS_NAME).mak
+
+#
+# Include host specific definitions
+#
+include $(PJDIR)/build/host-$(HOST_NAME).mak
+
+#
+# (Optionally) Include host specific configuration that is
+# specific to this project. This configuration file is
+# located in this directory.
+#
+-include host-$(HOST_NAME).mak
+
+#
+# Include global user configuration, if any
+#
+-include $(PJDIR)/user.mak
+
+
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1a2098f7ecb8f23d38e3b9c51f905ec5df31963.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1a2098f7ecb8f23d38e3b9c51f905ec5df31963.svn-base
new file mode 100644
index 0000000..7b14884
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1a2098f7ecb8f23d38e3b9c51f905ec5df31963.svn-base
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>

+<!DOCTYPE scenario SYSTEM "sipp.dtd">

+

+<!-- 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             -->

+<!--                                                                    -->

+<!--                                                                    -->

+

+<scenario name="UAC OPTIONS">

+  <!-- UAC with bad ACK causes assertion with pjsip 1.4			-->

+  <send retrans="500">

+    <![CDATA[

+

+      OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0

+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]

+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]

+      To: sut <sip:[service]@[remote_ip]:[remote_port]>

+      Call-ID: [call_id]

+      CSeq: 1 OPTIONS

+      Contact: sip:sipp@[local_ip]:[local_port]

+      Max-Forwards: 70

+      Subject: Performance Test

+      Content-Length: [len]

+

+    ]]>

+  </send>

+

+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->

+  <!-- are saved and used for following messages sent. Useful to test   -->

+  <!-- against stateful SIP proxies/B2BUAs.                             -->

+  <recv response="200" rtd="true">

+  </recv>

+

+

+  <!-- 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/d1/d1b3040600e50bfd82ea0ed30fa0940269a07e8d.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1b3040600e50bfd82ea0ed30fa0940269a07e8d.svn-base
new file mode 100644
index 0000000..80c7a33
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1b3040600e50bfd82ea0ed30fa0940269a07e8d.svn-base
@@ -0,0 +1,447 @@
+/* $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 __PJSIP_SIP_REG_H__
+#define __PJSIP_SIP_REG_H__
+
+/**
+ * @file sip_regc.h
+ * @brief SIP Registration Client
+ */
+
+#include <pjsip/sip_types.h>
+#include <pjsip/sip_auth.h>
+#include <pjsip/sip_transport.h>
+
+
+/**
+ * @defgroup PJSUA_REGC Client Registration
+ * @ingroup PJSIP_HIGH_UA
+ * @brief High Layer API for performing client registration.
+ * @{
+ *
+ * This provides API for performing client registration. Application must
+ * link with  <b>pjsip-ua</b> static library to use this API.
+
+ */
+
+
+PJ_BEGIN_DECL
+
+/** Typedef for client registration data. */
+typedef struct pjsip_regc pjsip_regc;
+
+/** Maximum contacts in registration. */
+#define PJSIP_REGC_MAX_CONTACT	10
+
+/** Expiration not specified. */
+#define PJSIP_REGC_EXPIRATION_NOT_SPECIFIED	((pj_uint32_t)0xFFFFFFFFUL)
+
+/** Buffer to hold all contacts. */
+#define PJSIP_REGC_CONTACT_BUF_SIZE	512
+
+/** Structure to hold parameters when calling application's callback.
+ *  The application's callback is called when the client registration process
+ *  has finished.
+ */
+struct pjsip_regc_cbparam
+{
+    pjsip_regc		*regc;	    /**< Client registration structure.	    */
+    void		*token;	    /**< Arbitrary token set by application */
+
+    /** Error status. If this value is non-PJ_SUCCESS, some error has occured.
+     *  Note that even when this contains PJ_SUCCESS the registration might
+     *  have failed; in this case the \a code field will contain non
+     *  successful (non-2xx status class) code
+     */
+    pj_status_t		 status;
+    int			 code;	    /**< SIP status code received.	    */
+    pj_str_t		 reason;    /**< SIP reason phrase received.	    */
+    pjsip_rx_data	*rdata;	    /**< The complete received response.    */
+    int			 expiration;/**< Next expiration interval.	    */
+    int			 contact_cnt;/**<Number of contacts in response.    */
+    pjsip_contact_hdr	*contact[PJSIP_REGC_MAX_CONTACT]; /**< Contacts.    */
+};
+
+
+/** Type declaration for callback to receive registration result. */
+typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param);
+
+/**
+ * Structure to hold parameters when calling application's callback
+ * specified in #pjsip_regc_set_reg_tsx_cb().
+ * To update contact address, application can set the field contact_cnt
+ * and contact inside the callback.
+ */
+struct pjsip_regc_tsx_cb_param
+{
+    struct pjsip_regc_cbparam   cbparam;
+    int                         contact_cnt;
+    pj_str_t                    contact[PJSIP_REGC_MAX_CONTACT];
+};
+
+/** Type declaration for callback set in #pjsip_regc_set_reg_tsx_cb(). */
+typedef void pjsip_regc_tsx_cb(struct pjsip_regc_tsx_cb_param *param);
+
+/**
+ * Client registration information.
+ */
+struct pjsip_regc_info
+{
+    pj_str_t	server_uri; /**< Server URI,				    */
+    pj_str_t	client_uri; /**< Client URI (From header).		    */
+    pj_bool_t	is_busy;    /**< Have pending transaction?		    */
+    pj_bool_t	auto_reg;   /**< Will register automatically?		    */
+    int		interval;   /**< Registration interval (seconds).	    */
+    int		next_reg;   /**< Time until next registration (seconds).    */
+    pjsip_transport *transport; /**< Last transport used.		    */
+};
+
+/**
+ * @see pjsip_regc_info
+ */
+typedef struct pjsip_regc_info pjsip_regc_info;
+
+
+/**
+ * Get the module instance for client registration module.
+ *
+ * @return	    client registration module.
+ */
+PJ_DECL(pjsip_module*) pjsip_regc_get_module(void);
+
+
+/**
+ * Create client registration structure.
+ *
+ * @param endpt	    Endpoint, used to allocate pool from.
+ * @param token	    A data to be associated with the client registration struct.
+ * @param cb	    Pointer to callback function to receive registration status.
+ * @param p_regc    Pointer to receive client registration structure.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
+				        pjsip_regc_cb *cb, 
+					pjsip_regc **p_regc);
+
+
+/**
+ * Destroy client registration structure. If a registration transaction is
+ * in progress, then the structure will be deleted only after a final response
+ * has been received, and in this case, the callback won't be called.
+ *
+ * @param regc	    The client registration structure.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc);
+
+/**
+ * Get registration info.
+ *
+ * @param regc	    The client registration structure.
+ * @param info	    Client registration info.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
+					  pjsip_regc_info *info );
+
+
+/**
+ * Get the memory pool associated with a registration client handle.
+ *
+ * @param regc	    The client registration structure.
+ * @return pool	    handle.
+ */
+PJ_DECL(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc);
+
+/**
+ * Initialize client registration structure with various information needed to
+ * perform the registration.
+ *
+ * @param regc	    The client registration structure.
+ * @param srv_url   Server URL.
+ * @param from_url  The person performing the registration, must be a SIP URL type.
+ * @param to_url    The address of record for which the registration is targetd, must
+ *		    be a SIP/SIPS URL.
+ * @param ccnt	    Number of contacts in the array.
+ * @param contact   Array of contacts, each contact item must be formatted
+ *		    as described in RFC 3261 Section 20.10:
+ *		    When the header field value contains a display 
+ *		    name, the URI including all URI parameters is 
+ *		    enclosed in "<" and ">".  If no "<" and ">" are 
+ *		    present, all parameters after the URI are header
+ *		    parameters, not URI parameters.  The display name 
+ *		    can be tokens, or a quoted string, if a larger 
+ *		    character set is desired.
+ * @param expires   Default expiration interval (in seconds) to be applied for
+ *		    contact URL that doesn't have expiration settings. If the
+ *		    value PJSIP_REGC_EXPIRATION_NOT_SPECIFIED is given, then 
+ *		    no default expiration will be applied.
+ * @return	    zero on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_init(pjsip_regc *regc,
+				     const pj_str_t *srv_url,
+				     const pj_str_t *from_url,
+				     const pj_str_t *to_url,
+				     int ccnt,
+				     const pj_str_t contact[],
+				     pj_uint32_t expires);
+
+/**
+ * Set callback to be called when the registration received a final response.
+ * This callback is different with the one specified during creation via
+ * #pjsip_regc_create(). This callback will be called for any final response
+ * (including 401/407/423) and before any subsequent requests are sent.
+ * In case of unregistration, this callback will not be called.
+ *
+ * @param regc	    The client registration structure.
+ * @param tsx_cb    Pointer to callback function to receive registration status.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_reg_tsx_cb(pjsip_regc *regc,
+				               pjsip_regc_tsx_cb *tsx_cb);
+
+/**
+ * Set the "sent-by" field of the Via header for outgoing requests.
+ *
+ * @param regc	    The client registration structure.
+ * @param via_addr  Set via_addr to use for the Via header or NULL to use
+ *                  the transport's published name.
+ * @param via_tp    via_addr will only be used if we are using via_tp
+ *                  transport.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_via_sent_by(pjsip_regc *regc,
+				                pjsip_host_port *via_addr,
+                                                pjsip_transport *via_tp);
+
+/**
+ * Set the number of seconds to refresh the client registration before
+ * the registration expires.
+ *
+ * @param regc	    The registration structure.
+ * @param delay     The number of seconds to refresh the client
+ *                  registration before the registration expires.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t)
+pjsip_regc_set_delay_before_refresh( pjsip_regc *regc,
+				     pj_uint32_t delay );
+
+
+/**
+ * Set authentication credentials to use by this registration.
+ *
+ * @param regc	    The registration structure.
+ * @param count	    Number of credentials in the array.
+ * @param cred	    Array of credentials.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
+						 int count,
+						 const pjsip_cred_info cred[] );
+
+/**
+ * Set authentication preference.
+ *
+ * @param regc	    The registration structure.
+ * @param pref	    Authentication preference.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_prefs( pjsip_regc *regc,
+					   const pjsip_auth_clt_pref *pref);
+
+/**
+ * Set route set to be used for outgoing requests.
+ *
+ * @param regc	    The client registration structure.
+ * @param route_set List containing Route headers.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_route_set(pjsip_regc *regc,
+					      const pjsip_route_hdr*route_set);
+
+
+/**
+ * Lock/bind client registration to a specific transport/listener. 
+ * This is optional, as normally transport will be selected automatically
+ * based on the destination of requests upon resolver completion. 
+ * When the client registration is explicitly bound to the specific 
+ * transport/listener, all UAC transactions originated by the client
+ * registration will use the specified transport/listener when sending 
+ * outgoing requests.
+ *
+ * Note that this doesn't affect the Contact header set for this client
+ * registration. Application must manually update the Contact header if
+ * necessary, to adjust the address according to the transport being
+ * selected.
+ *
+ * @param regc	    The client registration instance.
+ * @param sel	    Transport selector containing the specification of
+ *		    transport or listener to be used by this session
+ *		    to send requests.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_transport(pjsip_regc *regc,
+					      const pjsip_tpselector *sel);
+
+/**
+ * Release the reference to current transport being used by the regc, if any.
+ * The regc keeps the reference to the last transport being used in order
+ * to prevent it from being destroyed. In some situation however, such as
+ * when the transport is disconnected, it is necessary to instruct the
+ * regc to release this reference so that the transport can be destroyed.
+ * See https://trac.pjsip.org/repos/ticket/1481 for background info.
+ *
+ * @param regc	    The client registration instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_release_transport(pjsip_regc *regc);
+
+/**
+ * Add headers to be added to outgoing REGISTER requests.
+ *
+ * @param regc	    The client registration structure.
+ * @param hdr_list  List containing SIP headers to be added for all outgoing
+ *		    REGISTER requests.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_add_headers(pjsip_regc *regc,
+					    const pjsip_hdr *hdr_list);
+
+
+/**
+ * Create REGISTER request for the specified client registration structure.
+ *
+ * After successfull registration, application can inspect the contacts in
+ * the client registration structure to list what contacts are associaciated
+ * with the address of record being targeted in the registration.
+ *
+ * @param regc	    The client registration structure.
+ * @param autoreg   If non zero, the library will automatically refresh the
+ *		    next registration until application unregister.
+ * @param p_tdata   Pointer to receive the REGISTER request.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
+					 pjsip_tx_data **p_tdata);
+
+
+/**
+ * Create REGISTER request to unregister the contacts that were previously
+ * registered by this client registration.
+ *
+ * @param regc	    The client registration structure.
+ * @param p_tdata   Pointer to receive the REGISTER request.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
+					   pjsip_tx_data **p_tdata);
+
+/**
+ * Create REGISTER request to unregister all contacts from server records.
+ * Note that this will unregister all registered contact for the AOR
+ * including contacts registered by other user agents. To only unregister
+ * contact registered by this client registration instance, use
+ * #pjsip_regc_unregister() instead.
+ *
+ * @param regc	    The client registration structure.
+ * @param p_tdata   Pointer to receive the REGISTER request.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_unregister_all(pjsip_regc *regc,
+					       pjsip_tx_data **p_tdata);
+
+/**
+ * Update Contact details in the client registration structure. For each
+ * contact, if the contact is not found in existing contact, it will be
+ * added to the Contact list. If it matches existing contact, nothing
+ * will be added. This function will also mark existing contacts which
+ * are not specified in the new contact list as to be removed, by adding
+ * "expires=0" parameter to these contacts.
+ *
+ * Once the contact list has been updated, application must update the
+ * registration by creating a new REGISTER request and send it to the
+ * registrar. This request will contain both old and new contacts; the
+ * old contacts will have it's expires parameter set to zero to instruct
+ * the registrar to remove the bindings.
+ *
+ * @param regc	    The client registration structure.
+ * @param ccnt	    Number of contacts.
+ * @param contact   Array of contacts, each contact item must be formatted
+ *		    as described in RFC 3261 Section 20.10:
+ *		    When the header field value contains a display 
+ *		    name, the URI including all URI parameters is 
+ *		    enclosed in "<" and ">".  If no "<" and ">" are 
+ *		    present, all parameters after the URI are header
+ *		    parameters, not URI parameters.  The display name 
+ *		    can be tokens, or a quoted string, if a larger 
+ *		    character set is desired.
+ * @return	    PJ_SUCCESS if sucessfull.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,
+					        int ccnt,
+						const pj_str_t contact[] );
+
+/**
+ * Update the expires value. The next REGISTER request will contain
+ * new expires value for the registration.
+ *
+ * @param regc	    The client registration structure.
+ * @param expires   The new expires value.
+ * @return	    zero on successfull.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,
+					        pj_uint32_t expires );
+
+/**
+ * Sends outgoing REGISTER request.
+ * The process will complete asynchronously, and application
+ * will be notified via the callback when the process completes.
+ *
+ * @param regc	    The client registration structure.
+ * @param tdata	    Transmit data.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata);
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+#endif	/* __PJSIP_REG_H__ */
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1b3fbfd488daa2c787af5717ec33597ec869c8b.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1b3fbfd488daa2c787af5717ec33597ec869c8b.svn-base
new file mode 100644
index 0000000..ca8102a
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1b3fbfd488daa2c787af5717ec33597ec869c8b.svn-base
@@ -0,0 +1,729 @@
+/* $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-codec/l16.h>
+#include <pjmedia/codec.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/endpoint.h>
+#include <pjmedia/plc.h>
+#include <pjmedia/silencedet.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/sock.h>
+#include <pj/string.h>
+
+
+/*
+ * Only build this file if PJMEDIA_HAS_L16_CODEC != 0
+ */
+#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
+
+#define PLC_DISABLED	0
+
+
+static const pj_str_t STR_L16 = { "L16", 3 };
+
+/* To keep frame size below 1400 MTU, set ptime to 10ms for
+ * sampling rate > 35 KHz
+ */
+#define GET_PTIME(clock_rate)	((pj_uint16_t)(clock_rate > 35000 ? 10 : 20))
+
+
+/* Prototypes for L16 factory */
+static pj_status_t l16_test_alloc( pjmedia_codec_factory *factory, 
+				    const pjmedia_codec_info *id );
+static pj_status_t l16_default_attr( pjmedia_codec_factory *factory, 
+				      const pjmedia_codec_info *id, 
+				      pjmedia_codec_param *attr );
+static pj_status_t l16_enum_codecs (pjmedia_codec_factory *factory, 
+				     unsigned *count, 
+				     pjmedia_codec_info codecs[]);
+static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory, 
+				     const pjmedia_codec_info *id, 
+				     pjmedia_codec **p_codec);
+static pj_status_t l16_dealloc_codec( pjmedia_codec_factory *factory, 
+				       pjmedia_codec *codec );
+
+/* Prototypes for L16 implementation. */
+static pj_status_t  l16_init( pjmedia_codec *codec, 
+			       pj_pool_t *pool );
+static pj_status_t  l16_open( pjmedia_codec *codec, 
+			      pjmedia_codec_param *attr );
+static pj_status_t  l16_close( pjmedia_codec *codec );
+static pj_status_t  l16_modify(pjmedia_codec *codec, 
+			       const pjmedia_codec_param *attr );
+static pj_status_t  l16_parse(pjmedia_codec *codec,
+			      void *pkt,
+			      pj_size_t pkt_size,
+			      const pj_timestamp *ts,
+			      unsigned *frame_cnt,
+			      pjmedia_frame frames[]);
+static pj_status_t  l16_encode( pjmedia_codec *codec, 
+				 const struct pjmedia_frame *input,
+				 unsigned output_buf_len, 
+				 struct pjmedia_frame *output);
+static pj_status_t  l16_decode( pjmedia_codec *codec, 
+				 const struct pjmedia_frame *input,
+				 unsigned output_buf_len, 
+				 struct pjmedia_frame *output);
+#if !PLC_DISABLED
+static pj_status_t  l16_recover(pjmedia_codec *codec,
+				unsigned output_buf_len,
+				struct pjmedia_frame *output);
+#endif
+
+/* Definition for L16 codec operations. */
+static pjmedia_codec_op l16_op = 
+{
+    &l16_init,
+    &l16_open,
+    &l16_close,
+    &l16_modify,
+    &l16_parse,
+    &l16_encode,
+    &l16_decode,
+#if !PLC_DISABLED
+    &l16_recover
+#else
+    NULL
+#endif
+};
+
+/* Definition for L16 codec factory operations. */
+static pjmedia_codec_factory_op l16_factory_op =
+{
+    &l16_test_alloc,
+    &l16_default_attr,
+    &l16_enum_codecs,
+    &l16_alloc_codec,
+    &l16_dealloc_codec,
+    &pjmedia_codec_l16_deinit
+};
+
+/* L16 factory private data */
+static struct l16_factory
+{
+    pjmedia_codec_factory	base;
+    pjmedia_endpt	       *endpt;
+    pj_pool_t		       *pool;
+    pj_mutex_t		       *mutex;
+} l16_factory;
+
+
+/* L16 codec private data. */
+struct l16_data
+{
+    pj_pool_t		*pool;
+    unsigned		 frame_size;    /* Frame size, in bytes */
+    unsigned		 clock_rate;    /* Clock rate */
+
+#if !PLC_DISABLED
+    pj_bool_t		 plc_enabled;
+    pjmedia_plc		*plc;
+#endif
+    pj_bool_t		 vad_enabled;
+    pjmedia_silence_det	*vad;
+    pj_timestamp	 last_tx;
+};
+
+
+
+PJ_DEF(pj_status_t) pjmedia_codec_l16_init(pjmedia_endpt *endpt,
+					   unsigned options)
+{
+    pjmedia_codec_mgr *codec_mgr;
+    pj_status_t status;
+
+
+    PJ_UNUSED_ARG(options);
+
+
+    if (l16_factory.endpt != NULL) {
+	/* Already initialized. */
+	return PJ_SUCCESS;
+    }
+
+    /* Init factory */
+    l16_factory.base.op = &l16_factory_op;
+    l16_factory.base.factory_data = NULL;
+    l16_factory.endpt = endpt;
+
+    /* Create pool */
+    l16_factory.pool = pjmedia_endpt_create_pool(endpt, "l16", 4000, 4000);
+    if (!l16_factory.pool)
+	return PJ_ENOMEM;
+
+    /* Create mutex. */
+    status = pj_mutex_create_simple(l16_factory.pool, "l16", 
+				    &l16_factory.mutex);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Get the codec manager. */
+    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
+    if (!codec_mgr) {
+	return PJ_EINVALIDOP;
+    }
+
+    /* Register codec factory to endpoint. */
+    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
+						&l16_factory.base);
+    if (status != PJ_SUCCESS)
+	return status;
+
+
+    return PJ_SUCCESS;
+
+on_error:
+    if (l16_factory.mutex) {
+	pj_mutex_destroy(l16_factory.mutex);
+	l16_factory.mutex = NULL;
+    }
+    if (l16_factory.pool) {
+	pj_pool_release(l16_factory.pool);
+	l16_factory.pool = NULL;
+    }
+    return status;
+}
+
+PJ_DEF(pj_status_t) pjmedia_codec_l16_deinit(void)
+{
+    pjmedia_codec_mgr *codec_mgr;
+    pj_status_t status;
+
+    if (l16_factory.endpt == NULL) {
+	/* Not registered. */
+	return PJ_SUCCESS;
+    }
+
+    /* Lock mutex. */
+    pj_mutex_lock(l16_factory.mutex);
+
+    /* Get the codec manager. */
+    codec_mgr = pjmedia_endpt_get_codec_mgr(l16_factory.endpt);
+    if (!codec_mgr) {
+	l16_factory.endpt = NULL;
+	pj_mutex_unlock(l16_factory.mutex);
+	return PJ_EINVALIDOP;
+    }
+
+    /* Unregister L16 codec factory. */
+    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
+						  &l16_factory.base);
+    l16_factory.endpt = NULL;
+
+    /* Destroy mutex. */
+    pj_mutex_destroy(l16_factory.mutex);
+    l16_factory.mutex = NULL;
+
+
+    /* Release pool. */
+    pj_pool_release(l16_factory.pool);
+    l16_factory.pool = NULL;
+
+
+    return status;
+}
+
+static pj_status_t l16_test_alloc(pjmedia_codec_factory *factory, 
+				  const pjmedia_codec_info *id )
+{
+    PJ_UNUSED_ARG(factory);
+
+    if (pj_stricmp(&id->encoding_name, &STR_L16)==0) {
+	/* Match! */
+	return PJ_SUCCESS;
+    }
+
+    return -1;
+}
+
+static pj_status_t l16_default_attr( pjmedia_codec_factory *factory, 
+				     const pjmedia_codec_info *id, 
+				     pjmedia_codec_param *attr )
+{
+    PJ_UNUSED_ARG(factory);
+
+    pj_bzero(attr, sizeof(pjmedia_codec_param));
+    attr->info.pt = (pj_uint8_t)id->pt;
+    attr->info.clock_rate = id->clock_rate;
+    attr->info.channel_cnt = id->channel_cnt;
+    attr->info.avg_bps = id->clock_rate * id->channel_cnt * 16;
+    attr->info.max_bps = attr->info.avg_bps;
+    attr->info.pcm_bits_per_sample = 16;
+
+    /* To keep frame size below 1400 MTU, set ptime to 10ms for
+     * sampling rate > 35 KHz
+     */
+    attr->info.frm_ptime = GET_PTIME(id->clock_rate);
+
+    attr->setting.frm_per_pkt = 1;
+
+    attr->setting.vad = 1;
+#if !PLC_DISABLED
+    attr->setting.plc = 1;
+#endif
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory, 
+				    unsigned *max_count, 
+				    pjmedia_codec_info codecs[])
+{
+    unsigned count = 0;
+
+    PJ_UNUSED_ARG(factory);
+
+    if (count < *max_count) {
+	/* Register 44100Hz 1 channel L16 codec */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_1;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 44100;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* Register 44100Hz 2 channels L16 codec */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_2;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 44100;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 8KHz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 8000;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 8KHz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 8000;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+
+// disable some L16 modes
+#if 0
+    if (count < *max_count) {
+	/* 11025 Hz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 11025;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 11025 Hz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 11025;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+#endif
+
+    if (count < *max_count) {
+	/* 16000 Hz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 16000;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+
+    if (count < *max_count) {
+	/* 16000 Hz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 16000;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+
+// disable some L16 modes
+#if 0
+    if (count < *max_count) {
+	/* 22050 Hz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 22050;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+
+    if (count < *max_count) {
+	/* 22050 Hz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 22050;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 32000 Hz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 32000;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 32000 Hz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 32000;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 48KHz mono */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 48000;
+	codecs[count].channel_cnt = 1;
+	++count;
+    }
+
+    if (count < *max_count) {
+	/* 48KHz stereo */
+	codecs[count].type = PJMEDIA_TYPE_AUDIO;
+	codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_STEREO;
+	codecs[count].encoding_name = STR_L16;
+	codecs[count].clock_rate = 48000;
+	codecs[count].channel_cnt = 2;
+	++count;
+    }
+#endif
+
+
+    *max_count = count;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory, 
+				    const pjmedia_codec_info *id,
+				    pjmedia_codec **p_codec)
+{
+    pjmedia_codec *codec = NULL;
+    struct l16_data *data;
+    unsigned ptime;
+    pj_pool_t *pool;
+
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
+
+    /* Lock mutex. */
+    pj_mutex_lock(l16_factory.mutex);
+
+
+    pool = pjmedia_endpt_create_pool(l16_factory.endpt, "l16", 4000, 4000);
+    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
+    codec->codec_data = pj_pool_alloc(pool, sizeof(struct l16_data));
+    codec->factory = factory;
+    codec->op = &l16_op;
+
+    /* Init private data */
+    ptime = GET_PTIME(id->clock_rate);
+    data = (struct l16_data*) codec->codec_data;
+    data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
+    data->clock_rate = id->clock_rate;
+    data->pool = pool;
+
+#if !PLC_DISABLED
+    /* Create PLC */
+    status = pjmedia_plc_create(pool, id->clock_rate, 
+				data->frame_size >> 1, 0, 
+				&data->plc);
+    if (status != PJ_SUCCESS) {
+	pj_mutex_unlock(l16_factory.mutex);
+	return status;
+    }
+#endif
+
+    /* Create silence detector */
+    status = pjmedia_silence_det_create(pool, id->clock_rate, 
+					data->frame_size >> 1,
+					&data->vad);
+    if (status != PJ_SUCCESS) {
+	pj_mutex_unlock(l16_factory.mutex);
+	return status;
+    }
+
+    *p_codec = codec;
+
+    /* Unlock mutex. */
+    pj_mutex_unlock(l16_factory.mutex);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory, 
+				     pjmedia_codec *codec )
+{
+    struct l16_data *data;
+
+    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
+    PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
+
+    /* Lock mutex. */
+    pj_mutex_lock(l16_factory.mutex);
+
+    /* Just release codec data pool */
+    data = (struct l16_data*) codec->codec_data;
+    pj_assert(data);
+    pj_pool_release(data->pool);
+
+    /* Unlock mutex. */
+    pj_mutex_unlock(l16_factory.mutex);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_init( pjmedia_codec *codec, pj_pool_t *pool )
+{
+    /* There's nothing to do here really */
+    PJ_UNUSED_ARG(codec);
+    PJ_UNUSED_ARG(pool);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_open(pjmedia_codec *codec, 
+			    pjmedia_codec_param *attr )
+{
+    struct l16_data *data = NULL;
+    
+    PJ_ASSERT_RETURN(codec && codec->codec_data && attr, PJ_EINVAL);
+
+    data = (struct l16_data*) codec->codec_data;
+
+    data->vad_enabled = (attr->setting.vad != 0);
+#if !PLC_DISABLED
+    data->plc_enabled = (attr->setting.plc != 0);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_close( pjmedia_codec *codec )
+{
+    PJ_UNUSED_ARG(codec);
+    /* Nothing to do */
+    return PJ_SUCCESS;
+}
+
+static pj_status_t  l16_modify(pjmedia_codec *codec, 
+			       const pjmedia_codec_param *attr )
+{
+    struct l16_data *data = (struct l16_data*) codec->codec_data;
+
+    pj_assert(data != NULL);
+
+    data->vad_enabled = (attr->setting.vad != 0);
+#if !PLC_DISABLED
+    data->plc_enabled = (attr->setting.plc != 0);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t  l16_parse( pjmedia_codec *codec,
+			       void *pkt,
+			       pj_size_t pkt_size,
+			       const pj_timestamp *ts,
+			       unsigned *frame_cnt,
+			       pjmedia_frame frames[])
+{
+    unsigned count = 0;
+    struct l16_data *data = (struct l16_data*) codec->codec_data;
+
+    PJ_UNUSED_ARG(codec);
+    PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
+
+    while (pkt_size >= data->frame_size && count < *frame_cnt) {
+	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frames[count].buf = pkt;
+	frames[count].size = data->frame_size;
+	frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size);
+
+	pkt = ((char*)pkt) + data->frame_size;
+	pkt_size -= data->frame_size;
+
+	++count;
+    }
+
+    *frame_cnt = count;
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_encode(pjmedia_codec *codec, 
+			      const struct pjmedia_frame *input,
+			      unsigned output_buf_len, 
+			      struct pjmedia_frame *output)
+{
+    struct l16_data *data = (struct l16_data*) codec->codec_data;
+    const pj_int16_t *samp = (const pj_int16_t*) input->buf;
+    const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
+    pj_int16_t *samp_out = (pj_int16_t*) output->buf;    
+
+    pj_assert(data && input && output);
+
+    /* Check output buffer length */
+    if (output_buf_len < input->size)
+	return PJMEDIA_CODEC_EFRMTOOSHORT;
+
+    /* Detect silence */
+    if (data->vad_enabled) {
+	pj_bool_t is_silence;
+	pj_int32_t silence_duration;
+
+	silence_duration = pj_timestamp_diff32(&data->last_tx, 
+					       &input->timestamp);
+
+	is_silence = pjmedia_silence_det_detect(data->vad, 
+					        (const pj_int16_t*) input->buf,
+						(input->size >> 1),
+						NULL);
+	if (is_silence &&
+	    (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
+	     silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*
+			        (int)data->clock_rate/1000))
+	{
+	    output->type = PJMEDIA_FRAME_TYPE_NONE;
+	    output->buf = NULL;
+	    output->size = 0;
+	    output->timestamp = input->timestamp;
+	    return PJ_SUCCESS;
+	} else {
+	    data->last_tx = input->timestamp;
+	}
+    }
+
+    /* Encode */
+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
+    while (samp!=samp_end)
+	*samp_out++ = pj_htons(*samp++);
+#else
+    pjmedia_copy_samples(samp_out, samp, input->size >> 1);
+#endif
+
+
+    /* Done */
+    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    output->size = input->size;
+    output->timestamp = input->timestamp;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t l16_decode(pjmedia_codec *codec, 
+			      const struct pjmedia_frame *input,
+			      unsigned output_buf_len, 
+			      struct pjmedia_frame *output)
+{
+    struct l16_data *l16_data = (struct l16_data*) codec->codec_data;
+    const pj_int16_t *samp = (const pj_int16_t*) input->buf;
+    const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
+    pj_int16_t *samp_out = (pj_int16_t*) output->buf;    
+
+    pj_assert(l16_data != NULL);
+    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
+
+
+    /* Check output buffer length */
+    if (output_buf_len < input->size)
+	return PJMEDIA_CODEC_EPCMTOOSHORT;
+
+
+    /* Decode */
+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
+    while (samp!=samp_end)
+	*samp_out++ = pj_ntohs(*samp++);
+#else
+    pjmedia_copy_samples(samp_out, samp, input->size >> 1);
+#endif
+
+
+    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    output->size = input->size;
+    output->timestamp = input->timestamp;
+
+#if !PLC_DISABLED
+    if (l16_data->plc_enabled)
+	pjmedia_plc_save( l16_data->plc, (pj_int16_t*)output->buf);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+#if !PLC_DISABLED
+/*
+ * Recover lost frame.
+ */
+static pj_status_t  l16_recover(pjmedia_codec *codec,
+				      unsigned output_buf_len,
+				      struct pjmedia_frame *output)
+{
+    struct l16_data *data = (struct l16_data*) codec->codec_data;
+
+    PJ_ASSERT_RETURN(data->plc_enabled, PJ_EINVALIDOP);
+
+    PJ_ASSERT_RETURN(output_buf_len >= data->frame_size, 
+		     PJMEDIA_CODEC_EPCMTOOSHORT);
+
+    pjmedia_plc_generate(data->plc, (pj_int16_t*)output->buf);
+    output->size = data->frame_size;
+
+    return PJ_SUCCESS;
+}
+#endif
+
+#endif	/* PJMEDIA_HAS_L16_CODEC */
+
+
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1bfce91c2421aff7acf1836b0f9b5c8749d861c.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1bfce91c2421aff7acf1836b0f9b5c8749d861c.svn-base
new file mode 100644
index 0000000..3a66c09
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1bfce91c2421aff7acf1836b0f9b5c8749d861c.svn-base
@@ -0,0 +1,496 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
+	<data>
+		<int key="IBDocument.SystemTarget">784</int>
+		<string key="IBDocument.SystemVersion">10C540</string>
+		<string key="IBDocument.InterfaceBuilderVersion">740</string>
+		<string key="IBDocument.AppKitVersion">1038.25</string>
+		<string key="IBDocument.HIToolboxVersion">458.00</string>
+		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+			<string key="NS.object.0">62</string>
+		</object>
+		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+			<bool key="EncodedWithXMLCoder">YES</bool>
+			<integer value="1"/>
+		</object>
+		<object class="NSArray" key="IBDocument.PluginDependencies">
+			<bool key="EncodedWithXMLCoder">YES</bool>
+			<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+		</object>
+		<object class="NSMutableDictionary" key="IBDocument.Metadata">
+			<bool key="EncodedWithXMLCoder">YES</bool>
+			<object class="NSArray" key="dict.sortedKeys" id="0">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+			</object>
+			<object class="NSMutableArray" key="dict.values">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+			</object>
+		</object>
+		<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+			<bool key="EncodedWithXMLCoder">YES</bool>
+			<object class="IBProxyObject" id="372490531">
+				<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+			</object>
+			<object class="IBProxyObject" id="711762367">
+				<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+			</object>
+			<object class="IBUIView" id="191373211">
+				<reference key="NSNextResponder"/>
+				<int key="NSvFlags">292</int>
+				<object class="NSMutableArray" key="NSSubviews">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+					<object class="IBUITextView" id="613869543">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">274</int>
+						<string key="NSFrameSize">{320, 358}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<bool key="IBUIMultipleTouchEnabled">YES</bool>
+						<bool key="IBUIShowsHorizontalScrollIndicator">NO</bool>
+						<bool key="IBUIDelaysContentTouches">NO</bool>
+						<bool key="IBUICanCancelContentTouches">NO</bool>
+						<bool key="IBUIBouncesZoom">NO</bool>
+						<string key="IBUIText">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
+						<object class="IBUITextInputTraits" key="IBUITextInputTraits">
+							<int key="IBUIAutocapitalizationType">2</int>
+						</object>
+					</object>
+					<object class="IBUIButton" id="669764012">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">292</int>
+						<string key="NSFrame">{{228, 366}, {72, 37}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+						<int key="IBUIContentHorizontalAlignment">0</int>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<object class="NSFont" key="IBUIFont" id="892040736">
+							<string key="NSName">Helvetica-Bold</string>
+							<double key="NSSize">15</double>
+							<int key="NSfFlags">16</int>
+						</object>
+						<int key="IBUIButtonType">1</int>
+						<string key="IBUINormalTitle">OK</string>
+						<object class="NSColor" key="IBUIHighlightedTitleColor" id="501426315">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MQA</bytes>
+						</object>
+						<object class="NSColor" key="IBUINormalTitleColor">
+							<int key="NSColorSpace">1</int>
+							<bytes key="NSRGB">MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA</bytes>
+						</object>
+						<object class="NSColor" key="IBUINormalTitleShadowColor" id="88580318">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MC41AA</bytes>
+						</object>
+					</object>
+					<object class="IBUIButton" id="970816430">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">292</int>
+						<string key="NSFrame">{{141, 366}, {72, 37}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+						<int key="IBUIContentHorizontalAlignment">0</int>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<reference key="IBUIFont" ref="892040736"/>
+						<int key="IBUIButtonType">1</int>
+						<string key="IBUINormalTitle">Cancel</string>
+						<reference key="IBUIHighlightedTitleColor" ref="501426315"/>
+						<object class="NSColor" key="IBUINormalTitleColor">
+							<int key="NSColorSpace">1</int>
+							<bytes key="NSRGB">MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA</bytes>
+						</object>
+						<reference key="IBUINormalTitleShadowColor" ref="88580318"/>
+					</object>
+				</object>
+				<string key="NSFrameSize">{320, 460}</string>
+				<reference key="NSSuperview"/>
+				<object class="NSColor" key="IBUIBackgroundColor">
+					<int key="NSColorSpace">3</int>
+					<bytes key="NSWhite">MQA</bytes>
+					<object class="NSColorSpace" key="NSCustomColorSpace">
+						<int key="NSID">2</int>
+					</object>
+				</object>
+				<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+			</object>
+		</object>
+		<object class="IBObjectContainer" key="IBDocument.Objects">
+			<object class="NSMutableArray" key="connectionRecords">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<object class="IBConnectionRecord">
+					<object class="IBCocoaTouchOutletConnection" key="connection">
+						<string key="label">testDesc</string>
+						<reference key="source" ref="372490531"/>
+						<reference key="destination" ref="613869543"/>
+					</object>
+					<int key="connectionID">4</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBCocoaTouchOutletConnection" key="connection">
+						<string key="label">view</string>
+						<reference key="source" ref="372490531"/>
+						<reference key="destination" ref="191373211"/>
+					</object>
+					<int key="connectionID">5</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBCocoaTouchOutletConnection" key="connection">
+						<string key="label">button1</string>
+						<reference key="source" ref="372490531"/>
+						<reference key="destination" ref="669764012"/>
+					</object>
+					<int key="connectionID">8</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBCocoaTouchOutletConnection" key="connection">
+						<string key="label">button2</string>
+						<reference key="source" ref="372490531"/>
+						<reference key="destination" ref="970816430"/>
+					</object>
+					<int key="connectionID">9</int>
+				</object>
+			</object>
+			<object class="IBMutableOrderedSet" key="objectRecords">
+				<object class="NSArray" key="orderedObjects">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+					<object class="IBObjectRecord">
+						<int key="objectID">0</int>
+						<reference key="object" ref="0"/>
+						<reference key="children" ref="1000"/>
+						<nil key="parent"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">1</int>
+						<reference key="object" ref="191373211"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="613869543"/>
+							<reference ref="669764012"/>
+							<reference ref="970816430"/>
+						</object>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-1</int>
+						<reference key="object" ref="372490531"/>
+						<reference key="parent" ref="0"/>
+						<string key="objectName">File's Owner</string>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-2</int>
+						<reference key="object" ref="711762367"/>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">3</int>
+						<reference key="object" ref="613869543"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">6</int>
+						<reference key="object" ref="669764012"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">7</int>
+						<reference key="object" ref="970816430"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+				</object>
+			</object>
+			<object class="NSMutableDictionary" key="flattenedProperties">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<object class="NSArray" key="dict.sortedKeys">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+					<string>-1.CustomClassName</string>
+					<string>-2.CustomClassName</string>
+					<string>1.IBEditorWindowLastContentRect</string>
+					<string>1.IBPluginDependency</string>
+					<string>3.IBPluginDependency</string>
+					<string>6.IBPluginDependency</string>
+					<string>7.IBPluginDependency</string>
+				</object>
+				<object class="NSMutableArray" key="dict.values">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+					<string>TestViewController</string>
+					<string>UIResponder</string>
+					<string>{{461, 327}, {320, 480}}</string>
+					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				</object>
+			</object>
+			<object class="NSMutableDictionary" key="unlocalizedProperties">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<reference key="dict.sortedKeys" ref="0"/>
+				<object class="NSMutableArray" key="dict.values">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+				</object>
+			</object>
+			<nil key="activeLocalization"/>
+			<object class="NSMutableDictionary" key="localizations">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<reference key="dict.sortedKeys" ref="0"/>
+				<object class="NSMutableArray" key="dict.values">
+					<bool key="EncodedWithXMLCoder">YES</bool>
+				</object>
+			</object>
+			<nil key="sourceID"/>
+			<int key="maxID">9</int>
+		</object>
+		<object class="IBClassDescriber" key="IBDocument.Classes">
+			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<object class="IBPartialClassDescription">
+					<string key="className">TestViewController</string>
+					<string key="superclassName">UIViewController</string>
+					<object class="NSMutableDictionary" key="outlets">
+						<bool key="EncodedWithXMLCoder">YES</bool>
+						<object class="NSArray" key="dict.sortedKeys">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<string>button1</string>
+							<string>button2</string>
+							<string>testDesc</string>
+						</object>
+						<object class="NSMutableArray" key="dict.values">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<string>UIButton</string>
+							<string>UIButton</string>
+							<string>UITextView</string>
+						</object>
+					</object>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBProjectSource</string>
+						<string key="minorKey">Classes/TestViewController.h</string>
+					</object>
+				</object>
+			</object>
+			<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSNetServices.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSPort.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSStream.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">Foundation.framework/Headers/NSXMLParser.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIAccessibility.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UINibLoading.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier" id="27432675">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIResponder.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIButton</string>
+					<string key="superclassName">UIControl</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIButton.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIControl</string>
+					<string key="superclassName">UIView</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIControl.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIResponder</string>
+					<string key="superclassName">NSObject</string>
+					<reference key="sourceIdentifier" ref="27432675"/>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIScrollView</string>
+					<string key="superclassName">UIView</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIScrollView.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UISearchBar</string>
+					<string key="superclassName">UIView</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UISearchBar.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UISearchDisplayController</string>
+					<string key="superclassName">NSObject</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UISearchDisplayController.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UITextView</string>
+					<string key="superclassName">UIScrollView</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UITextView.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIView</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UITextField.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIView</string>
+					<string key="superclassName">UIResponder</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIView.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIViewController</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UINavigationController.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIViewController</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UITabBarController.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">UIViewController</string>
+					<string key="superclassName">UIResponder</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">UIKit.framework/Headers/UIViewController.h</string>
+					</object>
+				</object>
+			</object>
+		</object>
+		<int key="IBDocument.localizationMode">0</int>
+		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
+			<integer value="3100" key="NS.object.0"/>
+		</object>
+		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+		<string key="IBDocument.LastKnownRelativeProjectPath">ipjsystest.xcodeproj</string>
+		<int key="IBDocument.defaultPropertyAccessControl">3</int>
+		<string key="IBCocoaTouchPluginVersion">3.1</string>
+	</data>
+</archive>
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1d9ab632d0c0a002bf13fb97b97d887ce34bdd6.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1d9ab632d0c0a002bf13fb97b97d887ce34bdd6.svn-base
new file mode 100644
index 0000000..74884d6
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1d9ab632d0c0a002bf13fb97b97d887ce34bdd6.svn-base
@@ -0,0 +1,1659 @@
+/* $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 
+ */
+
+#include <pjlib-util/http_client.h>
+#include <pj/activesock.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/errno.h>
+#include <pj/except.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/timer.h>
+#include <pj/rand.h>
+#include <pjlib-util/base64.h>
+#include <pjlib-util/errno.h>
+#include <pjlib-util/md5.h>
+#include <pjlib-util/scanner.h>
+#include <pjlib-util/string.h>
+
+#define THIS_FILE   "http_client.c"
+
+#if 0
+    /* Enable some tracing */
+    #define TRACE_(arg)	PJ_LOG(3,arg)
+#else
+    #define TRACE_(arg)
+#endif
+
+#define NUM_PROTOCOL            2
+#define HTTP_1_0                "1.0"
+#define HTTP_1_1                "1.1"
+#define CONTENT_LENGTH          "Content-Length"
+/* Buffer size for sending/receiving messages. */
+#define BUF_SIZE                2048
+/* Initial data buffer size to store the data in case content-
+ * length is not specified in the server's response.
+ */
+#define INITIAL_DATA_BUF_SIZE   2048
+#define INITIAL_POOL_SIZE       1024
+#define POOL_INCREMENT_SIZE     512
+
+enum http_protocol
+{
+    PROTOCOL_HTTP,
+    PROTOCOL_HTTPS
+};
+
+static const char *http_protocol_names[NUM_PROTOCOL] =
+{
+    "HTTP",
+    "HTTPS"
+};
+
+static const unsigned int http_default_port[NUM_PROTOCOL] =
+{
+    80,
+    443
+};
+
+enum http_method
+{
+    HTTP_GET,
+    HTTP_PUT,
+    HTTP_DELETE
+};
+
+static const char *http_method_names[3] =
+{
+    "GET",
+    "PUT",
+    "DELETE"
+};
+
+enum http_state
+{
+    IDLE,
+    CONNECTING,
+    SENDING_REQUEST,
+    SENDING_REQUEST_BODY,
+    REQUEST_SENT,
+    READING_RESPONSE,
+    READING_DATA,
+    READING_COMPLETE,
+    ABORTING,
+};
+
+enum auth_state
+{
+    AUTH_NONE,		/* Not authenticating */
+    AUTH_RETRYING,	/* New request with auth has been submitted */
+    AUTH_DONE		/* Done retrying the request with auth. */
+};
+
+struct pj_http_req
+{
+    pj_str_t                url;        /* Request URL */
+    pj_http_url             hurl;       /* Parsed request URL */
+    pj_sockaddr             addr;       /* The host's socket address */
+    pj_http_req_param       param;      /* HTTP request parameters */
+    pj_pool_t               *pool;      /* Pool to allocate memory from */
+    pj_timer_heap_t         *timer;     /* Timer for timeout management */
+    pj_ioqueue_t            *ioqueue;   /* Ioqueue to use */
+    pj_http_req_callback    cb;         /* Callbacks */
+    pj_activesock_t         *asock;     /* Active socket */
+    pj_status_t             error;      /* Error status */
+    pj_str_t                buffer;     /* Buffer to send/receive msgs */
+    enum http_state         state;      /* State of the HTTP request */
+    enum auth_state	    auth_state; /* Authentication state */
+    pj_timer_entry          timer_entry;/* Timer entry */
+    pj_bool_t               resolved;   /* Whether URL's host is resolved */
+    pj_http_resp            response;   /* HTTP response */
+    pj_ioqueue_op_key_t	    op_key;
+    struct tcp_state
+    {
+        /* Total data sent so far if the data is sent in segments (i.e.
+         * if on_send_data() is not NULL and if param.reqdata.total_size > 0)
+         */
+        pj_size_t tot_chunk_size;
+        /* Size of data to be sent (in a single activesock operation).*/
+        pj_size_t send_size;
+        /* Data size sent so far. */
+        pj_size_t current_send_size;
+        /* Total data received so far. */
+        pj_size_t current_read_size;
+    } tcp_state;
+};
+
+/* Start sending the request */
+static pj_status_t http_req_start_sending(pj_http_req *hreq);
+/* Start reading the response */
+static pj_status_t http_req_start_reading(pj_http_req *hreq);
+/* End the request */
+static pj_status_t http_req_end_request(pj_http_req *hreq);
+/* Parse the header data and populate the header fields with the result. */
+static pj_status_t http_headers_parse(char *hdata, pj_size_t size, 
+                                      pj_http_headers *headers);
+/* Parse the response */
+static pj_status_t http_response_parse(pj_pool_t *pool,
+                                       pj_http_resp *response,
+                                       void *data, pj_size_t size,
+                                       pj_size_t *remainder);
+/* Restart the request with authentication */
+static void restart_req_with_auth(pj_http_req *hreq);
+/* Parse authentication challenge */
+static pj_status_t parse_auth_chal(pj_pool_t *pool, pj_str_t *input,
+				   pj_http_auth_chal *chal);
+
+static pj_uint16_t get_http_default_port(const pj_str_t *protocol)
+{
+    int i;
+
+    for (i = 0; i < NUM_PROTOCOL; i++) {
+        if (!pj_stricmp2(protocol, http_protocol_names[i])) {
+            return (pj_uint16_t)http_default_port[i];
+        }
+    }
+    return 0;
+}
+
+static const char * get_protocol(const pj_str_t *protocol)
+{
+    int i;
+
+    for (i = 0; i < NUM_PROTOCOL; i++) {
+        if (!pj_stricmp2(protocol, http_protocol_names[i])) {
+            return http_protocol_names[i];
+        }
+    }
+
+    /* Should not happen */
+    pj_assert(0);
+    return NULL;
+}
+
+
+/* Syntax error handler for parser. */
+static void on_syntax_error(pj_scanner *scanner)
+{
+    PJ_UNUSED_ARG(scanner);
+    PJ_THROW(PJ_EINVAL);  // syntax error
+}
+
+/* Callback when connection is established to the server */
+static pj_bool_t http_on_connect(pj_activesock_t *asock,
+				 pj_status_t status)
+{
+    pj_http_req *hreq = (pj_http_req*) pj_activesock_get_user_data(asock);
+
+    if (hreq->state == ABORTING || hreq->state == IDLE)
+        return PJ_FALSE;
+
+    if (status != PJ_SUCCESS) {
+        hreq->error = status;
+        pj_http_req_cancel(hreq, PJ_TRUE);
+        return PJ_FALSE;
+    }
+
+    /* OK, we are connected. Start sending the request */
+    hreq->state = SENDING_REQUEST;
+    http_req_start_sending(hreq);
+    return PJ_TRUE;
+}
+
+static pj_bool_t http_on_data_sent(pj_activesock_t *asock,
+ 				   pj_ioqueue_op_key_t *op_key,
+				   pj_ssize_t sent)
+{
+    pj_http_req *hreq = (pj_http_req*) pj_activesock_get_user_data(asock);
+
+    PJ_UNUSED_ARG(op_key);
+
+    if (hreq->state == ABORTING || hreq->state == IDLE)
+        return PJ_FALSE;
+
+    if (sent <= 0) {
+        hreq->error = (sent < 0 ? (pj_status_t)-sent : PJLIB_UTIL_EHTTPLOST);
+        pj_http_req_cancel(hreq, PJ_TRUE);
+        return PJ_FALSE;
+    } 
+
+    hreq->tcp_state.current_send_size += sent;
+    TRACE_((THIS_FILE, "\nData sent: %d out of %d bytes", 
+           hreq->tcp_state.current_send_size, hreq->tcp_state.send_size));
+    if (hreq->tcp_state.current_send_size == hreq->tcp_state.send_size) {
+        /* Find out whether there is a request body to send. */
+        if (hreq->param.reqdata.total_size > 0 || 
+            hreq->param.reqdata.size > 0) 
+        {
+            if (hreq->state == SENDING_REQUEST) {
+                /* Start sending the request body */
+                hreq->state = SENDING_REQUEST_BODY;
+                hreq->tcp_state.tot_chunk_size = 0;
+                pj_assert(hreq->param.reqdata.total_size == 0 ||
+                          (hreq->param.reqdata.total_size > 0 && 
+                          hreq->param.reqdata.size == 0));
+            } else {
+                /* Continue sending the next chunk of the request body */
+                hreq->tcp_state.tot_chunk_size += hreq->tcp_state.send_size;
+                if (hreq->tcp_state.tot_chunk_size == 
+                    hreq->param.reqdata.total_size ||
+                    hreq->param.reqdata.total_size == 0) 
+                {
+                    /* Finish sending all the chunks, start reading 
+                     * the response.
+                     */
+                    hreq->state = REQUEST_SENT;
+                    http_req_start_reading(hreq);
+                    return PJ_TRUE;
+                }
+            }
+            if (hreq->param.reqdata.total_size > 0 &&
+                hreq->cb.on_send_data) 
+            {
+                /* Call the callback for the application to provide
+                 * the next chunk of data to be sent.
+                 */
+                (*hreq->cb.on_send_data)(hreq, &hreq->param.reqdata.data, 
+                                         &hreq->param.reqdata.size);
+                /* Make sure the total data size given by the user does not
+                 * exceed what the user originally said.
+                 */
+                pj_assert(hreq->tcp_state.tot_chunk_size + 
+                          hreq->param.reqdata.size <=
+                          hreq->param.reqdata.total_size);
+            }
+            http_req_start_sending(hreq);
+        } else {
+            /* No request body, proceed to reading the server's response. */
+            hreq->state = REQUEST_SENT;
+            http_req_start_reading(hreq);
+        }
+    }
+    return PJ_TRUE;
+}
+
+static pj_bool_t http_on_data_read(pj_activesock_t *asock,
+				  void *data,
+				  pj_size_t size,
+				  pj_status_t status,
+				  pj_size_t *remainder)
+{
+    pj_http_req *hreq = (pj_http_req*) pj_activesock_get_user_data(asock);
+
+    TRACE_((THIS_FILE, "\nData received: %d bytes", size));
+
+    if (hreq->state == ABORTING || hreq->state == IDLE)
+        return PJ_FALSE;
+
+    if (hreq->state == READING_RESPONSE) {
+        pj_status_t st;
+        pj_size_t rem;
+
+        if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+            hreq->error = status;
+            pj_http_req_cancel(hreq, PJ_TRUE);
+            return PJ_FALSE;
+        }
+
+        /* Parse the response. */
+        st = http_response_parse(hreq->pool, &hreq->response,
+                                 data, size, &rem);
+        if (st == PJLIB_UTIL_EHTTPINCHDR) {
+            /* If we already use up all our buffer and still
+             * hasn't received the whole header, return error
+             */
+            if (size == BUF_SIZE) {
+                hreq->error = PJ_ETOOBIG; // response header size is too big
+                pj_http_req_cancel(hreq, PJ_TRUE);
+                return PJ_FALSE;
+            }
+            /* Keep the data if we do not get the whole response header */
+            *remainder = size;
+        } else {
+            hreq->state = READING_DATA;
+            if (st != PJ_SUCCESS) {
+                /* Server replied with an invalid (or unknown) response 
+                 * format. We'll just pass the whole (unparsed) response 
+                 * to the user.
+                 */
+                hreq->response.data = data;
+                hreq->response.size = size - rem;
+            }
+
+            /* If code is 401 or 407, find and parse WWW-Authenticate or
+             * Proxy-Authenticate header
+             */
+            if (hreq->response.status_code == 401 ||
+        	hreq->response.status_code == 407)
+            {
+        	const pj_str_t STR_WWW_AUTH = { "WWW-Authenticate", 16 };
+        	const pj_str_t STR_PROXY_AUTH = { "Proxy-Authenticate", 18 };
+        	pj_http_resp *response = &hreq->response;
+        	pj_http_headers *hdrs = &response->headers;
+        	unsigned i;
+
+        	status = PJ_ENOTFOUND;
+        	for (i = 0; i < hdrs->count; i++) {
+        	    if (!pj_stricmp(&hdrs->header[i].name, &STR_WWW_AUTH) ||
+        		!pj_stricmp(&hdrs->header[i].name, &STR_PROXY_AUTH))
+        	    {
+        		status = parse_auth_chal(hreq->pool,
+        					 &hdrs->header[i].value,
+        					 &response->auth_chal);
+        		break;
+        	    }
+        	}
+
+                /* Check if we should perform authentication */
+                if (status == PJ_SUCCESS &&
+		    hreq->auth_state == AUTH_NONE &&
+		    hreq->response.auth_chal.scheme.slen &&
+		    hreq->param.auth_cred.username.slen &&
+		    (hreq->param.auth_cred.scheme.slen == 0 ||
+		     !pj_stricmp(&hreq->response.auth_chal.scheme,
+				 &hreq->param.auth_cred.scheme)) &&
+		    (hreq->param.auth_cred.realm.slen == 0 ||
+		     !pj_stricmp(&hreq->response.auth_chal.realm,
+				 &hreq->param.auth_cred.realm))
+		    )
+		    {
+		    /* Yes, authentication is required and we have been
+		     * configured with credential.
+		     */
+		    restart_req_with_auth(hreq);
+		    if (hreq->auth_state == AUTH_RETRYING) {
+			/* We'll be resending the request with auth. This
+			 * connection has been closed.
+			 */
+			return PJ_FALSE;
+		    }
+                }
+            }
+
+            /* We already received the response header, call the 
+             * appropriate callback.
+             */
+            if (hreq->cb.on_response)
+                (*hreq->cb.on_response)(hreq, &hreq->response);
+            hreq->response.data = NULL;
+            hreq->response.size = 0;
+
+	    if (rem > 0 || hreq->response.content_length == 0)
+		return http_on_data_read(asock, (rem == 0 ? NULL:
+		   	                 (char *)data + size - rem),
+				         rem, PJ_SUCCESS, NULL);
+        }
+
+        return PJ_TRUE;
+    }
+
+    if (hreq->state != READING_DATA)
+	return PJ_FALSE;
+    if (hreq->cb.on_data_read) {
+        /* If application wishes to receive the data once available, call
+         * its callback.
+         */
+        if (size > 0)
+            (*hreq->cb.on_data_read)(hreq, data, size);
+    } else {
+        if (hreq->response.size == 0) {
+            /* If we know the content length, allocate the data based
+             * on that, otherwise we'll use initial buffer size and grow 
+             * it later if necessary.
+             */
+            hreq->response.size = (hreq->response.content_length == -1 ? 
+                                   INITIAL_DATA_BUF_SIZE : 
+                                   hreq->response.content_length);
+            hreq->response.data = pj_pool_alloc(hreq->pool, 
+                                                hreq->response.size);
+        }
+
+        /* If the size of data received exceeds its current size,
+         * grow the buffer by a factor of 2.
+         */
+        if (hreq->tcp_state.current_read_size + size > 
+            hreq->response.size) 
+        {
+            void *olddata = hreq->response.data;
+
+            hreq->response.data = pj_pool_alloc(hreq->pool, 
+                                                hreq->response.size << 1);
+            pj_memcpy(hreq->response.data, olddata, hreq->response.size);
+            hreq->response.size <<= 1;
+        }
+
+        /* Append the response data. */
+        pj_memcpy((char *)hreq->response.data + 
+                  hreq->tcp_state.current_read_size, data, size);
+    }
+    hreq->tcp_state.current_read_size += size;
+
+    /* If the total data received so far is equal to the content length
+     * or if it's already EOF.
+     */
+    if ((hreq->response.content_length >=0 &&
+	(pj_ssize_t)hreq->tcp_state.current_read_size >=
+        hreq->response.content_length) ||
+        (status == PJ_EEOF && hreq->response.content_length == -1)) 
+    {
+	/* Finish reading */
+        http_req_end_request(hreq);
+        hreq->response.size = hreq->tcp_state.current_read_size;
+
+        /* HTTP request is completed, call the callback. */
+        if (hreq->cb.on_complete) {
+            (*hreq->cb.on_complete)(hreq, PJ_SUCCESS, &hreq->response);
+        }
+
+        return PJ_FALSE;
+    }
+
+    /* Error status or premature EOF. */
+    if ((status != PJ_SUCCESS && status != PJ_EPENDING && status != PJ_EEOF)
+        || (status == PJ_EEOF && hreq->response.content_length > -1)) 
+    {
+        hreq->error = status;
+        pj_http_req_cancel(hreq, PJ_TRUE);
+        return PJ_FALSE;
+    }
+    
+    return PJ_TRUE;
+}
+
+/* Callback to be called when query has timed out */
+static void on_timeout( pj_timer_heap_t *timer_heap,
+			struct pj_timer_entry *entry)
+{
+    pj_http_req *hreq = (pj_http_req *) entry->user_data;
+
+    PJ_UNUSED_ARG(timer_heap);
+
+    /* Recheck that the request is still not completed, since there is a 
+     * slight possibility of race condition (timer elapsed while at the 
+     * same time response arrives).
+     */
+    if (hreq->state == READING_COMPLETE) {
+	/* Yeah, we finish on time */
+	return;
+    }
+
+    /* Invalidate id. */
+    hreq->timer_entry.id = 0;
+
+    /* Request timed out. */
+    hreq->error = PJ_ETIMEDOUT;
+    pj_http_req_cancel(hreq, PJ_TRUE);
+}
+
+/* Parse authentication challenge */
+static pj_status_t parse_auth_chal(pj_pool_t *pool, pj_str_t *input,
+				   pj_http_auth_chal *chal)
+{
+    pj_scanner scanner;
+    const pj_str_t REALM_STR 	=    { "realm", 5},
+    		NONCE_STR 	=    { "nonce", 5},
+    		ALGORITHM_STR 	=    { "algorithm", 9 },
+    		STALE_STR 	=    { "stale", 5},
+    		QOP_STR 	=    { "qop", 3},
+    		OPAQUE_STR 	=    { "opaque", 6};
+    pj_status_t status = PJ_SUCCESS;
+    PJ_USE_EXCEPTION ;
+
+    pj_scan_init(&scanner, input->ptr, input->slen, PJ_SCAN_AUTOSKIP_WS,
+		 &on_syntax_error);
+    PJ_TRY {
+	/* Get auth scheme */
+	if (*scanner.curptr == '"') {
+	    pj_scan_get_quote(&scanner, '"', '"', &chal->scheme);
+	    chal->scheme.ptr++;
+	    chal->scheme.slen -= 2;
+	} else {
+	    pj_scan_get_until_chr(&scanner, " \t\r\n", &chal->scheme);
+	}
+
+	/* Loop parsing all parameters */
+	for (;;) {
+	    const char *end_param = ", \t\r\n;";
+	    pj_str_t name, value;
+
+	    /* Get pair of parameter name and value */
+	    value.ptr = NULL;
+	    value.slen = 0;
+	    pj_scan_get_until_chr(&scanner, "=, \t\r\n", &name);
+	    if (*scanner.curptr == '=') {
+		pj_scan_get_char(&scanner);
+		if (!pj_scan_is_eof(&scanner)) {
+		    if (*scanner.curptr == '"' || *scanner.curptr == '\'') {
+			int quote_char = *scanner.curptr;
+			pj_scan_get_quote(&scanner, quote_char, quote_char,
+					  &value);
+			value.ptr++;
+			value.slen -= 2;
+		    } else if (!strchr(end_param, *scanner.curptr)) {
+			pj_scan_get_until_chr(&scanner, end_param, &value);
+		    }
+		}
+		value = pj_str_unescape(pool, &value);
+	    }
+
+	    if (!pj_stricmp(&name, &REALM_STR)) {
+		chal->realm = value;
+
+	    } else if (!pj_stricmp(&name, &NONCE_STR)) {
+		chal->nonce = value;
+
+	    } else if (!pj_stricmp(&name, &ALGORITHM_STR)) {
+		chal->algorithm = value;
+
+	    } else if (!pj_stricmp(&name, &OPAQUE_STR)) {
+		chal->opaque = value;
+
+	    } else if (!pj_stricmp(&name, &QOP_STR)) {
+		chal->qop = value;
+
+	    } else if (!pj_stricmp(&name, &STALE_STR)) {
+		chal->stale = value.slen &&
+			      (*value.ptr != '0') &&
+			      (*value.ptr != 'f') &&
+			      (*value.ptr != 'F');
+
+	    }
+
+	    /* Eat comma */
+	    if (!pj_scan_is_eof(&scanner) && *scanner.curptr == ',')
+		pj_scan_get_char(&scanner);
+	    else
+		break;
+	}
+
+    }
+    PJ_CATCH_ANY {
+	status = PJ_GET_EXCEPTION();
+	pj_bzero(chal, sizeof(*chal));
+	TRACE_((THIS_FILE, "Error: parsing of auth header failed"));
+    }
+    PJ_END;
+    pj_scan_fini(&scanner);
+    return status;
+}
+
+/* The same as #pj_http_headers_add_elmt() with char * as
+ * its parameters.
+ */
+PJ_DEF(pj_status_t) pj_http_headers_add_elmt2(pj_http_headers *headers, 
+                                              char *name, char *val)
+{
+    pj_str_t f, v;
+    pj_cstr(&f, name);
+    pj_cstr(&v, val);
+    return pj_http_headers_add_elmt(headers, &f, &v);
+}   
+
+PJ_DEF(pj_status_t) pj_http_headers_add_elmt(pj_http_headers *headers, 
+                                             pj_str_t *name, 
+                                             pj_str_t *val)
+{
+    PJ_ASSERT_RETURN(headers && name && val, PJ_FALSE);
+    if (headers->count >= PJ_HTTP_HEADER_SIZE)
+        return PJ_ETOOMANY;
+    pj_strassign(&headers->header[headers->count].name, name);
+    pj_strassign(&headers->header[headers->count++].value, val);
+    return PJ_SUCCESS;
+}
+
+static pj_status_t http_response_parse(pj_pool_t *pool,
+                                       pj_http_resp *response,
+                                       void *data, pj_size_t size,
+                                       pj_size_t *remainder)
+{
+    pj_size_t i;
+    char *cptr;
+    char *end_status, *newdata;
+    pj_scanner scanner;
+    pj_str_t s;
+    const pj_str_t STR_CONTENT_LENGTH = { CONTENT_LENGTH, 14 };
+    pj_status_t status;
+
+    PJ_USE_EXCEPTION;
+
+    PJ_ASSERT_RETURN(response, PJ_EINVAL);
+    if (size < 2)
+        return PJLIB_UTIL_EHTTPINCHDR;
+    /* Detect whether we already receive the response's status-line
+     * and its headers. We're looking for a pair of CRLFs. A pair of
+     * LFs is also supported although it is not RFC standard.
+     */
+    cptr = (char *)data;
+    for (i = 1, cptr++; i < size; i++, cptr++) {
+        if (*cptr == '\n') {
+            if (*(cptr - 1) == '\n')
+                break;
+            if (*(cptr - 1) == '\r') {
+                if (i >= 3 && *(cptr - 2) == '\n' && *(cptr - 3) == '\r')
+                    break;
+            }
+        }
+    }
+    if (i == size)
+        return PJLIB_UTIL_EHTTPINCHDR;
+    *remainder = size - 1 - i;
+
+    pj_bzero(response, sizeof(*response));
+    response->content_length = -1;
+
+    newdata = (char*) pj_pool_alloc(pool, i);
+    pj_memcpy(newdata, data, i);
+
+    /* Parse the status-line. */
+    pj_scan_init(&scanner, newdata, i, 0, &on_syntax_error);
+    PJ_TRY {
+        pj_scan_get_until_ch(&scanner, ' ', &response->version);
+        pj_scan_advance_n(&scanner, 1, PJ_FALSE);
+        pj_scan_get_until_ch(&scanner, ' ', &s);
+        response->status_code = (pj_uint16_t)pj_strtoul(&s);
+        pj_scan_advance_n(&scanner, 1, PJ_FALSE);
+        pj_scan_get_until_ch(&scanner, '\n', &response->reason);
+        if (response->reason.ptr[response->reason.slen-1] == '\r')
+            response->reason.slen--;
+    }
+    PJ_CATCH_ANY {
+        pj_scan_fini(&scanner);
+        return PJ_GET_EXCEPTION();
+    }
+    PJ_END;
+
+    end_status = scanner.curptr;
+    pj_scan_fini(&scanner);
+
+    /* Parse the response headers. */
+    size = i - 2 - (end_status - newdata);
+    if (size > 0) {
+        status = http_headers_parse(end_status + 1, size,
+                                    &response->headers);
+    } else {
+        status = PJ_SUCCESS;
+    }
+
+    /* Find content-length header field. */
+    for (i = 0; i < response->headers.count; i++) {
+        if (!pj_stricmp(&response->headers.header[i].name,
+                        &STR_CONTENT_LENGTH))
+        {
+            response->content_length = 
+                pj_strtoul(&response->headers.header[i].value);
+            /* If content length is zero, make sure that it is because the
+             * header value is really zero and not due to parsing error.
+             */
+            if (response->content_length == 0) {
+                if (pj_strcmp2(&response->headers.header[i].value, "0")) {
+                    response->content_length = -1;
+                }
+            }
+            break;
+        }
+    }
+
+    return status;
+}
+
+static pj_status_t http_headers_parse(char *hdata, pj_size_t size, 
+                                      pj_http_headers *headers)
+{
+    pj_scanner scanner;
+    pj_str_t s, s2;
+    pj_status_t status;
+    PJ_USE_EXCEPTION;
+
+    PJ_ASSERT_RETURN(headers, PJ_EINVAL);
+
+    pj_scan_init(&scanner, hdata, size, 0, &on_syntax_error);
+
+    /* Parse each line of header field consisting of header field name and
+     * value, separated by ":" and any number of white spaces.
+     */
+    PJ_TRY {
+        do {
+            pj_scan_get_until_chr(&scanner, ":\n", &s);
+            if (*scanner.curptr == ':') {
+                pj_scan_advance_n(&scanner, 1, PJ_TRUE);
+                pj_scan_get_until_ch(&scanner, '\n', &s2);
+                if (s2.ptr[s2.slen-1] == '\r')
+                    s2.slen--;
+                status = pj_http_headers_add_elmt(headers, &s, &s2);
+                if (status != PJ_SUCCESS)
+                    PJ_THROW(status);
+            }
+            pj_scan_advance_n(&scanner, 1, PJ_TRUE);
+            /* Finish parsing */
+            if (pj_scan_is_eof(&scanner))
+                break;
+        } while (1);
+    }
+    PJ_CATCH_ANY {
+        pj_scan_fini(&scanner);
+        return PJ_GET_EXCEPTION();
+    }
+    PJ_END;
+
+    pj_scan_fini(&scanner);
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_http_req_param_default(pj_http_req_param *param)
+{
+    pj_assert(param);
+    pj_bzero(param, sizeof(*param));
+    param->addr_family = pj_AF_INET();
+    pj_strset2(&param->method, (char*)http_method_names[HTTP_GET]);
+    pj_strset2(&param->version, (char*)HTTP_1_0);
+    param->timeout.msec = PJ_HTTP_DEFAULT_TIMEOUT;
+    pj_time_val_normalize(&param->timeout);
+    param->max_retries = 3;
+}
+
+/* Get the location of '@' character to indicate the end of
+ * user:passwd part of an URI. If user:passwd part is not
+ * present, NULL will be returned.
+ */
+static char *get_url_at_pos(const char *str, pj_size_t len)
+{
+    const char *end = str + len;
+    const char *p = str;
+
+    /* skip scheme: */
+    while (p!=end && *p!='/') ++p;
+    if (p!=end && *p=='/') ++p;
+    if (p!=end && *p=='/') ++p;
+    if (p==end) return NULL;
+
+    for (; p!=end; ++p) {
+	switch (*p) {
+	case '/':
+	    return NULL;
+	case '@':
+	    return (char*)p;
+	}
+    }
+
+    return NULL;
+}
+
+
+PJ_DEF(pj_status_t) pj_http_req_parse_url(const pj_str_t *url, 
+                                          pj_http_url *hurl)
+{
+    pj_scanner scanner;
+    pj_size_t len = url->slen;
+    PJ_USE_EXCEPTION;
+
+    if (!len) return -1;
+    
+    pj_bzero(hurl, sizeof(*hurl));
+    pj_scan_init(&scanner, url->ptr, url->slen, 0, &on_syntax_error);
+
+    PJ_TRY {
+	pj_str_t s;
+
+        /* Exhaust any whitespaces. */
+        pj_scan_skip_whitespace(&scanner);
+
+        /* Parse the protocol */
+        pj_scan_get_until_ch(&scanner, ':', &s);
+        if (!pj_stricmp2(&s, http_protocol_names[PROTOCOL_HTTP])) {
+            pj_strset2(&hurl->protocol,
+        	       (char*)http_protocol_names[PROTOCOL_HTTP]);
+        } else if (!pj_stricmp2(&s, http_protocol_names[PROTOCOL_HTTPS])) {
+            pj_strset2(&hurl->protocol,
+		       (char*)http_protocol_names[PROTOCOL_HTTPS]);
+        } else {
+            PJ_THROW(PJ_ENOTSUP); // unsupported protocol
+        }
+
+        if (pj_scan_strcmp(&scanner, "://", 3)) {
+            PJ_THROW(PJLIB_UTIL_EHTTPINURL); // no "://" after protocol name
+        }
+        pj_scan_advance_n(&scanner, 3, PJ_FALSE);
+
+        if (get_url_at_pos(url->ptr, url->slen)) {
+            /* Parse username and password */
+            pj_scan_get_until_chr(&scanner, ":@", &hurl->username);
+            if (*scanner.curptr == ':') {
+        	pj_scan_get_char(&scanner);
+        	pj_scan_get_until_chr(&scanner, "@", &hurl->passwd);
+            } else {
+        	hurl->passwd.slen = 0;
+            }
+            pj_scan_get_char(&scanner);
+        }
+
+        /* Parse the host and port number (if any) */
+        pj_scan_get_until_chr(&scanner, ":/", &s);
+        pj_strassign(&hurl->host, &s);
+        if (hurl->host.slen==0)
+            PJ_THROW(PJ_EINVAL);
+        if (pj_scan_is_eof(&scanner) || *scanner.curptr == '/') {
+            /* No port number specified */
+            /* Assume default http/https port number */
+            hurl->port = get_http_default_port(&hurl->protocol);
+            pj_assert(hurl->port > 0);
+        } else {
+            pj_scan_advance_n(&scanner, 1, PJ_FALSE);
+            pj_scan_get_until_ch(&scanner, '/', &s);
+            /* Parse the port number */
+            hurl->port = (pj_uint16_t)pj_strtoul(&s);
+            if (!hurl->port)
+                PJ_THROW(PJLIB_UTIL_EHTTPINPORT); // invalid port number
+        }
+
+        if (!pj_scan_is_eof(&scanner)) {
+            hurl->path.ptr = scanner.curptr;
+            hurl->path.slen = scanner.end - scanner.curptr;
+        } else {
+            /* no path, append '/' */
+            pj_cstr(&hurl->path, "/");
+        }
+    }
+    PJ_CATCH_ANY {
+        pj_scan_fini(&scanner);
+	return PJ_GET_EXCEPTION();
+    }
+    PJ_END;
+
+    pj_scan_fini(&scanner);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_http_req_set_timeout(pj_http_req *http_req,
+                                     const pj_time_val* timeout)
+{
+    pj_memcpy(&http_req->param.timeout, timeout, sizeof(*timeout));
+}
+
+PJ_DEF(pj_status_t) pj_http_req_create(pj_pool_t *pool,
+                                       const pj_str_t *url,
+                                       pj_timer_heap_t *timer,
+                                       pj_ioqueue_t *ioqueue,
+                                       const pj_http_req_param *param,
+                                       const pj_http_req_callback *hcb,
+                                       pj_http_req **http_req)
+{
+    pj_pool_t *own_pool;
+    pj_http_req *hreq;
+    char *at_pos;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(pool && url && timer && ioqueue && 
+                     hcb && http_req, PJ_EINVAL);
+
+    *http_req = NULL;
+    own_pool = pj_pool_create(pool->factory, NULL, INITIAL_POOL_SIZE, 
+                              POOL_INCREMENT_SIZE, NULL);
+    hreq = PJ_POOL_ZALLOC_T(own_pool, struct pj_http_req);
+    if (!hreq)
+        return PJ_ENOMEM;
+
+    /* Initialization */
+    hreq->pool = own_pool;
+    hreq->ioqueue = ioqueue;
+    hreq->timer = timer;
+    hreq->asock = NULL;
+    pj_memcpy(&hreq->cb, hcb, sizeof(*hcb));
+    hreq->state = IDLE;
+    hreq->resolved = PJ_FALSE;
+    hreq->buffer.ptr = NULL;
+    pj_timer_entry_init(&hreq->timer_entry, 0, hreq, &on_timeout);
+
+    /* Initialize parameter */
+    if (param) {
+        pj_memcpy(&hreq->param, param, sizeof(*param));
+        /* TODO: validate the param here
+         * Should we validate the method as well? If yes, based on all HTTP
+         * methods or based on supported methods only? For the later, one 
+         * drawback would be that you can't use this if the method is not 
+         * officially supported
+         */
+        PJ_ASSERT_RETURN(hreq->param.addr_family==PJ_AF_UNSPEC || 
+                         hreq->param.addr_family==PJ_AF_INET || 
+                         hreq->param.addr_family==PJ_AF_INET6, PJ_EAFNOTSUP);
+        PJ_ASSERT_RETURN(!pj_strcmp2(&hreq->param.version, HTTP_1_0) || 
+                         !pj_strcmp2(&hreq->param.version, HTTP_1_1), 
+                         PJ_ENOTSUP); 
+        pj_time_val_normalize(&hreq->param.timeout);
+    } else {
+        pj_http_req_param_default(&hreq->param);
+    }
+
+    /* Parse the URL */
+    if (!pj_strdup_with_null(hreq->pool, &hreq->url, url)) {
+	pj_pool_release(hreq->pool);
+        return PJ_ENOMEM;
+    }
+    status = pj_http_req_parse_url(&hreq->url, &hreq->hurl);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(hreq->pool);
+        return status; // Invalid URL supplied
+    }
+
+    /* If URL contains username/password, move them to credential and
+     * remove them from the URL.
+     */
+    if ((at_pos=get_url_at_pos(hreq->url.ptr, hreq->url.slen)) != NULL) {
+	pj_str_t tmp;
+	char *user_pos = pj_strchr(&hreq->url, '/');
+	int removed_len;
+
+	/* Save credential first, unescape the string */
+	tmp = pj_str_unescape(hreq->pool, &hreq->hurl.username);;
+	pj_strdup(hreq->pool, &hreq->param.auth_cred.username, &tmp);
+
+	tmp = pj_str_unescape(hreq->pool, &hreq->hurl.passwd);
+	pj_strdup(hreq->pool, &hreq->param.auth_cred.data, &tmp);
+
+	hreq->hurl.username.ptr = hreq->hurl.passwd.ptr = NULL;
+	hreq->hurl.username.slen = hreq->hurl.passwd.slen = 0;
+
+	/* Remove "username:password@" from the URL */
+	pj_assert(user_pos != 0 && user_pos < at_pos);
+	user_pos += 2;
+	removed_len = (int)(at_pos + 1 - user_pos);
+	pj_memmove(user_pos, at_pos+1, hreq->url.ptr+hreq->url.slen-at_pos-1);
+	hreq->url.slen -= removed_len;
+
+	/* Need to adjust hostname and path pointers due to memmove*/
+	if (hreq->hurl.host.ptr > user_pos &&
+	    hreq->hurl.host.ptr < user_pos + hreq->url.slen)
+	{
+	    hreq->hurl.host.ptr -= removed_len;
+	}
+	/* path may come from a string constant, don't shift it if so */
+	if (hreq->hurl.path.ptr > user_pos &&
+	    hreq->hurl.path.ptr < user_pos + hreq->url.slen)
+	{
+	    hreq->hurl.path.ptr -= removed_len;
+	}
+    }
+
+    *http_req = hreq;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_bool_t) pj_http_req_is_running(const pj_http_req *http_req)
+{
+   PJ_ASSERT_RETURN(http_req, PJ_FALSE);
+   return (http_req->state != IDLE);
+}
+
+PJ_DEF(void*) pj_http_req_get_user_data(pj_http_req *http_req)
+{
+    PJ_ASSERT_RETURN(http_req, NULL);
+    return http_req->param.user_data;
+}
+
+static pj_status_t start_http_req(pj_http_req *http_req,
+                                  pj_bool_t notify_on_fail)
+{
+    pj_sock_t sock = PJ_INVALID_SOCKET;
+    pj_status_t status;
+    pj_activesock_cb asock_cb;
+    int retry = 0;
+
+    PJ_ASSERT_RETURN(http_req, PJ_EINVAL);
+    /* Http request is not idle, a request was initiated before and 
+     * is still in progress
+     */
+    PJ_ASSERT_RETURN(http_req->state == IDLE, PJ_EBUSY);
+
+    /* Reset few things to make sure restarting works */
+    http_req->error = 0;
+    http_req->response.headers.count = 0;
+    pj_bzero(&http_req->tcp_state, sizeof(http_req->tcp_state));
+
+    if (!http_req->resolved) {
+        /* Resolve the Internet address of the host */
+        status = pj_sockaddr_init(http_req->param.addr_family, 
+                                  &http_req->addr, &http_req->hurl.host,
+				  http_req->hurl.port);
+	if (status != PJ_SUCCESS ||
+	    !pj_sockaddr_has_addr(&http_req->addr) ||
+	    (http_req->param.addr_family==pj_AF_INET() &&
+	     http_req->addr.ipv4.sin_addr.s_addr==PJ_INADDR_NONE))
+	{
+	    goto on_return;
+        }
+        http_req->resolved = PJ_TRUE;
+    }
+
+    status = pj_sock_socket(http_req->param.addr_family, pj_SOCK_STREAM(), 
+                            0, &sock);
+    if (status != PJ_SUCCESS)
+        goto on_return; // error creating socket
+
+    pj_bzero(&asock_cb, sizeof(asock_cb));
+    asock_cb.on_data_read = &http_on_data_read;
+    asock_cb.on_data_sent = &http_on_data_sent;
+    asock_cb.on_connect_complete = &http_on_connect;
+	
+    do
+    {
+	pj_sockaddr_in bound_addr;
+	pj_uint16_t port = 0;
+
+	/* If we are using port restriction.
+	 * Get a random port within the range
+	 */
+	if (http_req->param.source_port_range_start != 0) {
+	    port = (pj_uint16_t)
+		   (http_req->param.source_port_range_start +
+		    (pj_rand() % http_req->param.source_port_range_size));
+	}
+
+	pj_sockaddr_in_init(&bound_addr, NULL, port);
+	status = pj_sock_bind(sock, &bound_addr, sizeof(bound_addr));
+
+    } while (status != PJ_SUCCESS && (retry++ < http_req->param.max_retries));
+
+    if (status != PJ_SUCCESS) {
+	PJ_PERROR(1,(THIS_FILE, status,
+		     "Unable to bind to the requested port"));
+	pj_sock_close(sock);
+	goto on_return;
+    }
+
+    // TODO: should we set whole data to 0 by default?
+    // or add it in the param?
+    status = pj_activesock_create(http_req->pool, sock, pj_SOCK_STREAM(), 
+                                  NULL, http_req->ioqueue,
+				  &asock_cb, http_req, &http_req->asock);
+    if (status != PJ_SUCCESS) {
+        pj_sock_close(sock);
+	goto on_return; // error creating activesock
+    }
+
+    /* Schedule timeout timer for the request */
+    pj_assert(http_req->timer_entry.id == 0);
+    http_req->timer_entry.id = 1;
+    status = pj_timer_heap_schedule(http_req->timer, &http_req->timer_entry, 
+                                    &http_req->param.timeout);
+    if (status != PJ_SUCCESS) {
+        http_req->timer_entry.id = 0;
+	goto on_return; // error scheduling timer
+    }
+
+    /* Connect to host */
+    http_req->state = CONNECTING;
+    status = pj_activesock_start_connect(http_req->asock, http_req->pool, 
+                                         (pj_sock_t *)&(http_req->addr), 
+                                         pj_sockaddr_get_len(&http_req->addr));
+    if (status == PJ_SUCCESS) {
+        http_req->state = SENDING_REQUEST;
+        status =  http_req_start_sending(http_req);
+        if (status != PJ_SUCCESS)
+            goto on_return;
+    } else if (status != PJ_EPENDING) {
+        goto on_return; // error connecting
+    }
+
+    return PJ_SUCCESS;
+
+on_return:
+    http_req->error = status;
+    if (notify_on_fail)
+	pj_http_req_cancel(http_req, PJ_TRUE);
+    else
+	http_req_end_request(http_req);
+
+    return status;
+}
+
+/* Starts an asynchronous HTTP request to the URL specified. */
+PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
+{
+    return start_http_req(http_req, PJ_FALSE);
+}
+
+/* Respond to basic authentication challenge */
+static pj_status_t auth_respond_basic(pj_http_req *hreq)
+{
+    /* Basic authentication:
+     *      credentials       = "Basic" basic-credentials
+     *      basic-credentials = base64-user-pass
+     *      base64-user-pass  = <base64 [4] encoding of user-pass>
+     *      user-pass         = userid ":" password
+     *
+     * Sample:
+     *       Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+     */
+    pj_str_t user_pass;
+    pj_http_header_elmt *phdr;
+    int len;
+
+    /* Use send buffer to store userid ":" password */
+    user_pass.ptr = hreq->buffer.ptr;
+    pj_strcpy(&user_pass, &hreq->param.auth_cred.username);
+    pj_strcat2(&user_pass, ":");
+    pj_strcat(&user_pass, &hreq->param.auth_cred.data);
+
+    /* Create Authorization header */
+    phdr = &hreq->param.headers.header[hreq->param.headers.count++];
+    pj_bzero(phdr, sizeof(*phdr));
+    if (hreq->response.status_code == 401)
+	phdr->name = pj_str("Authorization");
+    else
+	phdr->name = pj_str("Proxy-Authorization");
+
+    len = (int)(PJ_BASE256_TO_BASE64_LEN(user_pass.slen) + 10);
+    phdr->value.ptr = (char*)pj_pool_alloc(hreq->pool, len);
+    phdr->value.slen = 0;
+
+    pj_strcpy2(&phdr->value, "Basic ");
+    len -= (int)phdr->value.slen;
+    pj_base64_encode((pj_uint8_t*)user_pass.ptr, (int)user_pass.slen,
+		     phdr->value.ptr + phdr->value.slen, &len);
+    phdr->value.slen += len;
+
+    return PJ_SUCCESS;
+}
+
+/** Length of digest string. */
+#define MD5_STRLEN 32
+/* A macro just to get rid of type mismatch between char and unsigned char */
+#define MD5_APPEND(pms,buf,len)	pj_md5_update(pms, (const pj_uint8_t*)buf, \
+		   (unsigned)len)
+
+/* Transform digest to string.
+ * output must be at least PJSIP_MD5STRLEN+1 bytes.
+ *
+ * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED!
+ */
+static void digest2str(const unsigned char digest[], char *output)
+{
+    int i;
+    for (i = 0; i<16; ++i) {
+	pj_val_to_hex_digit(digest[i], output);
+	output += 2;
+    }
+}
+
+static void auth_create_digest_response(pj_str_t *result,
+					const pj_http_auth_cred *cred,
+				        const pj_str_t *nonce,
+				        const pj_str_t *nc,
+				        const pj_str_t *cnonce,
+				        const pj_str_t *qop,
+				        const pj_str_t *uri,
+				        const pj_str_t *realm,
+				        const pj_str_t *method)
+{
+    char ha1[MD5_STRLEN];
+    char ha2[MD5_STRLEN];
+    unsigned char digest[16];
+    pj_md5_context pms;
+
+    pj_assert(result->slen >= MD5_STRLEN);
+
+    TRACE_((THIS_FILE, "Begin creating digest"));
+
+    if (cred->data_type == 0) {
+	/***
+	 *** ha1 = MD5(username ":" realm ":" password)
+	 ***/
+	pj_md5_init(&pms);
+	MD5_APPEND( &pms, cred->username.ptr, cred->username.slen);
+	MD5_APPEND( &pms, ":", 1);
+	MD5_APPEND( &pms, realm->ptr, realm->slen);
+	MD5_APPEND( &pms, ":", 1);
+	MD5_APPEND( &pms, cred->data.ptr, cred->data.slen);
+	pj_md5_final(&pms, digest);
+
+	digest2str(digest, ha1);
+
+    } else if (cred->data_type == 1) {
+	pj_assert(cred->data.slen == 32);
+	pj_memcpy( ha1, cred->data.ptr, cred->data.slen );
+    } else {
+	pj_assert(!"Invalid data_type");
+    }
+
+    TRACE_((THIS_FILE, "  ha1=%.32s", ha1));
+
+    /***
+     *** ha2 = MD5(method ":" req_uri)
+     ***/
+    pj_md5_init(&pms);
+    MD5_APPEND( &pms, method->ptr, method->slen);
+    MD5_APPEND( &pms, ":", 1);
+    MD5_APPEND( &pms, uri->ptr, uri->slen);
+    pj_md5_final(&pms, digest);
+    digest2str(digest, ha2);
+
+    TRACE_((THIS_FILE, "  ha2=%.32s", ha2));
+
+    /***
+     *** When qop is not used:
+     ***    response = MD5(ha1 ":" nonce ":" ha2)
+     ***
+     *** When qop=auth is used:
+     ***    response = MD5(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)
+     ***/
+    pj_md5_init(&pms);
+    MD5_APPEND( &pms, ha1, MD5_STRLEN);
+    MD5_APPEND( &pms, ":", 1);
+    MD5_APPEND( &pms, nonce->ptr, nonce->slen);
+    if (qop && qop->slen != 0) {
+	MD5_APPEND( &pms, ":", 1);
+	MD5_APPEND( &pms, nc->ptr, nc->slen);
+	MD5_APPEND( &pms, ":", 1);
+	MD5_APPEND( &pms, cnonce->ptr, cnonce->slen);
+	MD5_APPEND( &pms, ":", 1);
+	MD5_APPEND( &pms, qop->ptr, qop->slen);
+    }
+    MD5_APPEND( &pms, ":", 1);
+    MD5_APPEND( &pms, ha2, MD5_STRLEN);
+
+    /* This is the final response digest. */
+    pj_md5_final(&pms, digest);
+
+    /* Convert digest to string and store in chal->response. */
+    result->slen = MD5_STRLEN;
+    digest2str(digest, result->ptr);
+
+    TRACE_((THIS_FILE, "  digest=%.32s", result->ptr));
+    TRACE_((THIS_FILE, "Digest created"));
+}
+
+/* Find out if qop offer contains "auth" token */
+static pj_bool_t auth_has_qop( pj_pool_t *pool, const pj_str_t *qop_offer)
+{
+    pj_str_t qop;
+    char *p;
+
+    pj_strdup_with_null( pool, &qop, qop_offer);
+    p = qop.ptr;
+    while (*p) {
+	*p = (char)pj_tolower(*p);
+	++p;
+    }
+
+    p = qop.ptr;
+    while (*p) {
+	if (*p=='a' && *(p+1)=='u' && *(p+2)=='t' && *(p+3)=='h') {
+	    int e = *(p+4);
+	    if (e=='"' || e==',' || e==0)
+		return PJ_TRUE;
+	    else
+		p += 4;
+	} else {
+	    ++p;
+	}
+    }
+
+    return PJ_FALSE;
+}
+
+#define STR_PREC(s) (int)(s).slen, (s).ptr
+
+/* Respond to digest authentication */
+static pj_status_t auth_respond_digest(pj_http_req *hreq)
+{
+    const pj_http_auth_chal *chal = &hreq->response.auth_chal;
+    const pj_http_auth_cred *cred = &hreq->param.auth_cred;
+    pj_http_header_elmt *phdr;
+    char digest_response_buf[MD5_STRLEN];
+    int len;
+    pj_str_t digest_response;
+
+    /* Check algorithm is supported. We only support MD5 */
+    if (chal->algorithm.slen!=0 &&
+	pj_stricmp2(&chal->algorithm, "MD5"))
+    {
+	TRACE_((THIS_FILE, "Error: Unsupported digest algorithm \"%.*s\"",
+		  chal->algorithm.slen, chal->algorithm.ptr));
+	return PJ_ENOTSUP;
+    }
+
+    /* Add Authorization header */
+    phdr = &hreq->param.headers.header[hreq->param.headers.count++];
+    pj_bzero(phdr, sizeof(*phdr));
+    if (hreq->response.status_code == 401)
+	phdr->name = pj_str("Authorization");
+    else
+	phdr->name = pj_str("Proxy-Authorization");
+
+    /* Allocate space for the header */
+    len = (int)(8 + /* Digest */
+	  16 + hreq->param.auth_cred.username.slen + /* username= */
+	  12 + chal->realm.slen + /* realm= */
+	  12 + chal->nonce.slen + /* nonce= */
+	  8 + hreq->hurl.path.slen + /* uri= */
+	  16 + /* algorithm=MD5 */
+	  16 + MD5_STRLEN + /* response= */
+	  12 + /* qop=auth */
+	  8 + /* nc=.. */
+	  30 + /* cnonce= */
+	  12 + chal->opaque.slen + /* opaque=".." */
+	  0);
+    phdr->value.ptr = (char*)pj_pool_alloc(hreq->pool, len);
+
+    /* Configure buffer to temporarily store the digest */
+    digest_response.ptr = digest_response_buf;
+    digest_response.slen = MD5_STRLEN;
+
+    if (chal->qop.slen == 0) {
+	const pj_str_t STR_MD5 = { "MD5", 3 };
+	int max_len;
+
+	/* Server doesn't require quality of protection. */
+	auth_create_digest_response(&digest_response, cred,
+				    &chal->nonce, NULL, NULL,  NULL,
+				    &hreq->hurl.path, &chal->realm,
+				    &hreq->param.method);
+
+	max_len = len;
+	len = pj_ansi_snprintf(
+		phdr->value.ptr, max_len,
+		"Digest username=\"%.*s\", "
+		"realm=\"%.*s\", "
+		"nonce=\"%.*s\", "
+		"uri=\"%.*s\", "
+		"algorithm=%.*s, "
+		"response=\"%.*s\"",
+		STR_PREC(cred->username),
+		STR_PREC(chal->realm),
+		STR_PREC(chal->nonce),
+		STR_PREC(hreq->hurl.path),
+		STR_PREC(STR_MD5),
+		STR_PREC(digest_response));
+	if (len < 0 || len >= max_len)
+	    return PJ_ETOOSMALL;
+	phdr->value.slen = len;
+
+    } else if (auth_has_qop(hreq->pool, &chal->qop)) {
+	/* Server requires quality of protection.
+	 * We respond with selecting "qop=auth" protection.
+	 */
+	const pj_str_t STR_MD5 = { "MD5", 3 };
+	const pj_str_t qop = pj_str("auth");
+	const pj_str_t nc = pj_str("00000001");
+	const pj_str_t cnonce = pj_str("b39971");
+	int max_len;
+
+	auth_create_digest_response(&digest_response, cred,
+				    &chal->nonce, &nc, &cnonce, &qop,
+				    &hreq->hurl.path, &chal->realm,
+				    &hreq->param.method);
+	max_len = len;
+	len = pj_ansi_snprintf(
+		phdr->value.ptr, max_len,
+		"Digest username=\"%.*s\", "
+		"realm=\"%.*s\", "
+		"nonce=\"%.*s\", "
+		"uri=\"%.*s\", "
+		"algorithm=%.*s, "
+		"response=\"%.*s\", "
+		"qop=%.*s, "
+		"nc=%.*s, "
+		"cnonce=\"%.*s\"",
+		STR_PREC(cred->username),
+		STR_PREC(chal->realm),
+		STR_PREC(chal->nonce),
+		STR_PREC(hreq->hurl.path),
+		STR_PREC(STR_MD5),
+		STR_PREC(digest_response),
+		STR_PREC(qop),
+		STR_PREC(nc),
+		STR_PREC(cnonce));
+	if (len < 0 || len >= max_len)
+	    return PJ_ETOOSMALL;
+	phdr->value.slen = len;
+
+	if (chal->opaque.slen) {
+	    pj_strcat2(&phdr->value, ", opaque=\"");
+	    pj_strcat(&phdr->value, &chal->opaque);
+	    pj_strcat2(&phdr->value, "\"");
+	}
+
+    } else {
+	/* Server requires quality protection that we don't support. */
+	TRACE_((THIS_FILE, "Error: Unsupported qop offer %.*s",
+		chal->qop.slen, chal->qop.ptr));
+	return PJ_ENOTSUP;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+static void restart_req_with_auth(pj_http_req *hreq)
+{
+    pj_http_auth_chal *chal = &hreq->response.auth_chal;
+    pj_http_auth_cred *cred = &hreq->param.auth_cred;
+    pj_status_t status;
+
+    if (hreq->param.headers.count >= PJ_HTTP_HEADER_SIZE) {
+	TRACE_((THIS_FILE, "Error: no place to put Authorization header"));
+	hreq->auth_state = AUTH_DONE;
+	return;
+    }
+
+    /* If credential specifies specific scheme, make sure they match */
+    if (cred->scheme.slen && pj_stricmp(&chal->scheme, &cred->scheme)) {
+	status = PJ_ENOTSUP;
+	TRACE_((THIS_FILE, "Error: auth schemes mismatch"));
+	goto on_error;
+    }
+
+    /* If credential specifies specific realm, make sure they match */
+    if (cred->realm.slen && pj_stricmp(&chal->realm, &cred->realm)) {
+	status = PJ_ENOTSUP;
+	TRACE_((THIS_FILE, "Error: auth realms mismatch"));
+	goto on_error;
+    }
+
+    if (!pj_stricmp2(&chal->scheme, "basic")) {
+	status = auth_respond_basic(hreq);
+    } else if (!pj_stricmp2(&chal->scheme, "digest")) {
+	status = auth_respond_digest(hreq);
+    } else {
+	TRACE_((THIS_FILE, "Error: unsupported HTTP auth scheme"));
+	status = PJ_ENOTSUP;
+    }
+
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    http_req_end_request(hreq);
+
+    status = start_http_req(hreq, PJ_TRUE);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    hreq->auth_state = AUTH_RETRYING;
+    return;
+
+on_error:
+    hreq->auth_state = AUTH_DONE;
+}
+
+
+/* snprintf() to a pj_str_t struct with an option to append the 
+ * result at the back of the string.
+ */
+void str_snprintf(pj_str_t *s, size_t size, 
+                  pj_bool_t append, const char *format, ...)
+{
+    va_list arg;
+    int retval;
+
+    va_start(arg, format);
+    if (!append)
+        s->slen = 0;
+    size -= s->slen;
+    retval = pj_ansi_vsnprintf(s->ptr + s->slen, 
+                               size, format, arg);
+    s->slen += ((retval < (int)size) ? retval : size - 1);
+    va_end(arg);
+}
+
+static pj_status_t http_req_start_sending(pj_http_req *hreq)
+{
+    pj_status_t status;
+    pj_str_t pkt;
+    pj_ssize_t len;
+    pj_size_t i;
+
+    PJ_ASSERT_RETURN(hreq->state == SENDING_REQUEST || 
+                     hreq->state == SENDING_REQUEST_BODY, PJ_EBUG);
+
+    if (hreq->state == SENDING_REQUEST) {
+        /* Prepare the request data */
+        if (!hreq->buffer.ptr)
+            hreq->buffer.ptr = (char*)pj_pool_alloc(hreq->pool, BUF_SIZE);
+        pj_strassign(&pkt, &hreq->buffer);
+        pkt.slen = 0;
+        /* Start-line */
+        str_snprintf(&pkt, BUF_SIZE, PJ_TRUE, "%.*s %.*s %s/%.*s\r\n",
+                     STR_PREC(hreq->param.method), 
+                     STR_PREC(hreq->hurl.path),
+                     get_protocol(&hreq->hurl.protocol), 
+                     STR_PREC(hreq->param.version));
+        /* Header field "Host" */
+        str_snprintf(&pkt, BUF_SIZE, PJ_TRUE, "Host: %.*s:%d\r\n",
+                     STR_PREC(hreq->hurl.host), hreq->hurl.port);
+        if (!pj_strcmp2(&hreq->param.method, http_method_names[HTTP_PUT])) {
+            char buf[16];
+
+            /* Header field "Content-Length" */
+            pj_utoa(hreq->param.reqdata.total_size ? 
+                    (unsigned long)hreq->param.reqdata.total_size: 
+                    (unsigned long)hreq->param.reqdata.size, buf);
+            str_snprintf(&pkt, BUF_SIZE, PJ_TRUE, "%s: %s\r\n",
+                         CONTENT_LENGTH, buf);
+        }
+
+        /* Append user-specified headers */
+        for (i = 0; i < hreq->param.headers.count; i++) {
+            str_snprintf(&pkt, BUF_SIZE, PJ_TRUE, "%.*s: %.*s\r\n",
+                         STR_PREC(hreq->param.headers.header[i].name),
+                         STR_PREC(hreq->param.headers.header[i].value));
+        }
+        if (pkt.slen >= BUF_SIZE - 1) {
+            status = PJLIB_UTIL_EHTTPINSBUF;
+            goto on_return;
+        }
+
+        pj_strcat2(&pkt, "\r\n");
+        pkt.ptr[pkt.slen] = 0;
+        TRACE_((THIS_FILE, "%s", pkt.ptr));
+    } else {
+        pkt.ptr = (char*)hreq->param.reqdata.data;
+        pkt.slen = hreq->param.reqdata.size;
+    }
+
+    /* Send the request */
+    len = pj_strlen(&pkt);
+    pj_ioqueue_op_key_init(&hreq->op_key, sizeof(hreq->op_key));
+    hreq->tcp_state.send_size = len;
+    hreq->tcp_state.current_send_size = 0;
+    status = pj_activesock_send(hreq->asock, &hreq->op_key, 
+                                pkt.ptr, &len, 0);
+
+    if (status == PJ_SUCCESS) {
+        http_on_data_sent(hreq->asock, &hreq->op_key, len);
+    } else if (status != PJ_EPENDING) {
+        goto on_return; // error sending data
+    }
+
+    return PJ_SUCCESS;
+
+on_return:
+    http_req_end_request(hreq);
+    return status;
+}
+
+static pj_status_t http_req_start_reading(pj_http_req *hreq)
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(hreq->state == REQUEST_SENT, PJ_EBUG);
+
+    /* Receive the response */
+    hreq->state = READING_RESPONSE;
+    hreq->tcp_state.current_read_size = 0;
+    pj_assert(hreq->buffer.ptr);
+    status = pj_activesock_start_read2(hreq->asock, hreq->pool, BUF_SIZE, 
+                                       (void**)&hreq->buffer.ptr, 0);
+    if (status != PJ_SUCCESS) {
+        /* Error reading */
+        http_req_end_request(hreq);
+        return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t http_req_end_request(pj_http_req *hreq)
+{
+    if (hreq->asock) {
+	pj_activesock_close(hreq->asock);
+        hreq->asock = NULL;
+    }
+
+    /* Cancel query timeout timer. */
+    if (hreq->timer_entry.id != 0) {
+        pj_timer_heap_cancel(hreq->timer, &hreq->timer_entry);
+        /* Invalidate id. */
+        hreq->timer_entry.id = 0;
+    }
+
+    hreq->state = IDLE;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_http_req_cancel(pj_http_req *http_req,
+                                       pj_bool_t notify)
+{
+    http_req->state = ABORTING;
+
+    http_req_end_request(http_req);
+
+    if (notify && http_req->cb.on_complete) {
+        (*http_req->cb.on_complete)(http_req, (!http_req->error? 
+                                    PJ_ECANCELLED: http_req->error), NULL);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_http_req_destroy(pj_http_req *http_req)
+{
+    PJ_ASSERT_RETURN(http_req, PJ_EINVAL);
+    
+    /* If there is any pending request, cancel it */
+    if (http_req->state != IDLE) {
+        pj_http_req_cancel(http_req, PJ_FALSE);
+    }
+
+    pj_pool_release(http_req->pool);
+
+    return PJ_SUCCESS;
+}
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1d9d4c3b55fcc55aedbd551ccf7ad4e099ef56f.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1d9d4c3b55fcc55aedbd551ccf7ad4e099ef56f.svn-base
new file mode 100644
index 0000000..5797d93
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1d9d4c3b55fcc55aedbd551ccf7ad4e099ef56f.svn-base
@@ -0,0 +1,97 @@
+# $Id$
+import imp
+import sys
+import inc_sip as sip
+import inc_const as const
+import re
+from inc_cfg import *
+
+# Read configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# Default server port (should we randomize?)
+srv_port = 50070
+
+def test_func(test):
+	pjsua = test.process[0]
+	dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port, 
+			 local_port=srv_port, 
+			 tcp=cfg_file.recvfrom_cfg.tcp)
+
+	last_cseq = 0
+	last_method = ""
+	last_call_id = ""
+	for t in cfg_file.recvfrom_cfg.transaction:
+		# Print transaction title
+		if t.title != "":
+			dlg.trace(t.title)
+		# Run command and expect patterns
+		for c in t.cmds:
+			if c[0] and c[0] != "":
+				pjsua.send(c[0])
+			if len(c)>1 and c[1] and c[1] != "":
+				pjsua.expect(c[1])
+		# Wait for request
+		if t.check_cseq:
+			# Absorbs retransmissions
+			cseq = 0
+			method = last_method
+			call_id = last_call_id
+			while cseq <= last_cseq and method == last_method and call_id == last_call_id:
+				request, src_addr = dlg.wait_msg_from(30)
+				if request==None or request=="":
+					raise TestError("Timeout waiting for request")
+				method = request.split(" ", 1)[0]
+				cseq_hval = sip.get_header(request, "CSeq")
+				cseq_hval = cseq_hval.split(" ")[0]
+				cseq = int(cseq_hval)
+				call_id = sip.get_header(request, "Call-ID")
+			last_cseq = cseq
+			last_method = method
+		else:
+			request, src_addr = dlg.wait_msg_from(30)
+			if request==None or request=="":
+				raise TestError("Timeout waiting for request")
+
+		# Check for include patterns
+		for pat in t.include:
+			if re.search(pat, request, re.M | re.I)==None:
+				if t.title:
+					tname = " in " + t.title + " transaction"
+				else:
+					tname = ""
+				raise TestError("Pattern " + pat + " not found" + tname)
+		# Check for exclude patterns
+		for pat in t.exclude:
+			if re.search(pat, request, re.M | re.I)!=None:
+				if t.title:
+					tname = " in " + t.title + " transaction"
+				else:
+					tname = ""
+				raise TestError("Excluded pattern " + pat + " found" + tname)
+		# Create response
+		if t.resp_code!=0:
+			response = dlg.create_response(request, t.resp_code, "Status reason")
+			# Add headers to response
+			for h in t.resp_hdr:
+				response = response + h + "\r\n"
+			# Add message body if required
+			if t.body:
+				response = response + t.body
+			# Send response
+			dlg.send_msg(response, src_addr)
+
+		# Expect something to happen in pjsua
+		if t.expect != "":
+			pjsua.expect(t.expect)
+		# Sync
+		pjsua.sync_stdout()
+
+# Replace "$PORT" with server port in pjsua args
+cfg_file.recvfrom_cfg.inst_param.arg = cfg_file.recvfrom_cfg.inst_param.arg.replace("$PORT", str(srv_port))
+
+# Here where it all comes together
+test = TestParam(cfg_file.recvfrom_cfg.name, 
+		 [cfg_file.recvfrom_cfg.inst_param], 
+		 test_func)
+
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1dd38f08617c4a3470cc354c65a1a56dda8298b.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1dd38f08617c4a3470cc354c65a1a56dda8298b.svn-base
new file mode 100644
index 0000000..6c9e617
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1dd38f08617c4a3470cc354c65a1a56dda8298b.svn-base
@@ -0,0 +1,56 @@
+/* $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_CC_MWCC_H__
+#define __PJ_COMPAT_CC_MWCC_H__
+
+/**
+ * @file cc_mwcc.h
+ * @brief Describes MWCC compiler specifics.
+ */
+
+#ifndef __CW32__
+#  error "This file is only for mwcc!"
+#endif
+
+#define PJ_CC_NAME		"mwcc32sym"
+#define PJ_CC_VER_1		1
+#define PJ_CC_VER_2		0
+#define PJ_CC_VER_3		0
+
+
+#define PJ_INLINE_SPECIFIER	static inline
+#define PJ_THREAD_FUNC	
+#define PJ_NORETURN		
+#define PJ_ATTR_NORETURN	__attribute__ ((noreturn))
+#define PJ_ATTR_MAY_ALIAS	
+
+#define PJ_HAS_INT64		1
+
+typedef long long pj_int64_t;
+typedef unsigned long long pj_uint64_t;
+
+#define PJ_INT64(val)		val##LL
+#define PJ_UINT64(val)		val##LLU
+#define PJ_INT64_FMT		"L"
+
+#define PJ_UNREACHED(x)	    	
+
+#endif	/* __PJ_COMPAT_CC_MWCC_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1e132d4872919b50761582e88afc6aec7d210bb.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1e132d4872919b50761582e88afc6aec7d210bb.svn-base
new file mode 100644
index 0000000..c1c5ca2
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1e132d4872919b50761582e88afc6aec7d210bb.svn-base
@@ -0,0 +1,698 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/except.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/high_precision.h>
+#include <pj/compat/sprintf.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/sched.h>
+//#include <linux/tqueue.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
+
+#include <asm/atomic.h>
+#include <asm/unistd.h>
+#include <asm/semaphore.h>
+
+#define THIS_FILE   "oslinuxkern"
+
+struct pj_thread_t
+{
+    /** Thread's name. */
+    char obj_name[PJ_MAX_OBJ_NAME];
+
+    /** Linux task structure for thread. */
+    struct task_struct *thread;	
+
+    /** Flags (specified in pj_thread_create) */
+    unsigned flags;
+
+    /** Task queue needed to launch thread. */
+    //struct tq_struct	tq;	
+
+    /** Semaphore needed to control thread startup. */
+    struct semaphore	startstop_sem;
+
+    /** Semaphore to suspend thread during startup. */
+    struct semaphore	suspend_sem;
+
+    /** Queue thread is waiting on. Gets initialized by
+        thread_initialize, can be used by thread itself.
+     */
+    wait_queue_head_t	queue;
+
+    /** Flag to tell thread whether to die or not.
+        When the thread receives a signal, it must check
+        the value of terminate and call thread_deinitialize and terminate
+        if set.
+     */
+    int terminate;    
+
+    /** Thread's entry. */
+    pj_thread_proc *func;
+
+    /** Argument. */
+    void *arg;
+};
+
+struct pj_atomic_t
+{
+    atomic_t atom;
+};
+
+struct pj_mutex_t
+{
+    struct semaphore sem;
+    pj_bool_t	     recursive;
+    pj_thread_t	    *owner;
+    int		     own_count;
+};
+
+struct pj_sem_t
+{
+    struct semaphore sem;
+};
+
+/*
+ * Static global variables.
+ */
+#define MAX_TLS_ID  32
+static void *tls_values[MAX_TLS_ID];
+static int tls_id;
+static long thread_tls_id;
+static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
+static unsigned long spinlock_flags;
+static pj_thread_t main_thread;
+
+/* private functions */
+//#define TRACE_(expr)	PJ_LOG(3,expr)
+#define TRACE_(x)
+
+
+/* This must be called in the context of the new thread. */
+static void thread_initialize( pj_thread_t *thread )
+{
+    TRACE_((THIS_FILE, "---new thread initializing..."));
+
+    /* Set TLS */
+    pj_thread_local_set(thread_tls_id, thread);
+
+    /* fill in thread structure */
+    thread->thread = current;
+    pj_assert(thread->thread != NULL);
+
+    /* set signal mask to what we want to respond */
+    siginitsetinv(&current->blocked, 
+		  sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
+
+    /* initialise wait queue */
+    init_waitqueue_head(&thread->queue);
+
+    /* initialise termination flag */
+    thread->terminate = 0;
+
+    /* set name of this process (making sure obj_name is null 
+     * terminated first) 
+     */
+    thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    sprintf(current->comm, thread->obj_name);
+        
+    /* tell the creator that we are ready and let him continue */
+    up(&thread->startstop_sem);	
+}
+
+/* cleanup of thread. Called by the exiting thread. */
+static void thread_deinitialize(pj_thread_t *thread)
+{
+    /* we are terminating */
+
+    /* lock the kernel, the exit will unlock it */
+    thread->thread = NULL;
+    mb();
+
+    /* notify the stop_kthread() routine that we are terminating. */
+    up(&thread->startstop_sem);
+
+    /* the kernel_thread that called clone() does a do_exit here. */
+
+    /* there is no race here between execution of the "killer" and 
+       real termination of the thread (race window between up and do_exit), 
+       since both the thread and the "killer" function are running with 
+       the kernel lock held.
+       The kernel lock will be freed after the thread exited, so the code
+       is really not executed anymore as soon as the unload functions gets
+       the kernel lock back.
+       The init process may not have made the cleanup of the process here,
+       but the cleanup can be done safely with the module unloaded.
+    */
+
+}
+
+static int thread_proc(void *arg)
+{
+    pj_thread_t *thread = arg;
+
+    TRACE_((THIS_FILE, "---new thread starting!"));
+
+    /* Initialize thread. */
+    thread_initialize( thread );
+
+    /* Wait if created suspended. */
+    if (thread->flags & PJ_THREAD_SUSPENDED) {
+	TRACE_((THIS_FILE, "---new thread suspended..."));
+	down(&thread->suspend_sem);
+    }
+
+    TRACE_((THIS_FILE, "---new thread running..."));
+
+    pj_assert(thread->func != NULL);
+
+    /* Call thread's entry. */
+    (*thread->func)(thread->arg);
+
+    TRACE_((THIS_FILE, "---thread exiting..."));
+
+    /* Cleanup thread. */
+    thread_deinitialize(thread);
+
+    return 0;
+}
+
+/* The very task entry. */
+static void kthread_launcher(void *arg)
+{
+    TRACE_((THIS_FILE, "...launching thread!..."));
+    kernel_thread(&thread_proc, arg, 0);
+}
+
+PJ_DEF(pj_status_t) pj_init(void)
+{
+    pj_status_t rc;
+
+    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+    rc = pj_thread_init();
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    /* Initialize exception ID for the pool. 
+     * Must do so after critical section is configured.
+     */
+    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+    if (rc != PJ_SUCCESS)
+        return rc;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+    return 1;
+}
+
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+					 pj_thread_desc desc,
+					 pj_thread_t **ptr_thread)
+{
+    char stack_ptr;
+    pj_thread_t *thread = (pj_thread_t *)desc;
+    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
+
+    /* Size sanity check. */
+    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
+	pj_assert(!"Not enough pj_thread_desc size!");
+	return PJ_EBUG;
+    }
+
+    /* If a thread descriptor has been registered before, just return it. */
+    if (pj_thread_local_get (thread_tls_id) != 0) {
+	// 2006-02-26 bennylp:
+	//  This wouldn't work in all cases!.
+	//  If thread is created by external module (e.g. sound thread),
+	//  thread may be reused while the pool used for the thread descriptor
+	//  has been deleted by application.
+	//*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+        //return PJ_SUCCESS;
+    }
+
+    /* Initialize and set the thread entry. */
+    pj_bzero(desc, sizeof(struct pj_thread_t));
+
+    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+	pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
+    else
+	pj_snprintf(thread->obj_name, sizeof(thread->obj_name), 
+		    "thr%p", (void*)thread->thread);
+    
+    /* Initialize. */
+    thread_initialize(thread);
+
+    /* Eat semaphore. */
+    down(&thread->startstop_sem);
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    thread->stk_start = &stack_ptr;
+    thread->stk_size = 0xFFFFFFFFUL;
+    thread->stk_max_usage = 0;
+#else
+    stack_ptr = '\0';
+#endif
+
+    *ptr_thread = thread;
+    return PJ_SUCCESS;
+}
+
+
+pj_status_t pj_thread_init(void)
+{
+    pj_status_t rc;
+    pj_thread_t *dummy;
+    
+    rc = pj_thread_local_alloc(&thread_tls_id);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
+}
+
+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
+				      pj_thread_proc *proc, void *arg,
+				      pj_size_t stack_size, unsigned flags,
+				      pj_thread_t **ptr_thread)
+{
+    pj_thread_t *thread;
+
+    TRACE_((THIS_FILE, "pj_thread_create()"));
+    
+    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
+
+    thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
+    if (!thread)
+	return PJ_ENOMEM;
+
+    PJ_UNUSED_ARG(stack_size);
+
+    /* Thread name. */
+    if (!thread_name) 
+	thread_name = "thr%p";
+    
+    if (strchr(thread_name, '%')) {
+	pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
+    } else {
+	strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+	thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+    
+    /* Init thread's semaphore. */
+    TRACE_((THIS_FILE, "...init semaphores..."));
+    init_MUTEX_LOCKED(&thread->startstop_sem);
+    init_MUTEX_LOCKED(&thread->suspend_sem);
+
+    thread->flags = flags;
+
+    if ((flags & PJ_THREAD_SUSPENDED) == 0) {
+	up(&thread->suspend_sem);
+    }
+
+    /* Store the functions and argument. */
+    thread->func = proc;
+    thread->arg = arg;
+    
+    /* Save return value. */
+    *ptr_thread = thread;
+    
+    /* Create the new thread by running a task through keventd. */
+
+#if 0
+    /* Initialize the task queue struct. */
+    thread->tq.sync = 0;
+    INIT_LIST_HEAD(&thread->tq.list);
+    thread->tq.routine = kthread_launcher;
+    thread->tq.data = thread;
+
+    /* and schedule it for execution. */
+    schedule_task(&thread->tq);
+#endif
+    kthread_launcher(thread);
+
+    /* Wait until thread has reached the setup_thread routine. */
+    TRACE_((THIS_FILE, "...wait for the new thread..."));
+    down(&thread->startstop_sem);
+
+    TRACE_((THIS_FILE, "...main thread resumed..."));
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
+{
+    return thread->obj_name;
+}
+
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
+{
+    up(&thread->suspend_sem);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+    return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
+}
+
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+    TRACE_((THIS_FILE, "pj_thread_join()"));
+    down(&p->startstop_sem);
+    TRACE_((THIS_FILE, "  joined!"));
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
+{
+    PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+    pj_highprec_t ticks;
+    pj_thread_t *thread = pj_thread_this();
+
+    PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
+    
+    /* Use high precision calculation to make sure we don't
+     * crop values:
+     *
+     *	ticks = HZ * msec / 1000
+     */
+    ticks = HZ;
+    pj_highprec_mul(ticks, msec);
+    pj_highprec_div(ticks, 1000);
+
+    TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
+    interruptible_sleep_on_timeout( &thread->queue, ticks);
+    return PJ_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
+				      pj_atomic_value_t value,
+				      pj_atomic_t **ptr_var)
+{
+    pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
+    if (!t) return PJ_ENOMEM;
+
+    atomic_set(&t->atom, value);
+    *ptr_var = t;
+    
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
+{
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
+{
+    atomic_set(&var->atom, value);
+}
+
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
+{
+    return atomic_read(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
+{
+    atomic_inc(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
+{
+    atomic_dec(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
+{
+    atomic_add(value, &var->atom);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+    if (tls_id >= MAX_TLS_ID)
+	return PJ_ETOOMANY;
+    
+    *index = tls_id++;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+    pj_assert(index >= 0 && index < MAX_TLS_ID);
+}
+
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+    pj_assert(index >= 0 && index < MAX_TLS_ID);
+    tls_values[index] = value;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+    pj_assert(index >= 0 && index < MAX_TLS_ID);
+    return tls_values[index];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+    spin_lock_irqsave(&critical_section, spinlock_flags);
+}
+
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+    spin_unlock_irqrestore(&critical_section, spinlock_flags);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, 
+				     const char *name, 
+				     int type,
+				     pj_mutex_t **ptr_mutex)
+{
+    pj_mutex_t *mutex;
+    
+    PJ_UNUSED_ARG(name);
+
+    mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
+    if (!mutex)
+	return PJ_ENOMEM;
+
+    init_MUTEX(&mutex->sem);
+
+    mutex->recursive = (type == PJ_MUTEX_RECURSE);
+    mutex->owner = NULL;
+    mutex->own_count = 0;
+    
+    /* Done. */
+    *ptr_mutex = mutex;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
+					    pj_mutex_t **mutex )
+{
+    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+					       const char *name,
+					       pj_mutex_t **mutex )
+{
+    return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    if (mutex->recursive) {
+	pj_thread_t *this_thread = pj_thread_this();
+	if (mutex->owner == this_thread) {
+	    ++mutex->own_count;
+	} else {
+	    down(&mutex->sem);
+	    pj_assert(mutex->own_count == 0);
+	    mutex->owner = this_thread;
+	    mutex->own_count = 1;
+	}
+    } else {
+	down(&mutex->sem);
+    }
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+    long rc;
+
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    if (mutex->recursive) {
+	pj_thread_t *this_thread = pj_thread_this();
+	if (mutex->owner == this_thread) {
+	    ++mutex->own_count;
+	} else {
+	    rc = down_interruptible(&mutex->sem);
+	    if (rc != 0)
+		return PJ_RETURN_OS_ERROR(-rc);
+	    pj_assert(mutex->own_count == 0);
+	    mutex->owner = this_thread;
+	    mutex->own_count = 1;
+	}
+    } else {
+	int rc = down_trylock(&mutex->sem);
+	if (rc != 0)
+	    return PJ_RETURN_OS_ERROR(-rc);
+    }
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    if (mutex->recursive) {
+	pj_thread_t *this_thread = pj_thread_this();
+	if (mutex->owner == this_thread) {
+	    pj_assert(mutex->own_count > 0);
+	    --mutex->own_count;
+	    if (mutex->own_count == 0) {
+		mutex->owner = NULL;
+		up(&mutex->sem);
+	    }
+	} else {
+	    pj_assert(!"Not owner!");
+	    return PJ_EINVALIDOP;
+	}
+    } else {
+	up(&mutex->sem);
+    }
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+    PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
+
+    return PJ_SUCCESS;
+}
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+    if (mutex->recursive)
+	return mutex->owner == pj_thread_this();
+    else
+	return 1;
+}
+#endif	/* PJ_DEBUG */
+
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+PJ_DEF(pj_status_t) pj_sem_create(  pj_pool_t *pool, 
+                                    const char *name,
+				    unsigned initial, 
+                                    unsigned max,
+				    pj_sem_t **sem)
+{
+    pj_sem_t *sem;
+
+    PJ_UNUSED_ARG(max);
+
+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+    
+    sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
+    sema_init(&sem->sem, initial);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+    down(&sem->sem);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+    int rc;
+
+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+    rc = down_trylock(&sem->sem);
+    if (rc != 0) {
+	return PJ_RETURN_OS_ERROR(-rc);
+    } else {
+	return PJ_SUCCESS;
+    }
+}
+
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+    up(&sem->sem);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+    return PJ_SUCCESS;
+}
+
+#endif	/* PJ_HAS_SEMAPHORE */
+
+
+
+
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1e9615748a2dc83bd7f555ab0f6e9a64616b3fc.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1e9615748a2dc83bd7f555ab0f6e9a64616b3fc.svn-base
new file mode 100644
index 0000000..188b17b
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1e9615748a2dc83bd7f555ab0f6e9a64616b3fc.svn-base
@@ -0,0 +1,19 @@
+# $Id$
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+	ADD_PARAM += "--null-audio"
+
+# Call with default pjsua settings
+test_param = TestParam(
+		"PESQ defaults pjsua settings",
+		[
+			InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --play-file wavs/input.16.wav --no-vad"),
+			InstanceParam("UA2", "--null-audio --max-calls=1 --rec-file  wavs/tmp.16.wav --clock-rate 16000 --auto-answer 200")
+		]
+		)
+
+pesq_threshold = 3.8
diff --git a/jni/pjproject-android/.svn/pristine/d1/d1f14058b0db53ba0881d2f9bfe8d3ab0e99c32d.svn-base b/jni/pjproject-android/.svn/pristine/d1/d1f14058b0db53ba0881d2f9bfe8d3ab0e99c32d.svn-base
new file mode 100644
index 0000000..1aba657
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/d1/d1f14058b0db53ba0881d2f9bfe8d3ab0e99c32d.svn-base
@@ -0,0 +1,326 @@
+
+   /******************************************************************
+
+       iLBC Speech Coder ANSI-C Source Code
+
+       helpfun.c
+
+       Copyright (C) The Internet Society (2004).
+       All Rights Reserved.
+
+   ******************************************************************/
+
+   #include <math.h>
+
+   #include "iLBC_define.h"
+   #include "constants.h"
+
+   /*----------------------------------------------------------------*
+    *  calculation of auto correlation
+    *---------------------------------------------------------------*/
+
+   void autocorr(
+       float *r,       /* (o) autocorrelation vector */
+       const float *x, /* (i) data vector */
+       int N,          /* (i) length of data vector */
+       int order       /* largest lag for calculated
+                          autocorrelations */
+   ){
+       int     lag, n;
+       float   sum;
+
+       for (lag = 0; lag <= order; lag++) {
+           sum = 0;
+           for (n = 0; n < N - lag; n++) {
+               sum += x[n] * x[n+lag];
+           }
+           r[lag] = sum;
+       }
+
+
+
+
+
+   }
+
+   /*----------------------------------------------------------------*
+    *  window multiplication
+    *---------------------------------------------------------------*/
+
+   void window(
+       float *z,       /* (o) the windowed data */
+       const float *x, /* (i) the original data vector */
+       const float *y, /* (i) the window */
+       int N           /* (i) length of all vectors */
+   ){
+       int     i;
+
+       for (i = 0; i < N; i++) {
+           z[i] = x[i] * y[i];
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  levinson-durbin solution for lpc coefficients
+    *---------------------------------------------------------------*/
+
+   void levdurb(
+       float *a,       /* (o) lpc coefficient vector starting
+                              with 1.0 */
+       float *k,       /* (o) reflection coefficients */
+       float *r,       /* (i) autocorrelation vector */
+       int order       /* (i) order of lpc filter */
+   ){
+       float  sum, alpha;
+       int     m, m_h, i;
+
+       a[0] = 1.0;
+
+       if (r[0] < EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
+           for (i = 0; i < order; i++) {
+               k[i] = 0;
+               a[i+1] = 0;
+           }
+       } else {
+           a[1] = k[0] = -r[1]/r[0];
+           alpha = r[0] + r[1] * k[0];
+           for (m = 1; m < order; m++){
+               sum = r[m + 1];
+               for (i = 0; i < m; i++){
+                   sum += a[i+1] * r[m - i];
+               }
+
+
+
+
+
+               k[m] = -sum / alpha;
+               alpha += k[m] * sum;
+               m_h = (m + 1) >> 1;
+               for (i = 0; i < m_h; i++){
+                   sum = a[i+1] + k[m] * a[m - i];
+                   a[m - i] += k[m] * a[i+1];
+                   a[i+1] = sum;
+               }
+               a[m+1] = k[m];
+           }
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  interpolation between vectors
+    *---------------------------------------------------------------*/
+
+   void interpolate(
+       float *out,      /* (o) the interpolated vector */
+       float *in1,     /* (i) the first vector for the
+                              interpolation */
+       float *in2,     /* (i) the second vector for the
+                              interpolation */
+       float coef,      /* (i) interpolation weights */
+       int length      /* (i) length of all vectors */
+   ){
+       int i;
+       float invcoef;
+
+       invcoef = (float)1.0 - coef;
+       for (i = 0; i < length; i++) {
+           out[i] = coef * in1[i] + invcoef * in2[i];
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  lpc bandwidth expansion
+    *---------------------------------------------------------------*/
+
+   void bwexpand(
+       float *out,      /* (o) the bandwidth expanded lpc
+                              coefficients */
+       float *in,      /* (i) the lpc coefficients before bandwidth
+                              expansion */
+       float coef,     /* (i) the bandwidth expansion factor */
+       int length      /* (i) the length of lpc coefficient vectors */
+   ){
+       int i;
+
+
+
+
+
+       float  chirp;
+
+       chirp = coef;
+
+       out[0] = in[0];
+       for (i = 1; i < length; i++) {
+           out[i] = chirp * in[i];
+           chirp *= coef;
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  vector quantization
+    *---------------------------------------------------------------*/
+
+   void vq(
+       float *Xq,      /* (o) the quantized vector */
+       int *index,     /* (o) the quantization index */
+       const float *CB,/* (i) the vector quantization codebook */
+       float *X,       /* (i) the vector to quantize */
+       int n_cb,       /* (i) the number of vectors in the codebook */
+       int dim         /* (i) the dimension of all vectors */
+   ){
+       int     i, j;
+       int     pos, minindex;
+       float   dist, tmp, mindist;
+
+       pos = 0;
+       mindist = FLOAT_MAX;
+       minindex = 0;
+       for (j = 0; j < n_cb; j++) {
+           dist = X[0] - CB[pos];
+           dist *= dist;
+           for (i = 1; i < dim; i++) {
+               tmp = X[i] - CB[pos + i];
+               dist += tmp*tmp;
+           }
+
+           if (dist < mindist) {
+               mindist = dist;
+               minindex = j;
+           }
+           pos += dim;
+       }
+       for (i = 0; i < dim; i++) {
+           Xq[i] = CB[minindex*dim + i];
+       }
+       *index = minindex;
+
+
+
+
+
+   }
+
+   /*----------------------------------------------------------------*
+    *  split vector quantization
+    *---------------------------------------------------------------*/
+
+   void SplitVQ(
+       float *qX,      /* (o) the quantized vector */
+       int *index,     /* (o) a vector of indexes for all vector
+                              codebooks in the split */
+       float *X,       /* (i) the vector to quantize */
+       const float *CB,/* (i) the quantizer codebook */
+       int nsplit,     /* the number of vector splits */
+       const int *dim, /* the dimension of X and qX */
+       const int *cbsize /* the number of vectors in the codebook */
+   ){
+       int    cb_pos, X_pos, i;
+
+       cb_pos = 0;
+       X_pos= 0;
+       for (i = 0; i < nsplit; i++) {
+           vq(qX + X_pos, index + i, CB + cb_pos, X + X_pos,
+               cbsize[i], dim[i]);
+           X_pos += dim[i];
+           cb_pos += dim[i] * cbsize[i];
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  scalar quantization
+    *---------------------------------------------------------------*/
+
+   void sort_sq(
+       float *xq,      /* (o) the quantized value */
+       int *index,     /* (o) the quantization index */
+       float x,    /* (i) the value to quantize */
+       const float *cb,/* (i) the quantization codebook */
+       int cb_size      /* (i) the size of the quantization codebook */
+   ){
+       int i;
+
+       if (x <= cb[0]) {
+           *index = 0;
+           *xq = cb[0];
+       } else {
+           i = 0;
+           while ((x > cb[i]) && i < cb_size - 1) {
+               i++;
+
+
+
+
+
+           }
+
+           if (x > ((cb[i] + cb[i - 1])/2)) {
+               *index = i;
+               *xq = cb[i];
+           } else {
+               *index = i - 1;
+               *xq = cb[i - 1];
+           }
+       }
+   }
+
+   /*----------------------------------------------------------------*
+    *  check for stability of lsf coefficients
+    *---------------------------------------------------------------*/
+
+   int LSF_check(    /* (o) 1 for stable lsf vectors and 0 for
+                              nonstable ones */
+       float *lsf,     /* (i) a table of lsf vectors */
+       int dim,    /* (i) the dimension of each lsf vector */
+       int NoAn    /* (i) the number of lsf vectors in the
+                              table */
+   ){
+       int k,n,m, Nit=2, change=0,pos;
+       float tmp;
+       static float eps=(float)0.039; /* 50 Hz */
+       static float eps2=(float)0.0195;
+       static float maxlsf=(float)3.14; /* 4000 Hz */
+       static float minlsf=(float)0.01; /* 0 Hz */
+
+       /* LSF separation check*/
+
+       for (n=0; n<Nit; n++) { /* Run through a couple of times */
+           for (m=0; m<NoAn; m++) { /* Number of analyses per frame */
+               for (k=0; k<(dim-1); k++) {
+                   pos=m*dim+k;
+
+                   if ((lsf[pos+1]-lsf[pos])<eps) {
+
+                       if (lsf[pos+1]<lsf[pos]) {
+                           tmp=lsf[pos+1];
+                           lsf[pos+1]= lsf[pos]+eps2;
+                           lsf[pos]= lsf[pos+1]-eps2;
+                       } else {
+                           lsf[pos]-=eps2;
+                           lsf[pos+1]+=eps2;
+                       }
+                       change=1;
+
+
+
+
+
+                   }
+
+                   if (lsf[pos]<minlsf) {
+                       lsf[pos]=minlsf;
+                       change=1;
+                   }
+
+                   if (lsf[pos]>maxlsf) {
+                       lsf[pos]=maxlsf;
+                       change=1;
+                   }
+               }
+           }
+       }
+
+       return change;
+   }
+