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