Index: /pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 1944)
+++ /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 1945)
@@ -99,4 +99,10 @@
     pj_bool_t		rtcp_xr_enabled;
 				    /**< Specify whether RTCP XR is enabled.*/
+    pj_uint32_t		rtcp_xr_interval; /**< RTCP XR interval.            */
+    pj_sockaddr		rtcp_xr_dest;/**<Additional remote RTCP XR address.
+				         This is useful for third-party (e.g:
+					 network monitor) to monitor the 
+					 stream. If sin_family is zero, 
+					 this will be ignored.		    */
 #endif
     pjmedia_codec_info	fmt;	    /**< Incoming codec format info.	    */
Index: /pjproject/trunk/pjmedia/src/pjmedia/rtcp_xr.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/rtcp_xr.c	(revision 1944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/rtcp_xr.c	(revision 1945)
@@ -270,4 +270,5 @@
 	pj_uint32_t c33;
 	pj_uint32_t ctotal, p32, p23, m;
+	unsigned est_extra_delay;
 
 	r = (pjmedia_rtcp_xr_rb_voip_mtc*) &sess->pkt.buf[size];
@@ -342,14 +343,24 @@
 				    (sess->rtcp_session->stat.rtt.last / 1000);
 	
-	/* End system delay estimation = RTT/2 + current jitter buffer size +
-	 *				 EXTRA
+	/* End system delay = RTT/2 + current jitter buffer size + 
+	 *                    EXTRA (estimated extra delay)
 	 * EXTRA will cover additional delay introduced by other components of
 	 * audio engine, e.g: sound device, codec, AEC, PLC, WSOLA.
 	 * Since it is difficult to get the exact value of EXTRA, estimation
-	 * is taken to be totally around 50 ms.
+	 * is taken to be totally around 30ms + sound device latency.
 	 */
+	est_extra_delay = 30 + 
+#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND
+			  PJMEDIA_PASOUND_MAX_LATENCY
+#elif PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_NULL_SOUND
+			  0
+#else
+			  (PJMEDIA_SOUND_BUFFER_COUNT * 15)
+#endif
+			  ;
 	sess->stat.rx.voip_mtc.end_sys_delay = (pj_uint16_t)
-				(sess->stat.rx.voip_mtc.rnd_trip_delay / 2 +
-				 sess->stat.rx.voip_mtc.jb_nom + 50);
+				 (sess->stat.rx.voip_mtc.rnd_trip_delay / 2 +
+				 sess->stat.rx.voip_mtc.jb_nom + 
+				 est_extra_delay);
 
 	/* Generate block contents */
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 1944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 1945)
@@ -158,4 +158,14 @@
 #endif
 
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    pj_uint32_t		     rtcp_xr_last_tx;  /**< RTCP XR tx time 
+					            in timestamp.           */
+    pj_uint32_t		     rtcp_xr_interval; /**< Interval, in timestamp. */
+    pj_sockaddr		     rtcp_xr_dest;     /**< Additional remote RTCP XR 
+						    dest. If sin_family is 
+						    zero, it will be ignored*/
+    unsigned		     rtcp_xr_dest_len; /**< Length of RTCP XR dest
+					            address		    */
+#endif
 };
 
@@ -468,16 +478,27 @@
 	pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len);
 
-	(*stream->transport->op->send_rtcp)(stream->transport, 
-					    rtcp_pkt, len);
+	pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
+
+	stream->rtcp_last_tx = timestamp;
+    }
 
 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
-	/* Temporarily always send RTCP XR after RTCP */
-	if (stream->rtcp.xr_enabled)
+    if (stream->rtcp.xr_enabled) {
+
+	if (stream->rtcp_xr_last_tx == 0) {
+    	
+	    stream->rtcp_xr_last_tx = timestamp;
+
+	} else if (timestamp - stream->rtcp_xr_last_tx >= 
+		   stream->rtcp_xr_interval)
 	{
 	    int i;
 	    pjmedia_jb_state jb_state;
-
+	    void *rtcp_pkt;
+	    int len;
+
+	    /* Update RTCP XR with current JB states */
 	    pjmedia_jbuf_get_state(stream->jb, &jb_state);
-	    
+    	    
 	    i = jb_state.size * stream->codec_param.info.frm_ptime;
 	    pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, 
@@ -490,14 +511,24 @@
 					i);
 
+	    /* Build RTCP XR packet */
 	    pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, 
 				       &rtcp_pkt, &len);
 
-	    (*stream->transport->op->send_rtcp)(stream->transport, 
-						rtcp_pkt, len);
+	    /* Send the RTCP XR to remote address */
+	    pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
+
+	    /* Send the RTCP XR to third-party destination if specified */
+	    if (stream->rtcp_xr_dest_len) {
+		pjmedia_transport_send_rtcp2(stream->transport, 
+					     &stream->rtcp_xr_dest,
+					     stream->rtcp_xr_dest_len, 
+					     rtcp_pkt, len);
+	    }
+
+	    /* Update last tx RTCP XR */
+	    stream->rtcp_xr_last_tx = timestamp;
 	}
+    }
 #endif
-
-	stream->rtcp_last_tx = timestamp;
-    }
 }
 
@@ -768,9 +799,6 @@
 
     /* Send the RTP packet to the transport. */
-    (*stream->transport->op->send_rtp)(stream->transport,
-				       channel->out_pkt, 
-				       frame_out.size + 
-					    sizeof(pjmedia_rtp_hdr));
-
+    pjmedia_transport_send_rtp(stream->transport, channel->out_pkt, 
+			       frame_out.size + sizeof(pjmedia_rtp_hdr));
 
     /* Update stat */
@@ -1565,4 +1593,19 @@
 	pjmedia_rtcp_enable_xr(&stream->rtcp, PJ_TRUE);
 
+	/* Set RTCP XR TX interval */
+	if (info->rtcp_xr_interval != 0)
+	    stream->rtcp_xr_interval = info->rtcp_xr_interval;
+	else
+	    stream->rtcp_xr_interval = (PJMEDIA_RTCP_INTERVAL + 
+				       (pj_rand() % 8000)) * 
+				       info->fmt.clock_rate / 1000;
+
+	/* Additional third-party RTCP XR destination */
+	if (info->rtcp_xr_dest.addr.sa_family != 0) {
+	    stream->rtcp_xr_dest_len = pj_sockaddr_get_len(&info->rtcp_xr_dest);
+	    pj_memcpy(&stream->rtcp_xr_dest, &info->rtcp_xr_dest,
+		      stream->rtcp_xr_dest_len);
+	}
+
 	/* jitter buffer adaptive info */
 	i = PJMEDIA_RTCP_XR_JB_ADAPTIVE;
@@ -1620,4 +1663,41 @@
     PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
 
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    /* Send RTCP XR on stream destroy */
+    if (stream->rtcp.xr_enabled) {
+	int i;
+	pjmedia_jb_state jb_state;
+	void *rtcp_pkt;
+	int len;
+
+	/* Update RTCP XR with current JB states */
+	pjmedia_jbuf_get_state(stream->jb, &jb_state);
+    	    
+	i = jb_state.size * stream->codec_param.info.frm_ptime;
+	pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, 
+				    PJMEDIA_RTCP_XR_INFO_JB_NOM,
+				    i);
+
+	i = jb_state.max_size* stream->codec_param.info.frm_ptime;
+	pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, 
+				    PJMEDIA_RTCP_XR_INFO_JB_MAX,
+				    i);
+
+	/* Build RTCP XR packet */
+	pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, 
+				   &rtcp_pkt, &len);
+
+	/* Send the RTCP XR to remote address */
+	pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
+	
+	/* Send the RTCP XR to third-party destination if specified */
+	if (stream->rtcp_xr_dest_len) {
+	    pjmedia_transport_send_rtcp2(stream->transport, 
+					 &stream->rtcp_xr_dest,
+					 stream->rtcp_xr_dest_len, 
+					 rtcp_pkt, len);
+	}
+    }
+#endif
 
     /* Detach from transport 
