(Major) Task #737 and #738: integration of APS-Direct and Audiodev from aps-direct branch to trunk.

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2506 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/build.symbian/symbian_ua.mmp b/build.symbian/symbian_ua.mmp
index 9521476..a96da6a 100644
--- a/build.symbian/symbian_ua.mmp
+++ b/build.symbian/symbian_ua.mmp
@@ -1,6 +1,6 @@
-#define SND_HAS_APS	1
+#define SND_HAS_APS	0
 #define SND_HAS_VAS	0
-#define SND_HAS_MDA	0
+#define SND_HAS_MDA	1
 
 TARGET 			symbian_ua.exe
 TARGETTYPE 		exe
diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c
index a5a5616..6e01ba6 100644
--- a/pjlib-util/src/pjlib-util/scanner.c
+++ b/pjlib-util/src/pjlib-util/scanner.c
@@ -28,7 +28,7 @@
 #define PJ_SCAN_IS_SPACE(c)		((c)==' ' || (c)=='\t')
 #define PJ_SCAN_IS_NEWLINE(c)		((c)=='\r' || (c)=='\n')
 #define PJ_SCAN_IS_PROBABLY_SPACE(c)	((c) <= 32)
-#define PJ_SCAN_CHECK_EOF(s)		(*s)
+#define PJ_SCAN_CHECK_EOF(s)		(s != scanner->end)
 
 
 #if defined(PJ_SCANNER_USE_BITWISE) && PJ_SCANNER_USE_BITWISE != 0
@@ -375,7 +375,7 @@
      */
     do {
 	/* loop until end_quote is found. */
-	while (*s && *s != '\n' && *s != end_quote[qpair]) {
+	while (PJ_SCAN_CHECK_EOF(s) && *s != '\n' && *s != end_quote[qpair]) {
 	    ++s;
 	}
 
diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h
index 0bd1863..4a5a77f 100644
--- a/pjlib/include/pj/os.h
+++ b/pjlib/include/pj/os.h
@@ -394,6 +394,18 @@
  */
 PJ_DECL(pj_status_t) pj_symbianos_set_params(pj_symbianos_params *prm);
 
+/**
+ *  Notify PJLIB that the access point connection has been down or unusable
+ *  and PJLIB should not try to access the Symbian socket API (especially ones
+ *  that send packets). Sending packet when RConnection is reconnected to 
+ *  different access point may cause the WaitForRequest() for the function to 
+ *  block indefinitely.
+ *  
+ *  @param up		If set to PJ_FALSE it will cause PJLIB to not try
+ *  			to access socket API, and error will be returned
+ *  			immediately instead.
+ */
+PJ_DECL(void) pj_symbianos_set_connection_status(pj_bool_t up);
 
 /**
  * @}
diff --git a/pjlib/src/pj/addr_resolv_symbian.cpp b/pjlib/src/pj/addr_resolv_symbian.cpp
index cfd8aa5..fbca108 100644
--- a/pjlib/src/pj/addr_resolv_symbian.cpp
+++ b/pjlib/src/pj/addr_resolv_symbian.cpp
@@ -71,6 +71,9 @@
     
     PJ_ASSERT_RETURN(name && count && ai, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+	
     // Get resolver for the specified address family
     RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(af);
 
diff --git a/pjlib/src/pj/ioqueue_symbian.cpp b/pjlib/src/pj/ioqueue_symbian.cpp
index ba4092b..ee6d7e0 100644
--- a/pjlib/src/pj/ioqueue_symbian.cpp
+++ b/pjlib/src/pj/ioqueue_symbian.cpp
@@ -635,6 +635,9 @@
     TInetAddr inetAddr;
     TRequestStatus reqStatus;
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+    
     // Convert address
     status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen, 
     				  inetAddr);
@@ -747,6 +750,9 @@
     // Forcing pending operation is not supported.
     PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+
     // Clear flag
     flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
 
@@ -785,6 +791,9 @@
     // Forcing pending operation is not supported.
     PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+
     // Convert address
     status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen, 
     				  inetAddr);
diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp
index 5fbf3d4..983ce88 100644
--- a/pjlib/src/pj/os_core_symbian.cpp
+++ b/pjlib/src/pj/os_core_symbian.cpp
@@ -151,7 +151,8 @@
 //
 
 PjSymbianOS::PjSymbianOS()
-: isSocketServInitialized_(false), isResolverInitialized_(false),
+: isConnectionUp_(false),
+  isSocketServInitialized_(false), isResolverInitialized_(false),
   console_(NULL), selectTimeoutTimer_(NULL),
   appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL),
   appHostResolver6_(NULL)
@@ -229,6 +230,8 @@
 	isResolverInitialized_ = true;
     }
 
+    isConnectionUp_ = true;
+    
     return KErrNone;
 
 on_error:
@@ -239,6 +242,8 @@
 // Shutdown
 void PjSymbianOS::Shutdown()
 {
+    isConnectionUp_ = false;
+    
     if (isResolverInitialized_) {
 		hostResolver_.Close();
 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
@@ -252,15 +257,16 @@
 	isSocketServInitialized_ = false;
     }
 
-    if (console_) {
-	delete console_;
-	console_ = NULL;
-    }
+    delete console_;
+    console_ = NULL;
 
-    if (selectTimeoutTimer_) {
-	delete selectTimeoutTimer_;
-	selectTimeoutTimer_ = NULL;
-    }
+    delete selectTimeoutTimer_;
+    selectTimeoutTimer_ = NULL;
+    
+    appSocketServ_ = NULL;
+    appConnection_ = NULL;
+    appHostResolver_ = NULL;
+    appHostResolver6_ = NULL;
 }
 
 // Convert to Unicode
@@ -306,6 +312,13 @@
 }
 
 
+/* Set connection status */
+PJ_DEF(void) pj_symbianos_set_connection_status(pj_bool_t up)
+{
+    PjSymbianOS::Instance()->SetConnectionStatus(up != 0);
+}
+
+
 /*
  * pj_init(void).
  * Init PJLIB!
diff --git a/pjlib/src/pj/os_symbian.h b/pjlib/src/pj/os_symbian.h
index 74ae7f0..3497e7a 100644
--- a/pjlib/src/pj/os_symbian.h
+++ b/pjlib/src/pj/os_symbian.h
@@ -313,6 +313,21 @@
     	}
     }
 
+    //
+    // Return true if the access point connection is up
+    //
+    bool IsConnectionUp() const
+    {
+	return isConnectionUp_;
+    }
+
+    //
+    // Set access point connection status
+    //
+    void SetConnectionStatus(bool up)
+    {
+	isConnectionUp_ = up;
+    }
 
     //
     // Unicode Converter
@@ -353,6 +368,8 @@
     }
 
 private:
+    bool isConnectionUp_;
+    
     bool isSocketServInitialized_;
     RSocketServ socketServ_;
 
@@ -374,6 +391,17 @@
     PjSymbianOS();
 };
 
+// This macro is used to check the access point connection status and return
+// failure if the AP connection is down or unusable. See the documentation
+// of pj_symbianos_set_connection_status() for more info
+#define PJ_SYMBIAN_CHECK_CONNECTION() \
+    PJ_SYMBIAN_CHECK_CONNECTION2(PJ_ECANCELLED)
+
+#define PJ_SYMBIAN_CHECK_CONNECTION2(retval) \
+    do { \
+	if (!PjSymbianOS::Instance()->IsConnectionUp()) \
+	    return retval; \
+    } while (0);
 
 #endif	/* __OS_SYMBIAN_H__ */
 
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
index a1bd0a3..a0ca80e 100644
--- a/pjlib/src/pj/sock_symbian.cpp
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -463,6 +463,9 @@
 	TRequestStatus reqStatus;
 	THostName tmpName;
 
+	// Return empty hostname if access point is marked as down by app.
+	PJ_SYMBIAN_CHECK_CONNECTION2(&hostname);
+
 	resv.GetHostName(tmpName, reqStatus);
 	User::WaitForRequest(reqStatus);
 
@@ -488,6 +491,9 @@
     /* Sanity checks. */
     PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+    
     /* Set proto if none is specified. */
     if (proto == 0) {
 	if (type == pj_SOCK_STREAM())
@@ -642,6 +648,9 @@
     PJ_CHECK_STACK();
     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+    
     CPjSocket *pjSock = (CPjSocket*)sock;
     RSocket &rSock = pjSock->Socket();
 
@@ -678,6 +687,9 @@
     PJ_CHECK_STACK();
     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+    
     CPjSocket *pjSock = (CPjSocket*)sock;
     RSocket &rSock = pjSock->Socket();
 
@@ -717,6 +729,9 @@
     PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
     PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+
     CPjSocket *pjSock = (CPjSocket*)sock;
     RSocket &rSock = pjSock->Socket();
 
@@ -771,6 +786,9 @@
     PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
     PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+
     CPjSocket *pjSock = (CPjSocket*)sock;
     RSocket &rSock = pjSock->Socket();
 
@@ -868,6 +886,9 @@
     PJ_ASSERT_RETURN(((pj_sockaddr*)addr)->addr.sa_family == PJ_AF_INET, 
 		     PJ_EINVAL);
 
+    // Return failure if access point is marked as down by app.
+    PJ_SYMBIAN_CHECK_CONNECTION();
+    
     CPjSocket *pjSock = (CPjSocket*)sock;
     RSocket &rSock = pjSock->Socket();
 
diff --git a/pjmedia/src/pjmedia-audiodev/wmme_dev.c b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
index aafce59..4c690eb 100644
--- a/pjmedia/src/pjmedia-audiodev/wmme_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
@@ -38,6 +38,14 @@
 #   pragma warning(pop)
 #endif
 
+/* mingw lacks WAVE_FORMAT_ALAW/MULAW */
+#ifndef WAVE_FORMAT_ALAW
+#   define  WAVE_FORMAT_ALAW       0x0006
+#endif
+#ifndef WAVE_FORMAT_MULAW
+#   define  WAVE_FORMAT_MULAW      0x0007
+#endif
+
 #if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
 #   pragma comment(lib, "Coredll.lib")
 #elif defined(_MSC_VER)
diff --git a/pjmedia/src/pjmedia-codec/l16.c b/pjmedia/src/pjmedia-codec/l16.c
index 18baf67..d520d25 100644
--- a/pjmedia/src/pjmedia-codec/l16.c
+++ b/pjmedia/src/pjmedia-codec/l16.c
@@ -98,7 +98,11 @@
     &l16_parse,
     &l16_encode,
     &l16_decode,
+#if !PLC_DISABLED
     &l16_recover
+#else
+    NULL
+#endif
 };
 
 /* Definition for L16 codec factory operations. */
@@ -128,8 +132,8 @@
     unsigned		 frame_size;    /* Frame size, in bytes */
     unsigned		 clock_rate;    /* Clock rate */
 
-    pj_bool_t		 plc_enabled;
 #if !PLC_DISABLED
+    pj_bool_t		 plc_enabled;
     pjmedia_plc		*plc;
 #endif
     pj_bool_t		 vad_enabled;
@@ -526,9 +530,17 @@
 static pj_status_t l16_open(pjmedia_codec *codec, 
 			    pjmedia_codec_param *attr )
 {
-    /* Nothing to do.. */
-    PJ_UNUSED_ARG(codec);
-    PJ_UNUSED_ARG(attr);
+    struct l16_data *data = NULL;
+    
+    PJ_ASSERT_RETURN(codec && codec->codec_data && attr, PJ_EINVAL);
+
+    data = (struct l16_data*) codec->codec_data;
+
+    data->vad_enabled = (attr->setting.vad != 0);
+#if !PLC_DISABLED
+    data->plc_enabled = (attr->setting.plc != 0);
+#endif
+
     return PJ_SUCCESS;
 }
 
@@ -547,7 +559,9 @@
     pj_assert(data != NULL);
 
     data->vad_enabled = (attr->setting.vad != 0);
+#if !PLC_DISABLED
     data->plc_enabled = (attr->setting.plc != 0);
+#endif
 
     return PJ_SUCCESS;
 }
diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c
index c9a47f2..2cbb164 100644
--- a/pjmedia/src/pjmedia/jbuf.c
+++ b/pjmedia/src/pjmedia/jbuf.c
@@ -267,6 +267,13 @@
 				    framelist->flist_max_count;
 	}
     } else {
+	// check if frame is not too late, but watch out for sequence restart.
+	if (index < framelist->flist_origin && 
+	    framelist->flist_origin - index < 0x7FFF) 
+	{
+	    return PJ_FALSE;
+	}
+
 	where = framelist->flist_tail;
 	framelist->flist_origin = index;
 	framelist->flist_tail = (framelist->flist_tail + 1) % 
diff --git a/pjmedia/src/pjmedia/rtcp_xr.c b/pjmedia/src/pjmedia/rtcp_xr.c
index a4cc603..580924e 100644
--- a/pjmedia/src/pjmedia/rtcp_xr.c
+++ b/pjmedia/src/pjmedia/rtcp_xr.c
@@ -27,7 +27,7 @@
 #include <pj/sock.h>
 #include <pj/string.h>
 
-#if 1 //defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
 
 #define THIS_FILE "rtcp_xr.c"
 
@@ -246,7 +246,7 @@
 	pj_uint32_t c31;
 	pj_uint32_t c32;
 	pj_uint32_t c33;
-	pj_uint32_t ctotal, p32, p23, m;
+	pj_uint32_t ctotal, m;
 	unsigned est_extra_delay;
 
 	r = (pjmedia_rtcp_xr_rb_voip_mtc*) &sess->pkt.buf[size];
@@ -257,59 +257,79 @@
 	r->header.specific = 0;
 	r->header.length = pj_htons(8);
 
-	/* Calculate additional transition counts. */
+	/* Use temp vars for easiness. */
 	c11 = sess->voip_mtc_stat.c11;
 	c13 = sess->voip_mtc_stat.c13;
 	c14 = sess->voip_mtc_stat.c14;
 	c22 = sess->voip_mtc_stat.c22;
 	c23 = sess->voip_mtc_stat.c23;
 	c33 = sess->voip_mtc_stat.c33;
+	m = sess->ptime * sess->frames_per_packet;
+
+	/* Calculate additional transition counts. */
 	c31 = c13;
 	c32 = c23;
 	ctotal = c11 + c14 + c13 + c22 + c23 + c31 + c32 + c33;
-	m = sess->ptime * sess->frames_per_packet;
 
-	/* Calculate burst and densities. */
-	if (c11 && (c23 || c33)) {
-	    p32 = c32 / (c31 + c32 + c33);
-	    if((c22 + c23) < 1) {
-		p23 = 1;
+	if (ctotal) {
+	    pj_uint32_t p32, p23;
+
+	    //original version:
+	    //p32 = c32 / (c31 + c32 + c33);
+	    if (c31 + c32 + c33 == 0)
+		p32 = 0;
+	    else
+		p32 = (c32 << 16) / (c31 + c32 + c33);
+
+	    //original version:
+	    //if ((c22 + c23) < 1) {
+	    //    p23 = 1;
+	    //} else {
+	    //    p23 = 1 - c22 / (c22 + c23);
+	    //}
+	    if (c23 == 0) {
+	        p23 = 0;
 	    } else {
-		p23 = 1 - c22/(c22 + c23);
+	        p23 = (c23 << 16) / (c22 + c23);
 	    }
-	    sess->stat.rx.voip_mtc.burst_den = (pj_uint8_t)(256*p23/(p23 + p32));
-	    sess->stat.rx.voip_mtc.gap_den = (pj_uint8_t)(256*c14/(c11 + c14));
 
-	    /* Calculate burst and gap durations in ms */
-	    sess->stat.rx.voip_mtc.gap_dur = (pj_uint16_t)((c11+c14+c13)*m/c13);
-	    sess->stat.rx.voip_mtc.burst_dur = (pj_uint16_t)(ctotal*m/c13 - 
-					       sess->stat.rx.voip_mtc.gap_dur);
+	    /* Calculate loss/discard densities, scaled of 0-256 */
+	    if (c11 == 0)
+		sess->stat.rx.voip_mtc.gap_den = 0;
+	    else
+		sess->stat.rx.voip_mtc.gap_den = (pj_uint8_t)
+						 ((c14 << 8) / (c11 + c14));
+	    if (p23 == 0)
+		sess->stat.rx.voip_mtc.burst_den = 0;
+	    else
+		sess->stat.rx.voip_mtc.burst_den = (pj_uint8_t)
+						   ((p23 << 8) / (p23 + p32));
+
+	    /* Calculate (average) durations, in ms */
+	    if (c13 == 0) {
+		c13 = 1;
+		ctotal += 1;
+	    }
+	    sess->stat.rx.voip_mtc.gap_dur = (pj_uint16_t)
+					    ((c11+c14+c13) * m / c13);
+	    sess->stat.rx.voip_mtc.burst_dur = (pj_uint16_t)
+					    ((ctotal - (c11+c14+c13)) * m / c13);
+
+	    /* Callculate loss/discard rates, scaled 0-256 */
+	    sess->stat.rx.voip_mtc.loss_rate = (pj_uint8_t)
+			((sess->voip_mtc_stat.loss_count << 8) / ctotal);
+	    sess->stat.rx.voip_mtc.discard_rate = (pj_uint8_t)
+			((sess->voip_mtc_stat.discard_count << 8) / ctotal);
 	} else {
-	    /* No burst occurred yet until this time?
-	     * Just report full gap.
-	     */
-	    ctotal = sess->rtcp_session->stat.rx.pkt + 
-		     sess->voip_mtc_stat.loss_count +
-		     sess->voip_mtc_stat.discard_count;
-
+	    /* No lost/discarded packet yet. */
+	    sess->stat.rx.voip_mtc.gap_den = 0;
 	    sess->stat.rx.voip_mtc.burst_den = 0;
-	    sess->stat.rx.voip_mtc.gap_den = (pj_uint8_t)(256 * 
-					(sess->voip_mtc_stat.loss_count + 
-					sess->voip_mtc_stat.discard_count) / 
-					ctotal);
-
-	    /* Calculate burst and gap durations in ms */
-	    sess->stat.rx.voip_mtc.gap_dur = (pj_uint16_t)((m*ctotal) < 0xFFFF?
-					     (m*ctotal) : 0xFFFF);
+	    sess->stat.rx.voip_mtc.gap_dur = 0;
 	    sess->stat.rx.voip_mtc.burst_dur = 0;
+	    sess->stat.rx.voip_mtc.loss_rate = 0;
+	    sess->stat.rx.voip_mtc.discard_rate = 0;
 	}
 
-	/* Calculate loss and discard rates */
-	sess->stat.rx.voip_mtc.loss_rate = (pj_uint8_t)
-			     (256 * sess->voip_mtc_stat.loss_count / ctotal);
-	sess->stat.rx.voip_mtc.discard_rate = (pj_uint8_t)
-			     (256 * sess->voip_mtc_stat.discard_count / ctotal);
-
 	/* Set round trip delay (in ms) to RTT calculated after receiving
 	 * DLRR or DLSR.
 	 */
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index fff8023..1e289e9 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -52,8 +52,6 @@
     pjmedia_dir		    dir;	    /**< Channel direction.	    */
     unsigned		    pt;		    /**< Payload type.		    */
     pj_bool_t		    paused;	    /**< Paused?.		    */
-    unsigned		    in_pkt_size;    /**< Size of input buffer.	    */
-    void		   *in_pkt;	    /**< Input buffer.		    */
     unsigned		    out_pkt_size;   /**< Size of output buffer.	    */
     void		   *out_pkt;	    /**< Output buffer.		    */
     pjmedia_rtp_session	    rtp;	    /**< RTP session.		    */
@@ -1508,12 +1506,6 @@
     channel->paused = 1;
     channel->pt = pt;
 
-    /* Allocate buffer for incoming packet. */
-
-    channel->in_pkt_size = PJMEDIA_MAX_MTU;
-    channel->in_pkt = pj_pool_alloc( pool, channel->in_pkt_size );
-    PJ_ASSERT_RETURN(channel->in_pkt != NULL, PJ_ENOMEM);
-
     
     /* Allocate buffer for outgoing packet. */
 
@@ -1790,25 +1782,26 @@
 #endif
 
     /* Init jitter buffer parameters: */
-    if (info->jb_max > 0)
-	jb_max = info->jb_max;
+    if (info->jb_max >= stream->codec_param.info.frm_ptime)
+	jb_max = (info->jb_max + stream->codec_param.info.frm_ptime - 1) / 
+		 stream->codec_param.info.frm_ptime;
     else
 	jb_max = 500 / stream->codec_param.info.frm_ptime;
 
-    if (info->jb_min_pre > 0)
-	jb_min_pre = info->jb_min_pre;
+    if (info->jb_min_pre >= stream->codec_param.info.frm_ptime)
+	jb_min_pre = info->jb_min_pre / stream->codec_param.info.frm_ptime;
     else
 	//jb_min_pre = 60 / stream->codec_param.info.frm_ptime;
 	jb_min_pre = 1;
 
-    if (info->jb_max_pre > 0)
-	jb_max_pre = info->jb_max_pre;
+    if (info->jb_max_pre >= stream->codec_param.info.frm_ptime)
+	jb_max_pre = info->jb_max_pre / stream->codec_param.info.frm_ptime;
     else
 	//jb_max_pre = 240 / stream->codec_param.info.frm_ptime;
 	jb_max_pre = jb_max * 4 / 5;
 
-    if (info->jb_init > 0)
-	jb_init = info->jb_init;
+    if (info->jb_init >= stream->codec_param.info.frm_ptime)
+	jb_init = info->jb_init / stream->codec_param.info.frm_ptime;
     else
 	//jb_init = (jb_min_pre + jb_max_pre) / 2;
 	jb_init = 0;
diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h
index dae0b30..5dcaad2 100644
--- a/pjnath/include/pjnath/stun_sock.h
+++ b/pjnath/include/pjnath/stun_sock.h
@@ -74,6 +74,12 @@
      */
     PJ_STUN_SOCK_KEEP_ALIVE_OP,
 
+    /**
+     * IP address change notification from the keep-alive operation.
+     */
+    PJ_STUN_SOCK_MAPPED_ADDR_CHANGE
+
+
 } pj_stun_sock_op;
 
 
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index c9ad487..3cb5f4e 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -1265,12 +1265,16 @@
 	}
 	break;
     case PJ_STUN_SOCK_BINDING_OP:
+    case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
 	if (status == PJ_SUCCESS) {
 	    pj_stun_sock_info info;
 
 	    status = pj_stun_sock_get_info(stun_sock, &info);
 	    if (status == PJ_SUCCESS) {
 		char ipaddr[PJ_INET6_ADDRSTRLEN+10];
+		const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
+				    "Binding discovery complete" :
+				    "srflx address changed";
 		pj_bool_t dup = PJ_FALSE;
 
 		/* Eliminate the srflx candidate if the address is
@@ -1308,9 +1312,9 @@
 		}
 
 		PJ_LOG(4,(comp->ice_st->obj_name, 
-			  "Comp %d: Binding discovery complete, "
+			  "Comp %d: %s, "
 			  "srflx address is %s",
-			  comp->comp_id, 
+			  comp->comp_id, op_name, 
 			  pj_sockaddr_print(&info.mapped_addr, ipaddr, 
 					     sizeof(ipaddr), 3)));
 
diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c
index 9bcd7c9..70c257a 100644
--- a/pjnath/src/pjnath/stun_sock.c
+++ b/pjnath/src/pjnath/stun_sock.c
@@ -669,11 +669,13 @@
 
 	pj_sockaddr_cp(&stun_sock->mapped_addr, &mapped_attr->sockaddr);
 
-	resched = (*stun_sock->cb.on_status)(stun_sock, op, PJ_SUCCESS);
-
-	goto on_return;
+	if (op==PJ_STUN_SOCK_KEEP_ALIVE_OP)
+	    op = PJ_STUN_SOCK_MAPPED_ADDR_CHANGE;
     }
 
+    /* Notify user */
+    resched = (*stun_sock->cb.on_status)(stun_sock, op, PJ_SUCCESS);
+
 on_return:
     /* Start/restart keep-alive timer */
     if (resched)
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 0fd1095..5944043 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -1488,6 +1488,14 @@
 
     pj_strcat2(&cfg, "\n#\n# Network settings:\n#\n");
 
+    /* Nameservers */
+    for (i=0; i<config->cfg.nameserver_count; ++i) {
+	pj_ansi_sprintf(line, "--nameserver %.*s\n",
+			      (int)config->cfg.nameserver[i].slen,
+			      config->cfg.nameserver[i].ptr);
+	pj_strcat2(&cfg, line);
+    }
+
     /* Outbound proxy */
     for (i=0; i<config->cfg.outbound_proxy_cnt; ++i) {
 	pj_ansi_sprintf(line, "--outbound %.*s\n",
@@ -4015,6 +4023,97 @@
     ;
 }
 
+/*****************************************************************************
+ * A simple module to handle otherwise unhandled request. We will register
+ * this with the lowest priority.
+ */
+
+/* Notification on incoming request */
+static pj_bool_t default_mod_on_rx_request(pjsip_rx_data *rdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_status_code status_code;
+    pj_status_t status;
+
+    /* Don't respond to ACK! */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, 
+			 &pjsip_ack_method) == 0)
+	return PJ_TRUE;
+
+    /* Create basic response. */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, 
+			 &pjsip_notify_method) == 0)
+    {
+	/* Unsolicited NOTIFY's, send with Bad Request */
+	status_code = PJSIP_SC_BAD_REQUEST;
+    } else {
+	/* Probably unknown method */
+	status_code = PJSIP_SC_METHOD_NOT_ALLOWED;
+    }
+    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(), 
+					 rdata, status_code, 
+					 NULL, &tdata);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create response", status);
+	return PJ_TRUE;
+    }
+
+    /* Add Allow if we're responding with 405 */
+    if (status_code == PJSIP_SC_METHOD_NOT_ALLOWED) {
+	const pjsip_hdr *cap_hdr;
+	cap_hdr = pjsip_endpt_get_capability(pjsua_get_pjsip_endpt(), 
+					     PJSIP_H_ALLOW, NULL);
+	if (cap_hdr) {
+	    pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, 
+							   cap_hdr));
+	}
+    }
+
+    /* Add User-Agent header */
+    {
+	pj_str_t user_agent;
+	char tmp[80];
+	const pj_str_t USER_AGENT = { "User-Agent", 10};
+	pjsip_hdr *h;
+
+	pj_ansi_snprintf(tmp, sizeof(tmp), "PJSUA v%s/%s", 
+			 pj_get_version(), PJ_OS_NAME);
+	pj_strdup2_with_null(tdata->pool, &user_agent, tmp);
+
+	h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
+							 &USER_AGENT,
+							 &user_agent);
+	pjsip_msg_add_hdr(tdata->msg, h);
+    }
+
+    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(), rdata, tdata, 
+			       NULL, NULL);
+
+    return PJ_TRUE;
+}
+
+
+/* The module instance. */
+static pjsip_module mod_default_handler = 
+{
+    NULL, NULL,				/* prev, next.		*/
+    { "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()	*/
+
+};
+
+
+
 
 /*****************************************************************************
  * Public API
@@ -4071,6 +4170,12 @@
     if (status != PJ_SUCCESS)
 	return status;
 
+    /* Initialize our module to handle otherwise unhandled request */
+    status = pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
+					 &mod_default_handler);
+    if (status != PJ_SUCCESS)
+	return status;
+
 #ifdef STEREO_DEMO
     stereo_demo();
 #endif
diff --git a/pjsip-apps/src/symbian_ua/ua.cpp b/pjsip-apps/src/symbian_ua/ua.cpp
index b34e7fa..033a2f2 100644
--- a/pjsip-apps/src/symbian_ua/ua.cpp
+++ b/pjsip-apps/src/symbian_ua/ua.cpp
@@ -440,6 +440,7 @@
 {
 public:
     ConsoleUI(CConsoleBase *con);
+    ~ConsoleUI();
 
     // Run console UI
     void Run();
@@ -465,6 +466,11 @@
     CActiveScheduler::Add(this);
 }
 
+ConsoleUI::~ConsoleUI() 
+{
+    Stop();
+}
+
 // Run console UI
 void ConsoleUI::Run() 
 {
@@ -475,7 +481,7 @@
 // Stop console UI
 void ConsoleUI::Stop() 
 {
-    DoCancel();
+    Cancel();
 }
 
 // Cancel asynchronous read.
@@ -875,6 +881,96 @@
 #endif
 
 
+// Class CConnMon to monitor network connection (RConnection). Whenever
+// the connection is down, it will notify PJLIB and restart PJSUA-LIB.
+class CConnMon : public CActive {
+public:
+    static CConnMon* NewL(RConnection &conn, RSocketServ &sserver) {
+	CConnMon *self = new (ELeave) CConnMon(conn, sserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+    }
+    
+    void Start() {
+	conn_.ProgressNotification(nif_progress_, iStatus);
+	SetActive();
+    }
+    
+    void Stop() {
+	Cancel();
+    }
+    
+    ~CConnMon() { Stop(); }
+    
+private:
+    CConnMon(RConnection &conn, RSocketServ &sserver) : 
+	CActive(EPriorityHigh), 
+	conn_(conn), 
+	sserver_(sserver)
+    {
+	CActiveScheduler::Add(this);
+    }
+    
+    void ConstructL() {}
+
+    void DoCancel() {
+	conn_.CancelProgressNotification();
+    }
+
+    void RunL() {
+	int stage = nif_progress_().iStage;
+	
+	if (stage == KLinkLayerClosed) {
+	    pj_status_t status;
+	    TInt err;
+
+	    // Tell pjlib that connection is down.
+	    pj_symbianos_set_connection_status(PJ_FALSE);
+	    
+	    PJ_LOG(3, (THIS_FILE, "RConnection closed, restarting PJSUA.."));
+	    
+	    // Destroy pjsua
+	    pjsua_destroy();
+	    PJ_LOG(3, (THIS_FILE, "PJSUA destroyed."));
+
+	    // Reopen the connection
+	    err = conn_.Open(sserver_);
+	    if (err == KErrNone)
+		err = conn_.Start();
+	    if (err != KErrNone) {
+		CActiveScheduler::Stop();
+		return;
+	    }
+
+	    // Reinit Symbian OS param before pj_init()
+	    pj_symbianos_params sym_params;
+	    pj_bzero(&sym_params, sizeof(sym_params));
+	    sym_params.rsocketserv = &sserver_;
+	    sym_params.rconnection = &conn_;
+	    pj_symbianos_set_params(&sym_params);
+
+	    // Reinit pjsua
+	    status = app_startup();
+	    if (status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, "app_startup() error", status);
+		CActiveScheduler::Stop();
+		return;
+	    }
+	    
+	    PJ_LOG(3, (THIS_FILE, "PJSUA restarted."));
+	    PrintMainMenu();
+	}
+	
+	Start();
+    }
+    
+    RConnection& conn_;
+    RSocketServ& sserver_;
+    TNifProgressBuf nif_progress_;
+};
+
 ////////////////////////////////////////////////////////////////////////////
 int ua_main() 
 {
@@ -917,14 +1013,20 @@
 	return status;
     }
 
+    
     // Run the UI
     ConsoleUI *con = new ConsoleUI(console);
     
     con->Run();
     PrintMainMenu();
 
+    // Init & start connection monitor
+    CConnMon *connmon = CConnMon::NewL(aConn, aSocketServer);
+    connmon->Start();
+
     CActiveScheduler::Start();
     
+    delete connmon;
     delete con;
 
     // Dump memory statistics
diff --git a/pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp b/pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp
index 0a09fcb..5128ca6 100644
--- a/pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp
+++ b/pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp
@@ -39,6 +39,7 @@
 

 STATICLIBRARY	pjsua_lib.lib pjsip_ua.lib

 STATICLIBRARY	pjsip_simple.lib pjsip.lib pjsdp.lib pjmedia.lib

+STATICLIBRARY	pjmedia_audiodev.lib

 STATICLIBRARY	pjnath.lib pjlib_util.lib pjlib.lib

 STATICLIBRARY	libsrtp.lib

 STATICLIBRARY	libgsmcodec.lib

@@ -49,12 +50,10 @@
     STATICLIBRARY	null_audio.lib

     CAPABILITY		NetworkServices LocalServices ReadUserData WriteUserData UserEnvironment 

 #elif SND_USE_APS

-    STATICLIBRARY	symbian_audio_aps.lib

-    LIBRARY		APSSession2.lib

+    LIBRARY			APSSession2.lib

     CAPABILITY		NetworkServices LocalServices ReadUserData WriteUserData UserEnvironment MultimediaDD

-    MACRO		PJMEDIA_SYM_SND_USE_APS=1

+    MACRO			PJMEDIA_SYM_SND_USE_APS=1

 #else

-    STATICLIBRARY	symbian_audio.lib

     LIBRARY 		mediaclientaudiostream.lib

     LIBRARY 		mediaclientaudioinputstream.lib

     CAPABILITY		NetworkServices LocalServices ReadUserData WriteUserData UserEnvironment 

diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index 5a45817..bb470c7 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -54,8 +54,6 @@
  */
 #define GENERIC_URI_CHARS   "#?;:@&=+-_.!~*'()%$,/" "%"
 
-#define PJSIP_VERSION		"SIP/2.0"
-
 #define UNREACHED(expr)
 
 #define IS_NEWLINE(c)	((c)=='\r' || (c)=='\n')
@@ -893,6 +891,36 @@
     return NULL;
 }
 
+/* SIP version */
+static void parse_sip_version(pj_scanner *scanner)
+{
+    pj_str_t SIP = { "SIP", 3 };
+    pj_str_t V2 = { "2.0", 3 };
+    pj_str_t sip, version;
+
+    pj_scan_get( scanner, &pconst.pjsip_ALPHA_SPEC, &sip);
+    if (pj_scan_get_char(scanner) != '/')
+	on_syntax_error(scanner);
+    pj_scan_get_n( scanner, 3, &version);
+    if (pj_stricmp(&sip, &SIP) || pj_stricmp(&version, &V2))
+	on_syntax_error(scanner);
+}
+
+static pj_bool_t is_next_sip_version(pj_scanner *scanner)
+{
+    pj_str_t SIP = { "SIP", 3 };
+    pj_str_t sip;
+    int c;
+
+    c = pj_scan_peek(scanner, &pconst.pjsip_ALPHA_SPEC, &sip);
+    /* return TRUE if it is "SIP" followed by "/" or space.
+     * we include space since the "/" may be separated by space,
+     * although this would mean it would return TRUE if it is a
+     * request and the method is "SIP"!
+     */
+    return c && (c=='/' || c==' ' || c=='\t') && pj_stricmp(&sip, &SIP)==0;
+}
+
 /* Internal function to parse SIP message */
 static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,
 				 pjsip_parser_err_report *err_list)
@@ -926,7 +954,7 @@
 	    return NULL;
 
 	/* Parse request or status line */
-	if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) == 0) {
+	if (is_next_sip_version(scanner)) {
 	    msg = pjsip_msg_create(pool, PJSIP_RESPONSE_MSG);
 	    int_parse_status_line( scanner, &msg->line.status );
 	} else {
@@ -1125,7 +1153,7 @@
 }
 
 
-/* Parse parameter (";" pname ["=" pvalue]) in header. */
+/* Parse parameter (";" pname ["=" pvalue]) in SIP header. */
 static void int_parse_param( pj_scanner *scanner, pj_pool_t *pool,
 			     pj_str_t *pname, pj_str_t *pvalue,
 			     unsigned option)
@@ -1513,9 +1541,7 @@
     pjsip_method_init_np( &req_line->method, &token);
 
     req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE);
-    if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) != 0)
-	PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
-    pj_scan_advance_n (scanner, 7, 1);
+    parse_sip_version(scanner);
     pj_scan_get_newline( scanner );
 }
 
@@ -1525,10 +1551,7 @@
 {
     pj_str_t token;
 
-    if (pj_scan_stricmp_alnum(scanner, PJSIP_VERSION, 7) != 0)
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-    pj_scan_advance_n( scanner, 7, 1);
-
+    parse_sip_version(scanner);
     pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token);
     status_line->code = pj_strtoul(&token);
     if (*scanner->curptr != '\r' && *scanner->curptr != '\n')
@@ -1618,12 +1641,32 @@
 
 /* Parse generic string header. */
 static void parse_generic_string_hdr( pjsip_generic_string_hdr *hdr,
-				      pj_scanner *scanner )
+				      pjsip_parse_ctx *ctx)
 {
-    if (pj_cis_match(&pconst.pjsip_NOT_NEWLINE, *scanner->curptr))
+    pj_scanner *scanner = ctx->scanner;
+
+    hdr->hvalue.slen = 0;
+
+    /* header may be mangled hence the loop */
+    while (pj_cis_match(&pconst.pjsip_NOT_NEWLINE, *scanner->curptr)) {
+	pj_str_t next, tmp;
+
 	pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &hdr->hvalue);
-    else
-	hdr->hvalue.slen = 0;
+	if (IS_NEWLINE(*scanner->curptr))
+	    break;
+	/* mangled, get next fraction */
+	pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &next);
+	/* concatenate */
+	tmp.ptr = (char*)pj_pool_alloc(ctx->pool, 
+				       hdr->hvalue.slen + next.slen + 2);
+	tmp.slen = 0;
+	pj_strcpy(&tmp, &hdr->hvalue);
+	pj_strcat2(&tmp, " ");
+	pj_strcat(&tmp, &next);
+	tmp.ptr[tmp.slen] = '\0';
+
+	hdr->hvalue = tmp;
+    }
 
     parse_hdr_end(scanner);
 }
@@ -1934,13 +1977,12 @@
 	pj_str_t pname, pvalue;
 
 	//Parse with PARAM_CHAR instead, to allow IPv6
+	//No, back to using int_parse_param() for the "`" character!
 	//int_parse_param( scanner, pool, &pname, &pvalue, 0);
-	/* Get ';' character */
-	pj_scan_get_char(scanner);
-
-	parse_param_imp(scanner, pool, &pname, &pvalue, 
-			&pconst.pjsip_PARAM_CHAR_SPEC,
-			&pconst.pjsip_PARAM_CHAR_SPEC_ESC, 0);
+	//parse_param_imp(scanner, pool, &pname, &pvalue, 
+	//		&pconst.pjsip_TOKEN_SPEC,
+	//		&pconst.pjsip_TOKEN_SPEC_ESC, 0);
+	int_parse_param(scanner, pool, &pname, &pvalue, 0);
 
 	if (!parser_stricmp(pname, pconst.pjsip_BRANCH_STR) && pvalue.slen) {
 	    hdr->branch_param = pvalue;
@@ -2075,10 +2117,9 @@
 	else
 	    pj_list_insert_before(first, hdr);
 
-	if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION "/", 8) != 0)
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-
-	pj_scan_advance_n( scanner, 8, 1);
+	parse_sip_version(scanner);
+	if (pj_scan_get_char(scanner) != '/')
+	    on_syntax_error(scanner);
 
 	pj_scan_get( scanner, &pconst.pjsip_TOKEN_SPEC, &hdr->transport);
 	int_parse_host(scanner, &hdr->sent_by.host);
@@ -2119,7 +2160,7 @@
     pjsip_generic_string_hdr *hdr;
 
     hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL, NULL);
-    parse_generic_string_hdr(hdr, ctx->scanner);
+    parse_generic_string_hdr(hdr, ctx);
     return (pjsip_hdr*)hdr;
 
 }
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
index 42f8093..24525c8 100644
--- a/pjsip/src/pjsip/sip_tel_uri.c
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -442,6 +442,7 @@
     }
 
     scanner->skip_ws = skip_ws;
+    pj_scan_skip_whitespace(scanner);
     return uri;
 }
 
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index f99a1a4..5a6f7dc 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -1376,6 +1376,9 @@
 	pj_memcpy(&tsx->addr, &tsx->res_addr.addr, tsx->res_addr.addr_len);
 	tsx->addr_len = tsx->res_addr.addr_len;
 	tsx->is_reliable = PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport);
+    } else {
+	tsx->is_reliable = 
+	    (tsx->res_addr.dst_host.flag & PJSIP_TRANSPORT_RELIABLE);
     }
 
 
@@ -2315,7 +2318,7 @@
 		     */
 		    timeout = timeout_timer_val;
 		    
-		} else if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
+		} else if (!tsx->is_reliable) {
 		    
 		    /* For non-INVITE, start timer J at 64*T1 for unreliable
 		     * transport.
@@ -2655,9 +2658,7 @@
 
 	/* Start Timer D with TD/T4 timer if unreliable transport is used. */
 	/* Note: tsx->transport may be NULL! */
-	if ((tsx->transport && PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0)
-	    || ((tsx->transport_flag & PJSIP_TRANSPORT_RELIABLE) == 0)) 
-	{
+	if (!tsx->is_reliable) {
 	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
 		timeout = td_timer_val;
 	    } else {
@@ -2722,7 +2723,7 @@
 	    /* Timer I is T4 timer for unreliable transports, and
 	     * zero seconds for reliable transports.
 	     */
-	    if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
+	    if (!tsx->is_reliable) {
 		timeout.sec = 0; 
 		timeout.msec = 0;
 	    } else {
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 18116c0..381ccad 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -859,12 +859,17 @@
 		     PJSIP_ENOTREQUESTMSG);
     PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL);
 
-    /* Assert if the request contains strict route and strict
-     * route processing has been applied before. We need to
-     * restore the strict route with pjsip_restore_strict_route_set()
-     * before we can call this function again, otherwise strict
-     * route will be swapped twice!
+    /* If the request contains strict route, check that the strict route
+     * has been restored to its original values before processing the
+     * route set. The strict route is restored to the original values
+     * with pjsip_restore_strict_route_set(). If caller did not restore
+     * the strict route before calling this function, we need to call it
+     * here, or otherwise the strict-route and Request-URI will be swapped
+     * twice!
      */
+    if (tdata->saved_strict_route != NULL) {
+	pjsip_restore_strict_route_set(tdata);
+    }
     PJ_ASSERT_RETURN(tdata->saved_strict_route==NULL, PJ_EBUG);
 
     /* Find the first and last "Route" headers from the message. */
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 84bfe20..7430fc1 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -89,7 +89,7 @@
 {
     pj_bzero(cfg, sizeof(*cfg));
 
-    cfg->max_calls = 4;
+    cfg->max_calls = ((PJSUA_MAX_CALLS) < 4) ? (PJSUA_MAX_CALLS) : 4;
     cfg->thread_cnt = 1;
     cfg->nat_type_in_sdp = 1;
     cfg->force_lr = PJ_TRUE;
@@ -838,8 +838,10 @@
     pj_time_val_normalize(&timeout);
 
     do {
-	while (pjsua_handle_events(10) > 0)
-	    ;
+	int i;
+	i = msec / 10;
+	while (pjsua_handle_events(10) > 0 && i > 0)
+	    --i;
 	pj_gettimeofday(&now);
     } while (PJ_TIME_VAL_LT(now, timeout));
 }
diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c
index ad19b41..f825a98 100644
--- a/pjsip/src/test-pjsip/msg_test.c
+++ b/pjsip/src/test-pjsip/msg_test.c
@@ -824,7 +824,7 @@
 {
     char *hname;
     char *hshort_name;
-    char hcontent[1024];
+    char *hcontent;
     int  (*test)(pjsip_hdr*);
     unsigned flags;
 } hdr_test_data[] =
@@ -1734,6 +1734,11 @@
 	pj_pool_t *pool;
 	pjsip_hdr *parsed_hdr1=NULL, *parsed_hdr2=NULL;
 	char *input, *output;
+#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
+	static char hcontent[1024];
+#else
+	char *hcontent;
+#endif
 	int rc;
 
 	pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE);
@@ -1741,8 +1746,15 @@
 	/* Parse the header */
 	hname = pj_str(test->hname);
 	len = strlen(test->hcontent);
+#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
+	PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG);
+	strcpy(hcontent, test->hcontent);
+#else
+	hcontent = test->hcontent;
+#endif
+	
 	parsed_hdr1 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, 
-						   test->hcontent, len, 
+						   hcontent, len, 
 						   &parsed_len);
 	if (parsed_hdr1 == NULL) {
 	    if (test->flags & HDR_FLAG_PARSE_FAIL) {
@@ -1765,7 +1777,14 @@
 	if (test->hshort_name) {
 	    hname = pj_str(test->hshort_name);
 	    len = strlen(test->hcontent);
-	    parsed_hdr2 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, test->hcontent, len, &parsed_len);
+#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
+	    PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG);
+	    strcpy(hcontent, test->hcontent);
+#else
+	    hcontent = test->hcontent;
+#endif
+
+	    parsed_hdr2 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, hcontent, len, &parsed_len);
 	    if (parsed_hdr2 == NULL) {
 		PJ_LOG(3,(THIS_FILE, "    error parsing header %s: %s", test->hshort_name, test->hcontent));
 		return -510;
diff --git a/tests/pjsua/inc_sip.py b/tests/pjsua/inc_sip.py
index 6d5ef05..0c05756 100644
--- a/tests/pjsua/inc_sip.py
+++ b/tests/pjsua/inc_sip.py
@@ -91,11 +91,7 @@
 		if self.trace_enabled:
 			print str(time.strftime("%H:%M:%S ")) + txt
 
-	def create_req(self, method, sdp, branch="", extra_headers=""):
-		if branch=="":
-			self.cseq = self.cseq + 1
-		msg = req_templ
-		msg = msg.replace("$METHOD", method)
+	def update_fields(self, msg):
 		if self.tcp:
 			transport_param = ";transport=tcp"
 		else:
@@ -103,14 +99,23 @@
 		msg = msg.replace("$TARGET_URI", "sip:"+self.dst_addr+":"+str(self.dst_port) + transport_param)
 		msg = msg.replace("$LOCAL_IP", self.local_ip)
 		msg = msg.replace("$LOCAL_PORT", str(self.local_port))
-		if branch=="":
-			branch=str(random.random())
-		msg = msg.replace("$BRANCH", branch)
 		msg = msg.replace("$FROM_TAG", self.local_tag)
 		msg = msg.replace("$TO_TAG", self.rem_tag)
 		msg = msg.replace("$CALL_ID", self.call_id)
 		msg = msg.replace("$CSEQ", str(self.cseq))
+		branch=str(random.random())
+		msg = msg.replace("$BRANCH", branch)
+		return msg
+
+	def create_req(self, method, sdp, branch="", extra_headers=""):
+		if branch=="":
+			self.cseq = self.cseq + 1
+		msg = req_templ
+		msg = msg.replace("$METHOD", method)
 		msg = msg.replace("$SIP_HEADERS", extra_headers)
+		if branch=="":
+			branch=str(random.random())
+		msg = msg.replace("$BRANCH", branch)
 		if sdp!="":
 			msg = msg.replace("$CONTENT_LENGTH", str(len(sdp)))
 			msg = msg + "Content-Type: application/sdp\r\n"
@@ -118,7 +123,7 @@
 			msg = msg.replace("$CONTENT_LENGTH", "0")
 		msg = msg + "\r\n"
 		msg = msg + sdp
-		return msg
+		return self.update_fields(msg)
 
 	def create_response(self, request, code, reason, to_tag=""):
 		response = "SIP/2.0 " + str(code) + " " + reason + "\r\n"
diff --git a/tests/pjsua/mod_sendto.py b/tests/pjsua/mod_sendto.py
index 4cc12a4..a2f4521 100644
--- a/tests/pjsua/mod_sendto.py
+++ b/tests/pjsua/mod_sendto.py
@@ -19,7 +19,7 @@
 	cfg = cfg_file.sendto_cfg
 	
 	if len(cfg.complete_msg) != 0:
-		req = cfg.complete_msg
+		req = dlg.update_fields(cfg.complete_msg)
 	else:
 		req = dlg.create_invite(cfg.sdp, cfg.extra_headers)
 	resp = dlg.send_request_wait(req, 10)
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py
new file mode 100644
index 0000000..35f803c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py
@@ -0,0 +1,52 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1.  Valid Messages
+# 3.1.1.1.  A Short Tortuous INVITE
+complete_msg = \
+"""INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0
+TO :
+ sip:vivekg@chair-dnrc.example.com ;   tag    = 1918181833n
+from   : "J Rosenberg \\\\\\""       <sip:jdrosen@example.com>
+  ;
+  tag = 98asjd8
+MaX-fOrWaRdS: 0068
+Call-ID: wsinv.ndaksdj@192.0.2.1
+Content-Length   : 150
+cseq: 0009
+  INVITE
+Via  : SIP  /   2.0
+ /UDP
+    192.0.2.2;rport;branch=390skdjuw
+s :
+NewFangledHeader:   newfangled value
+ continued newfangled value
+UnknownHeaderWithUnusualValue: ;;,,;;,;
+Content-Type: application/sdp
+Route:
+ <sip:services.example.com;lr;unknownwith=value;unknown-no-value>
+v:  SIP  / 2.0  / TCP     spindle.example.com   ;
+  branch  =   z9hG4bK9ikj8  ,
+ SIP  /    2.0   / UDP  192.168.255.111   ; branch=
+ z9hG4bK30239
+m:"Quoted string \\"\\"" <sip:jdrosen@example.com> ; newparam =
+      newvalue ;
+  secondparam ; q = 0.33
+
+v=0
+o=mhandley 29739 7272939 IN IP4 192.0.2.3
+s=-
+c=IN IP4 192.0.2.4
+t=0 0
+m=audio 49217 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.1", 
+			    "--null-audio --auto-answer 200", 
+			    "", 481, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py
new file mode 100644
index 0000000..88fd249
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py
@@ -0,0 +1,25 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1.  Valid Messages
+# 3.1.1.2.  Wide Range of Valid Characters
+complete_msg = \
+"""!interesting-Method0123456789_*+`.%indeed'~ sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*:&it+has=1,weird!*pas$wo~d_too.(doesn't-it)@example.com SIP/2.0
+Via: SIP/2.0/UDP host1.example.com;rport;branch=z9hG4bK-.!%66*_+`'~
+To: "BEL:\\\x07 NUL:\\\x00 DEL:\\\x7F" <sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*@example.com>
+From: token1~` token2'+_ token3*%!.- <sip:mundane@example.com> ;fromParam''~+*_!.-%="\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9";tag=_token~1'+`*%!-.
+Call-ID: intmeth.word%ZK-!.*_+'@word`~)(><:\\/"][?}{
+CSeq: 139122385 !interesting-Method0123456789_*+`.%indeed'~
+Max-Forwards: 255
+extensionHeader-!.%*+_`'~: \xEF\xBB\xBF\xE5\xA4\xA7\xE5\x81\x9C\xE9\x9B\xBB
+Content-Length: 0
+
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.2", 
+			    "--null-audio --auto-answer 200", 
+			    "", 405, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py
new file mode 100644
index 0000000..4f32e97
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py
@@ -0,0 +1,35 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1.  Valid Messages
+# 3.1.1.3. Valid Use of the % Escaping Mechanism
+complete_msg = \
+"""INVITE sip:sips%3Auser%40example.com@example.net SIP/2.0
+To: sip:%75se%72@example.com
+From: <sip:I%20have%20spaces@example.net>;tag=$FROM_TAG
+Max-Forwards: 87
+i: esc01.239409asdfakjkn23onasd0-3234
+CSeq: 234234 INVITE
+Via: SIP/2.0/UDP host5.example.net;rport;branch=z9hG4bKkdjuw
+C: application/sdp
+Contact:
+  <sip:cal%6Cer@$LOCAL_IP:$LOCAL_PORT;%6C%72;n%61me=v%61lue%25%34%31>
+Content-Length: 150
+
+v=0
+o=mhandley 29739 7272939 IN IP4 192.0.2.1
+s=-
+c=IN IP4 192.0.2.1
+t=0 0
+m=audio 49217 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.3", 
+			    "--null-audio --auto-answer 200", 
+			    "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py
new file mode 100644
index 0000000..7a05c14
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py
@@ -0,0 +1,25 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1.  Valid Messages
+# 3.1.1.4. Escaped Nulls in URIs
+complete_msg = \
+"""REGISTER sip:example.com SIP/2.0
+To: sip:null-%00-null@example.com
+From: sip:null-%00-null@example.com;tag=839923423
+Max-Forwards: 70
+Call-ID: escnull.39203ndfvkjdasfkq3w4otrq0adsfdfnavd
+CSeq: 14398234 REGISTER
+Via: SIP/2.0/UDP host5.example.com;rport;branch=z9hG4bKkdjuw
+Contact: <sip:%00@host5.example.com>
+Contact: <sip:%00%00@host5.example.com>
+L:0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.4", 
+			    "--null-audio --auto-answer 200", 
+			    "", 405, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py
new file mode 100644
index 0000000..2b449d1
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py
@@ -0,0 +1,25 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1.  Valid Messages
+# 3.1.1.5. Use of % When It Is Not an Escape 
+complete_msg = \
+"""RE%47IST%45R sip:registrar.example.com SIP/2.0
+To: "%Z%45" <sip:resource@example.com>
+From: "%Z%45" <sip:resource@example.com>;tag=f232jadfj23
+Call-ID: esc02.asdfnqwo34rq23i34jrjasdcnl23nrlknsdf
+Via: SIP/2.0/TCP host.example.com;rport;branch=z9hG4bK209%fzsnel234
+CSeq: 29344 RE%47IST%45R
+Max-Forwards: 70
+Contact: <sip:alias1@host1.example.com>
+C%6Fntact: <sip:alias2@host2.example.com>
+Contact: <sip:alias3@host3.example.com>
+l: 0
+"""
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.5", 
+			    "--null-audio --auto-answer 200", 
+			    "", 405, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/110_tel_uri.py b/tests/pjsua/scripts-sendto/110_tel_uri.py
new file mode 100644
index 0000000..1d5e645
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/110_tel_uri.py
@@ -0,0 +1,46 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Handling of incoming tel: URI.
+complete_msg = \
+"""INVITE tel:+2065551212 SIP/2.0
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;x-route-tag="tgrp:cococisco1";branch=z9hG4bK61E05
+From: <tel:12345>$FROM_TAG
+To: <tel:+2065551212>
+Date: Thu, 12 Feb 2009 18:32:33 GMT
+Call-ID: 58F8F7D6-F86A11DD-8013D591-5694EF79
+Supported: 100rel,timer,resource-priority
+Min-SE:  86400
+Cisco-Guid: 1492551325-4167700957-2148586897-1452601209
+User-Agent: Cisco-SIPGateway/IOS-12.x
+Allow: INVITE, OPTIONS, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY, INFO, REGISTER
+CSeq: 101 INVITE
+Max-Forwards: 70
+Timestamp: 1234463553
+Contact: <tel:+1234;ext=1>
+Contact: <sip:tester@$LOCAL_IP:$LOCAL_PORT>
+Record-Route: <sip:tester@$LOCAL_IP:$LOCAL_PORT;lr>
+Expires: 180
+Allow-Events: telephone-event
+Content-Type: application/sdp
+Content-Disposition: session;handling=required
+Content-Length: 265
+
+v=0
+o=CiscoSystemsSIP-GW-UserAgent 1296 9529 IN IP4 X.X.X.X
+s=SIP Call
+c=IN IP4 $LOCAL_IP
+t=0 0
+m=audio 18676 RTP/AVP 0 101 19
+c=IN IP4 $LOCAL_IP
+a=rtpmap:0 PCMU/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=rtpmap:19 CN/8000
+a=ptime:20
+"""
+
+sendto_cfg = sip.SendtoCfg( "tel: URI", "--null-audio --auto-answer 200", 
+			    "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/159_no_rport.py b/tests/pjsua/scripts-sendto/159_no_rport.py
new file mode 100644
index 0000000..d34e4a9
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/159_no_rport.py
@@ -0,0 +1,38 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Ticket http://trac.pjsip.org/repos/ticket/718
+# RTC doesn't put rport in Via, and it is report to have caused segfault.
+complete_msg = \
+"""INVITE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;branch=z9hG4bK74a60ee5
+From: <sip:tester@localhost>;tag=as2858a32c
+To: <sip:pjsua@localhost>
+Contact: <sip:tester@$LOCAL_IP:$LOCAL_PORT>
+Call-ID: 123@localhost
+CSeq: 1 INVITE
+Max-Forwards: 70
+Content-Type: application/sdp
+Content-Length: 285
+
+v=0
+o=root 4236 4236 IN IP4 192.168.1.11
+s=session
+c=IN IP4 192.168.1.11
+t=0 0
+m=audio 14390 RTP/AVP 0 3 8 101
+a=rtpmap:0 PCMU/8000
+a=rtpmap:3 GSM/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=silenceSupp:off - - - -
+a=ptime:20
+a=sendrecv
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RTC no rport", "--null-audio --auto-answer 200", 
+			    "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/159_no_rport_nit.py b/tests/pjsua/scripts-sendto/159_no_rport_nit.py
new file mode 100644
index 0000000..2af9ab1
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/159_no_rport_nit.py
@@ -0,0 +1,25 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Ticket http://trac.pjsip.org/repos/ticket/718
+# RTC doesn't put rport in Via, and it is reported to have caused segfault.
+#
+complete_msg = \
+"""MESSAGE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP localhost:$LOCAL_PORT;branch=z9hG4bK$BRANCH
+From: <sip:tester@localhost>;tag=as2858a32c
+To: <sip:pjsua@localhost>
+Call-ID: 123@localhost
+CSeq: 1 MESSAGE
+Max-Forwards: 70
+Content-Length: 11
+Content-Type: text/plain
+
+Hello world
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RTC no rport", "--null-audio --auto-answer 200", 
+			    "", 200, complete_msg=complete_msg)
+