* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/a7/a751b61f68c57952a340ce5ae5df5866daf403f1.svn-base b/jni/pjproject-android/.svn/pristine/a7/a751b61f68c57952a340ce5ae5df5866daf403f1.svn-base
new file mode 100644
index 0000000..ddd7078
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a751b61f68c57952a340ce5ae5df5866daf403f1.svn-base
@@ -0,0 +1,1106 @@
+/* $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/rtcp.h>
+#include <pjmedia/errno.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/sock.h>
+#include <pj/string.h>
+
+#define THIS_FILE "rtcp.c"
+
+#define RTCP_SR   200
+#define RTCP_RR   201
+#define RTCP_SDES 202
+#define RTCP_BYE  203
+#define RTCP_XR   207
+
+enum {
+    RTCP_SDES_NULL  = 0,
+    RTCP_SDES_CNAME = 1,
+    RTCP_SDES_NAME  = 2,
+    RTCP_SDES_EMAIL = 3,
+    RTCP_SDES_PHONE = 4,
+    RTCP_SDES_LOC   = 5,
+    RTCP_SDES_TOOL  = 6,
+    RTCP_SDES_NOTE  = 7
+};
+
+#if PJ_HAS_HIGH_RES_TIMER==0
+#   error "High resolution timer needs to be enabled"
+#endif
+
+
+
+#if 0
+#   define TRACE_(x)	PJ_LOG(3,x)
+#else
+#   define TRACE_(x)	;
+#endif
+
+
+/*
+ * Get NTP time.
+ */
+PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
+					      pjmedia_rtcp_ntp_rec *ntp)
+{
+/* Seconds between 1900-01-01 to 1970-01-01 */
+#define JAN_1970  (2208988800UL)
+    pj_timestamp ts;
+    pj_status_t status;
+
+    status = pj_get_timestamp(&ts);
+
+    /* Fill up the high 32bit part */
+    ntp->hi = (pj_uint32_t)((ts.u64 - sess->ts_base.u64) / sess->ts_freq.u64)
+	      + sess->tv_base.sec + JAN_1970;
+
+    /* Calculate seconds fractions */
+    ts.u64 = (ts.u64 - sess->ts_base.u64) % sess->ts_freq.u64;
+    pj_assert(ts.u64 < sess->ts_freq.u64);
+    ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64;
+
+    /* Fill up the low 32bit part */
+    ntp->lo = ts.u32.lo;
+
+
+#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
+    (defined(PJ_WIN64) && PJ_WIN64!=0) || \
+    (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0)
+
+    /* On Win32, since we use QueryPerformanceCounter() as the backend
+     * timestamp API, we need to protect against this bug:
+     *   Performance counter value may unexpectedly leap forward
+     *   http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323
+     */
+    {
+	/*
+	 * Compare elapsed time reported by timestamp with actual elapsed 
+	 * time. If the difference is too excessive, then we use system
+	 * time instead.
+	 */
+
+	/* MIN_DIFF needs to be large enough so that "normal" diff caused
+	 * by system activity or context switch doesn't trigger the time
+	 * correction.
+	 */
+	enum { MIN_DIFF = 400 };
+
+	pj_time_val ts_time, elapsed, diff;
+
+	pj_gettimeofday(&elapsed);
+
+	ts_time.sec = ntp->hi - sess->tv_base.sec - JAN_1970;
+	ts_time.msec = (long)(ntp->lo * 1000.0 / 0xFFFFFFFF);
+
+	PJ_TIME_VAL_SUB(elapsed, sess->tv_base);
+
+	if (PJ_TIME_VAL_LT(ts_time, elapsed)) {
+	    diff = elapsed;
+	    PJ_TIME_VAL_SUB(diff, ts_time);
+	} else {
+	    diff = ts_time;
+	    PJ_TIME_VAL_SUB(diff, elapsed);
+	}
+
+	if (PJ_TIME_VAL_MSEC(diff) >= MIN_DIFF) {
+
+	    TRACE_((sess->name, "RTCP NTP timestamp corrected by %d ms",
+		    PJ_TIME_VAL_MSEC(diff)));
+
+
+	    ntp->hi = elapsed.sec + sess->tv_base.sec + JAN_1970;
+	    ntp->lo = (elapsed.msec * 65536 / 1000) << 16;
+	}
+
+    }
+#endif
+
+    return status;
+}
+
+
+/*
+ * Initialize RTCP session setting.
+ */
+PJ_DEF(void) pjmedia_rtcp_session_setting_default(
+				    pjmedia_rtcp_session_setting *settings)
+{
+    pj_bzero(settings, sizeof(*settings));
+}
+
+
+/*
+ * Initialize bidirectional RTCP statistics.
+ *
+ */
+PJ_DEF(void) pjmedia_rtcp_init_stat(pjmedia_rtcp_stat *stat)
+{
+    pj_time_val now;
+
+    pj_assert(stat);
+
+    pj_bzero(stat, sizeof(pjmedia_rtcp_stat));
+
+    pj_math_stat_init(&stat->rtt);
+    pj_math_stat_init(&stat->rx.loss_period);
+    pj_math_stat_init(&stat->rx.jitter);
+    pj_math_stat_init(&stat->tx.loss_period);
+    pj_math_stat_init(&stat->tx.jitter);
+
+#if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
+    pj_math_stat_init(&stat->rx_ipdv);
+#endif
+
+#if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
+    pj_math_stat_init(&stat->rx_raw_jitter);
+#endif
+
+    pj_gettimeofday(&now);
+    stat->start = now;
+}
+
+
+/*
+ * Initialize RTCP session.
+ */
+PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *sess, 
+			       char *name,
+			       unsigned clock_rate,
+			       unsigned samples_per_frame,
+			       pj_uint32_t ssrc)
+{
+    pjmedia_rtcp_session_setting settings;
+
+    pjmedia_rtcp_session_setting_default(&settings);
+    settings.name = name;
+    settings.clock_rate = clock_rate;
+    settings.samples_per_frame = samples_per_frame;
+    settings.ssrc = ssrc;
+
+    pjmedia_rtcp_init2(sess, &settings);
+}
+
+
+/*
+ * Initialize RTCP session.
+ */
+PJ_DEF(void) pjmedia_rtcp_init2( pjmedia_rtcp_session *sess,
+				 const pjmedia_rtcp_session_setting *settings)
+{
+    pjmedia_rtcp_sr_pkt *sr_pkt = &sess->rtcp_sr_pkt;
+    pj_time_val now;
+    
+    /* Memset everything */
+    pj_bzero(sess, sizeof(pjmedia_rtcp_session));
+
+    /* Last RX timestamp in RTP packet */
+    sess->rtp_last_ts = (unsigned)-1;
+
+    /* Name */
+    sess->name = settings->name ? settings->name : (char*)THIS_FILE;
+
+    /* Set clock rate */
+    sess->clock_rate = settings->clock_rate;
+    sess->pkt_size = settings->samples_per_frame;
+
+    /* Init common RTCP SR header */
+    sr_pkt->common.version = 2;
+    sr_pkt->common.count = 1;
+    sr_pkt->common.pt = RTCP_SR;
+    sr_pkt->common.length = pj_htons(12);
+    sr_pkt->common.ssrc = pj_htonl(settings->ssrc);
+    
+    /* Copy to RTCP RR header */
+    pj_memcpy(&sess->rtcp_rr_pkt.common, &sr_pkt->common, 
+	      sizeof(pjmedia_rtcp_common));
+    sess->rtcp_rr_pkt.common.pt = RTCP_RR;
+    sess->rtcp_rr_pkt.common.length = pj_htons(7);
+
+    /* Get time and timestamp base and frequency */
+    pj_gettimeofday(&now);
+    sess->tv_base = now;
+    pj_get_timestamp(&sess->ts_base);
+    pj_get_timestamp_freq(&sess->ts_freq);
+    sess->rtp_ts_base = settings->rtp_ts_base;
+
+    /* Initialize statistics states */
+    pjmedia_rtcp_init_stat(&sess->stat);
+
+    /* RR will be initialized on receipt of the first RTP packet. */
+}
+
+
+PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess)
+{
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    pjmedia_rtcp_xr_fini(&sess->xr_session);
+#else
+    /* Nothing to do. */
+    PJ_UNUSED_ARG(sess);
+#endif
+}
+
+static void rtcp_init_seq(pjmedia_rtcp_session *sess)
+{
+    sess->received = 0;
+    sess->exp_prior = 0;
+    sess->rx_prior = 0;
+    sess->transit = 0;
+    sess->jitter = 0;
+}
+
+PJ_DEF(void) pjmedia_rtcp_rx_rtp( pjmedia_rtcp_session *sess, 
+				  unsigned seq, 
+				  unsigned rtp_ts,
+				  unsigned payload)
+{
+    pjmedia_rtcp_rx_rtp2(sess, seq, rtp_ts, payload, PJ_FALSE);
+}
+
+PJ_DEF(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *sess, 
+				  unsigned seq, 
+				  unsigned rtp_ts,
+				  unsigned payload,
+				  pj_bool_t discarded)
+{   
+    pj_timestamp ts;
+    pj_uint32_t arrival;
+    pj_int32_t transit;
+    pjmedia_rtp_status seq_st;
+    unsigned last_seq;
+
+#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
+    PJ_UNUSED_ARG(discarded);
+#endif
+
+    if (sess->stat.rx.pkt == 0) {
+	/* Init sequence for the first time. */
+	pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq);
+    } 
+
+    sess->stat.rx.pkt++;
+    sess->stat.rx.bytes += payload;
+
+    /* Process the RTP packet. */
+    last_seq = sess->seq_ctrl.max_seq;
+    pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st);
+
+    if (seq_st.status.flag.restart) {
+	rtcp_init_seq(sess);
+    }
+    
+    if (seq_st.status.flag.dup) {
+	sess->stat.rx.dup++;
+	TRACE_((sess->name, "Duplicate packet detected"));
+    }
+
+    if (seq_st.status.flag.outorder && !seq_st.status.flag.probation) {
+	sess->stat.rx.reorder++;
+	TRACE_((sess->name, "Out-of-order packet detected"));
+    }
+
+    if (seq_st.status.flag.bad) {
+	sess->stat.rx.discard++;
+
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+	pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
+			       -1,				 /* lost    */
+			       (seq_st.status.flag.dup? 1:0),	 /* dup     */
+			       (!seq_st.status.flag.dup? 1:-1),  /* discard */
+			       -1,				 /* jitter  */
+			       -1, 0);				 /* toh	    */
+#endif
+
+	TRACE_((sess->name, "Bad packet discarded"));
+	return;
+    }
+
+    /* Only mark "good" packets */
+    ++sess->received;
+
+    /* Calculate loss periods. */
+    if (seq_st.diff > 1) {
+	unsigned count = seq_st.diff - 1;
+	unsigned period;
+
+	period = count * sess->pkt_size * 1000 / sess->clock_rate;
+	period *= 1000;
+
+	/* Update packet lost. 
+	 * The packet lost number will also be updated when we're sending
+	 * outbound RTCP RR.
+	 */
+	sess->stat.rx.loss += (seq_st.diff - 1);
+	TRACE_((sess->name, "%d packet(s) lost", seq_st.diff - 1));
+
+	/* Update loss period stat */
+	pj_math_stat_update(&sess->stat.rx.loss_period, period);
+    }
+
+
+    /*
+     * Calculate jitter only when sequence is good (see RFC 3550 section A.8),
+     * AND only when the timestamp is different than the last packet
+     * (see RTP FAQ).
+     */
+    if (seq_st.diff == 1 && rtp_ts != sess->rtp_last_ts) {
+	/* Get arrival time and convert timestamp to samples */
+	pj_get_timestamp(&ts);
+	ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64;
+	arrival = ts.u32.lo;
+
+	transit = arrival - rtp_ts;
+    
+	/* Ignore the first N packets as they normally have bad jitter
+	 * due to other threads working to establish the call
+	 */
+	if (sess->transit == 0 || 
+	    sess->received < PJMEDIA_RTCP_IGNORE_FIRST_PACKETS) 
+	{
+	    sess->transit = transit;
+	    sess->stat.rx.jitter.min = (unsigned)-1;
+	} else {
+	    pj_int32_t d;
+	    pj_uint32_t jitter;
+
+	    d = transit - sess->transit;
+	    if (d < 0) 
+		d = -d;
+	    
+	    sess->jitter += d - ((sess->jitter + 8) >> 4);
+
+	    /* Update jitter stat */
+	    jitter = sess->jitter >> 4;
+	    
+	    /* Convert jitter unit from samples to usec */
+	    if (jitter < 4294)
+		jitter = jitter * 1000000 / sess->clock_rate;
+	    else {
+		jitter = jitter * 1000 / sess->clock_rate;
+		jitter *= 1000;
+	    }
+	    pj_math_stat_update(&sess->stat.rx.jitter, jitter);
+
+
+#if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
+	    {
+		pj_uint32_t raw_jitter;
+
+		/* Convert raw jitter unit from samples to usec */
+		if (d < 4294)
+		    raw_jitter = d * 1000000 / sess->clock_rate;
+		else {
+		    raw_jitter = d * 1000 / sess->clock_rate;
+		    raw_jitter *= 1000;
+		}
+		
+		/* Update jitter stat */
+		pj_math_stat_update(&sess->stat.rx_raw_jitter, raw_jitter);
+	    }
+#endif
+
+
+#if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
+	    {
+		pj_int32_t ipdv;
+
+		ipdv = transit - sess->transit;
+		/* Convert IPDV unit from samples to usec */
+		if (ipdv > -2147 && ipdv < 2147)
+		    ipdv = ipdv * 1000000 / (int)sess->clock_rate;
+		else {
+		    ipdv = ipdv * 1000 / (int)sess->clock_rate;
+		    ipdv *= 1000;
+		}
+		
+		/* Update jitter stat */
+		pj_math_stat_update(&sess->stat.rx_ipdv, ipdv);
+	    }
+#endif
+
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+	    pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
+				   0,			    /* lost    */
+				   0,			    /* dup     */
+				   discarded,		    /* discard */
+				   (sess->jitter >> 4),	    /* jitter  */
+				   -1, 0);		    /* toh     */
+#endif
+
+	    /* Update session transit */
+	    sess->transit = transit;
+	}
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    } else if (seq_st.diff > 1) {
+	int i;
+
+	/* Report RTCP XR about packet losses */
+	for (i=seq_st.diff-1; i>0; --i) {
+	    pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq - i, 
+				   1,			    /* lost    */
+				   0,			    /* dup     */
+				   0,			    /* discard */
+				   -1,			    /* jitter  */
+				   -1, 0);		    /* toh     */
+	}
+
+	/* Report RTCP XR this packet */
+	pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
+			       0,			    /* lost    */
+			       0,			    /* dup     */
+			       discarded,		    /* discard */
+			       -1,			    /* jitter  */
+			       -1, 0);			    /* toh     */
+#endif
+    }
+
+    /* Update timestamp of last RX RTP packet */
+    sess->rtp_last_ts = rtp_ts;
+}
+
+PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess, 
+				 unsigned bytes_payload_size)
+{
+    /* Update statistics */
+    sess->stat.tx.pkt++;
+    sess->stat.tx.bytes += bytes_payload_size;
+}
+
+
+static void parse_rtcp_report( pjmedia_rtcp_session *sess,
+			       const void *pkt,
+			       pj_size_t size)
+{
+    pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt;
+    const pjmedia_rtcp_rr *rr = NULL;
+    const pjmedia_rtcp_sr *sr = NULL;
+    pj_uint32_t last_loss, jitter_samp, jitter;
+
+    /* Parse RTCP */
+    if (common->pt == RTCP_SR) {
+	sr = (pjmedia_rtcp_sr*) (((char*)pkt) + sizeof(pjmedia_rtcp_common));
+	if (common->count > 0 && size >= (sizeof(pjmedia_rtcp_sr_pkt))) {
+	    rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common)
+				    + sizeof(pjmedia_rtcp_sr)));
+	}
+    } else if (common->pt == RTCP_RR && common->count > 0) {
+	rr = (pjmedia_rtcp_rr*)(((char*)pkt) + sizeof(pjmedia_rtcp_common));
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    } else if (common->pt == RTCP_XR) {
+	if (sess->xr_enabled)
+	    pjmedia_rtcp_xr_rx_rtcp_xr(&sess->xr_session, pkt, size);
+
+	return;
+#endif
+    }
+
+
+    if (sr) {
+	/* Save LSR from NTP timestamp of RTCP packet */
+	sess->rx_lsr = ((pj_ntohl(sr->ntp_sec) & 0x0000FFFF) << 16) | 
+		       ((pj_ntohl(sr->ntp_frac) >> 16) & 0xFFFF);
+
+	/* Calculate SR arrival time for DLSR */
+	pj_get_timestamp(&sess->rx_lsr_time);
+
+	TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p", 
+		sess->rx_lsr,
+		(pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64)));
+    }
+
+
+    /* Nothing more to do if there's no RR packet */
+    if (rr == NULL)
+	return;
+
+
+    last_loss = sess->stat.tx.loss;
+
+    /* Get packet loss */
+    sess->stat.tx.loss = (rr->total_lost_2 << 16) +
+			 (rr->total_lost_1 << 8) +
+			  rr->total_lost_0;
+
+    TRACE_((sess->name, "Rx RTCP RR: total_lost_2=%x, 1=%x, 0=%x, lost=%d", 
+	    (int)rr->total_lost_2,
+	    (int)rr->total_lost_1,
+	    (int)rr->total_lost_0,
+	    sess->stat.tx.loss));
+    
+    /* We can't calculate the exact loss period for TX, so just give the
+     * best estimation.
+     */
+    if (sess->stat.tx.loss > last_loss) {
+	unsigned period;
+
+	/* Loss period in msec */
+	period = (sess->stat.tx.loss - last_loss) * sess->pkt_size *
+		 1000 / sess->clock_rate;
+
+	/* Loss period in usec */
+	period *= 1000;
+
+	/* Update loss period stat */
+	pj_math_stat_update(&sess->stat.tx.loss_period, period);
+    }
+
+    /* Get jitter value in usec */
+    jitter_samp = pj_ntohl(rr->jitter);
+    /* Calculate jitter in usec, avoiding overflows */
+    if (jitter_samp <= 4294)
+	jitter = jitter_samp * 1000000 / sess->clock_rate;
+    else {
+	jitter = jitter_samp * 1000 / sess->clock_rate;
+	jitter *= 1000;
+    }
+
+    /* Update jitter statistics */
+    pj_math_stat_update(&sess->stat.tx.jitter, jitter);
+
+    /* Can only calculate if LSR and DLSR is present in RR */
+    if (rr->lsr && rr->dlsr) {
+	pj_uint32_t lsr, now, dlsr;
+	pj_uint64_t eedelay;
+	pjmedia_rtcp_ntp_rec ntp;
+
+	/* LSR is the middle 32bit of NTP. It has 1/65536 second 
+	 * resolution 
+	 */
+	lsr = pj_ntohl(rr->lsr);
+
+	/* DLSR is delay since LSR, also in 1/65536 resolution */
+	dlsr = pj_ntohl(rr->dlsr);
+
+	/* Get current time, and convert to 1/65536 resolution */
+	pjmedia_rtcp_get_ntp_time(sess, &ntp);
+	now = ((ntp.hi & 0xFFFF) << 16) + (ntp.lo >> 16);
+
+	/* End-to-end delay is (now-lsr-dlsr) */
+	eedelay = now - lsr - dlsr;
+
+	/* Convert end to end delay to usec (keeping the calculation in
+         * 64bit space)::
+	 *   sess->ee_delay = (eedelay * 1000) / 65536;
+	 */
+	if (eedelay < 4294) {
+	    eedelay = (eedelay * 1000000) >> 16;
+	} else {
+	    eedelay = (eedelay * 1000) >> 16;
+	    eedelay *= 1000;
+	}
+
+	TRACE_((sess->name, "Rx RTCP RR: lsr=%p, dlsr=%p (%d:%03dms), "
+			   "now=%p, rtt=%p",
+		lsr, dlsr, dlsr/65536, (dlsr%65536)*1000/65536,
+		now, (pj_uint32_t)eedelay));
+	
+	/* Only save calculation if "now" is greater than lsr, or
+	 * otherwise rtt will be invalid 
+	 */
+	if (now-dlsr >= lsr) {
+	    unsigned rtt = (pj_uint32_t)eedelay;
+	    
+	    /* Check that eedelay value really makes sense. 
+	     * We allow up to 30 seconds RTT!
+	     */
+	    if (eedelay > 30 * 1000 * 1000UL) {
+
+		TRACE_((sess->name, "RTT not making any sense, ignored.."));
+		goto end_rtt_calc;
+	    }
+
+#if defined(PJMEDIA_RTCP_NORMALIZE_FACTOR) && PJMEDIA_RTCP_NORMALIZE_FACTOR!=0
+	    /* "Normalize" rtt value that is exceptionally high. For such
+	     * values, "normalize" the rtt to be PJMEDIA_RTCP_NORMALIZE_FACTOR
+	     * times the average value.
+	     */
+	    if (rtt > ((unsigned)sess->stat.rtt.mean *
+		       PJMEDIA_RTCP_NORMALIZE_FACTOR) && sess->stat.rtt.n!=0)
+	    {
+		unsigned orig_rtt = rtt;
+		rtt = sess->stat.rtt.mean * PJMEDIA_RTCP_NORMALIZE_FACTOR;
+		PJ_LOG(5,(sess->name,
+			  "RTT value %d usec is normalized to %d usec",
+			  orig_rtt, rtt));
+	    }
+#endif
+	    TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
+
+	    /* Update RTT stat */
+	    pj_math_stat_update(&sess->stat.rtt, rtt);
+
+	} else {
+	    PJ_LOG(5, (sess->name, "Internal RTCP NTP clock skew detected: "
+				   "lsr=%p, now=%p, dlsr=%p (%d:%03dms), "
+				   "diff=%d",
+				   lsr, now, dlsr, dlsr/65536,
+				   (dlsr%65536)*1000/65536,
+				   dlsr-(now-lsr)));
+	}
+    }
+
+end_rtt_calc:
+
+    pj_gettimeofday(&sess->stat.tx.update);
+    sess->stat.tx.update_cnt++;
+}
+
+
+static void parse_rtcp_sdes(pjmedia_rtcp_session *sess,
+			    const void *pkt,
+			    pj_size_t size)
+{
+    pjmedia_rtcp_sdes *sdes = &sess->stat.peer_sdes;
+    char *p, *p_end;
+    char *b, *b_end;
+
+    p = (char*)pkt + 8;
+    p_end = (char*)pkt + size;
+
+    pj_bzero(sdes, sizeof(*sdes));
+    b = sess->stat.peer_sdes_buf_;
+    b_end = b + sizeof(sess->stat.peer_sdes_buf_);
+
+    while (p < p_end) {
+	pj_uint8_t sdes_type, sdes_len;
+	pj_str_t sdes_value = {NULL, 0};
+
+	sdes_type = *p++;
+
+	/* Check for end of SDES item list */
+	if (sdes_type == RTCP_SDES_NULL || p == p_end)
+	    break;
+
+	sdes_len = *p++;
+
+	/* Check for corrupted SDES packet */
+	if (p + sdes_len > p_end)
+	    break;
+
+	/* Get SDES item */
+	if (b + sdes_len < b_end) {
+	    pj_memcpy(b, p, sdes_len);
+	    sdes_value.ptr = b;
+	    sdes_value.slen = sdes_len;
+	    b += sdes_len;
+	} else {
+	    /* Insufficient SDES buffer */
+	    PJ_LOG(5, (sess->name,
+		    "Unsufficient buffer to save RTCP SDES type %d:%.*s",
+		    sdes_type, sdes_len, p));
+	    p += sdes_len;
+	    continue;
+	}
+
+	switch (sdes_type) {
+	case RTCP_SDES_CNAME:
+	    sdes->cname = sdes_value;
+	    break;
+	case RTCP_SDES_NAME:
+	    sdes->name = sdes_value;
+	    break;
+	case RTCP_SDES_EMAIL:
+	    sdes->email = sdes_value;
+	    break;
+	case RTCP_SDES_PHONE:
+	    sdes->phone = sdes_value;
+	    break;
+	case RTCP_SDES_LOC:
+	    sdes->loc = sdes_value;
+	    break;
+	case RTCP_SDES_TOOL:
+	    sdes->tool = sdes_value;
+	    break;
+	case RTCP_SDES_NOTE:
+	    sdes->note = sdes_value;
+	    break;
+	default:
+	    TRACE_((sess->name, "Received unknown RTCP SDES type %d:%.*s",
+		    sdes_type, sdes_value.slen, sdes_value.ptr));
+	    break;
+	}
+
+	p += sdes_len;
+    }
+}
+
+
+static void parse_rtcp_bye(pjmedia_rtcp_session *sess,
+			   const void *pkt,
+			   pj_size_t size)
+{
+    pj_str_t reason = {"-", 1};
+
+    /* Check and get BYE reason */
+    if (size > 8) {
+	reason.slen = PJ_MIN(sizeof(sess->stat.peer_sdes_buf_),
+                             *((pj_uint8_t*)pkt+8));
+	pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9),
+		  reason.slen);
+	reason.ptr = sess->stat.peer_sdes_buf_;
+    }
+
+    /* Just print RTCP BYE log */
+    PJ_LOG(5, (sess->name, "Received RTCP BYE, reason: %.*s",
+	       reason.slen, reason.ptr));
+}
+
+
+PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
+				   const void *pkt,
+				   pj_size_t size)
+{
+    pj_uint8_t *p, *p_end;
+
+    p = (pj_uint8_t*)pkt;
+    p_end = p + size;
+    while (p < p_end) {
+	pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p;
+	unsigned len;
+
+	len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4;
+	switch(common->pt) {
+	case RTCP_SR:
+	case RTCP_RR:
+	case RTCP_XR:
+	    parse_rtcp_report(sess, p, len);
+	    break;
+	case RTCP_SDES:
+	    parse_rtcp_sdes(sess, p, len);
+	    break;
+	case RTCP_BYE:
+	    parse_rtcp_bye(sess, p, len);
+	    break;
+	default:
+	    /* Ignore unknown RTCP */
+	    TRACE_((sess->name, "Received unknown RTCP packet type=%d",
+		    common->pt));
+	    break;
+	}
+
+	p += len;
+    }
+}
+
+
+PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess, 
+				     void **ret_p_pkt, int *len)
+{
+    pj_uint32_t expected, expected_interval, received_interval, lost_interval;
+    pjmedia_rtcp_common *common;
+    pjmedia_rtcp_sr *sr;
+    pjmedia_rtcp_rr *rr;
+    pj_timestamp ts_now;
+    pjmedia_rtcp_ntp_rec ntp;
+
+    /* Get current NTP time. */
+    pj_get_timestamp(&ts_now);
+    pjmedia_rtcp_get_ntp_time(sess, &ntp);
+
+
+    /* See if we have transmitted RTP packets since last time we
+     * sent RTCP SR.
+     */
+    if (sess->stat.tx.pkt != pj_ntohl(sess->rtcp_sr_pkt.sr.sender_pcount)) {
+	pj_time_val ts_time;
+	pj_uint32_t rtp_ts;
+
+	/* So we should send RTCP SR */
+	*ret_p_pkt = (void*) &sess->rtcp_sr_pkt;
+	*len = sizeof(pjmedia_rtcp_sr_pkt);
+	common = &sess->rtcp_sr_pkt.common;
+	rr = &sess->rtcp_sr_pkt.rr;
+	sr = &sess->rtcp_sr_pkt.sr;
+
+	/* Update packet count */
+	sr->sender_pcount = pj_htonl(sess->stat.tx.pkt);
+
+	/* Update octets count */
+	sr->sender_bcount = pj_htonl(sess->stat.tx.bytes);
+
+	/* Fill in NTP timestamp in SR. */
+	sr->ntp_sec = pj_htonl(ntp.hi);
+	sr->ntp_frac = pj_htonl(ntp.lo);
+
+	/* Fill in RTP timestamp (corresponds to NTP timestamp) in SR. */
+	ts_time.sec = ntp.hi - sess->tv_base.sec - JAN_1970;
+	ts_time.msec = (long)(ntp.lo * 1000.0 / 0xFFFFFFFF);
+	rtp_ts = sess->rtp_ts_base +
+		 (pj_uint32_t)(sess->clock_rate*ts_time.sec) +
+		 (pj_uint32_t)(sess->clock_rate*ts_time.msec/1000);
+	sr->rtp_ts = pj_htonl(rtp_ts);
+
+	TRACE_((sess->name, "TX RTCP SR: ntp_ts=%p", 
+			   ((ntp.hi & 0xFFFF) << 16) + ((ntp.lo & 0xFFFF0000) 
+				>> 16)));
+
+
+    } else {
+	/* We should send RTCP RR then */
+	*ret_p_pkt = (void*) &sess->rtcp_rr_pkt;
+	*len = sizeof(pjmedia_rtcp_rr_pkt);
+	common = &sess->rtcp_rr_pkt.common;
+	rr = &sess->rtcp_rr_pkt.rr;
+	sr = NULL;
+    }
+    
+    /* SSRC and last_seq */
+    rr->ssrc = pj_htonl(sess->peer_ssrc);
+    rr->last_seq = (sess->seq_ctrl.cycles & 0xFFFF0000L);
+    /* Since this is an "+=" operation, make sure we update last_seq on
+     * both RR and SR.
+     */
+    sess->rtcp_sr_pkt.rr.last_seq += sess->seq_ctrl.max_seq;
+    sess->rtcp_rr_pkt.rr.last_seq += sess->seq_ctrl.max_seq;
+    rr->last_seq = pj_htonl(rr->last_seq);
+
+
+    /* Jitter */
+    rr->jitter = pj_htonl(sess->jitter >> 4);
+    
+    
+    /* Total lost. */
+    expected = pj_ntohl(rr->last_seq) - sess->seq_ctrl.base_seq;
+
+    /* This is bug: total lost already calculated on each incoming RTP!
+    if (expected >= sess->received)
+	sess->stat.rx.loss = expected - sess->received;
+    else
+	sess->stat.rx.loss = 0;
+    */
+
+    rr->total_lost_2 = (sess->stat.rx.loss >> 16) & 0xFF;
+    rr->total_lost_1 = (sess->stat.rx.loss >> 8) & 0xFF;
+    rr->total_lost_0 = (sess->stat.rx.loss & 0xFF);
+
+    /* Fraction lost calculation */
+    expected_interval = expected - sess->exp_prior;
+    sess->exp_prior = expected;
+    
+    received_interval = sess->received - sess->rx_prior;
+    sess->rx_prior = sess->received;
+    
+    if (expected_interval >= received_interval)
+	lost_interval = expected_interval - received_interval;
+    else
+	lost_interval = 0;
+    
+    if (expected_interval==0 || lost_interval == 0) {
+	rr->fract_lost = 0;
+    } else {
+	rr->fract_lost = (lost_interval << 8) / expected_interval;
+    }
+    
+    if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) {
+	rr->lsr = 0;
+	rr->dlsr = 0;
+    } else {
+	pj_timestamp ts;
+	pj_uint32_t lsr = sess->rx_lsr;
+	pj_uint64_t lsr_time = sess->rx_lsr_time.u64;
+	pj_uint32_t dlsr;
+	
+	/* Convert LSR time to 1/65536 seconds resolution */
+	lsr_time = (lsr_time << 16) / sess->ts_freq.u64;
+
+	/* Fill in LSR.
+	   LSR is the middle 32bit of the last SR NTP time received.
+	 */
+	rr->lsr = pj_htonl(lsr);
+	
+	/* Fill in DLSR.
+	   DLSR is Delay since Last SR, in 1/65536 seconds.
+	 */
+	ts.u64 = ts_now.u64;
+
+	/* Convert interval to 1/65536 seconds value */
+	ts.u64 = (ts.u64 << 16) / sess->ts_freq.u64;
+
+	/* Get DLSR */
+	dlsr = (pj_uint32_t)(ts.u64 - lsr_time);
+	rr->dlsr = pj_htonl(dlsr);
+
+	TRACE_((sess->name,"Tx RTCP RR: lsr=%p, lsr_time=%p, now=%p, dlsr=%p"
+			   "(%ds:%03dms)",
+			   lsr, 
+			   (pj_uint32_t)lsr_time,
+			   (pj_uint32_t)ts.u64, 
+			   dlsr,
+			   dlsr/65536,
+			   (dlsr%65536)*1000/65536 ));
+    }
+    
+    /* Update counter */
+    pj_gettimeofday(&sess->stat.rx.update);
+    sess->stat.rx.update_cnt++;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
+					    pjmedia_rtcp_session *session, 
+					    void *buf,
+					    pj_size_t *length,
+					    const pjmedia_rtcp_sdes *sdes)
+{
+    pjmedia_rtcp_common *hdr;
+    pj_uint8_t *p;
+    pj_size_t len;
+
+    PJ_ASSERT_RETURN(session && buf && length && sdes, PJ_EINVAL);
+
+    /* Verify SDES item length */
+    if (sdes->cname.slen > 255 || sdes->name.slen  > 255 ||
+	sdes->email.slen > 255 || sdes->phone.slen > 255 ||
+	sdes->loc.slen   > 255 || sdes->tool.slen  > 255 ||
+	sdes->note.slen  > 255)
+    {
+	return PJ_EINVAL;
+    }
+
+    /* Verify buffer length */
+    len = sizeof(*hdr);
+    if (sdes->cname.slen) len += sdes->cname.slen + 2;
+    if (sdes->name.slen)  len += sdes->name.slen  + 2;
+    if (sdes->email.slen) len += sdes->email.slen + 2;
+    if (sdes->phone.slen) len += sdes->phone.slen + 2;
+    if (sdes->loc.slen)   len += sdes->loc.slen   + 2;
+    if (sdes->tool.slen)  len += sdes->tool.slen  + 2;
+    if (sdes->note.slen)  len += sdes->note.slen  + 2;
+    len++; /* null termination */
+    len = ((len+3)/4) * 4;
+    if (len > *length)
+	return PJ_ETOOSMALL;
+
+    /* Build RTCP SDES header */
+    hdr = (pjmedia_rtcp_common*)buf;
+    pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr));
+    hdr->pt = RTCP_SDES;
+    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
+
+    /* Build RTCP SDES items */
+    p = (pj_uint8_t*)hdr + sizeof(*hdr);
+#define BUILD_SDES_ITEM(SDES_NAME, SDES_TYPE) \
+    if (sdes->SDES_NAME.slen) { \
+	*p++ = SDES_TYPE; \
+	*p++ = (pj_uint8_t)sdes->SDES_NAME.slen; \
+	pj_memcpy(p, sdes->SDES_NAME.ptr, sdes->SDES_NAME.slen); \
+	p += sdes->SDES_NAME.slen; \
+    }
+    BUILD_SDES_ITEM(cname, RTCP_SDES_CNAME);
+    BUILD_SDES_ITEM(name,  RTCP_SDES_NAME);
+    BUILD_SDES_ITEM(email, RTCP_SDES_EMAIL);
+    BUILD_SDES_ITEM(phone, RTCP_SDES_PHONE);
+    BUILD_SDES_ITEM(loc,   RTCP_SDES_LOC);
+    BUILD_SDES_ITEM(tool,  RTCP_SDES_TOOL);
+    BUILD_SDES_ITEM(note,  RTCP_SDES_NOTE);
+#undef BUILD_SDES_ITEM
+
+    /* Null termination */
+    *p++ = 0;
+
+    /* Pad to 32bit */
+    while ((p-(pj_uint8_t*)buf) % 4)
+	*p++ = 0;
+
+    /* Finally */
+    pj_assert((int)len == p-(pj_uint8_t*)buf);
+    *length = len;
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_bye(pjmedia_rtcp_session *session,
+						void *buf,
+						pj_size_t *length,
+						const pj_str_t *reason)
+{
+    pjmedia_rtcp_common *hdr;
+    pj_uint8_t *p;
+    pj_size_t len;
+
+    PJ_ASSERT_RETURN(session && buf && length, PJ_EINVAL);
+
+    /* Verify BYE reason length */
+    if (reason && reason->slen > 255)
+	return PJ_EINVAL;
+
+    /* Verify buffer length */
+    len = sizeof(*hdr);
+    if (reason && reason->slen) len += reason->slen + 1;
+    len = ((len+3)/4) * 4;
+    if (len > *length)
+	return PJ_ETOOSMALL;
+
+    /* Build RTCP BYE header */
+    hdr = (pjmedia_rtcp_common*)buf;
+    pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr));
+    hdr->pt = RTCP_BYE;
+    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
+
+    /* Write RTCP BYE reason */
+    p = (pj_uint8_t*)hdr + sizeof(*hdr);
+    if (reason && reason->slen) {
+	*p++ = (pj_uint8_t)reason->slen;
+	pj_memcpy(p, reason->ptr, reason->slen);
+	p += reason->slen;
+    }
+
+    /* Pad to 32bit */
+    while ((p-(pj_uint8_t*)buf) % 4)
+	*p++ = 0;
+
+    pj_assert((int)len == p-(pj_uint8_t*)buf);
+    *length = len;
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess, 
+					    pj_bool_t enable)
+{
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+
+    /* Check if request won't change anything */
+    if (!(enable ^ sess->xr_enabled))
+	return PJ_SUCCESS;
+
+    if (!enable) {
+	sess->xr_enabled = PJ_FALSE;
+	return PJ_SUCCESS;
+    }
+
+    pjmedia_rtcp_xr_init(&sess->xr_session, sess, 0, 1);
+    sess->xr_enabled = PJ_TRUE;
+
+    return PJ_SUCCESS;
+
+#else
+
+    PJ_UNUSED_ARG(sess);
+    PJ_UNUSED_ARG(enable);
+    return PJ_ENOTSUP;
+
+#endif
+}
diff --git a/jni/pjproject-android/.svn/pristine/a7/a75f806ccadd1c1c1ccc76851fb6aca4cd803be1.svn-base b/jni/pjproject-android/.svn/pristine/a7/a75f806ccadd1c1c1ccc76851fb6aca4cd803be1.svn-base
new file mode 100644
index 0000000..e1b0535
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a75f806ccadd1c1c1ccc76851fb6aca4cd803be1.svn-base
@@ -0,0 +1,27 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:x AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used invalid crypto tag (non-numeric), callee must not accept the call", 
+			    pjsua_args=args, sdp=sdp, resp_code=406, 
+			    resp_inc=include, resp_exc=exclude)
diff --git a/jni/pjproject-android/.svn/pristine/a7/a76f7c45aa341bc685acbc6792c6f976c3163c00.svn-base b/jni/pjproject-android/.svn/pristine/a7/a76f7c45aa341bc685acbc6792c6f976c3163c00.svn-base
new file mode 100644
index 0000000..03c8659
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a76f7c45aa341bc685acbc6792c6f976c3163c00.svn-base
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_destroy.c,v 1.3 1994/11/28 19:52:25 jutta Exp $ */
+
+#include "gsm.h"
+#include "config.h"
+#include "proto.h"
+
+#ifdef	HAS_STDLIB_H
+#	include	<stdlib.h>
+#else
+#	ifdef	HAS_MALLOC_H
+#		include 	<malloc.h>
+#	else
+		extern void free();
+#	endif
+#endif
+
+void gsm_destroy P1((S), gsm S)
+{
+	if (S) free((char *)S);
+}
diff --git a/jni/pjproject-android/.svn/pristine/a7/a770d4e03a1da20fd942f8089181aa6303f6d98b.svn-base b/jni/pjproject-android/.svn/pristine/a7/a770d4e03a1da20fd942f8089181aa6303f6d98b.svn-base
new file mode 100644
index 0000000..76b64dd
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a770d4e03a1da20fd942f8089181aa6303f6d98b.svn-base
@@ -0,0 +1,65 @@
+#if defined(PJ_BUILD_DLL)
+TARGET		pjnath.dll
+TARGETTYPE	dll
+UID		0x0 0xA0000005
+
+CAPABILITY	None
+LIBRARY		pjlib_util.lib pjlib.lib esock.lib insock.lib charconv.lib euser.lib estlib.lib
+MACRO		PJ_DLL
+MACRO		PJ_EXPORTING
+
+DEFFILE		.\pjnath.def
+
+#else
+
+TARGET 		pjnath.lib
+TARGETTYPE 	lib
+
+#endif
+
+OPTION          ARMCC --gnu
+
+SOURCEPATH	..\pjnath\src\pjnath
+
+MACRO		PJ_M_I386=1
+MACRO		PJ_SYMBIAN=1
+
+//
+// PJNATH files
+//
+SOURCE	errno.c
+SOURCE	ice_session.c
+SOURCE	ice_strans.c
+SOURCE	nat_detect.c
+SOURCE	stun_auth.c
+SOURCE	stun_msg.c
+SOURCE	stun_msg_dump.c
+SOURCE	stun_session.c
+SOURCE	stun_sock.c
+SOURCE	stun_transaction.c
+SOURCE	turn_session.c
+SOURCE	turn_sock.c
+
+//
+// Include files
+//
+//DOCUMENT pjnath\config.h
+//DOCUMENT pjnath\\errno.h
+//DOCUMENT pjnath\\ice_session.h
+//DOCUMENT pjnath\\ice_strans.h
+//DOCUMENT pjnath\\stun_auth.h
+//DOCUMENT pjnath\\stun_config.h
+//DOCUMENT pjnath\\stun_msg.h
+//DOCUMENT pjnath\\stun_session.h
+//DOCUMENT pjnath\\stun_transaction.h
+//DOCUMENT pjnath\\types.h
+
+
+
+SYSTEMINCLUDE	..\pjlib\include 
+SYSTEMINCLUDE	..\pjlib-util\include
+SYSTEMINCLUDE	..\pjnath\include
+
+SYSTEMINCLUDE	\epoc32\include
+SYSTEMINCLUDE	\epoc32\include\libc
+
diff --git a/jni/pjproject-android/.svn/pristine/a7/a79629e56df654e92847dc41efd5e4e62d320171.svn-base b/jni/pjproject-android/.svn/pristine/a7/a79629e56df654e92847dc41efd5e4e62d320171.svn-base
new file mode 100644
index 0000000..ed81195
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a79629e56df654e92847dc41efd5e4e62d320171.svn-base
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>

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

+

+<!-- This program is free software; you can redistribute it and/or      -->

+<!-- modify it under the terms of the GNU General Public License as     -->

+<!-- published by the Free Software Foundation; either version 2 of the -->

+<!-- License, or (at your option) any later version.                    -->

+<!--                                                                    -->

+<!-- This program is distributed in the hope that it will be useful,    -->

+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of     -->

+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      -->

+<!-- GNU General Public License for more details.                       -->

+<!--                                                                    -->

+<!-- You should have received a copy of the GNU General Public License  -->

+<!-- along with this program; if not, write to the                      -->

+<!-- Free Software Foundation, Inc.,                                    -->

+<!-- 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA             -->

+<!--                                                                    -->

+

+<scenario name="MWI server">

+  <recv request="SUBSCRIBE" crlf="true">

+    <action>

+	<ereg regexp=".*" search_in="hdr" header="From" assign_to="3"/>

+	<ereg regexp="sip:(.*)>" search_in="hdr" header="Contact" assign_to="4,5"/>

+        <assign assign_to="4" variable="5" />

+    </action>

+  </recv>

+

+

+  <send>

+    <![CDATA[

+

+      SIP/2.0 200 OK

+      [last_Via:]

+      [last_From:]

+      [last_To:];tag=[call_number]

+      [last_Call-ID:]

+      [last_CSeq:]

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

+      Content-Length: 0

+      Expires: 600

+    ]]>

+  </send>

+

+  <!-- initial notify -->

+  <send retrans="500">

+    <![CDATA[

+      NOTIFY sip:[$5] SIP/2.0

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

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

+      To[$3]

+      Call-ID: [call_id]

+      Cseq: 1 NOTIFY

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

+      Max-Forwards: 70

+      Event: message-summary

+      Subscription-State: active;expires=50

+      Content-Type: application/simple-message-summary

+      Content-Length: [len]

+

+      Messages-Waiting: yes

+      Voice-Message: 4/8 (1/2)

+

+    ]]>

+  </send>

+

+   <recv response="200">

+   </recv>

+

+  <pause milliseconds="2000"/> 

+

+

+  <!-- terminate subscription -->

+  <send retrans="500">

+    <![CDATA[

+      NOTIFY sip:[$5] SIP/2.0

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

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

+      To[$3]

+      Call-ID: [call_id]

+      Cseq: 2 NOTIFY

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

+      Max-Forwards: 70

+      Event: message-summary

+      Subscription-State: terminated;reason=noresource

+      Content-Type: application/simple-message-summary

+      Content-Length: [len]

+

+      Messages-Waiting: yes

+      Voice-Message: 4/8 (1/2)

+

+    ]]>

+  </send>

+

+   <recv response="200">

+   </recv>

+

+  <!-- definition of the response time repartition table (unit is ms)   -->

+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>

+

+  <!-- definition of the call length repartition table (unit is ms)     -->

+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>

+

+</scenario>

+

diff --git a/jni/pjproject-android/.svn/pristine/a7/a7ab0b107cc966579b47133a6ab9dd6c71dde214.svn-base b/jni/pjproject-android/.svn/pristine/a7/a7ab0b107cc966579b47133a6ab9dd6c71dde214.svn-base
new file mode 100644
index 0000000..61d2b8b
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a7ab0b107cc966579b47133a6ab9dd6c71dde214.svn-base
@@ -0,0 +1,563 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2007 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 
+ */
+
+/*
+ * Contributed by:
+ *  Toni < buldozer at aufbix dot org >
+ */
+#include "mp3_port.h"
+#include <pjmedia/errno.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>
+#include <pj/unicode.h>
+
+
+/* Include BladeDLL declarations */
+#include "BladeMP3EncDLL.h"
+
+
+#define THIS_FILE	    "mp3_writer.c"
+#define SIGNATURE	    PJMEDIA_SIG_CLASS_PORT_AUD('M','W')
+#define BYTES_PER_SAMPLE    2
+
+static struct BladeDLL
+{
+    void		*hModule;
+    int			 refCount;
+    BEINITSTREAM	 beInitStream;
+    BEENCODECHUNK	 beEncodeChunk;
+    BEDEINITSTREAM	 beDeinitStream;
+    BECLOSESTREAM	 beCloseStream;
+    BEVERSION		 beVersion;
+    BEWRITEVBRHEADER	 beWriteVBRHeader;
+    BEWRITEINFOTAG	 beWriteInfoTag;
+} BladeDLL;
+
+
+struct mp3_file_port
+{
+    pjmedia_port    base;
+    pj_size_t	    total;
+    pj_oshandle_t   fd;
+    pj_size_t	    cb_size;
+    pj_status_t	   (*cb)(pjmedia_port*, void*);
+
+    unsigned	    silence_duration;
+
+    pj_str_t			mp3_filename;
+    pjmedia_mp3_encoder_option  mp3_option;
+    unsigned		        mp3_samples_per_frame;
+    pj_int16_t		       *mp3_sample_buf;
+    unsigned			mp3_sample_pos;
+    HBE_STREAM		        mp3_stream;
+    unsigned char	       *mp3_buf;
+};
+
+
+static pj_status_t file_put_frame(pjmedia_port *this_port, 
+				  const 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);
+
+
+#if defined(PJ_WIN32) || defined(_WIN32) || defined(WIN32)
+
+#include <windows.h>
+#define DLL_NAME    PJ_T("LAME_ENC.DLL")
+
+/*
+ * Load BladeEncoder DLL.
+ */
+static pj_status_t init_blade_dll(void)
+{
+    if (BladeDLL.refCount == 0) {
+	#define GET_PROC(type, name)  \
+	    BladeDLL.name = (type)GetProcAddress(BladeDLL.hModule, PJ_T(#name)); \
+	    if (BladeDLL.name == NULL) { \
+		PJ_LOG(1,(THIS_FILE, "Unable to find %s in %s", #name, DLL_NAME)); \
+		return PJ_RETURN_OS_ERROR(GetLastError()); \
+	    }
+
+	BE_VERSION beVersion;
+	BladeDLL.hModule = (void*)LoadLibrary(DLL_NAME);
+	if (BladeDLL.hModule == NULL) {
+	    pj_status_t status = PJ_RETURN_OS_ERROR(GetLastError());
+	    char errmsg[PJ_ERR_MSG_SIZE];
+
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    PJ_LOG(1,(THIS_FILE, "Unable to load %s: %s", DLL_NAME, errmsg));
+	    return status;
+	}
+
+	GET_PROC(BEINITSTREAM, beInitStream);
+	GET_PROC(BEENCODECHUNK, beEncodeChunk);
+	GET_PROC(BEDEINITSTREAM, beDeinitStream);
+	GET_PROC(BECLOSESTREAM, beCloseStream);
+	GET_PROC(BEVERSION, beVersion);
+	GET_PROC(BEWRITEVBRHEADER, beWriteVBRHeader);
+	GET_PROC(BEWRITEINFOTAG, beWriteInfoTag);
+
+	#undef GET_PROC
+
+	BladeDLL.beVersion(&beVersion);
+	PJ_LOG(4,(THIS_FILE, "%s encoder v%d.%d loaded (%s)", DLL_NAME,
+		  beVersion.byMajorVersion, beVersion.byMinorVersion,
+		  beVersion.zHomepage));
+    }
+    ++BladeDLL.refCount;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Decrement the reference counter of the DLL.
+ */
+static void deinit_blade_dll()
+{
+    --BladeDLL.refCount;
+    if (BladeDLL.refCount == 0 && BladeDLL.hModule) {
+	FreeLibrary(BladeDLL.hModule);
+	BladeDLL.hModule = NULL;
+	PJ_LOG(4,(THIS_FILE, "%s unloaded", DLL_NAME));
+    }
+}
+
+#else
+
+static pj_status_t init_blade_dll(void)
+{
+    PJ_LOG(1,(THIS_FILE, "Error: MP3 writer port only works on Windows for now"));
+    return PJ_ENOTSUP;
+}
+
+static void deinit_blade_dll()
+{
+}
+#endif
+
+
+
+/*
+ * Initialize MP3 encoder.
+ */
+static pj_status_t init_mp3_encoder(struct mp3_file_port *fport,
+				    pj_pool_t *pool)
+{
+    BE_CONFIG LConfig;
+    unsigned  long InSamples;
+    unsigned  long OutBuffSize;
+    long MP3Err;
+
+    /*
+     * Initialize encoder configuration.
+     */
+    pj_bzero(&LConfig, sizeof(BE_CONFIG));
+    LConfig.dwConfig = BE_CONFIG_LAME;
+    LConfig.format.LHV1.dwStructVersion = 1;
+    LConfig.format.LHV1.dwStructSize = sizeof(BE_CONFIG);
+    LConfig.format.LHV1.dwSampleRate = PJMEDIA_PIA_SRATE(&fport->base.info);
+    LConfig.format.LHV1.dwReSampleRate = 0;
+
+    if (PJMEDIA_PIA_CCNT(&fport->base.info)==1)
+	LConfig.format.LHV1.nMode = BE_MP3_MODE_MONO;
+    else if (PJMEDIA_PIA_CCNT(&fport->base.info)==2)
+	LConfig.format.LHV1.nMode = BE_MP3_MODE_STEREO;
+    else
+	return PJMEDIA_ENCCHANNEL;
+
+    LConfig.format.LHV1.dwBitrate = fport->mp3_option.bit_rate / 1000;
+    LConfig.format.LHV1.nPreset = LQP_NOPRESET;
+    LConfig.format.LHV1.bCopyright = 0;
+    LConfig.format.LHV1.bCRC = 1;
+    LConfig.format.LHV1.bOriginal = 1;
+    LConfig.format.LHV1.bPrivate = 0;
+
+    if (!fport->mp3_option.vbr) {
+	LConfig.format.LHV1.nVbrMethod = VBR_METHOD_NONE;
+	LConfig.format.LHV1.bWriteVBRHeader = 0;
+	LConfig.format.LHV1.bEnableVBR = 0;
+    } else {
+	LConfig.format.LHV1.nVbrMethod = VBR_METHOD_DEFAULT;
+	LConfig.format.LHV1.bWriteVBRHeader = 1;
+	LConfig.format.LHV1.dwVbrAbr_bps = fport->mp3_option.bit_rate;
+	LConfig.format.LHV1.nVBRQuality =  (pj_uint16_t)
+					   fport->mp3_option.quality;
+	LConfig.format.LHV1.bEnableVBR = 1;
+    }
+
+    LConfig.format.LHV1.nQuality = (pj_uint16_t) 
+				   (((0-fport->mp3_option.quality-1)<<8) | 
+				    fport->mp3_option.quality);
+
+    /*
+     * Init MP3 stream.
+     */
+    InSamples = 0;
+    MP3Err = BladeDLL.beInitStream(&LConfig, &InSamples, &OutBuffSize,
+				   &fport->mp3_stream);
+    if (MP3Err != BE_ERR_SUCCESSFUL) 
+	return PJMEDIA_ERROR;
+
+    /*
+     * Allocate sample buffer.
+     */
+    fport->mp3_samples_per_frame = (unsigned)InSamples;
+    fport->mp3_sample_buf = pj_pool_alloc(pool, fport->mp3_samples_per_frame * 2);
+    if (!fport->mp3_sample_buf)
+	return PJ_ENOMEM;
+
+    /*
+     * Allocate encoded MP3 buffer.
+     */
+    fport->mp3_buf = pj_pool_alloc(pool, (pj_size_t)OutBuffSize);
+    if (fport->mp3_buf == NULL)
+	return PJ_ENOMEM;
+
+    
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Create MP3 file writer port.
+ */
+PJ_DEF(pj_status_t) 
+pjmedia_mp3_writer_port_create( pj_pool_t *pool,
+				const char *filename,
+				unsigned sampling_rate,
+				unsigned channel_count,
+				unsigned samples_per_frame,
+				unsigned bits_per_sample,
+				const pjmedia_mp3_encoder_option *param_option,
+				pjmedia_port **p_port )
+{
+    struct mp3_file_port *fport;
+    pj_status_t status;
+
+    status = init_blade_dll();
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);
+
+    /* Only supports 16bits per sample for now. */
+    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
+
+    /* Create file port instance. */
+    fport = pj_pool_zalloc(pool, sizeof(struct mp3_file_port));
+    PJ_ASSERT_RETURN(fport != NULL, PJ_ENOMEM);
+
+    /* Initialize port info. */
+    pj_strdup2_with_null(pool, &fport->mp3_filename, filename);
+    pjmedia_port_info_init(&fport->base.info, &fport->mp3_filename, 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;
+
+
+    /* 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) {
+	deinit_blade_dll();
+	return status;
+    }
+
+    /* Copy and initialize option with default settings */
+    if (param_option) {
+	pj_memcpy(&fport->mp3_option, param_option, 
+		   sizeof(pjmedia_mp3_encoder_option));
+    } else {
+	pj_bzero(&fport->mp3_option, sizeof(pjmedia_mp3_encoder_option));
+	fport->mp3_option.vbr = PJ_TRUE;
+    }
+
+    /* Calculate bitrate if it's not specified, only if it's not VBR. */
+    if (fport->mp3_option.bit_rate == 0 && !fport->mp3_option.vbr) 
+	fport->mp3_option.bit_rate = sampling_rate * channel_count;
+
+    /* Set default quality if it's not specified */
+    if (fport->mp3_option.quality == 0) 
+	fport->mp3_option.quality = 2;
+
+    /* Init mp3 encoder */
+    status = init_mp3_encoder(fport, pool);
+    if (status != PJ_SUCCESS) {
+	pj_file_close(fport->fd);
+	deinit_blade_dll();
+	return status;
+    }
+
+    /* Done. */
+    *p_port = &fport->base;
+
+    PJ_LOG(4,(THIS_FILE, 
+	      "MP3 file writer '%.*s' created: samp.rate=%dKHz, "
+	      "bitrate=%dkbps%s, quality=%d",
+	      (int)fport->base.info.name.slen,
+	      fport->base.info.name.ptr,
+		  PJMEDIA_PIA_SRATE(&fport->base.info),
+	      fport->mp3_option.bit_rate/1000,
+	      (fport->mp3_option.vbr ? " (VBR)" : ""),
+	      fport->mp3_option.quality));
+
+    return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Register callback.
+ */
+PJ_DEF(pj_status_t) 
+pjmedia_mp3_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 mp3_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 mp3_file_port*) port;
+
+    fport->cb_size = pos;
+    fport->base.port_data.pdata = user_data;
+    fport->cb = cb;
+
+    return PJ_SUCCESS;
+
+}
+
+
+/*
+ * 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, 
+				  const pjmedia_frame *frame)
+{
+    struct mp3_file_port *fport = (struct mp3_file_port *)this_port;
+    unsigned long MP3Err;
+    pj_ssize_t	bytes;
+    pj_status_t status;
+    unsigned long WriteSize;
+
+    /* Record silence if input is no-frame */
+    if (frame->type == PJMEDIA_FRAME_TYPE_NONE || frame->size == 0) {
+	unsigned samples_left = PJMEDIA_PIA_SPF(&fport->base.info);
+	unsigned samples_copied = 0;
+
+	/* Only want to record at most 1 second of silence */
+	if (fport->silence_duration >= PJMEDIA_PIA_SRATE(&fport->base.info))
+	    return PJ_SUCCESS;
+
+	while (samples_left) {
+	    unsigned samples_needed = fport->mp3_samples_per_frame -
+				      fport->mp3_sample_pos;
+	    if (samples_needed > samples_left)
+		samples_needed = samples_left;
+
+	    pjmedia_zero_samples(fport->mp3_sample_buf + fport->mp3_sample_pos,
+				 samples_needed);
+	    fport->mp3_sample_pos += samples_needed;
+	    samples_left -= samples_needed;
+	    samples_copied += samples_needed;
+
+	    /* Encode if we have full frame */
+	    if (fport->mp3_sample_pos == fport->mp3_samples_per_frame) {
+		
+		/* Clear position */
+		fport->mp3_sample_pos = 0;
+
+		/* Encode ! */
+		MP3Err = BladeDLL.beEncodeChunk(fport->mp3_stream,
+						fport->mp3_samples_per_frame,
+						fport->mp3_sample_buf, 
+						fport->mp3_buf, 
+						&WriteSize);
+		if (MP3Err != BE_ERR_SUCCESSFUL)
+		    return PJMEDIA_ERROR;
+
+		/* Write the chunk */
+		bytes = WriteSize;
+		status = pj_file_write(fport->fd, fport->mp3_buf, &bytes);
+		if (status != PJ_SUCCESS)
+		    return status;
+
+		/* Increment total written. */
+		fport->total += bytes;
+	    }
+	}
+
+	fport->silence_duration += PJMEDIA_PIA_SPF(&fport->base.info);
+
+    }
+    /* If encoder is expecting different sample size, then we need to
+     * buffer the samples.
+     */
+    else if (fport->mp3_samples_per_frame != 
+	     PJMEDIA_PIA_SPF(&fport->base.info)) 
+    {
+	unsigned samples_left = frame->size / 2;
+	unsigned samples_copied = 0;
+	const pj_int16_t *src_samples = frame->buf;
+
+	fport->silence_duration = 0;
+
+	while (samples_left) {
+	    unsigned samples_needed = fport->mp3_samples_per_frame -
+				      fport->mp3_sample_pos;
+	    if (samples_needed > samples_left)
+		samples_needed = samples_left;
+
+	    pjmedia_copy_samples(fport->mp3_sample_buf + fport->mp3_sample_pos,
+				 src_samples + samples_copied,
+				 samples_needed);
+	    fport->mp3_sample_pos += samples_needed;
+	    samples_left -= samples_needed;
+	    samples_copied += samples_needed;
+
+	    /* Encode if we have full frame */
+	    if (fport->mp3_sample_pos == fport->mp3_samples_per_frame) {
+		
+		/* Clear position */
+		fport->mp3_sample_pos = 0;
+
+		/* Encode ! */
+		MP3Err = BladeDLL.beEncodeChunk(fport->mp3_stream,
+						fport->mp3_samples_per_frame,
+						fport->mp3_sample_buf, 
+						fport->mp3_buf, 
+						&WriteSize);
+		if (MP3Err != BE_ERR_SUCCESSFUL)
+		    return PJMEDIA_ERROR;
+
+		/* Write the chunk */
+		bytes = WriteSize;
+		status = pj_file_write(fport->fd, fport->mp3_buf, &bytes);
+		if (status != PJ_SUCCESS)
+		    return status;
+
+		/* Increment total written. */
+		fport->total += bytes;
+	    }
+	}
+
+    } else {
+
+	fport->silence_duration = 0;
+
+	/* Encode ! */
+	MP3Err = BladeDLL.beEncodeChunk(fport->mp3_stream,
+					fport->mp3_samples_per_frame,
+					frame->buf, 
+					fport->mp3_buf, 
+					&WriteSize);
+	if (MP3Err != BE_ERR_SUCCESSFUL)
+	    return PJMEDIA_ERROR;
+
+	/* Write the chunk */
+	bytes = WriteSize;
+	status = pj_file_write(fport->fd, fport->mp3_buf, &bytes);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Increment total written. */
+	fport->total += bytes;
+    }
+
+    /* Increment total written, and check if we need to call callback */
+    
+    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)
+{
+    struct mp3_file_port *fport = (struct mp3_file_port*)this_port;
+    pj_status_t status;
+    unsigned long WriteSize;
+    unsigned long MP3Err;
+
+
+    /* Close encoder */
+    MP3Err = BladeDLL.beDeinitStream(fport->mp3_stream, fport->mp3_buf, 
+				     &WriteSize);
+    if (MP3Err == BE_ERR_SUCCESSFUL) {
+	pj_ssize_t bytes = WriteSize;
+	status = pj_file_write(fport->fd, fport->mp3_buf, &bytes);
+    }
+
+    /* Close file */
+    status = pj_file_close(fport->fd);
+
+    /* Write additional VBR header */
+    if (fport->mp3_option.vbr) {
+	MP3Err = BladeDLL.beWriteVBRHeader(fport->mp3_filename.ptr);
+    }
+
+
+    /* Decrement DLL reference counter */
+    deinit_blade_dll();
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/a7/a7cb2e36741e5bcab828270e9e71ab768d4419f3.svn-base b/jni/pjproject-android/.svn/pristine/a7/a7cb2e36741e5bcab828270e9e71ab768d4419f3.svn-base
new file mode 100644
index 0000000..4707522
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a7cb2e36741e5bcab828270e9e71ab768d4419f3.svn-base
@@ -0,0 +1,599 @@
+/*
+ * datatypes.c
+ *
+ * data types for finite fields and functions for input, output, and
+ * manipulation
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+/*
+ *	
+ * Copyright (c) 2001-2006 Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "datatypes.h"
+
+int 
+octet_weight[256] = {
+  0, 1, 1, 2, 1, 2, 2, 3,
+  1, 2, 2, 3, 2, 3, 3, 4,
+  1, 2, 2, 3, 2, 3, 3, 4,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  1, 2, 2, 3, 2, 3, 3, 4,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  1, 2, 2, 3, 2, 3, 3, 4,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  4, 5, 5, 6, 5, 6, 6, 7,
+  1, 2, 2, 3, 2, 3, 3, 4,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  4, 5, 5, 6, 5, 6, 6, 7,
+  2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  4, 5, 5, 6, 5, 6, 6, 7,
+  3, 4, 4, 5, 4, 5, 5, 6,
+  4, 5, 5, 6, 5, 6, 6, 7,
+  4, 5, 5, 6, 5, 6, 6, 7,
+  5, 6, 6, 7, 6, 7, 7, 8
+};
+
+int
+octet_get_weight(uint8_t octet) {
+  extern int octet_weight[256];
+
+  return octet_weight[octet];
+}  
+
+/*
+ * bit_string is a buffer that is used to hold output strings, e.g.
+ * for printing.
+ */
+
+/* the value MAX_PRINT_STRING_LEN is defined in datatypes.h */
+
+char bit_string[MAX_PRINT_STRING_LEN];
+
+uint8_t
+nibble_to_hex_char(uint8_t nibble) {
+  char buf[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+		  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+  return buf[nibble & 0xF];
+}
+
+char *
+octet_string_hex_string(const void *s, int length) {
+  const uint8_t *str = (const uint8_t *)s;
+  int i;
+  
+  /* double length, since one octet takes two hex characters */
+  length *= 2;
+
+  /* truncate string if it would be too long */
+  if (length > MAX_PRINT_STRING_LEN)
+    length = MAX_PRINT_STRING_LEN-1;
+  
+  for (i=0; i < length; i+=2) {
+    bit_string[i]   = nibble_to_hex_char(*str >> 4);
+    bit_string[i+1] = nibble_to_hex_char(*str++ & 0xF);
+  }
+  bit_string[i] = 0; /* null terminate string */
+  return bit_string;
+}
+
+static inline int
+hex_char_to_nibble(uint8_t c) {
+  switch(c) {
+  case ('0'): return 0x0;
+  case ('1'): return 0x1;
+  case ('2'): return 0x2;
+  case ('3'): return 0x3;
+  case ('4'): return 0x4;
+  case ('5'): return 0x5;
+  case ('6'): return 0x6;
+  case ('7'): return 0x7;
+  case ('8'): return 0x8;
+  case ('9'): return 0x9;
+  case ('a'): return 0xa;
+  case ('A'): return 0xa;
+  case ('b'): return 0xb;
+  case ('B'): return 0xb;
+  case ('c'): return 0xc;
+  case ('C'): return 0xc;
+  case ('d'): return 0xd;
+  case ('D'): return 0xd;
+  case ('e'): return 0xe;
+  case ('E'): return 0xe;
+  case ('f'): return 0xf;
+  case ('F'): return 0xf;
+  default: break;   /* this flags an error */
+  }
+  return -1;
+}
+
+int
+is_hex_string(char *s) {
+  while(*s != 0)
+    if (hex_char_to_nibble(*s++) == -1)
+      return 0;
+  return 1;
+}
+
+/*
+ * hex_string_to_octet_string converts a hexadecimal string
+ * of length 2 * len to a raw octet string of length len
+ */
+
+int
+hex_string_to_octet_string(char *raw, char *hex, int len) {
+  uint8_t x;
+  int tmp;
+  int hex_len;
+
+  hex_len = 0;
+  while (hex_len < len) {
+    tmp = hex_char_to_nibble(hex[0]);
+    if (tmp == -1)
+      return hex_len;
+    x = (tmp << 4);
+    hex_len++;
+    tmp = hex_char_to_nibble(hex[1]);
+    if (tmp == -1)
+      return hex_len;
+    x |= (tmp & 0xff);
+    hex_len++;
+    *raw++ = x;
+    hex += 2;
+  }
+  return hex_len;
+}
+
+char *
+v128_hex_string(v128_t *x) {
+  int i, j;
+
+  for (i=j=0; i < 16; i++) {
+    bit_string[j++]  = nibble_to_hex_char(x->v8[i] >> 4);
+    bit_string[j++]  = nibble_to_hex_char(x->v8[i] & 0xF);
+  }
+  
+  bit_string[j] = 0; /* null terminate string */
+  return bit_string;
+}
+
+char *
+v128_bit_string(v128_t *x) {
+  int j, index;
+  uint32_t mask;
+  
+  for (j=index=0; j < 4; j++) {
+    for (mask=0x80000000; mask > 0; mask >>= 1) {
+      if (x->v32[j] & mask)
+	bit_string[index] = '1';
+      else
+	bit_string[index] = '0';
+      ++index;
+    }
+  }
+  bit_string[128] = 0; /* null terminate string */
+
+  return bit_string;
+}
+
+void
+v128_copy_octet_string(v128_t *x, const uint8_t s[16]) {
+#ifdef ALIGNMENT_32BIT_REQUIRED
+  if ((((uint32_t) &s[0]) & 0x3) != 0)
+#endif
+  {
+	  x->v8[0]  = s[0];
+	  x->v8[1]  = s[1];
+	  x->v8[2]  = s[2];
+	  x->v8[3]  = s[3];
+	  x->v8[4]  = s[4];
+	  x->v8[5]  = s[5];
+	  x->v8[6]  = s[6];
+	  x->v8[7]  = s[7];
+	  x->v8[8]  = s[8];
+	  x->v8[9]  = s[9];
+	  x->v8[10] = s[10];
+	  x->v8[11] = s[11];
+	  x->v8[12] = s[12];
+	  x->v8[13] = s[13];
+	  x->v8[14] = s[14];
+	  x->v8[15] = s[15];
+  }
+#ifdef ALIGNMENT_32BIT_REQUIRED
+  else 
+  {
+	  v128_t *v = (v128_t *) &s[0];
+
+	  v128_copy(x,v);
+  }
+#endif
+}
+
+#ifndef DATATYPES_USE_MACROS /* little functions are not macros */
+
+void
+v128_set_to_zero(v128_t *x) {
+  _v128_set_to_zero(x);
+}
+
+void
+v128_copy(v128_t *x, const v128_t *y) {
+  _v128_copy(x, y);
+}
+
+void
+v128_xor(v128_t *z, v128_t *x, v128_t *y) {
+  _v128_xor(z, x, y);
+} 
+
+void
+v128_and(v128_t *z, v128_t *x, v128_t *y) {
+  _v128_and(z, x, y);
+}
+
+void
+v128_or(v128_t *z, v128_t *x, v128_t *y) {
+  _v128_or(z, x, y);
+}
+
+void
+v128_complement(v128_t *x) {
+  _v128_complement(x);
+}
+
+int
+v128_is_eq(const v128_t *x, const v128_t *y) {
+  return _v128_is_eq(x, y);
+}
+
+int
+v128_xor_eq(v128_t *x, const v128_t *y) {
+  return _v128_xor_eq(x, y);
+}
+
+int
+v128_get_bit(const v128_t *x, int i) {
+  return _v128_get_bit(x, i);
+}
+
+void
+v128_set_bit(v128_t *x, int i) {
+  _v128_set_bit(x, i);
+}     
+
+void
+v128_clear_bit(v128_t *x, int i){
+  _v128_clear_bit(x, i);
+}    
+
+void
+v128_set_bit_to(v128_t *x, int i, int y){
+  _v128_set_bit_to(x, i, y);
+}
+
+
+#endif /* DATATYPES_USE_MACROS */
+
+void
+v128_right_shift(v128_t *x, int index) {
+  const int base_index = index >> 5;
+  const int bit_index = index & 31;
+  int i, from;
+  uint32_t b;
+    
+  if (index > 127) {
+    v128_set_to_zero(x);
+    return;
+  }
+
+  if (bit_index == 0) {
+
+    /* copy each word from left size to right side */
+    x->v32[4-1] = x->v32[4-1-base_index];
+    for (i=4-1; i > base_index; i--) 
+      x->v32[i-1] = x->v32[i-1-base_index];
+
+  } else {
+    
+    /* set each word to the "or" of the two bit-shifted words */
+    for (i = 4; i > base_index; i--) {
+      from = i-1 - base_index;
+      b = x->v32[from] << bit_index;
+      if (from > 0)
+        b |= x->v32[from-1] >> (32-bit_index);
+      x->v32[i-1] = b;
+    }
+    
+  }
+
+  /* now wrap up the final portion */
+  for (i=0; i < base_index; i++) 
+    x->v32[i] = 0;
+  
+}
+
+void
+v128_left_shift(v128_t *x, int index) {
+  int i;
+  const int base_index = index >> 5;
+  const int bit_index = index & 31;
+
+  if (index > 127) {
+    v128_set_to_zero(x);
+    return;
+  } 
+  
+  if (bit_index == 0) {
+    for (i=0; i < 4 - base_index; i++)
+      x->v32[i] = x->v32[i+base_index];
+  } else {
+    for (i=0; i < 4 - base_index - 1; i++)
+      x->v32[i] = (x->v32[i+base_index] >> bit_index) ^
+	(x->v32[i+base_index+1] << (32 - bit_index));
+    x->v32[4 - base_index-1] = x->v32[4-1] >> bit_index;
+  }
+
+  /* now wrap up the final portion */
+  for (i = 4 - base_index; i < 4; i++) 
+    x->v32[i] = 0;
+
+}
+
+
+int
+octet_string_is_eq(uint8_t *a, uint8_t *b, int len) {
+  uint8_t *end = b + len;
+  while (b < end)
+    if (*a++ != *b++)
+      return 1;
+  return 0;
+}
+
+void
+octet_string_set_to_zero(uint8_t *s, int len) {
+  uint8_t *end = s + len;
+
+  do {
+    *s = 0;
+  } while (++s < end);
+  
+}
+
+
+/*
+ *  From RFC 1521: The Base64 Alphabet
+ *
+ *   Value Encoding  Value Encoding  Value Encoding  Value Encoding
+ *        0 A            17 R            34 i            51 z
+ *        1 B            18 S            35 j            52 0
+ *        2 C            19 T            36 k            53 1
+ *        3 D            20 U            37 l            54 2
+ *        4 E            21 V            38 m            55 3
+ *        5 F            22 W            39 n            56 4
+ *        6 G            23 X            40 o            57 5
+ *        7 H            24 Y            41 p            58 6
+ *        8 I            25 Z            42 q            59 7
+ *        9 J            26 a            43 r            60 8
+ *       10 K            27 b            44 s            61 9
+ *       11 L            28 c            45 t            62 +
+ *       12 M            29 d            46 u            63 /
+ *       13 N            30 e            47 v
+ *       14 O            31 f            48 w         (pad) =
+ *       15 P            32 g            49 x
+ *       16 Q            33 h            50 y
+ */
+
+int
+base64_char_to_sextet(uint8_t c) {
+  switch(c) {
+  case 'A':
+    return 0;
+  case 'B':
+    return 1;
+  case 'C':
+    return 2;
+  case 'D':
+    return 3;
+  case 'E':
+    return 4;
+  case 'F':
+    return 5;
+  case 'G':
+    return 6;
+  case 'H':
+    return 7;
+  case 'I':
+    return 8;
+  case 'J':
+    return 9;
+  case 'K':
+    return 10;
+  case 'L':
+    return 11;
+  case 'M':
+    return 12;
+  case 'N':
+    return 13;
+  case 'O':
+    return 14;
+  case 'P':
+    return 15;
+  case 'Q':
+    return 16;
+  case 'R':
+    return 17;
+  case 'S':
+    return 18;
+  case 'T':
+    return 19;
+  case 'U':
+    return 20;
+  case 'V':
+    return 21;
+  case 'W':
+    return 22;
+  case 'X':
+    return 23;
+  case 'Y':
+    return 24;
+  case 'Z':
+    return 25;
+  case 'a':
+    return 26;
+  case 'b':
+    return 27;
+  case 'c':
+    return 28;
+  case 'd':
+    return 29;
+  case 'e':
+    return 30;
+  case 'f':
+    return 31;
+  case 'g':
+    return 32;
+  case 'h':
+    return 33;
+  case 'i':
+    return 34;
+  case 'j':
+    return 35;
+  case 'k':
+    return 36;
+  case 'l':
+    return 37;
+  case 'm':
+    return 38;
+  case 'n':
+    return 39;
+  case 'o':
+    return 40;
+  case 'p':
+    return 41;
+  case 'q':
+    return 42;
+  case 'r':
+    return 43;
+  case 's':
+    return 44;
+  case 't':
+    return 45;
+  case 'u':
+    return 46;
+  case 'v':
+    return 47;
+  case 'w':
+    return 48;
+  case 'x':
+    return 49;
+  case 'y':
+    return 50;
+  case 'z':
+    return 51;
+  case '0':
+    return 52;
+  case '1':
+    return 53;
+  case '2':
+    return 54;
+  case '3':
+    return 55;
+  case '4':
+    return 56;
+  case '5':
+    return 57;
+  case '6':
+    return 58;
+  case '7':
+    return 59;
+  case '8':
+    return 60;
+  case '9':
+    return 61;
+  case '+':
+    return 62;
+  case '/':
+    return 63;
+  case '=':
+    return 64;
+  default:
+    break;
+ }
+ return -1;
+}
+
+/*
+ * base64_string_to_octet_string converts a hexadecimal string
+ * of length 2 * len to a raw octet string of length len
+ */
+
+int
+base64_string_to_octet_string(char *raw, char *base64, int len) {
+  uint8_t x;
+  int tmp;
+  int base64_len;
+
+  base64_len = 0;
+  while (base64_len < len) {
+    tmp = base64_char_to_sextet(base64[0]);
+    if (tmp == -1)
+      return base64_len;
+    x = (tmp << 6);
+    base64_len++;
+    tmp = base64_char_to_sextet(base64[1]);
+    if (tmp == -1)
+      return base64_len;
+    x |= (tmp & 0xffff);
+    base64_len++;
+    *raw++ = x;
+    base64 += 2;
+  }
+  return base64_len;
+}
diff --git a/jni/pjproject-android/.svn/pristine/a7/a7d4d7d267d01430105e9c126fc00344d2edd412.svn-base b/jni/pjproject-android/.svn/pristine/a7/a7d4d7d267d01430105e9c126fc00344d2edd412.svn-base
new file mode 100644
index 0000000..c3c2a9c
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a7d4d7d267d01430105e9c126fc00344d2edd412.svn-base
@@ -0,0 +1,86 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/os.h>
+#include <pj/compat/time.h>
+#include <pj/errno.h>
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
+{
+    struct tm *local_time;
+
+    PJ_CHECK_STACK();
+
+    local_time = localtime((time_t*)&tv->sec);
+
+    pt->year = local_time->tm_year+1900;
+    pt->mon = local_time->tm_mon;
+    pt->day = local_time->tm_mday;
+    pt->hour = local_time->tm_hour;
+    pt->min = local_time->tm_min;
+    pt->sec = local_time->tm_sec;
+    pt->wday = local_time->tm_wday;
+    pt->msec = tv->msec;
+
+    return PJ_SUCCESS;
+}
+
+/**
+ * Encode parsed time to time value.
+ */
+PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv)
+{
+    struct tm local_time;
+
+    local_time.tm_year = pt->year-1900;
+    local_time.tm_mon = pt->mon;
+    local_time.tm_mday = pt->day;
+    local_time.tm_hour = pt->hour;
+    local_time.tm_min = pt->min;
+    local_time.tm_sec = pt->sec;
+    local_time.tm_isdst = 0;
+    
+    tv->sec = mktime(&local_time);
+    tv->msec = pt->msec;
+
+    return PJ_SUCCESS;
+}
+
+/**
+ * Convert local time to GMT.
+ */
+PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv)
+{
+    PJ_UNUSED_ARG(tv);
+    return PJ_EBUG;
+}
+
+/**
+ * Convert GMT to local time.
+ */
+PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv)
+{
+    PJ_UNUSED_ARG(tv);
+    return PJ_EBUG;
+}
+
+
diff --git a/jni/pjproject-android/.svn/pristine/a7/a7f6eeb5b994954afe5c6f207f6cb7af8ed02769.svn-base b/jni/pjproject-android/.svn/pristine/a7/a7f6eeb5b994954afe5c6f207f6cb7af8ed02769.svn-base
new file mode 100644
index 0000000..8312fcf
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a7f6eeb5b994954afe5c6f207f6cb7af8ed02769.svn-base
Binary files differ
diff --git a/jni/pjproject-android/.svn/pristine/a7/a7faff827674616c551a35eb6c1476b4246ffb03.svn-base b/jni/pjproject-android/.svn/pristine/a7/a7faff827674616c551a35eb6c1476b4246ffb03.svn-base
new file mode 100644
index 0000000..4a0b4d7
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/a7/a7faff827674616c551a35eb6c1476b4246ffb03.svn-base
@@ -0,0 +1,735 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include "vidgui.h"
+#include "vidwin.h"
+
+#if defined(PJ_WIN32)
+#   define SDL_MAIN_HANDLED
+#endif
+
+#include <SDL.h>
+#include <assert.h>
+#include <QMessageBox>
+
+#define LOG_FILE		"vidgui.log"
+#define THIS_FILE		"vidgui.cpp"
+
+///////////////////////////////////////////////////////////////////////////
+//
+// SETTINGS
+//
+
+//
+// These configure SIP registration
+//
+#define USE_REGISTRATION	0
+#define SIP_DOMAIN		"pjsip.org"
+#define SIP_USERNAME		"vidgui"
+#define SIP_PASSWORD		"secret"
+#define SIP_PORT		5080
+#define SIP_TCP			1
+
+//
+// NAT helper settings
+//
+#define USE_ICE			1
+#define USE_STUN		0
+#define STUN_SRV		"stun.pjsip.org"
+
+//
+// Devices settings
+//
+#define DEFAULT_CAP_DEV		PJMEDIA_VID_DEFAULT_CAPTURE_DEV
+//#define DEFAULT_CAP_DEV		1
+#define DEFAULT_REND_DEV	PJMEDIA_VID_DEFAULT_RENDER_DEV
+
+
+//
+// End of Settings
+///////////////////////////////////////////////////////////////////////////
+
+
+MainWin *MainWin::theInstance_;
+
+MainWin::MainWin(QWidget *parent)
+: QWidget(parent), accountId_(-1), currentCall_(-1),
+  preview_on(false), video_(NULL), video_prev_(NULL)
+{
+    theInstance_ = this;
+
+    initLayout();
+    emit signalCallReleased();
+}
+
+MainWin::~MainWin()
+{
+    quit();
+    theInstance_ = NULL;
+}
+
+MainWin *MainWin::instance()
+{
+    return theInstance_;
+}
+
+void MainWin::initLayout()
+{
+    //statusBar_ = new QStatusBar(this);
+
+    /* main layout */
+    QHBoxLayout *hbox_main = new QHBoxLayout;
+    //QVBoxLayout *vbox_left = new QVBoxLayout;
+    vbox_left = new QVBoxLayout;
+    QVBoxLayout *vbox_right = new QVBoxLayout;
+    hbox_main->addLayout(vbox_left);
+    hbox_main->addLayout(vbox_right);
+
+    /* Left pane */
+    QHBoxLayout *hbox_url = new QHBoxLayout;
+    hbox_url->addWidget(new QLabel(tr("Url:")));
+    hbox_url->addWidget(url_=new QLineEdit(tr("sip:")), 1);
+    vbox_left->addLayout(hbox_url);
+
+    /* Right pane */
+    vbox_right->addWidget((localUri_ = new QLabel));
+    vbox_right->addWidget((vidEnabled_ = new QCheckBox(tr("Enable &video"))));
+    vbox_right->addWidget((previewButton_=new QPushButton(tr("Start &Preview"))));
+    vbox_right->addWidget((callButton_=new QPushButton(tr("Call"))));
+    vbox_right->addWidget((hangupButton_=new QPushButton(tr("Hangup"))));
+    vbox_right->addWidget((quitButton_=new QPushButton(tr("Quit"))));
+
+#if PJMEDIA_HAS_VIDEO
+    vidEnabled_->setCheckState(Qt::Checked);
+#else
+    vidEnabled_->setCheckState(Qt::Unchecked);
+    vidEnabled_->setEnabled(false);
+#endif
+
+    /* Outest layout */
+    QVBoxLayout *vbox_outest = new QVBoxLayout;
+    vbox_outest->addLayout(hbox_main);
+    vbox_outest->addWidget((statusBar_ = new QLabel));
+
+    setLayout(vbox_outest);
+
+    connect(previewButton_, SIGNAL(clicked()), this, SLOT(preview()));
+    connect(callButton_, SIGNAL(clicked()), this, SLOT(call()));
+    connect(hangupButton_, SIGNAL(clicked()), this, SLOT(hangup()));
+    connect(quitButton_, SIGNAL(clicked()), this, SLOT(quit()));
+    //connect(this, SIGNAL(close()), this, SLOT(quit()));
+    connect(vidEnabled_, SIGNAL(stateChanged(int)), this, SLOT(onVidEnabledChanged(int)));
+
+    // UI updates must be done in the UI thread!
+    connect(this, SIGNAL(signalNewCall(int, bool)),
+	    this, SLOT(onNewCall(int, bool)));
+    connect(this, SIGNAL(signalCallReleased()),
+	    this, SLOT(onCallReleased()));
+    connect(this, SIGNAL(signalInitVideoWindow()),
+	    this, SLOT(initVideoWindow()));
+    connect(this, SIGNAL(signalShowStatus(const QString&)),
+	    this, SLOT(doShowStatus(const QString&)));
+}
+
+void MainWin::quit()
+{
+    delete video_prev_;
+    video_prev_ = NULL;
+    delete video_;
+    video_ = NULL;
+
+    pjsua_destroy();
+    qApp->quit();
+}
+
+void MainWin::showStatus(const char *msg)
+{
+    PJ_LOG(3,(THIS_FILE, "%s", msg));
+
+    QString msg_ = QString::fromUtf8(msg);
+    emit signalShowStatus(msg_);
+}
+
+void MainWin::doShowStatus(const QString& msg)
+{
+    //statusBar_->showMessage(msg);
+    statusBar_->setText(msg);
+}
+
+void MainWin::showError(const char *title, pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+    char errline[120];
+
+    pj_strerror(status, errmsg, sizeof(errmsg));
+    snprintf(errline, sizeof(errline), "%s error: %s", title, errmsg);
+    showStatus(errline);
+}
+
+void MainWin::onVidEnabledChanged(int state)
+{
+    pjsua_call_setting call_setting;
+
+    if (currentCall_ == -1)
+	return;
+
+    pjsua_call_setting_default(&call_setting);
+    call_setting.vid_cnt = (state == Qt::Checked);
+
+    pjsua_call_reinvite2(currentCall_, &call_setting, NULL);
+}
+
+void MainWin::onNewCall(int cid, bool incoming)
+{
+    pjsua_call_info ci;
+
+    pj_assert(currentCall_ == -1);
+    currentCall_ = cid;
+
+    pjsua_call_get_info(cid, &ci);
+    url_->setText(ci.remote_info.ptr);
+    url_->setEnabled(false);
+    hangupButton_->setEnabled(true);
+
+    if (incoming) {
+	callButton_->setText(tr("Answer"));
+	callButton_->setEnabled(true);
+    } else {
+	callButton_->setEnabled(false);
+    }
+
+    //video_->setText(ci.remote_contact.ptr);
+    //video_->setWindowTitle(ci.remote_contact.ptr);
+}
+
+void MainWin::onCallReleased()
+{
+    url_->setEnabled(true);
+    callButton_->setEnabled(true);
+    callButton_->setText(tr("Call"));
+    hangupButton_->setEnabled(false);
+    currentCall_ = -1;
+
+    delete video_;
+    video_ = NULL;
+}
+
+void MainWin::preview()
+{
+    if (preview_on) {
+	delete video_prev_;
+	video_prev_ = NULL;
+
+	pjsua_vid_preview_stop(DEFAULT_CAP_DEV);
+
+	showStatus("Preview stopped");
+	previewButton_->setText(tr("Start &Preview"));
+    } else {
+	pjsua_vid_win_id wid;
+	pjsua_vid_win_info wi;
+	pjsua_vid_preview_param pre_param;
+	pj_status_t status;
+
+	pjsua_vid_preview_param_default(&pre_param);
+	pre_param.rend_id = DEFAULT_REND_DEV;
+	pre_param.show = PJ_FALSE;
+
+	status = pjsua_vid_preview_start(DEFAULT_CAP_DEV, &pre_param);
+	if (status != PJ_SUCCESS) {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    QMessageBox::critical(0, "Error creating preview", errmsg);
+	    return;
+	}
+	wid = pjsua_vid_preview_get_win(DEFAULT_CAP_DEV);
+	pjsua_vid_win_get_info(wid, &wi);
+
+	video_prev_ = new VidWin(&wi.hwnd);
+        video_prev_->putIntoLayout(vbox_left);
+	//Using this will cause SDL window to display blank
+	//screen sometimes, probably because it's using different
+	//X11 Display
+	//status = pjsua_vid_win_set_show(wid, PJ_TRUE);
+	//This is handled by VidWin now
+	//video_prev_->show_sdl();
+	showStatus("Preview started");
+
+	previewButton_->setText(tr("Stop &Preview"));
+    }
+    preview_on = !preview_on;
+}
+
+
+void MainWin::call()
+{
+    if (callButton_->text() == "Answer") {
+	pjsua_call_setting call_setting;
+
+	pj_assert(currentCall_ != -1);
+
+	pjsua_call_setting_default(&call_setting);
+	call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
+
+	pjsua_call_answer2(currentCall_, &call_setting, 200, NULL, NULL);
+	callButton_->setEnabled(false);
+    } else {
+	pj_status_t status;
+	QString dst = url_->text();
+	char uri[256];
+	pjsua_call_setting call_setting;
+
+	pj_ansi_strncpy(uri, dst.toAscii().data(), sizeof(uri));
+	pj_str_t uri2 = pj_str((char*)uri);
+
+	pj_assert(currentCall_ == -1);
+
+	pjsua_call_setting_default(&call_setting);
+	call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
+
+	status = pjsua_call_make_call(accountId_, &uri2, &call_setting,
+				      NULL, NULL, &currentCall_);
+	if (status != PJ_SUCCESS) {
+	    showError("make call", status);
+	    return;
+	}
+    }
+}
+
+void MainWin::hangup()
+{
+    pj_assert(currentCall_ != -1);
+    //pjsua_call_hangup(currentCall_, PJSIP_SC_BUSY_HERE, NULL, NULL);
+    pjsua_call_hangup_all();
+    emit signalCallReleased();
+}
+
+
+void MainWin::initVideoWindow()
+{
+    pjsua_call_info ci;
+    unsigned i;
+
+    if (currentCall_ == -1)
+	return;
+
+    delete video_;
+    video_ = NULL;
+
+    pjsua_call_get_info(currentCall_, &ci);
+    for (i = 0; i < ci.media_cnt; ++i) {
+	if ((ci.media[i].type == PJMEDIA_TYPE_VIDEO) &&
+	    (ci.media[i].dir & PJMEDIA_DIR_DECODING))
+	{
+	    pjsua_vid_win_info wi;
+	    pjsua_vid_win_get_info(ci.media[i].stream.vid.win_in, &wi);
+
+	    video_= new VidWin(&wi.hwnd);
+            video_->putIntoLayout(vbox_left);
+
+	    break;
+	}
+    }
+}
+
+void MainWin::on_reg_state(pjsua_acc_id acc_id)
+{
+    pjsua_acc_info info;
+
+    pjsua_acc_get_info(acc_id, &info);
+
+    char reg_status[80];
+    char status[120];
+
+    if (!info.has_registration) {
+	pj_ansi_snprintf(reg_status, sizeof(reg_status), "%.*s",
+			 (int)info.status_text.slen,
+			 info.status_text.ptr);
+
+    } else {
+	pj_ansi_snprintf(reg_status, sizeof(reg_status),
+			 "%d/%.*s (expires=%d)",
+			 info.status,
+			 (int)info.status_text.slen,
+			 info.status_text.ptr,
+			 info.expires);
+
+    }
+
+    snprintf(status, sizeof(status),
+	     "%.*s: %s\n",
+	     (int)info.acc_uri.slen, info.acc_uri.ptr,
+	     reg_status);
+    showStatus(status);
+}
+
+void MainWin::on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    pjsua_call_info ci;
+
+    PJ_UNUSED_ARG(e);
+
+    pjsua_call_get_info(call_id, &ci);
+
+    if (currentCall_ == -1 && ci.state < PJSIP_INV_STATE_DISCONNECTED &&
+	ci.role == PJSIP_ROLE_UAC)
+    {
+	emit signalNewCall(call_id, false);
+    }
+
+    char status[80];
+    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
+	snprintf(status, sizeof(status), "Call is %s (%s)",
+	         ci.state_text.ptr,
+	         ci.last_status_text.ptr);
+	showStatus(status);
+	emit signalCallReleased();
+    } else {
+	snprintf(status, sizeof(status), "Call is %s", pjsip_inv_state_name(ci.state));
+	showStatus(status);
+    }
+}
+
+void MainWin::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+                               pjsip_rx_data *rdata)
+{
+    PJ_UNUSED_ARG(acc_id);
+    PJ_UNUSED_ARG(rdata);
+
+    if (currentCall_ != -1) {
+	pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
+	return;
+    }
+
+    emit signalNewCall(call_id, true);
+
+    pjsua_call_info ci;
+    char status[80];
+
+    pjsua_call_get_info(call_id, &ci);
+    snprintf(status, sizeof(status), "Incoming call from %.*s",
+             (int)ci.remote_info.slen, ci.remote_info.ptr);
+    showStatus(status);
+}
+
+void MainWin::on_call_media_state(pjsua_call_id call_id)
+{
+    pjsua_call_info ci;
+
+    pjsua_call_get_info(call_id, &ci);
+
+    for (unsigned i=0; i<ci.media_cnt; ++i) {
+	if (ci.media[i].type == PJMEDIA_TYPE_AUDIO) {
+	    switch (ci.media[i].status) {
+	    case PJSUA_CALL_MEDIA_ACTIVE:
+		pjsua_conf_connect(ci.media[i].stream.aud.conf_slot, 0);
+		pjsua_conf_connect(0, ci.media[i].stream.aud.conf_slot);
+		break;
+	    default:
+		break;
+	    }
+	} else if (ci.media[i].type == PJMEDIA_TYPE_VIDEO) {
+	    emit signalInitVideoWindow();
+	}
+    }
+}
+
+//
+// pjsua callbacks
+//
+static void on_reg_state(pjsua_acc_id acc_id)
+{
+    MainWin::instance()->on_reg_state(acc_id);
+}
+
+static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    MainWin::instance()->on_call_state(call_id, e);
+}
+
+static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+                             pjsip_rx_data *rdata)
+{
+    MainWin::instance()->on_incoming_call(acc_id, call_id, rdata);
+}
+
+static void on_call_media_state(pjsua_call_id call_id)
+{
+    MainWin::instance()->on_call_media_state(call_id);
+}
+
+//
+// initStack()
+//
+bool MainWin::initStack()
+{
+    pj_status_t status;
+
+    //showStatus("Creating stack..");
+    status = pjsua_create();
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_create", status);
+	return false;
+    }
+
+    showStatus("Initializing stack..");
+
+    pjsua_config ua_cfg;
+    pjsua_config_default(&ua_cfg);
+    pjsua_callback ua_cb;
+    pj_bzero(&ua_cb, sizeof(ua_cb));
+    ua_cfg.cb.on_reg_state = &::on_reg_state;
+    ua_cfg.cb.on_call_state = &::on_call_state;
+    ua_cfg.cb.on_incoming_call = &::on_incoming_call;
+    ua_cfg.cb.on_call_media_state = &::on_call_media_state;
+#if USE_STUN
+    ua_cfg.stun_srv_cnt = 1;
+    ua_cfg.stun_srv[0] = pj_str((char*)STUN_SRV);
+#endif
+
+    pjsua_logging_config log_cfg;
+    pjsua_logging_config_default(&log_cfg);
+    log_cfg.log_filename = pj_str((char*)LOG_FILE);
+
+    pjsua_media_config med_cfg;
+    pjsua_media_config_default(&med_cfg);
+    med_cfg.enable_ice = USE_ICE;
+
+    status = pjsua_init(&ua_cfg, &log_cfg, &med_cfg);
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_init", status);
+	goto on_error;
+    }
+
+    //
+    // Create UDP and TCP transports
+    //
+    pjsua_transport_config udp_cfg;
+    pjsua_transport_id udp_id;
+    pjsua_transport_config_default(&udp_cfg);
+    udp_cfg.port = SIP_PORT;
+
+    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP,
+                                    &udp_cfg, &udp_id);
+    if (status != PJ_SUCCESS) {
+	showError("UDP transport creation", status);
+	goto on_error;
+    }
+
+    pjsua_transport_info udp_info;
+    status = pjsua_transport_get_info(udp_id, &udp_info);
+    if (status != PJ_SUCCESS) {
+	showError("UDP transport info", status);
+	goto on_error;
+    }
+
+#if SIP_TCP
+    pjsua_transport_config tcp_cfg;
+    pjsua_transport_config_default(&tcp_cfg);
+    tcp_cfg.port = 0;
+
+    status = pjsua_transport_create(PJSIP_TRANSPORT_TCP,
+                                    &tcp_cfg, NULL);
+    if (status != PJ_SUCCESS) {
+	showError("TCP transport creation", status);
+	goto on_error;
+    }
+#endif
+
+    //
+    // Create account
+    //
+    pjsua_acc_config acc_cfg;
+    pjsua_acc_config_default(&acc_cfg);
+#if USE_REGISTRATION
+    acc_cfg.id = pj_str( (char*)"<sip:" SIP_USERNAME "@" SIP_DOMAIN ">");
+    acc_cfg.reg_uri = pj_str((char*) ("sip:" SIP_DOMAIN));
+    acc_cfg.cred_count = 1;
+    acc_cfg.cred_info[0].realm = pj_str((char*)"*");
+    acc_cfg.cred_info[0].scheme = pj_str((char*)"digest");
+    acc_cfg.cred_info[0].username = pj_str((char*)SIP_USERNAME);
+    acc_cfg.cred_info[0].data = pj_str((char*)SIP_PASSWORD);
+
+# if SIP_TCP
+    acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_str((char*) "<sip:" SIP_DOMAIN ";transport=tcp>");
+# endif
+
+#else
+    char sip_id[80];
+    snprintf(sip_id, sizeof(sip_id),
+	     "sip:%s@%.*s:%u", SIP_USERNAME,
+	     (int)udp_info.local_name.host.slen,
+	     udp_info.local_name.host.ptr,
+	     udp_info.local_name.port);
+    acc_cfg.id = pj_str(sip_id);
+#endif
+
+    acc_cfg.vid_cap_dev = DEFAULT_CAP_DEV;
+    acc_cfg.vid_rend_dev = DEFAULT_REND_DEV;
+    acc_cfg.vid_in_auto_show = PJ_TRUE;
+    acc_cfg.vid_out_auto_transmit = PJ_TRUE;
+
+    status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &accountId_);
+    if (status != PJ_SUCCESS) {
+	showError("Account creation", status);
+	goto on_error;
+    }
+
+    localUri_->setText(acc_cfg.id.ptr);
+
+    //
+    // Start pjsua!
+    //
+    showStatus("Starting stack..");
+    status = pjsua_start();
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_start", status);
+	goto on_error;
+    }
+
+    showStatus("Ready");
+
+    return true;
+
+on_error:
+    pjsua_destroy();
+    return false;
+}
+
+/*
+ * A simple registrar, invoked by default_mod_on_rx_request()
+ */
+static void simple_registrar(pjsip_rx_data *rdata)
+{
+    pjsip_tx_data *tdata;
+    const pjsip_expires_hdr *exp;
+    const pjsip_hdr *h;
+    unsigned cnt = 0;
+    pjsip_generic_string_hdr *srv;
+    pj_status_t status;
+
+    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(),
+				 rdata, 200, NULL, &tdata);
+    if (status != PJ_SUCCESS)
+	return;
+
+    exp = (pjsip_expires_hdr*)
+	  pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
+
+    h = rdata->msg_info.msg->hdr.next;
+    while (h != &rdata->msg_info.msg->hdr) {
+	if (h->type == PJSIP_H_CONTACT) {
+	    const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h;
+	    int e = c->expires;
+
+	    if (e < 0) {
+		if (exp)
+		    e = exp->ivalue;
+		else
+		    e = 3600;
+	    }
+
+	    if (e > 0) {
+		pjsip_contact_hdr *nc = (pjsip_contact_hdr*)
+					pjsip_hdr_clone(tdata->pool, h);
+		nc->expires = e;
+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc);
+		++cnt;
+	    }
+	}
+	h = h->next;
+    }
+
+    srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL);
+    srv->name = pj_str((char*)"Server");
+    srv->hvalue = pj_str((char*)"pjsua simple registrar");
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv);
+
+    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(),
+                               rdata, tdata, NULL, NULL);
+}
+
+/* Notification on incoming request */
+static pj_bool_t default_mod_on_rx_request(pjsip_rx_data *rdata)
+{
+    /* Simple registrar */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
+                         &pjsip_register_method) == 0)
+    {
+	simple_registrar(rdata);
+	return PJ_TRUE;
+    }
+
+    return PJ_FALSE;
+}
+
+/* The module instance. */
+static pjsip_module mod_default_handler =
+{
+    NULL, NULL,				/* prev, next.		*/
+    { (char*)"mod-default-handler", 19 },	/* Name.		*/
+    -1,					/* Id			*/
+    PJSIP_MOD_PRIORITY_APPLICATION+99,	/* Priority	        */
+    NULL,				/* load()		*/
+    NULL,				/* start()		*/
+    NULL,				/* stop()		*/
+    NULL,				/* unload()		*/
+    &default_mod_on_rx_request,		/* on_rx_request()	*/
+    NULL,				/* on_rx_response()	*/
+    NULL,				/* on_tx_request.	*/
+    NULL,				/* on_tx_response()	*/
+    NULL,				/* on_tsx_state()	*/
+
+};
+
+int main(int argc, char *argv[])
+{
+    /* At least on Linux, we have to initialize SDL video subsystem prior to
+     * creating/initializing QApplication, otherwise we'll segfault miserably
+     * in SDL_CreateWindow(). Here's a stack trace if you're interested:
+
+	Thread [7] (Suspended: Signal 'SIGSEGV' received. Description: Segmentation fault.)
+	13 XCreateIC()
+	12 SetupWindowData()
+	11 X11_CreateWindow()
+	10 SDL_CreateWindow()
+	..
+     */
+    if ( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) {
+        printf("Unable to init SDL: %s\n", SDL_GetError());
+        return 1;
+    }
+
+    QApplication app(argc, argv);
+
+    MainWin win;
+    win.show();
+
+    if (!win.initStack()) {
+	win.quit();
+	return 1;
+    }
+
+    /* We want to be registrar too! */
+    if (pjsua_get_pjsip_endpt()) {
+	pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
+				    &mod_default_handler);
+    }
+
+    return app.exec();
+}
+