Index: /pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 5751)
+++ /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 5752)
@@ -1108,4 +1108,14 @@
 
 
+/* Setting to determine if media transport should switch RTP and RTCP
+ * remote address to the source address of the packets it receives.
+ *
+ * By default it is enabled.
+ */
+#ifndef PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR
+#   define PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR	    1
+#endif
+
+
 /**
  * Transport info (pjmedia_transport_info) contains a socket info and list
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 5751)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 5752)
@@ -564,4 +564,37 @@
 };
 
+/**
+ * This structure describes the data passed when calling #rtp_cb2().
+ */
+typedef struct pjmedia_tp_cb_param
+{
+    /**
+     * User data.
+     */
+    void 	       *user_data;
+
+    /**
+     * Packet buffer.
+     */
+    void 	       *pkt;
+
+    /**
+     * Packet size.
+     */
+    pj_ssize_t 		size;
+
+    /**
+     * Packet's source address.
+     */
+    pj_sockaddr	       *src_addr;
+
+    /**
+     * Should media transport switch remote address to \a rtp_src_addr?
+     * Media transport should initialize it to PJ_FALSE, and application
+     * can change the value as necessary.
+     */
+    pj_bool_t	        rem_switch;
+
+} pjmedia_tp_cb_param;
 
 /**
@@ -613,4 +646,10 @@
      */
     void (*rtcp_cb)(void *user_data, void *pkt, pj_ssize_t);
+
+    /**
+     * Callback to be called when RTP packet is received on the transport.
+     */
+    void (*rtp_cb2)(pjmedia_tp_cb_param *param);
+
 };
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/rtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/rtp.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/rtp.c	(revision 5752)
@@ -247,5 +247,6 @@
     if (pj_ntohl(hdr->ssrc) != ses->peer_ssrc) {
 	seq_st.status.flag.badssrc = 1;
-	ses->peer_ssrc = pj_ntohl(hdr->ssrc);
+	if (!ses->has_peer_ssrc)
+	    ses->peer_ssrc = pj_ntohl(hdr->ssrc);
     }
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5752)
@@ -231,4 +231,12 @@
 #endif
 
+    pj_sockaddr		     rem_rtp_addr;     /**< Remote RTP address	    */
+    unsigned		     rem_rtp_flag;     /**< Indicator flag about
+						    packet from this addr. 
+						    0=no pkt, 1=good ssrc, 
+						    2=bad ssrc pkts	    */
+    unsigned		     rtp_src_cnt;      /**< How many pkt from
+    						    this addr.   	    */
+
 #if TRACE_JB
     pj_oshandle_t	    trace_jb_fd;	    /**< Jitter tracing file handle.*/
@@ -1663,10 +1671,9 @@
  * in the RTP socket.
  */
-static void on_rx_rtp( void *data,
-		       void *pkt,
-                       pj_ssize_t bytes_read)
-
-{
-    pjmedia_stream *stream = (pjmedia_stream*) data;
+static void on_rx_rtp( pjmedia_tp_cb_param *param)
+{
+    pjmedia_stream *stream = (pjmedia_stream*) param->user_data;
+    void *pkt = param->pkt;
+    pj_ssize_t bytes_read = param->size;
     pjmedia_channel *channel = stream->dec;
     const pjmedia_rtp_hdr *hdr;
@@ -1735,5 +1742,5 @@
 	}
 
-	if (seq_st.status.flag.badssrc) {
+	if (!stream->si.has_rem_ssrc && seq_st.status.flag.badssrc) {
 	    PJ_LOG(4,(stream->port.info.name.ptr,
 		      "Changed RTP peer SSRC %d (previously %d)",
@@ -1768,4 +1775,60 @@
 	handle_incoming_dtmf(stream, payload, payloadlen);
 	goto on_return;
+    }
+
+    /* See if source address of RTP packet is different than the 
+     * configured address, and check if we need to tell the
+     * media transport to switch RTP remote address.
+     */
+    if (param->src_addr) {
+        pj_bool_t badssrc = (stream->si.has_rem_ssrc &&
+        		     seq_st.status.flag.badssrc);
+
+	if (pj_sockaddr_cmp(&stream->rem_rtp_addr, param->src_addr) == 0) {
+	    /* We're still receiving from rem_rtp_addr. */
+	    stream->rtp_src_cnt = 0;
+	    stream->rem_rtp_flag = badssrc? 2: 1;
+	} else {
+	    stream->rtp_src_cnt++;
+	    
+	    if (stream->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
+	    	if (stream->rem_rtp_flag == 1 ||
+	    	    (stream->rem_rtp_flag == 2 && badssrc))
+	    	{
+		    /* Only discard if:
+		     * - we have ever received packet with good ssrc from
+		     *   remote address (rem_rtp_addr), or
+		     * - we have ever received packet with bad ssrc from
+		     *   remote address and this packet also has bad ssrc.
+		     */
+	    	    pkt_discarded = PJ_TRUE;
+	    	    goto on_return;
+	    	}	    	
+	    	if (stream->si.has_rem_ssrc && !seq_st.status.flag.badssrc &&
+	    	    stream->rem_rtp_flag != 1)
+	    	{
+	    	    /* Immediately switch if we receive packet with the
+	    	     * correct ssrc AND we never receive packets with
+	    	     * good ssrc from rem_rtp_addr.
+	    	     */
+	    	    param->rem_switch = PJ_TRUE;
+	    	}
+	    } else {
+	        /* Switch. We no longer receive packets from rem_rtp_addr. */
+	        param->rem_switch = PJ_TRUE;
+	    }
+
+	    if (param->rem_switch) {
+		/* Set remote RTP address to source address */
+		pj_sockaddr_cp(&stream->rem_rtp_addr, param->src_addr);
+
+		/* Reset counter and flag */
+		stream->rtp_src_cnt = 0;
+		stream->rem_rtp_flag = badssrc? 2: 1;
+
+		/* Update RTCP peer ssrc */
+	    	stream->rtcp.peer_ssrc = pj_ntohl(hdr->ssrc);
+	    }
+	}
     }
 
@@ -2425,8 +2488,9 @@
     att_param.user_data = stream;
     pj_sockaddr_cp(&att_param.rem_addr, &info->rem_addr);
+    pj_sockaddr_cp(&stream->rem_rtp_addr, &info->rem_addr);
     if (pj_sockaddr_has_addr(&info->rem_rtcp.addr))
 	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);
     att_param.addr_len = pj_sockaddr_get_len(&info->rem_addr);
-    att_param.rtp_cb = &on_rx_rtp;
+    att_param.rtp_cb2 = &on_rx_rtp;
     att_param.rtcp_cb = &on_rx_rtcp;
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5752)
@@ -77,10 +77,8 @@
     pj_sockaddr		 remote_rtcp;
     unsigned		 addr_len;	/**< Length of addresses.	    */
-    unsigned		 rem_rtp_cnt;	/**< How many pkt from this addr.   */
 
     pj_bool_t		 use_ice;
     pj_sockaddr		 rtp_src_addr;	/**< Actual source RTP address.	    */
     pj_sockaddr		 rtcp_src_addr;	/**< Actual source RTCP address.    */
-    unsigned		 rtp_src_cnt;	/**< How many pkt from this addr.   */
     unsigned		 rtcp_src_cnt;  /**< How many pkt from this addr.   */
 
@@ -91,4 +89,5 @@
 			         void*,
 				 pj_ssize_t);
+    void	       (*rtp_cb2)(pjmedia_tp_cb_param*);
     void	       (*rtcp_cb)(void*,
 				  void*,
@@ -113,4 +112,7 @@
 						       void*,
 						       pj_ssize_t));
+static pj_status_t transport_attach2  (pjmedia_transport *tp,
+				       pjmedia_transport_attach_param
+				           *att_param);
 static void	   transport_detach   (pjmedia_transport *tp,
 				       void *strm);
@@ -178,5 +180,6 @@
     &transport_media_stop,
     &transport_simulate_lost,
-    &transport_destroy
+    &transport_destroy,
+    &transport_attach2
 };
 
@@ -1663,5 +1666,5 @@
      * ICE activated or received any packets.
      */
-    if (tp_ice->use_ice || tp_ice->rtp_src_cnt) {
+    if (tp_ice->use_ice) {
 	info->src_rtp_name  = tp_ice->rtp_src_addr;
     }
@@ -1724,19 +1727,34 @@
 						      pj_ssize_t))
 {
+    pjmedia_transport_attach_param param;
+    
+    pj_bzero(&param, sizeof(param));
+    param.user_data = stream;
+    pj_sockaddr_cp(&param.rem_addr, rem_addr);
+    pj_sockaddr_cp(&param.rem_rtcp, rem_rtcp);
+    param.addr_len = addr_len;
+    param.rtp_cb = rtp_cb;
+    return transport_attach2(tp, &param);
+}
+
+
+static pj_status_t transport_attach2  (pjmedia_transport *tp,
+				       pjmedia_transport_attach_param
+				           *att_param)
+{
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
 
-    tp_ice->stream = stream;
-    tp_ice->rtp_cb = rtp_cb;
-    tp_ice->rtcp_cb = rtcp_cb;
-
-    pj_memcpy(&tp_ice->remote_rtp, rem_addr, addr_len);
-    pj_memcpy(&tp_ice->remote_rtcp, rem_rtcp, addr_len);
-    tp_ice->addr_len = addr_len;
-    tp_ice->rem_rtp_cnt = 0;
+    tp_ice->stream = att_param->user_data;
+    tp_ice->rtp_cb = att_param->rtp_cb;
+    tp_ice->rtp_cb2 = att_param->rtp_cb2;
+    tp_ice->rtcp_cb = att_param->rtcp_cb;
+
+    pj_memcpy(&tp_ice->remote_rtp, &att_param->rem_addr, att_param->addr_len);
+    pj_memcpy(&tp_ice->remote_rtcp, &att_param->rem_rtcp, att_param->addr_len);
+    tp_ice->addr_len = att_param->addr_len;
 
     /* Init source RTP & RTCP addresses and counter */
     tp_ice->rtp_src_addr = tp_ice->remote_rtp;
-    tp_ice->rtcp_src_addr = tp_ice->remote_rtcp;
-    tp_ice->rtp_src_cnt = 0;
+    pj_bzero(&tp_ice->rtcp_src_addr, sizeof(tp_ice->rtcp_src_addr));
     tp_ice->rtcp_src_cnt = 0;
 
@@ -1753,4 +1771,5 @@
 
     tp_ice->rtp_cb = NULL;
+    tp_ice->rtp_cb2 = NULL;
     tp_ice->rtcp_cb = NULL;
     tp_ice->stream = NULL;
@@ -1823,5 +1842,6 @@
     }
 
-    if (comp_id==1 && tp_ice->rtp_cb) {
+    if (comp_id==1 && (tp_ice->rtp_cb || tp_ice->rtp_cb2)) {
+        pj_bool_t rem_switch = PJ_FALSE;
 
 	/* Simulate packet lost on RX direction */
@@ -1835,81 +1855,64 @@
 	}
 
-	/* See if source address of RTP packet is different than the 
-	 * configured address, and switch RTP remote address to 
-	 * source packet address after several consecutive packets
-	 * have been received.
-	 */
-	if (!tp_ice->use_ice) {
-	    pj_bool_t enable_switch =
-		    ((tp_ice->options & PJMEDIA_ICE_NO_SRC_ADDR_CHECKING)==0);
-
-	    if (!enable_switch ||
-		pj_sockaddr_cmp(&tp_ice->remote_rtp, src_addr) == 0)
-	    {
-		/* Don't switch while we're receiving from remote_rtp */
-		tp_ice->rtp_src_cnt = 0;
-		tp_ice->rem_rtp_cnt++;
+	if (!discard) {
+	    if (tp_ice->rtp_cb2) {
+		pjmedia_tp_cb_param param;
+
+	    	param.user_data = tp_ice->stream;
+	    	param.pkt = pkt;
+	    	param.size = size;
+	    	param.src_addr = (tp_ice->use_ice? NULL:
+	    			  (pj_sockaddr_t *)src_addr);
+	    	param.rem_switch = PJ_FALSE;
+	    	(*tp_ice->rtp_cb2)(&param);
+	    	rem_switch = param.rem_switch;
 	    } else {
-
-		++tp_ice->rtp_src_cnt;
-
-		/* Check if the source address is recognized. */
-		if (pj_sockaddr_cmp(src_addr, &tp_ice->rtp_src_addr) != 0) {
-		    /* Remember the new source address. */
-		    pj_sockaddr_cp(&tp_ice->rtp_src_addr, src_addr);
-		    /* Reset counter */
-		    tp_ice->rtp_src_cnt = 0;
-		    discard = PJ_TRUE;
-		}
-
-		if (tp_ice->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
-		    /* Only discard if we have ever received packet from
-		     * remote address (remote_rtp).
-		     */
-		    discard = (tp_ice->rem_rtp_cnt != 0);
-		} else {
-		    char addr_text[80];
-
-		    /* Set remote RTP address to source address */
-		    pj_sockaddr_cp(&tp_ice->remote_rtp, &tp_ice->rtp_src_addr);
-		    tp_ice->addr_len = pj_sockaddr_get_len(&tp_ice->remote_rtp);
-
-		    /* Reset counter */
-		    tp_ice->rtp_src_cnt = 0;
-
-		    PJ_LOG(4,(tp_ice->base.name,
-			      "Remote RTP address switched to %s",
-			      pj_sockaddr_print(&tp_ice->remote_rtp, addr_text,
-						sizeof(addr_text), 3)));
-
-		    /* Also update remote RTCP address if actual RTCP source
-		     * address is not heard yet.
-		     */
-		    if (!pj_sockaddr_has_addr(&tp_ice->rtcp_src_addr)) {
-			pj_uint16_t port;
-
-			pj_sockaddr_cp(&tp_ice->remote_rtcp, 
-				       &tp_ice->remote_rtp);
-
-			port = (pj_uint16_t)
-			       (pj_sockaddr_get_port(&tp_ice->remote_rtp)+1);
-			pj_sockaddr_set_port(&tp_ice->remote_rtcp, port);
-
-			PJ_LOG(4,(tp_ice->base.name,
-				  "Remote RTCP address switched to predicted "
-				  "address %s",
-				  pj_sockaddr_print(&tp_ice->remote_rtcp, 
-						    addr_text,
-						    sizeof(addr_text), 3)));
-		    }
-		}
+	    	(*tp_ice->rtp_cb)(tp_ice->stream, pkt, size);
 	    }
 	}
-
-	if (!discard)
-	    (*tp_ice->rtp_cb)(tp_ice->stream, pkt, size);
+	
+#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
+    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
+	if (rem_switch &&
+	    (tp_ice->options & PJMEDIA_ICE_NO_SRC_ADDR_CHECKING)==0)
+	{
+	    char addr_text[PJ_INET6_ADDRSTRLEN+10];
+
+	    /* Set remote RTP address to source address */
+	    pj_sockaddr_cp(&tp_ice->rtp_src_addr, src_addr);
+	    pj_sockaddr_cp(&tp_ice->remote_rtp, src_addr);
+	    tp_ice->addr_len = pj_sockaddr_get_len(&tp_ice->remote_rtp);
+
+	    PJ_LOG(4,(tp_ice->base.name,
+		      "Remote RTP address switched to %s",
+		      pj_sockaddr_print(&tp_ice->remote_rtp, addr_text,
+					sizeof(addr_text), 3)));
+
+	    /* Also update remote RTCP address if actual RTCP source
+	     * address is not heard yet.
+	     */
+	    if (!pj_sockaddr_has_addr(&tp_ice->rtcp_src_addr)) {
+		pj_uint16_t port;
+
+		pj_sockaddr_cp(&tp_ice->remote_rtcp, &tp_ice->remote_rtp);
+
+		port = (pj_uint16_t)
+		       (pj_sockaddr_get_port(&tp_ice->remote_rtp)+1);
+		pj_sockaddr_set_port(&tp_ice->remote_rtcp, port);
+
+		PJ_LOG(4,(tp_ice->base.name,
+			  "Remote RTCP address switched to predicted "
+			  "address %s",
+			  pj_sockaddr_print(&tp_ice->remote_rtcp, 
+					    addr_text,
+					    sizeof(addr_text), 3)));
+	    }
+	}
+#endif
 
     } else if (comp_id==2 && tp_ice->rtcp_cb) {
 
+#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
+    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
 	/* Check if RTCP source address is the same as the configured
 	 * remote address, and switch the address when they are
@@ -1922,5 +1925,5 @@
 		tp_ice->rtcp_src_cnt = 0;
 	    } else {
-		char addr_text[80];
+		char addr_text[PJ_INET6_ADDRSTRLEN+10];
 
 		++tp_ice->rtcp_src_cnt;
@@ -1942,4 +1945,5 @@
 	    }
 	}
+#endif
 
 	if (!discard)
@@ -2019,4 +2023,5 @@
     tp_ice->base.user_data = NULL;
     tp_ice->rtp_cb = NULL;
+    tp_ice->rtp_cb2 = NULL;
     tp_ice->rtcp_cb = NULL;
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5752)
@@ -257,4 +257,5 @@
 				   void *pkt,
 				   pj_ssize_t size);
+    void  		(*rtp_cb2)(pjmedia_tp_cb_param*);
     void		(*rtcp_cb)(void *user_data,
 				   void *pkt,
@@ -305,5 +306,5 @@
  * This callback is called by transport when incoming rtp is received
  */
-static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size);
+static void srtp_rtp_cb(pjmedia_tp_cb_param *param);
 
 /*
@@ -1065,4 +1066,5 @@
     pj_lock_acquire(srtp->mutex);
     srtp->rtp_cb = param->rtp_cb;
+    srtp->rtp_cb2 = param->rtp_cb2;
     srtp->rtcp_cb = param->rtcp_cb;
     srtp->user_data = param->user_data;
@@ -1072,5 +1074,6 @@
     member_param = *param;
     member_param.user_data = srtp;
-    member_param.rtp_cb = &srtp_rtp_cb;
+    member_param.rtp_cb = NULL;
+    member_param.rtp_cb2 = &srtp_rtp_cb;
     member_param.rtcp_cb = &srtp_rtcp_cb;
     status = pjmedia_transport_attach2(srtp->member_tp, &member_param);
@@ -1102,4 +1105,5 @@
     pj_lock_acquire(srtp->mutex);
     srtp->rtp_cb = NULL;
+    srtp->rtp_cb2 = NULL;
     srtp->rtcp_cb = NULL;
     srtp->user_data = NULL;
@@ -1233,14 +1237,24 @@
  * This callback is called by transport when incoming rtp is received
  */
-static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
-{
-    transport_srtp *srtp = (transport_srtp *) user_data;
+static void srtp_rtp_cb(pjmedia_tp_cb_param *param)
+{
+    transport_srtp *srtp = (transport_srtp *) param->user_data;
+    void *pkt = param->pkt;
+    pj_ssize_t size = param->size;
     int len = (int)size;
     srtp_err_status_t err;
     void (*cb)(void*, void*, pj_ssize_t) = NULL;
+    void (*cb2)(pjmedia_tp_cb_param*) = NULL;
     void *cb_data = NULL;
 
     if (srtp->bypass_srtp) {
-	srtp->rtp_cb(srtp->user_data, pkt, size);
+        if (srtp->rtp_cb2) {
+            pjmedia_tp_cb_param param2 = *param;
+            param2.user_data = srtp->user_data;
+            srtp->rtp_cb2(&param2);
+            param->rem_switch = param2.rem_switch;
+        } else if (srtp->rtp_cb) {
+	    srtp->rtp_cb(srtp->user_data, pkt, size);
+	}
 	return;
     }
@@ -1314,4 +1328,5 @@
     } else {
 	cb = srtp->rtp_cb;
+	cb2 = srtp->rtp_cb2;
 	cb_data = srtp->user_data;
     }
@@ -1319,5 +1334,12 @@
     pj_lock_release(srtp->mutex);
 
-    if (cb) {
+    if (cb2) {
+        pjmedia_tp_cb_param param2 = *param;
+        param2.user_data = cb_data;
+        param2.pkt = pkt;
+        param2.size = len;
+        (*cb2)(&param2);
+        param->rem_switch = param2.rem_switch;
+    } else if (cb) {
 	(*cb)(cb_data, pkt, len);
     }
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5752)
@@ -59,5 +59,4 @@
     pj_bool_t		started;	/**< Has started?		    */
     pj_sockaddr		rem_rtp_addr;	/**< Remote RTP address		    */
-    unsigned		rem_rtp_cnt;	/**< How many pkt from this addr.   */
     pj_sockaddr		rem_rtcp_addr;	/**< Remote RTCP address	    */
     int			addr_len;	/**< Length of addresses.	    */
@@ -65,4 +64,5 @@
 			void*,
 			pj_ssize_t);
+    void  (*rtp_cb2)(pjmedia_tp_cb_param*); /**< To report incoming RTP.    */
     void  (*rtcp_cb)(	void*,		/**< To report incoming RTCP.	    */
 			void*,
@@ -80,5 +80,4 @@
     pending_write	rtp_pending_write[MAX_PENDING];  /**< Pending write */
     pj_sockaddr		rtp_src_addr;	/**< Actual packet src addr.	    */
-    unsigned		rtp_src_cnt;	/**< How many pkt from this addr.   */
     int			rtp_addrlen;	/**< Address length.		    */
     char		rtp_pkt[RTP_LEN];/**< Incoming RTP packet buffer    */
@@ -120,4 +119,7 @@
 						       void*,
 						       pj_ssize_t));
+static pj_status_t transport_attach2  (pjmedia_transport *tp,
+				       pjmedia_transport_attach_param
+				           *att_param);
 static void	   transport_detach   (pjmedia_transport *tp,
 				       void *strm);
@@ -171,5 +173,6 @@
     &transport_media_stop,
     &transport_simulate_lost,
-    &transport_destroy
+    &transport_destroy,
+    &transport_attach2
 };
 
@@ -456,4 +459,5 @@
     struct transport_udp *udp;
     pj_status_t status;
+    pj_bool_t rem_switch = PJ_FALSE;
 
     PJ_UNUSED_ARG(op_key);
@@ -479,8 +483,10 @@
     do {
 	void (*cb)(void*,void*,pj_ssize_t);
+	void (*cb2)(pjmedia_tp_cb_param*);
 	void *user_data;
 	pj_bool_t discard = PJ_FALSE;
 
 	cb = udp->rtp_cb;
+	cb2 = udp->rtp_cb2;
 	user_data = udp->user_data;
 
@@ -495,73 +501,57 @@
 	}
 
-	/* See if source address of RTP packet is different than the 
-	 * configured address, and switch RTP remote address to 
-	 * source packet address after several consecutive packets
-	 * have been received.
-	 */
-	if (bytes_read>0 && 
-	    (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0) 
+	//if (!discard && udp->attached && cb)
+	if (!discard) {
+	    if (cb2) {
+		pjmedia_tp_cb_param param;
+
+	    	param.user_data = user_data;
+	    	param.pkt = udp->rtp_pkt;
+	    	param.size = bytes_read;
+	    	param.src_addr = &udp->rtp_src_addr;
+	    	param.rem_switch = PJ_FALSE;
+	    	(*cb2)(&param);
+	    	rem_switch = param.rem_switch;
+	    } else if (cb) {
+	    	(*cb)(user_data, udp->rtp_pkt, bytes_read);
+	    }
+	}
+
+#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
+    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
+	if (rem_switch &&
+	    (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0)
 	{
-	    if (pj_sockaddr_cmp(&udp->rem_rtp_addr, &udp->rtp_src_addr) == 0) {
-		/* We're still receiving from rem_rtp_addr. Don't switch. */
-		udp->rtp_src_cnt = 0;
-		udp->rem_rtp_cnt++;
-	    } else {
-		udp->rtp_src_cnt++;
-
-		if (udp->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
-		    /* Only discard if we have ever received packet from
-		     * remote address (rem_rtp_addr).
-		     */
-		    //discard = PJ_TRUE;
-		    discard = (udp->rem_rtp_cnt != 0);
-		} else {
-		
-		    char addr_text[80];
-
-		    /* Set remote RTP address to source address */
-		    pj_memcpy(&udp->rem_rtp_addr, &udp->rtp_src_addr,
-			      sizeof(pj_sockaddr));
-
-		    /* Reset counter */
-		    udp->rtp_src_cnt = 0;
-
-		    PJ_LOG(4,(udp->base.name,
-			      "Remote RTP address switched to %s",
-			      pj_sockaddr_print(&udp->rtp_src_addr, addr_text,
-						sizeof(addr_text), 3)));
-
-		    /* Also update remote RTCP address if actual RTCP source
-		     * address is not heard yet.
-		     */
-		    if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) {
-			pj_uint16_t port;
-
-			pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr, 
-				  sizeof(pj_sockaddr));
-			pj_sockaddr_copy_addr(&udp->rem_rtcp_addr,
-					      &udp->rem_rtp_addr);
-			port = (pj_uint16_t)
-			       (pj_sockaddr_get_port(&udp->rem_rtp_addr)+1);
-			pj_sockaddr_set_port(&udp->rem_rtcp_addr, port);
-
-			pj_memcpy(&udp->rtcp_src_addr, &udp->rem_rtcp_addr, 
-				  sizeof(pj_sockaddr));
-
-			PJ_LOG(4,(udp->base.name,
-				  "Remote RTCP address switched to predicted"
-				  " address %s",
-				  pj_sockaddr_print(&udp->rtcp_src_addr, 
-						    addr_text,
-						    sizeof(addr_text), 3)));
-
-		    }
-		}
+	    char addr_text[PJ_INET6_ADDRSTRLEN+10];
+
+	    /* Set remote RTP address to source address */
+	    pj_sockaddr_cp(&udp->rem_rtp_addr, &udp->rtp_src_addr);
+
+	    PJ_LOG(4,(udp->base.name,
+		      "Remote RTP address switched to %s",
+		      pj_sockaddr_print(&udp->rtp_src_addr, addr_text,
+					sizeof(addr_text), 3)));
+
+	    /* Also update remote RTCP address if actual RTCP source
+	     * address is not heard yet.
+	     */
+	    if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) {
+		pj_uint16_t port;
+
+		pj_sockaddr_cp(&udp->rem_rtcp_addr, &udp->rem_rtp_addr);
+		port = (pj_uint16_t)
+		       (pj_sockaddr_get_port(&udp->rem_rtp_addr)+1);
+		pj_sockaddr_set_port(&udp->rem_rtcp_addr, port);
+
+		pj_sockaddr_cp(&udp->rtcp_src_addr, &udp->rem_rtcp_addr);
+
+		PJ_LOG(4,(udp->base.name,
+			  "Remote RTCP address switched to predicted"
+			  " address %s",
+			  pj_sockaddr_print(&udp->rtcp_src_addr, addr_text,
+					    sizeof(addr_text), 3)));
 	    }
 	}
-
-	//if (!discard && udp->attached && cb)
-	if (!discard && cb)
-	    (*cb)(user_data, udp->rtp_pkt, bytes_read);
+#endif
 
 	bytes_read = sizeof(udp->rtp_pkt);
@@ -619,4 +609,6 @@
 	    (*cb)(user_data, udp->rtcp_pkt, bytes_read);
 
+#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
+    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1)
 	/* Check if RTCP source address is the same as the configured
 	 * remote address, and switch the address when they are
@@ -633,5 +625,5 @@
 
 		if (udp->rtcp_src_cnt >= PJMEDIA_RTCP_NAT_PROBATION_CNT	) {
-		    char addr_text[80];
+		    char addr_text[PJ_INET6_ADDRSTRLEN+10];
 
 		    udp->rtcp_src_cnt = 0;
@@ -646,4 +638,5 @@
 	    }
 	}
+#endif
 
 	bytes_read = sizeof(udp->rtcp_pkt);
@@ -681,6 +674,5 @@
 
 
-/* Called by application to initialize the transport */
-static pj_status_t transport_attach(   pjmedia_transport *tp,
+static pj_status_t tp_attach  	      (pjmedia_transport *tp,
 				       void *user_data,
 				       const pj_sockaddr_t *rem_addr,
@@ -690,4 +682,5 @@
 						      void*,
 						      pj_ssize_t),
+				       void (*rtp_cb2)(pjmedia_tp_cb_param*),
 				       void (*rtcp_cb)(void*,
 						       void*,
@@ -751,4 +744,5 @@
     /* Save the callbacks */
     udp->rtp_cb = rtp_cb;
+    udp->rtp_cb2 = rtp_cb2;
     udp->rtcp_cb = rtcp_cb;
     udp->user_data = user_data;
@@ -763,7 +757,5 @@
     pj_bzero(&udp->rtp_src_addr, sizeof(udp->rtp_src_addr));
     pj_bzero(&udp->rtcp_src_addr, sizeof(udp->rtcp_src_addr));
-    udp->rtp_src_cnt = 0;
     udp->rtcp_src_cnt = 0;
-    udp->rem_rtp_cnt = 0;
 
     /* Set buffer size for RTP socket */
@@ -817,4 +809,34 @@
 
 
+/* Called by application to initialize the transport */
+static pj_status_t transport_attach(   pjmedia_transport *tp,
+				       void *user_data,
+				       const pj_sockaddr_t *rem_addr,
+				       const pj_sockaddr_t *rem_rtcp,
+				       unsigned addr_len,
+				       void (*rtp_cb)(void*,
+						      void*,
+						      pj_ssize_t),
+				       void (*rtcp_cb)(void*,
+						       void*,
+						       pj_ssize_t))
+{
+    return tp_attach(tp, user_data, rem_addr, rem_rtcp, addr_len,
+    		     rtp_cb, NULL, rtcp_cb);
+}
+
+
+static pj_status_t transport_attach2(pjmedia_transport *tp,
+				     pjmedia_transport_attach_param *att_param)
+{
+    return tp_attach(tp, att_param->user_data, 
+			    (pj_sockaddr_t*)&att_param->rem_addr, 
+			    (pj_sockaddr_t*)&att_param->rem_rtcp, 
+			    att_param->addr_len, att_param->rtp_cb,
+			    att_param->rtp_cb2, 
+			    att_param->rtcp_cb);
+}
+
+
 /* Called by application when it no longer needs the transport */
 static void transport_detach( pjmedia_transport *tp,
@@ -846,4 +868,5 @@
 	/* Clear up application infos from transport */
 	udp->rtp_cb = NULL;
+	udp->rtp_cb2 = NULL;
 	udp->rtcp_cb = NULL;
 	udp->user_data = NULL;
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5751)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5752)
@@ -181,4 +181,12 @@
     pj_timestamp	     ts_freq;	    /**< Timestamp frequency.	    */
 
+    pj_sockaddr		     rem_rtp_addr;  /**< Remote RTP address	    */
+    unsigned		     rem_rtp_flag;  /**< Indicator flag about
+						 packet from this addr. 
+						 0=no pkt, 1=good ssrc pkts, 
+						 2=bad ssrc pkts	    */
+    pj_sockaddr		     rtp_src_addr;  /**< Actual packet src addr.    */
+    unsigned		     rtp_src_cnt;   /**< How many pkt from this addr*/
+
 #if TRACE_RC
     unsigned		     rc_total_sleep;
@@ -599,10 +607,9 @@
  * in the RTP socket. 
  */
-static void on_rx_rtp( void *data, 
-		       void *pkt,
-                       pj_ssize_t bytes_read)
-
-{
-    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) data;
+static void on_rx_rtp( pjmedia_tp_cb_param *param)
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) param->user_data;
+    void *pkt = param->pkt;
+    pj_ssize_t bytes_read = param->size;
     pjmedia_vid_channel *channel = stream->dec;
     const pjmedia_rtp_hdr *hdr;
@@ -670,5 +677,5 @@
 	}
 
-	if (seq_st.status.flag.badssrc) {
+	if (!stream->info.has_rem_ssrc && seq_st.status.flag.badssrc) {
 	    PJ_LOG(4,(channel->port.info.name.ptr,
 		      "Changed RTP peer SSRC %d (previously %d)",
@@ -690,4 +697,60 @@
 	pkt_discarded = PJ_TRUE;
 	goto on_return;
+    }
+
+    /* See if source address of RTP packet is different than the 
+     * configured address, and check if we need to tell the
+     * media transport to switch RTP remote address.
+     */
+    if (param->src_addr) {
+        pj_bool_t badssrc = (stream->info.has_rem_ssrc &&
+        		     seq_st.status.flag.badssrc);
+
+	if (pj_sockaddr_cmp(&stream->rem_rtp_addr, param->src_addr) == 0) {
+	    /* We're still receiving from rem_rtp_addr. */
+	    stream->rtp_src_cnt = 0;
+	    stream->rem_rtp_flag = badssrc? 2: 1;
+	} else {
+	    stream->rtp_src_cnt++;
+	    
+	    if (stream->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
+	    	if (stream->rem_rtp_flag == 1 ||
+	    	    (stream->rem_rtp_flag == 2 && badssrc))
+	    	{
+		    /* Only discard if:
+		     * - we have ever received packet with good ssrc from
+		     *   remote address (rem_rtp_addr), or
+		     * - we have ever received packet with bad ssrc from
+		     *   remote address and this packet also has bad ssrc.
+		     */
+	    	    pkt_discarded = PJ_TRUE;
+	    	    goto on_return;
+	    	}	    	
+	    	if (stream->info.has_rem_ssrc && !seq_st.status.flag.badssrc
+	    	    && stream->rem_rtp_flag != 1)
+	    	{
+	    	    /* Immediately switch if we receive packet with the
+	    	     * correct ssrc AND we never receive packets with
+	    	     * good ssrc from rem_rtp_addr.
+	    	     */
+	    	    param->rem_switch = PJ_TRUE;
+	    	}
+	    } else {
+	        /* Switch. We no longer receive packets from rem_rtp_addr. */
+	        param->rem_switch = PJ_TRUE;
+	    }
+
+	    if (param->rem_switch) {
+		/* Set remote RTP address to source address */
+		pj_sockaddr_cp(&stream->rem_rtp_addr, param->src_addr);
+
+		/* Reset counter and flag */
+		stream->rtp_src_cnt = 0;
+		stream->rem_rtp_flag = badssrc? 2: 1;
+
+		/* Update RTCP peer ssrc */
+	    	stream->rtcp.peer_ssrc = pj_ntohl(hdr->ssrc);
+	    }
+	}
     }
 
@@ -1673,8 +1736,9 @@
     att_param.user_data = stream;
     pj_sockaddr_cp(&att_param.rem_addr, &info->rem_addr);
+    pj_sockaddr_cp(&stream->rem_rtp_addr, &info->rem_addr);
     if (pj_sockaddr_has_addr(&info->rem_rtcp.addr))
 	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);    
     att_param.addr_len = pj_sockaddr_get_len(&info->rem_addr);
-    att_param.rtp_cb = &on_rx_rtp;
+    att_param.rtp_cb2 = &on_rx_rtp;
     att_param.rtcp_cb = &on_rx_rtcp;
 
