* #27232: jni: added pjproject checkout as regular git content

We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/f4/f403d504d3745ca5d933332c6450cb230581c7de.svn-base b/jni/pjproject-android/.svn/pristine/f4/f403d504d3745ca5d933332c6450cb230581c7de.svn-base
new file mode 100644
index 0000000..2ee1475
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f403d504d3745ca5d933332c6450cb230581c7de.svn-base
@@ -0,0 +1,112 @@
+/*
+========================================================================
+ Name        : pjsuaContainer.h
+ Author      : nanang
+ Copyright   : Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ Description : 
+========================================================================
+*/
+#ifndef PJSUACONTAINER_H
+#define PJSUACONTAINER_H
+
+// [[[ begin generated region: do not modify [Generated Includes]
+#include <coecntrl.h>		
+// ]]] end generated region [Generated Includes]
+
+
+// [[[ begin [Event Handler Includes]
+// ]]] end [Event Handler Includes]
+
+// [[[ begin generated region: do not modify [Generated Forward Declarations]
+class MEikCommandObserver;		
+class CEikImage;
+class CEikLabel;
+// ]]] end generated region [Generated Forward Declarations]
+
+/**
+ * Container class for pjsuaContainer
+ * 
+ * @class	CPjsuaContainer pjsuaContainer.h
+ */
+class CPjsuaContainer : public CCoeControl
+	{
+public:
+	// constructors and destructor
+	CPjsuaContainer();
+	static CPjsuaContainer* NewL( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver );
+	static CPjsuaContainer* NewLC( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver );
+	void ConstructL( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver );
+	virtual ~CPjsuaContainer();
+
+public:
+	// from base class CCoeControl
+	TInt CountComponentControls() const;
+	CCoeControl* ComponentControl( TInt aIndex ) const;
+	TKeyResponse OfferKeyEventL( 
+			const TKeyEvent& aKeyEvent, 
+			TEventCode aType );
+	void HandleResourceChange( TInt aType );
+	
+protected:
+	// from base class CCoeControl
+	void SizeChanged();
+
+private:
+	// from base class CCoeControl
+	void Draw( const TRect& aRect ) const;
+
+private:
+	void InitializeControlsL();
+	void LayoutControls();
+	CCoeControl* iFocusControl;
+	MEikCommandObserver* iCommandObserver;
+	// [[[ begin generated region: do not modify [Generated Methods]
+public: 
+	// ]]] end generated region [Generated Methods]
+	
+	void PutMessageL( const char* msg );
+	// [[[ begin generated region: do not modify [Generated Type Declarations]
+public: 
+	// ]]] end generated region [Generated Type Declarations]
+	
+	// [[[ begin generated region: do not modify [Generated Instance Variables]
+private: 
+	CEikImage* iImage1;
+	CEikLabel* iLabel1;
+	// ]]] end generated region [Generated Instance Variables]
+	
+	
+	// [[[ begin [Overridden Methods]
+protected: 
+	// ]]] end [Overridden Methods]
+	
+	
+	// [[[ begin [User Handlers]
+protected: 
+	// ]]] end [User Handlers]
+	
+public: 
+	enum TControls
+		{
+		// [[[ begin generated region: do not modify [Generated Contents]
+		EImage1,
+		ELabel1,
+		
+		// ]]] end generated region [Generated Contents]
+		
+		// add any user-defined entries here...
+		
+		ELastControl
+		};
+	};
+				
+#endif // PJSUACONTAINER_H
diff --git a/jni/pjproject-android/.svn/pristine/f4/f425a28258b06d8f2a1d295ea816c0985170e9a0.svn-base b/jni/pjproject-android/.svn/pristine/f4/f425a28258b06d8f2a1d295ea816c0985170e9a0.svn-base
new file mode 100644
index 0000000..e2fb71d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f425a28258b06d8f2a1d295ea816c0985170e9a0.svn-base
@@ -0,0 +1,227 @@
+/* Copyright (C) 2006 Jean-Marc Valin */
+/**
+   @file filterbank.c
+   @brief Converting between psd and filterbank
+ */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "filterbank.h"
+#include "arch.h"
+#include <math.h>
+#include "math_approx.h"
+#include "os_support.h"
+      
+#ifdef FIXED_POINT
+
+#define toBARK(n)   (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n))
+      
+#else
+#define toBARK(n)   (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
+#endif
+       
+#define toMEL(n)    (2595.f*log10(1.f+(n)/700.f))
+
+FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type)
+{
+   FilterBank *bank;
+   spx_word32_t df;
+   spx_word32_t max_mel, mel_interval;
+   int i;
+   int id1;
+   int id2;
+   df = DIV32(SHL32(sampling,15),MULT16_16(2,len));
+   max_mel = toBARK(EXTRACT16(sampling/2));
+   mel_interval = PDIV32(max_mel,banks-1);
+   
+   bank = (FilterBank*)speex_alloc(sizeof(FilterBank));
+   bank->nb_banks = banks;
+   bank->len = len;
+   bank->bank_left = (int*)speex_alloc(len*sizeof(int));
+   bank->bank_right = (int*)speex_alloc(len*sizeof(int));
+   bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
+   bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
+   /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   bank->scaling = (float*)speex_alloc(banks*sizeof(float));
+#endif
+   for (i=0;i<len;i++)
+   {
+      spx_word16_t curr_freq;
+      spx_word32_t mel;
+      spx_word16_t val;
+      curr_freq = EXTRACT16(MULT16_32_P15(i,df));
+      mel = toBARK(curr_freq);
+      if (mel > max_mel)
+         break;
+#ifdef FIXED_POINT
+      id1 = DIV32(mel,mel_interval);
+#else      
+      id1 = (int)(floor(mel/mel_interval));
+#endif
+      if (id1>banks-2)
+      {
+         id1 = banks-2;
+         val = Q15_ONE;
+      } else {
+         val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15)));
+      }
+      id2 = id1+1;
+      bank->bank_left[i] = id1;
+      bank->filter_left[i] = SUB16(Q15_ONE,val);
+      bank->bank_right[i] = id2;
+      bank->filter_right[i] = val;
+   }
+   
+   /* Think I can safely disable normalisation for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   for (i=0;i<bank->nb_banks;i++)
+      bank->scaling[i] = 0;
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      bank->scaling[id] += bank->filter_left[i];
+      id = bank->bank_right[i];
+      bank->scaling[id] += bank->filter_right[i];
+   }
+   for (i=0;i<bank->nb_banks;i++)
+      bank->scaling[i] = Q15_ONE/(bank->scaling[i]);
+#endif
+   return bank;
+}
+
+void filterbank_destroy(FilterBank *bank)
+{
+   speex_free(bank->bank_left);
+   speex_free(bank->bank_right);
+   speex_free(bank->filter_left);
+   speex_free(bank->filter_right);
+#ifndef FIXED_POINT
+   speex_free(bank->scaling);
+#endif
+   speex_free(bank);
+}
+
+void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel)
+{
+   int i;
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] = 0;
+
+   for (i=0;i<bank->len;i++)
+   {
+      int id;
+      id = bank->bank_left[i];
+      mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]);
+      id = bank->bank_right[i];
+      mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]);
+   }
+   /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   /*for (i=0;i<bank->nb_banks;i++)
+      mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]);
+   */
+#endif
+}
+
+void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps)
+{
+   int i;
+   for (i=0;i<bank->len;i++)
+   {
+      spx_word32_t tmp;
+      int id1, id2;
+      id1 = bank->bank_left[i];
+      id2 = bank->bank_right[i];
+      tmp = MULT16_16(mel[id1],bank->filter_left[i]);
+      tmp += MULT16_16(mel[id2],bank->filter_right[i]);
+      ps[i] = EXTRACT16(PSHR32(tmp,15));
+   }
+}
+
+
+#ifndef FIXED_POINT
+void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel)
+{
+   int i;
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] = 0;
+
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      mel[id] += bank->filter_left[i]*ps[i];
+      id = bank->bank_right[i];
+      mel[id] += bank->filter_right[i]*ps[i];
+   }
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] *= bank->scaling[i];
+}
+
+void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps)
+{
+   int i;
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      ps[i] = mel[id]*bank->filter_left[i];
+      id = bank->bank_right[i];
+      ps[i] += mel[id]*bank->filter_right[i];
+   }
+}
+
+void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask)
+{
+   /* Low freq slope: 14 dB/Bark*/
+   /* High freq slope: 9 dB/Bark*/
+   /* Noise vs tone: 5 dB difference */
+   /* FIXME: Temporary kludge */
+   float bark[100];
+   int i;
+   /* Assumes 1/3 Bark resolution */
+   float decay_low = 0.34145f;
+   float decay_high = 0.50119f;
+   filterbank_compute_bank(bank, ps, bark);
+   for (i=1;i<bank->nb_banks;i++)
+   {
+      /*float decay_high = 13-1.6*log10(bark[i-1]);
+      decay_high = pow(10,(-decay_high/30.f));*/
+      bark[i] = bark[i] + decay_high*bark[i-1];
+   }
+   for (i=bank->nb_banks-2;i>=0;i--)
+   {
+      bark[i] = bark[i] + decay_low*bark[i+1];
+   }
+   filterbank_compute_psd(bank, bark, mask);
+}
+
+#endif
diff --git a/jni/pjproject-android/.svn/pristine/f4/f4391d07f8e7e215717199778b6607f58e1d556b.svn-base b/jni/pjproject-android/.svn/pristine/f4/f4391d07f8e7e215717199778b6607f58e1d556b.svn-base
new file mode 100644
index 0000000..645fd88
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f4391d07f8e7e215717199778b6607f58e1d556b.svn-base
@@ -0,0 +1,304 @@
+/* $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 
+ */
+
+
+/**
+ * \page page_pjmedia_samples_aectest_c Samples: AEC Test (aectest.c)
+ *
+ * Play a file to speaker, run AEC, and record the microphone input
+ * to see if echo is coming.
+ *
+ * This file is pjsip-apps/src/samples/aectest.c
+ *
+ * \includelineno aectest.c
+ */
+#include <pjmedia.h>
+#include <pjlib-util.h>	/* pj_getopt */
+#include <pjlib.h>
+
+#define THIS_FILE   "aectest.c"
+#define PTIME	    20
+#define TAIL_LENGTH 200
+
+static const char *desc = 
+" FILE		    						    \n"
+"		    						    \n"
+"  aectest.c	    						    \n"
+"		    						    \n"
+" PURPOSE	    						    \n"
+"		    						    \n"
+"  Test the AEC effectiveness.					    \n"
+"		    						    \n"
+" USAGE		    						    \n"
+"		    						    \n"
+"  aectest [options] <PLAY.WAV> <REC.WAV> <OUTPUT.WAV>		    \n"
+"		    						    \n"
+"  <PLAY.WAV>   is the signal played to the speaker.		    \n"
+"  <REC.WAV>    is the signal captured from the microphone.	    \n"
+"  <OUTPUT.WAV> is the output file to store the test result	    \n"
+"\n"
+" options:\n"
+"  -d  The delay between playback and capture in ms, at least 25 ms.\n"
+"      Default is 25 ms. See note below.                            \n"
+"  -l  Set the echo tail length in ms. Default is 200 ms	    \n"
+"  -r  Set repeat count (default=1)                                 \n"
+"  -a  Algorithm: 0=default, 1=speex, 3=echo suppress		    \n"
+"  -i  Interactive						    \n"
+"\n"
+" Note that for the AEC internal buffering mechanism, it is required\n"
+" that the echoed signal (in REC.WAV) is delayed from the           \n"
+" corresponding reference signal (in PLAY.WAV) at least as much as  \n"
+" frame time + PJMEDIA_WSOLA_DELAY_MSEC. In this application, frame \n"
+" time is 20 ms and default PJMEDIA_WSOLA_DELAY_MSEC is 5 ms, hence \n"
+" 25 ms delay is the minimum value.                                 \n";
+
+/* 
+ * Sample session:
+ *
+ * -d 100 -a 1 ../bin/orig8.wav ../bin/echo8.wav ../bin/result8.wav 
+ */
+
+static void app_perror(const char *sender, const char *title, pj_status_t st)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+
+    pj_strerror(st, errmsg, sizeof(errmsg));
+    PJ_LOG(3,(sender, "%s: %s", title, errmsg));
+}
+
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+    pj_caching_pool cp;
+    pjmedia_endpt *med_endpt;
+    pj_pool_t	  *pool;
+    pjmedia_port  *wav_play;
+    pjmedia_port  *wav_rec;
+    pjmedia_port  *wav_out;
+    pj_status_t status;
+    pjmedia_echo_state *ec;
+    pjmedia_frame play_frame, rec_frame;
+    unsigned opt = 0;
+    unsigned latency_ms = 25;
+    unsigned tail_ms = TAIL_LENGTH;
+    pj_timestamp t0, t1;
+    int i, repeat=1, interactive=0, c;
+
+    pj_optind = 0;
+    while ((c=pj_getopt(argc, argv, "d:l:a:r:i")) !=-1) {
+	switch (c) {
+	case 'd':
+	    latency_ms = atoi(pj_optarg);
+	    if (latency_ms < 25) {
+		puts("Invalid delay");
+		puts(desc);
+	    }
+	    break;
+	case 'l':
+	    tail_ms = atoi(pj_optarg);
+	    break;
+	case 'a':
+	    {
+		int alg = atoi(pj_optarg);
+		switch (alg) {
+		case 0:
+		    opt = 0;
+		case 1:
+		    opt = PJMEDIA_ECHO_SPEEX;
+		    break;
+		case 3:
+		    opt = PJMEDIA_ECHO_SIMPLE;
+		    break;
+		default:
+		    puts("Invalid algorithm");
+		    puts(desc);
+		    return 1;
+		}
+	    }
+	    break;
+	case 'r':
+	    repeat = atoi(pj_optarg);
+	    if (repeat < 1) {
+		puts("Invalid repeat count");
+		puts(desc);
+		return 1;
+	    }
+	    break;
+	case 'i':
+	    interactive = 1;
+	    break;
+	}
+    }
+
+    if (argc - pj_optind != 3) {
+	puts("Error: missing argument(s)");
+	puts(desc);
+	return 1;
+    }
+
+    /* Must init PJLIB first: */
+    status = pj_init();
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+    /* Must create a pool factory before we can allocate any memory. */
+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+    /* 
+     * Initialize media endpoint.
+     * This will implicitly initialize PJMEDIA too.
+     */
+    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+    /* Create memory pool for our file player */
+    pool = pj_pool_create( &cp.factory,	    /* pool factory	    */
+			   "wav",	    /* pool name.	    */
+			   4000,	    /* init size	    */
+			   4000,	    /* increment size	    */
+			   NULL		    /* callback on error    */
+			   );
+
+    /* Open wav_play */
+    status = pjmedia_wav_player_port_create(pool, argv[pj_optind], PTIME, 
+					    PJMEDIA_FILE_NO_LOOP, 0, 
+					    &wav_play);
+    if (status != PJ_SUCCESS) {
+	app_perror(THIS_FILE, "Error opening playback WAV file", status);
+	return 1;
+    }
+    
+    /* Open recorded wav */
+    status = pjmedia_wav_player_port_create(pool, argv[pj_optind+1], PTIME, 
+					    PJMEDIA_FILE_NO_LOOP, 0, 
+					    &wav_rec);
+    if (status != PJ_SUCCESS) {
+	app_perror(THIS_FILE, "Error opening recorded WAV file", status);
+	return 1;
+    }
+
+    /* play and rec WAVs must have the same clock rate */
+    if (PJMEDIA_PIA_SRATE(&wav_play->info) != PJMEDIA_PIA_SRATE(&wav_rec->info)) {
+	puts("Error: clock rate mismatch in the WAV files");
+	return 1;
+    }
+
+    /* .. and channel count */
+    if (PJMEDIA_PIA_CCNT(&wav_play->info) != PJMEDIA_PIA_CCNT(&wav_rec->info)) {
+	puts("Error: clock rate mismatch in the WAV files");
+	return 1;
+    }
+
+    /* Create output wav */
+    status = pjmedia_wav_writer_port_create(pool, argv[pj_optind+2],
+					    PJMEDIA_PIA_SRATE(&wav_play->info),
+					    PJMEDIA_PIA_CCNT(&wav_play->info),
+					    PJMEDIA_PIA_SPF(&wav_play->info),
+					    PJMEDIA_PIA_BITS(&wav_play->info),
+					    0, 0, &wav_out);
+    if (status != PJ_SUCCESS) {
+	app_perror(THIS_FILE, "Error opening output WAV file", status);
+	return 1;
+    }
+
+    /* Create echo canceller */
+    status = pjmedia_echo_create2(pool, PJMEDIA_PIA_SRATE(&wav_play->info),
+				  PJMEDIA_PIA_CCNT(&wav_play->info),
+				  PJMEDIA_PIA_SPF(&wav_play->info),
+				  tail_ms, latency_ms,
+				  opt, &ec);
+    if (status != PJ_SUCCESS) {
+	app_perror(THIS_FILE, "Error creating EC", status);
+	return 1;
+    }
+
+
+    /* Processing loop */
+    play_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
+    rec_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
+    pj_get_timestamp(&t0);
+    for (i=0; i < repeat; ++i) {
+	for (;;) {
+	    play_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
+	    status = pjmedia_port_get_frame(wav_play, &play_frame);
+	    if (status != PJ_SUCCESS)
+		break;
+
+	    status = pjmedia_echo_playback(ec, (short*)play_frame.buf);
+
+	    rec_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
+	    status = pjmedia_port_get_frame(wav_rec, &rec_frame);
+	    if (status != PJ_SUCCESS)
+		break;
+
+	    status = pjmedia_echo_capture(ec, (short*)rec_frame.buf, 0);
+
+	    //status = pjmedia_echo_cancel(ec, (short*)rec_frame.buf, 
+	    //			     (short*)play_frame.buf, 0, NULL);
+
+	    pjmedia_port_put_frame(wav_out, &rec_frame);
+	}
+
+	pjmedia_wav_player_port_set_pos(wav_play, 0);
+	pjmedia_wav_player_port_set_pos(wav_rec, 0);
+    }
+    pj_get_timestamp(&t1);
+
+    i = (int)pjmedia_wav_writer_port_get_pos(wav_out) / sizeof(pj_int16_t) * 1000 / 
+	 (PJMEDIA_PIA_SRATE(&wav_out->info) * PJMEDIA_PIA_CCNT(&wav_out->info));
+    PJ_LOG(3,(THIS_FILE, "Processed %3d.%03ds audio",
+	      i / 1000, i % 1000));
+    PJ_LOG(3,(THIS_FILE, "Completed in %u msec\n", pj_elapsed_msec(&t0, &t1)));
+
+    /* Destroy file port(s) */
+    status = pjmedia_port_destroy( wav_play );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+    status = pjmedia_port_destroy( wav_rec );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+    status = pjmedia_port_destroy( wav_out );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+    /* Destroy ec */
+    pjmedia_echo_destroy(ec);
+
+    /* Release application pool */
+    pj_pool_release( pool );
+
+    /* Destroy media endpoint. */
+    pjmedia_endpt_destroy( med_endpt );
+
+    /* Destroy pool factory */
+    pj_caching_pool_destroy( &cp );
+
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
+    if (interactive) {
+	char s[10], *dummy;
+	puts("ENTER to quit");
+	dummy = fgets(s, sizeof(s), stdin);
+    }
+
+    /* Done. */
+    return 0;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/f4/f448eef8bca4bc9647eb1eb80d4ce300b7858f09.svn-base b/jni/pjproject-android/.svn/pristine/f4/f448eef8bca4bc9647eb1eb80d4ce300b7858f09.svn-base
new file mode 100644
index 0000000..a88e77d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f448eef8bca4bc9647eb1eb80d4ce300b7858f09.svn-base
@@ -0,0 +1,479 @@
+/* $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/wav_port.h>
+#include <pjmedia/alaw_ulaw.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/wave.h>
+#include <pj/assert.h>
+#include <pj/file_access.h>
+#include <pj/file_io.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+#define THIS_FILE	    "wav_writer.c"
+#define SIGNATURE	    PJMEDIA_SIG_PORT_WAV_WRITER
+
+
+struct file_port
+{
+    pjmedia_port     base;
+    pjmedia_wave_fmt_tag fmt_tag;
+    pj_uint16_t	     bytes_per_sample;
+
+    pj_size_t	     bufsize;
+    char	    *buf;
+    char	    *writepos;
+    pj_size_t	     total;
+
+    pj_oshandle_t    fd;
+
+    pj_size_t	     cb_size;
+    pj_status_t	   (*cb)(pjmedia_port*, void*);
+};
+
+static pj_status_t file_put_frame(pjmedia_port *this_port, 
+				  pjmedia_frame *frame);
+static pj_status_t file_get_frame(pjmedia_port *this_port, 
+				  pjmedia_frame *frame);
+static pj_status_t file_on_destroy(pjmedia_port *this_port);
+
+
+/*
+ * Create file writer port.
+ */
+PJ_DEF(pj_status_t) pjmedia_wav_writer_port_create( pj_pool_t *pool,
+						     const char *filename,
+						     unsigned sampling_rate,
+						     unsigned channel_count,
+						     unsigned samples_per_frame,
+						     unsigned bits_per_sample,
+						     unsigned flags,
+						     pj_ssize_t buff_size,
+						     pjmedia_port **p_port )
+{
+    struct file_port *fport;
+    pjmedia_wave_hdr wave_hdr;
+    pj_ssize_t size;
+    pj_str_t name;
+    pj_status_t status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);
+
+    /* Only supports 16bits per sample for now.
+     * See flush_buffer().
+     */
+    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
+
+    /* Create file port instance. */
+    fport = PJ_POOL_ZALLOC_T(pool, struct file_port);
+    PJ_ASSERT_RETURN(fport != NULL, PJ_ENOMEM);
+
+    /* Initialize port info. */
+    pj_strdup2(pool, &name, filename);
+    pjmedia_port_info_init(&fport->base.info, &name, SIGNATURE,
+			   sampling_rate, channel_count, bits_per_sample,
+			   samples_per_frame);
+
+    fport->base.get_frame = &file_get_frame;
+    fport->base.put_frame = &file_put_frame;
+    fport->base.on_destroy = &file_on_destroy;
+
+    if (flags == PJMEDIA_FILE_WRITE_ALAW) {
+	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ALAW;
+	fport->bytes_per_sample = 1;
+    } else if (flags == PJMEDIA_FILE_WRITE_ULAW) {
+	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ULAW;
+	fport->bytes_per_sample = 1;
+    } else {
+	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_PCM;
+	fport->bytes_per_sample = 2;
+    }
+
+    /* Open file in write and read mode.
+     * We need the read mode because we'll modify the WAVE header once
+     * the recording has completed.
+     */
+    status = pj_file_open(pool, filename, PJ_O_WRONLY, &fport->fd);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Initialize WAVE header */
+    pj_bzero(&wave_hdr, sizeof(pjmedia_wave_hdr));
+    wave_hdr.riff_hdr.riff = PJMEDIA_RIFF_TAG;
+    wave_hdr.riff_hdr.file_len = 0; /* will be filled later */
+    wave_hdr.riff_hdr.wave = PJMEDIA_WAVE_TAG;
+
+    wave_hdr.fmt_hdr.fmt = PJMEDIA_FMT_TAG;
+    wave_hdr.fmt_hdr.len = 16;
+    wave_hdr.fmt_hdr.fmt_tag = (pj_uint16_t)fport->fmt_tag;
+    wave_hdr.fmt_hdr.nchan = (pj_int16_t)channel_count;
+    wave_hdr.fmt_hdr.sample_rate = sampling_rate;
+    wave_hdr.fmt_hdr.bytes_per_sec = sampling_rate * channel_count * 
+				     fport->bytes_per_sample;
+    wave_hdr.fmt_hdr.block_align = (pj_uint16_t)
+				   (fport->bytes_per_sample * channel_count);
+    wave_hdr.fmt_hdr.bits_per_sample = (pj_uint16_t)
+				       (fport->bytes_per_sample * 8);
+
+    wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG;
+    wave_hdr.data_hdr.len = 0;	    /* will be filled later */
+
+
+    /* Convert WAVE header from host byte order to little endian
+     * before writing the header.
+     */
+    pjmedia_wave_hdr_host_to_file(&wave_hdr);
+
+
+    /* Write WAVE header */
+    if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) {
+	pjmedia_wave_subchunk fact_chunk;
+	pj_uint32_t tmp = 0;
+
+	fact_chunk.id = PJMEDIA_FACT_TAG;
+	fact_chunk.len = 4;
+
+	PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&fact_chunk);
+
+	/* Write WAVE header without DATA chunk header */
+	size = sizeof(pjmedia_wave_hdr) - sizeof(wave_hdr.data_hdr);
+	status = pj_file_write(fport->fd, &wave_hdr, &size);
+	if (status != PJ_SUCCESS) {
+	    pj_file_close(fport->fd);
+	    return status;
+	}
+
+	/* Write FACT chunk if it stores compressed data */
+	size = sizeof(fact_chunk);
+	status = pj_file_write(fport->fd, &fact_chunk, &size);
+	if (status != PJ_SUCCESS) {
+	    pj_file_close(fport->fd);
+	    return status;
+	}
+	size = 4;
+	status = pj_file_write(fport->fd, &tmp, &size);
+	if (status != PJ_SUCCESS) {
+	    pj_file_close(fport->fd);
+	    return status;
+	}
+
+	/* Write DATA chunk header */
+	size = sizeof(wave_hdr.data_hdr);
+	status = pj_file_write(fport->fd, &wave_hdr.data_hdr, &size);
+	if (status != PJ_SUCCESS) {
+	    pj_file_close(fport->fd);
+	    return status;
+	}
+    } else {
+	size = sizeof(pjmedia_wave_hdr);
+	status = pj_file_write(fport->fd, &wave_hdr, &size);
+	if (status != PJ_SUCCESS) {
+	    pj_file_close(fport->fd);
+	    return status;
+	}
+    }
+
+    /* Set buffer size. */
+    if (buff_size < 1) buff_size = PJMEDIA_FILE_PORT_BUFSIZE;
+    fport->bufsize = buff_size;
+
+    /* Check that buffer size is greater than bytes per frame */
+    pj_assert(fport->bufsize >= PJMEDIA_PIA_AVG_FSZ(&fport->base.info));
+
+
+    /* Allocate buffer and set initial write position */
+    fport->buf = (char*) pj_pool_alloc(pool, fport->bufsize);
+    if (fport->buf == NULL) {
+	pj_file_close(fport->fd);
+	return PJ_ENOMEM;
+    }
+    fport->writepos = fport->buf;
+
+    /* Done. */
+    *p_port = &fport->base;
+
+    PJ_LOG(4,(THIS_FILE, 
+	      "File writer '%.*s' created: samp.rate=%d, bufsize=%uKB",
+	      (int)fport->base.info.name.slen,
+	      fport->base.info.name.ptr,
+	      PJMEDIA_PIA_SRATE(&fport->base.info),
+	      fport->bufsize / 1000));
+
+
+    return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Get current writing position. 
+ */
+PJ_DEF(pj_ssize_t) pjmedia_wav_writer_port_get_pos( pjmedia_port *port )
+{
+    struct file_port *fport;
+
+    /* Sanity check */
+    PJ_ASSERT_RETURN(port, -PJ_EINVAL);
+
+    /* Check that this is really a writer port */
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
+
+    fport = (struct file_port*) port;
+
+    return fport->total;
+}
+
+
+/*
+ * Register callback.
+ */
+PJ_DEF(pj_status_t) pjmedia_wav_writer_port_set_cb( pjmedia_port *port,
+				pj_size_t pos,
+				void *user_data,
+			        pj_status_t (*cb)(pjmedia_port *port,
+						  void *usr_data))
+{
+    struct file_port *fport;
+
+    /* Sanity check */
+    PJ_ASSERT_RETURN(port && cb, PJ_EINVAL);
+
+    /* Check that this is really a writer port */
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
+
+    fport = (struct file_port*) port;
+
+    fport->cb_size = pos;
+    fport->base.port_data.pdata = user_data;
+    fport->cb = cb;
+
+    return PJ_SUCCESS;
+}
+
+
+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
+    static void swap_samples(pj_int16_t *samples, unsigned count)
+    {
+	unsigned i;
+	for (i=0; i<count; ++i) {
+	    samples[i] = pj_swap16(samples[i]);
+	}
+    }
+#else
+#   define swap_samples(samples,count)
+#endif
+
+/*
+ * Flush the contents of the buffer to the file.
+ */
+static pj_status_t flush_buffer(struct file_port *fport)
+{
+    pj_ssize_t bytes = fport->writepos - fport->buf;
+    pj_status_t status;
+
+    /* Convert samples to little endian */
+    swap_samples((pj_int16_t*)fport->buf, bytes/fport->bytes_per_sample);
+
+    /* Write to file. */
+    status = pj_file_write(fport->fd, fport->buf, &bytes);
+
+    /* Reset writepos */
+    fport->writepos = fport->buf;
+
+    return status;
+}
+
+/*
+ * Put a frame into the buffer. When the buffer is full, flush the buffer
+ * to the file.
+ */
+static pj_status_t file_put_frame(pjmedia_port *this_port, 
+				  pjmedia_frame *frame)
+{
+    struct file_port *fport = (struct file_port *)this_port;
+    pj_size_t frame_size;
+
+    if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM)
+	frame_size = frame->size;
+    else
+	frame_size = frame->size >> 1;
+
+    /* Flush buffer if we don't have enough room for the frame. */
+    if (fport->writepos + frame_size > fport->buf + fport->bufsize) {
+	pj_status_t status;
+	status = flush_buffer(fport);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+
+    /* Check if frame is not too large. */
+    PJ_ASSERT_RETURN(fport->writepos+frame_size <= fport->buf+fport->bufsize,
+		     PJMEDIA_EFRMFILETOOBIG);
+
+    /* Copy frame to buffer. */
+    if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) {
+	pj_memcpy(fport->writepos, frame->buf, frame->size);
+    } else {
+	unsigned i;
+	pj_int16_t *src = (pj_int16_t*)frame->buf;
+	pj_uint8_t *dst = (pj_uint8_t*)fport->writepos;
+
+	if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) {
+	    for (i = 0; i < frame_size; ++i) {
+		*dst++ = pjmedia_linear2ulaw(*src++);
+	    }
+	} else {
+	    for (i = 0; i < frame_size; ++i) {
+		*dst++ = pjmedia_linear2alaw(*src++);
+	    }
+	}
+
+    }
+    fport->writepos += frame_size;
+
+    /* Increment total written, and check if we need to call callback */
+    fport->total += frame_size;
+    if (fport->cb && fport->total >= fport->cb_size) {
+	pj_status_t (*cb)(pjmedia_port*, void*);
+	pj_status_t status;
+
+	cb = fport->cb;
+	fport->cb = NULL;
+
+	status = (*cb)(this_port, this_port->port_data.pdata);
+	return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Get frame, basicy is a no-op operation.
+ */
+static pj_status_t file_get_frame(pjmedia_port *this_port, 
+				  pjmedia_frame *frame)
+{
+    PJ_UNUSED_ARG(this_port);
+    PJ_UNUSED_ARG(frame);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * Close the port, modify file header with updated file length.
+ */
+static pj_status_t file_on_destroy(pjmedia_port *this_port)
+{
+    enum { FILE_LEN_POS = 4, DATA_LEN_POS = 40 };
+    struct file_port *fport = (struct file_port *)this_port;
+    pj_off_t file_size;
+    pj_ssize_t bytes;
+    pj_uint32_t wave_file_len;
+    pj_uint32_t wave_data_len;
+    pj_status_t status;
+    pj_uint32_t data_len_pos = DATA_LEN_POS;
+
+    /* Flush remaining buffers. */
+    if (fport->writepos != fport->buf) 
+	flush_buffer(fport);
+
+    /* Get file size. */
+    status = pj_file_getpos(fport->fd, &file_size);
+    if (status != PJ_SUCCESS) {
+        pj_file_close(fport->fd);
+	return status;
+    }
+
+    /* Calculate wave fields */
+    wave_file_len = (pj_uint32_t)(file_size - 8);
+    wave_data_len = (pj_uint32_t)(file_size - sizeof(pjmedia_wave_hdr));
+
+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
+    wave_file_len = pj_swap32(wave_file_len);
+    wave_data_len = pj_swap32(wave_data_len);
+#endif
+
+    /* Seek to the file_len field. */
+    status = pj_file_setpos(fport->fd, FILE_LEN_POS, PJ_SEEK_SET);
+    if (status != PJ_SUCCESS) {
+        pj_file_close(fport->fd);
+	return status;
+    }
+
+    /* Write file_len */
+    bytes = sizeof(wave_file_len);
+    status = pj_file_write(fport->fd, &wave_file_len, &bytes);
+    if (status != PJ_SUCCESS) {
+        pj_file_close(fport->fd);
+	return status;
+    }
+
+    /* Write samples_len in FACT chunk */
+    if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) {
+	enum { SAMPLES_LEN_POS = 44};
+	pj_uint32_t wav_samples_len;
+
+	/* Adjust wave_data_len & data_len_pos since there is FACT chunk */
+	wave_data_len -= 12;
+	data_len_pos += 12;
+	wav_samples_len = wave_data_len;
+
+	/* Seek to samples_len field. */
+	status = pj_file_setpos(fport->fd, SAMPLES_LEN_POS, PJ_SEEK_SET);
+        if (status != PJ_SUCCESS) {
+            pj_file_close(fport->fd);
+	    return status;
+        }
+
+	/* Write samples_len */
+	bytes = sizeof(wav_samples_len);
+	status = pj_file_write(fport->fd, &wav_samples_len, &bytes);
+	if (status != PJ_SUCCESS) {
+            pj_file_close(fport->fd);
+	    return status;
+        }
+    }
+
+    /* Seek to data_len field. */
+    status = pj_file_setpos(fport->fd, data_len_pos, PJ_SEEK_SET);
+    if (status != PJ_SUCCESS) {
+        pj_file_close(fport->fd);
+	return status;
+    }
+
+    /* Write file_len */
+    bytes = sizeof(wave_data_len);
+    status = pj_file_write(fport->fd, &wave_data_len, &bytes);
+    if (status != PJ_SUCCESS) {
+        pj_file_close(fport->fd);
+	return status;
+    }
+
+    /* Close file */
+    status = pj_file_close(fport->fd);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/f4/f44db2f14f4aaddfa3017bd52abfa95d5f45eb4f.svn-base b/jni/pjproject-android/.svn/pristine/f4/f44db2f14f4aaddfa3017bd52abfa95d5f45eb4f.svn-base
new file mode 100644
index 0000000..ad81571
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f44db2f14f4aaddfa3017bd52abfa95d5f45eb4f.svn-base
@@ -0,0 +1,68 @@
+# @configure_input@
+include ../../../build.mak
+include $(PJDIR)/build/common.mak
+
+export LIBDIR := ../../lib
+
+RULES_MAK := $(PJDIR)/build/rules.mak
+
+export PORTAUDIO_LIB:=../../lib/libportaudio-$(TARGET_NAME)$(LIBEXT)
+
+PORTAUDIO_OBJS += pa_allocation.o \
+		  pa_converters.o \
+		  pa_cpuload.o \
+		  pa_dither.o \
+		  pa_debugprint.o \
+		  pa_front.o \
+		  pa_process.o \
+		  pa_skeleton.o \
+		  pa_stream.o \
+		  pa_trace.o
+
+
+###############################################################################
+# Gather all flags.
+#
+export _CFLAGS 	+= $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \
+		   $(CFLAGS) $(CC_INC). $(CC_INC)src 
+export _CXXFLAGS+= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \
+		   $(HOST_CXXFLAGS) $(CXXFLAGS)
+export _LDFLAGS += $(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \
+		   $(LDFLAGS) 
+
+###############################################################################
+# Defines for building PORTAUDIO library
+#
+export PORTAUDIO_SRCDIR = src
+export PORTAUDIO_OBJS += 
+export PORTAUDIO_CFLAGS += $(_CFLAGS)
+
+export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
+###############################################################################
+# Main entry
+#
+# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory.
+#
+TARGETS := libportaudio
+
+all: $(TARGETS)
+
+dep: depend
+distclean: realclean
+
+.PHONY: dep depend libportaudio clean realclean distclean
+
+libportaudio:
+	$(MAKE) -f $(RULES_MAK) APP=PORTAUDIO app=libportaudio $(PORTAUDIO_LIB)
+
+clean:
+	$(MAKE) -f $(RULES_MAK) APP=PORTAUDIO app=libportaudio $@
+
+realclean:
+	$(subst @@,$(subst /,$(HOST_PSEP),.libportaudio-$(TARGET_NAME).depend),$(HOST_RMR))
+	
+	$(MAKE) -f $(RULES_MAK) APP=PORTAUDIO app=libportaudio $@
+
+depend:
+	$(MAKE) -f $(RULES_MAK) APP=PORTAUDIO app=libportaudio $@
+
diff --git a/jni/pjproject-android/.svn/pristine/f4/f46fb0c47eb40d105e6b18136efc1d3c29fcf4c5.svn-base b/jni/pjproject-android/.svn/pristine/f4/f46fb0c47eb40d105e6b18136efc1d3c29fcf4c5.svn-base
new file mode 100644
index 0000000..7e0d3d4
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f46fb0c47eb40d105e6b18136efc1d3c29fcf4c5.svn-base
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+svn pset svn:keywords id $*
+svn pset svn:eol-style native $*
diff --git a/jni/pjproject-android/.svn/pristine/f4/f471fcbac9613b16f420e730c4b08be47870174e.svn-base b/jni/pjproject-android/.svn/pristine/f4/f471fcbac9613b16f420e730c4b08be47870174e.svn-base
new file mode 100644
index 0000000..9685fcd
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f471fcbac9613b16f420e730c4b08be47870174e.svn-base
@@ -0,0 +1,73 @@
+/* $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_AUTH_SIP_AUTH_PARSER_H__
+#define __PJSIP_AUTH_SIP_AUTH_PARSER_H__
+
+/**
+ * @file sip_auth_parser.h
+ * @brief SIP Authorization Parser Module.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * Initialize and register authorization parser module.
+ * This will register parser handler for various Authorization related headers
+ * such as Authorization, WWW-Authenticate, Proxy-Authorizization, and 
+ * Proxy-Authenticate headers.
+ *
+ * This function is called automatically by the main SIP parser.
+ *
+ * @return      PJ_SUCCESS or the appropriate status code.
+ */
+PJ_DECL(pj_status_t) pjsip_auth_init_parser(void);
+
+/**
+ * DeInitialize authorization parser module.
+ */
+PJ_DECL(void) pjsip_auth_deinit_parser();
+
+
+
+extern const pj_str_t	pjsip_USERNAME_STR, /**< "username" string const.   */
+			pjsip_REALM_STR,    /**< "realm" string const.	    */
+			pjsip_NONCE_STR,    /**< "nonce" string const.	    */
+			pjsip_URI_STR,	    /**< "uri" string const.	    */
+			pjsip_RESPONSE_STR, /**< "response" string const.   */
+			pjsip_ALGORITHM_STR,/**< "algorithm" string const.  */
+			pjsip_DOMAIN_STR,   /**< "domain" string const.	    */
+			pjsip_STALE_STR,    /**< "stale" string const.	    */
+			pjsip_QOP_STR,	    /**< "qop" string const.	    */
+			pjsip_CNONCE_STR,   /**< "cnonce" string const.	    */
+			pjsip_OPAQUE_STR,   /**< "opaque" string const.	    */
+			pjsip_NC_STR,	    /**< "nc" string const.	    */
+			pjsip_TRUE_STR,	    /**< "true" string const.	    */
+			pjsip_FALSE_STR,    /**< "false" string const.	    */
+			pjsip_DIGEST_STR,   /**< "digest" string const.	    */
+			pjsip_PGP_STR,	    /**< "pgp" string const.	    */
+			pjsip_MD5_STR,	    /**< "md5" string const.	    */
+			pjsip_AUTH_STR;	    /**< "auth" string const.	    */
+
+PJ_END_DECL
+
+#endif	/* __PJSIP_AUTH_SIP_AUTH_PARSER_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/f4/f49083a114260194647129497bec14da4776cd36.svn-base b/jni/pjproject-android/.svn/pristine/f4/f49083a114260194647129497bec14da4776cd36.svn-base
new file mode 100644
index 0000000..c403952
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f49083a114260194647129497bec14da4776cd36.svn-base
@@ -0,0 +1,116 @@
+/* $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_TURN_SRV_AUTH_H__
+#define __PJ_TURN_SRV_AUTH_H__
+
+#include <pjnath.h>
+
+/**
+ * Initialize TURN authentication subsystem.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_turn_auth_init(const char *realm);
+
+/**
+ * Shutdown TURN authentication subsystem.
+ */
+PJ_DECL(void) pj_turn_auth_dinit(void);
+
+/**
+ * This function is called by pj_stun_verify_credential() when
+ * server needs to challenge the request with 401 response.
+ *
+ * @param user_data	Should be ignored.
+ * @param pool		Pool to allocate memory.
+ * @param realm		On return, the function should fill in with
+ *			realm if application wants to use long term
+ *			credential. Otherwise application should set
+ *			empty string for the realm.
+ * @param nonce		On return, if application wants to use long
+ *			term credential, it MUST fill in the nonce
+ *			with some value. Otherwise  if short term 
+ *			credential is wanted, it MAY set this value.
+ *			If short term credential is wanted and the
+ *			application doesn't want to include NONCE,
+ *			then it must set this to empty string.
+ *
+ * @return		The callback should return PJ_SUCCESS, or
+ *			otherwise response message will not be 
+ *			created.
+ */
+PJ_DECL(pj_status_t) pj_turn_get_auth(void *user_data,
+				      pj_pool_t *pool,
+				      pj_str_t *realm,
+				      pj_str_t *nonce);
+
+/**
+ * This function is called to get the password for the specified username.
+ * This function is also used to check whether the username is valid.
+ *
+ * @param msg		The STUN message where the password will be
+ *			applied to.
+ * @param user_data	Should be ignored.
+ * @param realm		The realm as specified in the message.
+ * @param username	The username as specified in the message.
+ * @param pool		Pool to allocate memory when necessary.
+ * @param data_type	On return, application should fill up this
+ *			argument with the type of data (which should
+ *			be zero if data is a plaintext password).
+ * @param data		On return, application should fill up this
+ *			argument with the password according to
+ *			data_type.
+ *
+ * @return		The callback should return PJ_SUCCESS if
+ *			username has been successfully verified
+ *			and password was obtained. If non-PJ_SUCCESS
+ *			is returned, it is assumed that the
+ *			username is not valid.
+ */
+PJ_DECL(pj_status_t) pj_turn_get_password(const pj_stun_msg *msg,
+					  void *user_data, 
+					  const pj_str_t *realm,
+					  const pj_str_t *username,
+					  pj_pool_t *pool,
+					  pj_stun_passwd_type *data_type,
+					  pj_str_t *data);
+
+/**
+ * This function will be called to verify that the NONCE given
+ * in the message can be accepted. If this callback returns
+ * PJ_FALSE, 438 (Stale Nonce) response will be created.
+ *
+ * @param msg		The STUN message where the nonce was received.
+ * @param user_data	Should be ignored.
+ * @param realm		The realm as specified in the message.
+ * @param username	The username as specified in the message.
+ * @param nonce		The nonce to be verified.
+ *
+ * @return		The callback MUST return non-zero if the 
+ *			NONCE can be accepted.
+ */
+PJ_DECL(pj_bool_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
+					void *user_data,
+					const pj_str_t *realm,
+					const pj_str_t *username,
+					const pj_str_t *nonce);
+
+#endif	/* __PJ_TURN_SRV_AUTH_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/f4/f4b843afc421fc663f059134c67f481267d1b30f.svn-base b/jni/pjproject-android/.svn/pristine/f4/f4b843afc421fc663f059134c67f481267d1b30f.svn-base
new file mode 100644
index 0000000..6c5244d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f4/f4b843afc421fc663f059134c67f481267d1b30f.svn-base
@@ -0,0 +1,689 @@
+/* $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 
+ */
+
+
+/**
+ * sipecho.c
+ *
+ * - Accepts incoming calls and echoes back SDP and any media.
+ * - Specify URI in cmdline argument to make call
+ * - Accepts registration too!
+ */
+
+/* Include all headers. */
+#include <pjsip.h>
+#include <pjmedia/sdp.h>
+#include <pjsip_ua.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+
+/* For logging purpose. */
+#define THIS_FILE   "sipecho.c"
+
+#include "util.h"
+
+
+/* Settings */
+#define MAX_CALLS	8
+
+typedef struct call_t
+{
+    pjsip_inv_session	*inv;
+} call_t;
+
+static struct app_t
+{
+    pj_caching_pool	 cp;
+    pj_pool_t		*pool;
+
+    pjsip_endpoint	*sip_endpt;
+    //pjmedia_endpt	*med_endpt;
+
+    call_t		 call[MAX_CALLS];
+
+    pj_bool_t		 quit;
+    pj_thread_t		*worker_thread;
+
+    pj_bool_t		 enable_msg_logging;
+} app;
+
+/*
+ * Prototypes:
+ */
+
+static void call_on_media_update(pjsip_inv_session *inv, pj_status_t status);
+static void call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e);
+static void call_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer);
+static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
+static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
+
+/* Globals */
+static int sip_af;
+static int sip_port = 5060;
+static pj_bool_t sip_tcp;
+
+/* This is a PJSIP module to be registered by application to handle
+ * incoming requests outside any dialogs/transactions. The main purpose
+ * here is to handle incoming INVITE request message, where we will
+ * create a dialog and INVITE session for it.
+ */
+static pjsip_module mod_sipecho =
+{
+    NULL, NULL,			    /* prev, next.		*/
+    { "mod-sipecho", 11 },	    /* Name.			*/
+    -1,				    /* Id			*/
+    PJSIP_MOD_PRIORITY_APPLICATION, /* Priority			*/
+    NULL,			    /* load()			*/
+    NULL,			    /* start()			*/
+    NULL,			    /* stop()			*/
+    NULL,			    /* unload()			*/
+    &on_rx_request,		    /* on_rx_request()		*/
+    NULL,			    /* on_rx_response()		*/
+    NULL,			    /* on_tx_request.		*/
+    NULL,			    /* on_tx_response()		*/
+    NULL,			    /* on_tsx_state()		*/
+};
+
+/* Notification on incoming messages */
+static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
+{
+    if (!app.enable_msg_logging)
+	return PJ_FALSE;
+
+    PJ_LOG(3,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
+			 "%.*s\n"
+			 "--end msg--",
+			 rdata->msg_info.len,
+			 pjsip_rx_data_get_info(rdata),
+			 rdata->tp_info.transport->type_name,
+			 rdata->pkt_info.src_name,
+			 rdata->pkt_info.src_port,
+			 (int)rdata->msg_info.len,
+			 rdata->msg_info.msg_buf));
+    return PJ_FALSE;
+}
+
+/* Notification on outgoing messages */
+static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
+{
+    if (!app.enable_msg_logging)
+	return PJ_SUCCESS;
+
+    PJ_LOG(3,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
+			 "%.*s\n"
+			 "--end msg--",
+			 (tdata->buf.cur - tdata->buf.start),
+			 pjsip_tx_data_get_info(tdata),
+			 tdata->tp_info.transport->type_name,
+			 tdata->tp_info.dst_name,
+			 tdata->tp_info.dst_port,
+			 (int)(tdata->buf.cur - tdata->buf.start),
+			 tdata->buf.start));
+    return PJ_SUCCESS;
+}
+
+/* The module instance. */
+static pjsip_module msg_logger =
+{
+    NULL, NULL,				/* prev, next.		*/
+    { "mod-msg-log", 13 },		/* Name.		*/
+    -1,					/* Id			*/
+    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority	        */
+    NULL,				/* load()		*/
+    NULL,				/* start()		*/
+    NULL,				/* stop()		*/
+    NULL,				/* unload()		*/
+    &logging_on_rx_msg,			/* on_rx_request()	*/
+    &logging_on_rx_msg,			/* on_rx_response()	*/
+    &logging_on_tx_msg,			/* on_tx_request.	*/
+    &logging_on_tx_msg,			/* on_tx_response()	*/
+    NULL,				/* on_tsx_state()	*/
+
+};
+
+static int worker_proc(void *arg)
+{
+    PJ_UNUSED_ARG(arg);
+
+    while (!app.quit) {
+	pj_time_val interval = { 0, 20 };
+	pjsip_endpt_handle_events(app.sip_endpt, &interval);
+    }
+
+    return 0;
+}
+
+static void hangup_all(void)
+{
+    unsigned i;
+    for (i=0; i<MAX_CALLS; ++i) {
+    	call_t *call = &app.call[i];
+
+    	if (call->inv && call->inv->state <= PJSIP_INV_STATE_CONFIRMED) {
+    	    pj_status_t status;
+    	    pjsip_tx_data *tdata;
+
+    	    status = pjsip_inv_end_session(call->inv, PJSIP_SC_BUSY_HERE, NULL, &tdata);
+    	    if (status==PJ_SUCCESS && tdata)
+    		pjsip_inv_send_msg(call->inv, tdata);
+    	}
+    }
+}
+
+static void destroy_stack(void)
+{
+    enum { WAIT_CLEAR = 5000, WAIT_INTERVAL = 500 };
+    unsigned i;
+
+    PJ_LOG(3,(THIS_FILE, "Shutting down.."));
+
+    /* Wait until all clear */
+    hangup_all();
+    for (i=0; i<WAIT_CLEAR/WAIT_INTERVAL; ++i) {
+	unsigned j;
+
+	for (j=0; j<MAX_CALLS; ++j) {
+	    call_t *call = &app.call[j];
+	    if (call->inv && call->inv->state <= PJSIP_INV_STATE_CONFIRMED)
+		break;
+	}
+
+	if (j==MAX_CALLS)
+	    return;
+
+	pj_thread_sleep(WAIT_INTERVAL);
+    }
+
+    app.quit = PJ_TRUE;
+    if (app.worker_thread) {
+	pj_thread_join(app.worker_thread);
+	app.worker_thread = NULL;
+    }
+
+    //if (app.med_endpt)
+	//pjmedia_endpt_destroy(app.med_endpt);
+
+    if (app.sip_endpt)
+	pjsip_endpt_destroy(app.sip_endpt);
+
+    if (app.pool)
+	pj_pool_release(app.pool);
+
+    dump_pool_usage(THIS_FILE, &app.cp);
+    pj_caching_pool_destroy(&app.cp);
+}
+
+#define CHECK_STATUS()	do { if (status != PJ_SUCCESS) return status; } while (0)
+
+static pj_status_t init_stack()
+{
+    pj_sockaddr addr;
+    pjsip_inv_callback inv_cb;
+    pj_status_t status;
+
+    pj_log_set_level(3);
+
+    status = pjlib_util_init();
+    CHECK_STATUS();
+
+    pj_caching_pool_init(&app.cp, NULL, 0);
+    app.pool = pj_pool_create( &app.cp.factory, "sipecho", 512, 512, 0);
+
+    status = pjsip_endpt_create(&app.cp.factory, NULL, &app.sip_endpt);
+    CHECK_STATUS();
+
+    pj_log_set_level(4);
+    pj_sockaddr_init((pj_uint16_t)sip_af, &addr, NULL, (pj_uint16_t)sip_port);
+    if (sip_af == pj_AF_INET()) {
+	if (sip_tcp) {
+	    status = pjsip_tcp_transport_start( app.sip_endpt, &addr.ipv4, 1,
+						NULL);
+	} else {
+	    status = pjsip_udp_transport_start( app.sip_endpt, &addr.ipv4,
+	                                        NULL, 1, NULL);
+	}
+    } else if (sip_af == pj_AF_INET6()) {
+	    status = pjsip_udp_transport_start6(app.sip_endpt, &addr.ipv6,
+	                                        NULL, 1, NULL);
+    } else {
+	status = PJ_EAFNOTSUP;
+    }
+
+    pj_log_set_level(3);
+    CHECK_STATUS();
+
+    status = pjsip_tsx_layer_init_module(app.sip_endpt) ||
+	     pjsip_ua_init_module( app.sip_endpt, NULL );
+    CHECK_STATUS();
+
+    pj_bzero(&inv_cb, sizeof(inv_cb));
+    inv_cb.on_state_changed = &call_on_state_changed;
+    inv_cb.on_new_session = &call_on_forked;
+    inv_cb.on_media_update = &call_on_media_update;
+    inv_cb.on_rx_offer = &call_on_rx_offer;
+
+    status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb) ||
+	     pjsip_100rel_init_module(app.sip_endpt) ||
+	     pjsip_endpt_register_module( app.sip_endpt, &mod_sipecho) ||
+	     pjsip_endpt_register_module( app.sip_endpt, &msg_logger) ||
+	     //pjmedia_endpt_create(&app.cp.factory,
+		//		  pjsip_endpt_get_ioqueue(app.sip_endpt),
+		//		  0, &app.med_endpt) ||
+             pj_thread_create(app.pool, "sipecho", &worker_proc, NULL, 0, 0,
+                              &app.worker_thread);
+    CHECK_STATUS();
+
+    return PJ_SUCCESS;
+}
+
+static void destroy_call(call_t *call)
+{
+    call->inv = NULL;
+}
+
+static pjmedia_sdp_attr * find_remove_sdp_attrs(unsigned *cnt,
+                                                pjmedia_sdp_attr *attr[],
+                                                unsigned cnt_attr_to_remove,
+                                                const char* attr_to_remove[])
+{
+    pjmedia_sdp_attr *found_attr = NULL;
+    int i;
+
+    for (i=0; i<(int)*cnt; ++i) {
+	unsigned j;
+	for (j=0; j<cnt_attr_to_remove; ++j) {
+	    if (pj_strcmp2(&attr[i]->name, attr_to_remove[j])==0) {
+		if (!found_attr) found_attr = attr[i];
+		pj_array_erase(attr, sizeof(attr[0]), *cnt, i);
+		--(*cnt);
+		--i;
+		break;
+	    }
+	}
+    }
+
+    return found_attr;
+}
+
+static pjmedia_sdp_session *create_answer(int call_num, pj_pool_t *pool,
+                                          const pjmedia_sdp_session *offer)
+{
+    const char* dir_attrs[] = { "sendrecv", "sendonly", "recvonly", "inactive" };
+    const char *ice_attrs[] = {"ice-pwd", "ice-ufrag", "candidate"};
+    pjmedia_sdp_session *answer = pjmedia_sdp_session_clone(pool, offer);
+    pjmedia_sdp_attr *sess_dir_attr = NULL;
+    unsigned mi;
+
+    PJ_LOG(3,(THIS_FILE, "Call %d: creating answer:", call_num));
+
+    answer->name = pj_str("sipecho");
+    sess_dir_attr = find_remove_sdp_attrs(&answer->attr_count, answer->attr,
+                                          PJ_ARRAY_SIZE(dir_attrs),
+                                          dir_attrs);
+
+    for (mi=0; mi<answer->media_count; ++mi) {
+	pjmedia_sdp_media *m = answer->media[mi];
+	pjmedia_sdp_attr *m_dir_attr;
+	pjmedia_sdp_attr *dir_attr;
+	const char *our_dir = NULL;
+	pjmedia_sdp_conn *c;
+
+	/* Match direction */
+	m_dir_attr = find_remove_sdp_attrs(&m->attr_count, m->attr,
+	                                   PJ_ARRAY_SIZE(dir_attrs),
+	                                   dir_attrs);
+	dir_attr = m_dir_attr ? m_dir_attr : sess_dir_attr;
+
+	if (dir_attr) {
+	    if (pj_strcmp2(&dir_attr->name, "sendonly")==0)
+		our_dir = "recvonly";
+	    else if (pj_strcmp2(&dir_attr->name, "inactive")==0)
+		our_dir = "inactive";
+	    else if (pj_strcmp2(&dir_attr->name, "recvonly")==0)
+		our_dir = "inactive";
+
+	    if (our_dir) {
+		dir_attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+		dir_attr->name = pj_str((char*)our_dir);
+		m->attr[m->attr_count++] = dir_attr;
+	    }
+	}
+
+	/* Remove ICE attributes */
+	find_remove_sdp_attrs(&m->attr_count, m->attr, PJ_ARRAY_SIZE(ice_attrs), ice_attrs);
+
+	/* Done */
+	c = m->conn ? m->conn : answer->conn;
+	PJ_LOG(3,(THIS_FILE, "  Media %d, %.*s: %s <--> %.*s:%d",
+		  mi, (int)m->desc.media.slen, m->desc.media.ptr,
+		  (our_dir ? our_dir : "sendrecv"),
+		  (int)c->addr.slen, c->addr.ptr, m->desc.port));
+    }
+
+    return answer;
+}
+
+static void call_on_state_changed( pjsip_inv_session *inv, 
+				   pjsip_event *e)
+{
+    call_t *call = (call_t*)inv->mod_data[mod_sipecho.id];
+    if (!call)
+	return;
+
+    PJ_UNUSED_ARG(e);
+    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+	PJ_LOG(3,(THIS_FILE, "Call %d: DISCONNECTED [reason=%d (%s)]",
+		  call - app.call, inv->cause,
+		  pjsip_get_status_text(inv->cause)->ptr));
+	destroy_call(call);
+    } else {
+	PJ_LOG(3,(THIS_FILE, "Call %d: state changed to %s",
+		  call - app.call, pjsip_inv_state_name(inv->state)));
+    }
+}
+
+static void call_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
+{
+    call_t *call = (call_t*) inv->mod_data[mod_sipecho.id];
+    pjsip_inv_set_sdp_answer(inv, create_answer((int)(call - app.call), 
+			     inv->pool_prov, offer));
+}
+
+static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
+{
+    PJ_UNUSED_ARG(inv);
+    PJ_UNUSED_ARG(e);
+}
+
+static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
+{
+    pj_sockaddr hostaddr;
+    char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
+    pj_str_t local_uri;
+    pjsip_dialog *dlg;
+    pjsip_rdata_sdp_info *sdp_info;
+    pjmedia_sdp_session *answer = NULL;
+    pjsip_tx_data *tdata = NULL;
+    call_t *call = NULL;
+    unsigned i;
+    pj_status_t status;
+
+    PJ_LOG(3,(THIS_FILE, "RX %.*s from %s",
+	      (int)rdata->msg_info.msg->line.req.method.name.slen,
+	      rdata->msg_info.msg->line.req.method.name.ptr,
+	      rdata->pkt_info.src_name));
+
+    if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) {
+	/* Let me be a registrar! */
+	pjsip_hdr hdr_list, *h;
+	pjsip_msg *msg;
+	int expires = -1;
+
+	pj_list_init(&hdr_list);
+	msg = rdata->msg_info.msg;
+	h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
+	if (h) {
+	    expires = ((pjsip_expires_hdr*)h)->ivalue;
+	    pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
+	    PJ_LOG(3,(THIS_FILE, " Expires=%d", expires));
+	}
+	if (expires != 0) {
+	    h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
+	    if (h)
+		pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
+	}
+
+	pjsip_endpt_respond(app.sip_endpt, &mod_sipecho, rdata, 200, NULL,
+	                    &hdr_list, NULL, NULL);
+	return PJ_TRUE;
+    }
+
+    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
+	if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
+	    pj_str_t reason = pj_str("Go away");
+	    pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
+					   400, &reason,
+					   NULL, NULL);
+	}
+	return PJ_TRUE;
+    }
+
+    sdp_info = pjsip_rdata_get_sdp_info(rdata);
+    if (!sdp_info || !sdp_info->sdp) {
+	pj_str_t reason = pj_str("Require valid offer");
+	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
+				       400, &reason,
+				       NULL, NULL);
+    }
+
+    for (i=0; i<MAX_CALLS; ++i) {
+	if (app.call[i].inv == NULL) {
+	    call = &app.call[i];
+	    break;
+	}
+    }
+
+    if (i==MAX_CALLS) {
+	pj_str_t reason = pj_str("We're full");
+	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
+				       PJSIP_SC_BUSY_HERE, &reason,
+				       NULL, NULL);
+	return PJ_TRUE;
+    }
+
+    /* Generate Contact URI */
+    status = pj_gethostip(sip_af, &hostaddr);
+    if (status != PJ_SUCCESS) {
+	app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
+	return PJ_TRUE;
+    }
+    pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
+    pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, sip_port);
+    local_uri = pj_str(temp);
+
+    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
+				   &local_uri, &dlg);
+
+    if (status == PJ_SUCCESS)
+	answer = create_answer((int)(call-app.call), dlg->pool, sdp_info->sdp);
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &call->inv);
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_initial_answer(call->inv, rdata, 100,
+				          NULL, NULL, &tdata);
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_send_msg(call->inv, tdata);
+
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_answer(call->inv, 180, NULL,
+    	                          NULL, &tdata);
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_send_msg(call->inv, tdata);
+
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_answer(call->inv, 200, NULL,
+    	                          NULL, &tdata);
+    if (status == PJ_SUCCESS)
+    	status = pjsip_inv_send_msg(call->inv, tdata);
+
+    if (status != PJ_SUCCESS) {
+	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
+				       500, NULL, NULL, NULL);
+	destroy_call(call);
+    } else {
+	call->inv->mod_data[mod_sipecho.id] = call;
+    }
+
+    return PJ_TRUE;
+}
+
+static void call_on_media_update( pjsip_inv_session *inv,
+				  pj_status_t status)
+{
+    PJ_UNUSED_ARG(inv);
+    PJ_UNUSED_ARG(status);
+}
+
+
+static void usage()
+{
+    printf("\nUsage: sipecho OPTIONS\n");
+    printf("\n");
+    printf("where OPTIONS:\n");
+    printf("  --local-port, -p PORT        Bind to port PORT.\n");
+    printf("  --tcp, -t                    Listen to TCP instead.\n");
+    printf("  --ipv6, -6                   Use IPv6 instead.\n");
+    printf("  --help, -h                   Show this help page.\n");
+}
+
+/* main()
+ *
+ * If called with argument, treat argument as SIP URL to be called.
+ * Otherwise wait for incoming calls.
+ */
+int main(int argc, char *argv[])
+{
+    struct pj_getopt_option long_options[] = {
+        { "local-port",	1, 0, 'p' },
+        { "tcp",	0, 0, 't' },
+        { "ipv6",	0, 0, '6' },
+        { "help", 	0, 0, 'h' }
+    };
+    int c, option_index;
+
+    pj_log_set_level(5);
+
+    pj_init();
+
+    sip_af = pj_AF_INET();
+
+    pj_optind = 0;
+    while ((c = pj_getopt_long(argc, argv, "p:t6h", long_options,
+                               &option_index)) != -1)
+    {
+	switch (c) {
+	case 'p':
+	    sip_port = atoi(pj_optarg);
+	    break;
+	case 't':
+	    sip_tcp = PJ_TRUE;
+	    break;
+	case 'h':
+	    usage();
+	    return 0;
+	case '6':
+	    sip_af = pj_AF_INET6();
+	    break;
+	default:
+	    PJ_LOG(1,(THIS_FILE,
+		      "Argument \"%s\" is not valid. Use --help to see help",
+		      argv[pj_optind-1]));
+	    return -1;
+	}
+    }
+
+    if (init_stack())
+	goto on_error;
+
+    /* If URL is specified, then make call immediately. */
+    if (pj_optind != argc) {
+	pj_sockaddr hostaddr;
+	char hostip[PJ_INET6_ADDRSTRLEN+2];
+	char temp[80];
+	call_t *call;
+	pj_str_t dst_uri = pj_str(argv[pj_optind]);
+	pj_str_t local_uri;
+	pjsip_dialog *dlg;
+	pj_status_t status;
+	pjsip_tx_data *tdata;
+
+	if (pj_gethostip(sip_af, &hostaddr) != PJ_SUCCESS) {
+	    PJ_LOG(1,(THIS_FILE, "Unable to retrieve local host IP"));
+	    goto on_error;
+	}
+	pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
+
+	pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>",
+			hostip, sip_port);
+	local_uri = pj_str(temp);
+
+	call = &app.call[0];
+
+	status = pjsip_dlg_create_uac( pjsip_ua_instance(),
+				       &local_uri,  /* local URI */
+				       &local_uri,  /* local Contact */
+				       &dst_uri,    /* remote URI */
+				       &dst_uri,    /* remote target */
+				       &dlg);	    /* dialog */
+	if (status != PJ_SUCCESS) {
+	    app_perror(THIS_FILE, "Unable to create UAC dialog", status);
+	    return 1;
+	}
+
+	status = pjsip_inv_create_uac( dlg, NULL, 0, &call->inv);
+	if (status != PJ_SUCCESS) goto on_error;
+
+	call->inv->mod_data[mod_sipecho.id] = call;
+
+	status = pjsip_inv_invite(call->inv, &tdata);
+	if (status != PJ_SUCCESS) goto on_error;
+
+	status = pjsip_inv_send_msg(call->inv, tdata);
+	if (status != PJ_SUCCESS) goto on_error;
+
+	puts("Press ENTER to quit...");
+    } else {
+	puts("Ready for incoming calls. Press ENTER to quit...");
+    }
+
+    for (;;) {
+	char s[10];
+
+	printf("\nMenu:\n"
+	       "  h    Hangup all calls\n"
+	       "  l    %s message logging\n"
+	       "  q    Quit\n",
+	       (app.enable_msg_logging? "Disable" : "Enable"));
+
+	if (fgets(s, sizeof(s), stdin) == NULL)
+	    continue;
+
+	if (s[0]=='q')
+	    break;
+	switch (s[0]) {
+	case 'l':
+	    app.enable_msg_logging = !app.enable_msg_logging;
+	    break;
+	case 'h':
+	    hangup_all();
+	    break;
+	}
+    }
+
+    destroy_stack();
+
+    puts("Bye bye..");
+    return 0;
+
+on_error:
+    puts("An error has occurred. run a debugger..");
+    return 1;
+}
+