Index: pjproject/trunk/pjmedia/include/pjmedia/rtcp.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/rtcp.h	(revision 382)
+++ pjproject/trunk/pjmedia/include/pjmedia/rtcp.h	(revision 383)
@@ -117,6 +117,6 @@
 {
     pjmedia_rtcp_common  common;	/**< Common header.	    */
-    pjmedia_rtcp_sr sr;		/**< Sender report.	    */
-    pjmedia_rtcp_rr rr;		/**< variable-length list   */
+    pjmedia_rtcp_sr	 sr;		/**< Sender report.	    */
+    pjmedia_rtcp_rr	 rr;		/**< variable-length list   */
 };
 
@@ -147,5 +147,6 @@
 
 /**
- * RTCP session.
+ * RTCP session is used to monitor the RTP session of one endpoint. There
+ * should only be one RTCP session for a bidirectional RTP streams.
  */
 struct pjmedia_rtcp_session
@@ -155,16 +156,16 @@
     pjmedia_rtp_seq_session seq_ctrl;	/**< RTCP sequence number control.  */
 
-    unsigned	    clock_rate;	    /**< Clock rate.			    */
-    pj_uint32_t	    received;       /**< # pkts received		    */
-    pj_uint32_t	    expected_prior; /**< # pkts expected at last interval   */
-    pj_uint32_t	    received_prior; /**< # pkts received at last interval   */
-    pj_int32_t	    transit;        /**< Relative trans time for prev pkt   */
-    pj_uint32_t	    jitter;	    /**< Estimated jitter		    */
-    pj_timestamp    ts_freq;	    /**< System timestamp frequency.	    */
-
-    pjmedia_rtcp_ntp_rec rtcp_lsr;	 /**< NTP ts in last SR received    */
-    unsigned 		 rtcp_lsr_time;  /**< Time when last SR is received.*/
-    pj_uint32_t		 peer_ssrc;	 /**< Peer SSRC			    */
-    
+    unsigned		    clock_rate;	/**< Clock rate of the stream	    */
+    pj_uint32_t		    received;   /**< # pkt received		    */
+    pj_uint32_t		    exp_prior;	/**< # pkt expected at last interval*/
+    pj_uint32_t		    rx_prior;	/**< # pkt received at last interval*/
+    pj_int32_t		    transit;    /**< Rel transit time for prev pkt  */
+    pj_uint32_t		    jitter;	/**< Scaled jitter		    */
+    pj_timestamp	    ts_freq;	/**< System timestamp frequency.    */
+
+    pjmedia_rtcp_ntp_rec    rtcp_lsr;	 /**< NTP ts in last SR received    */
+    pj_timestamp	    rtcp_lsr_time;/**< Time when last SR is received*/
+    pj_uint32_t		    peer_ssrc;	 /**< Peer SSRC			    */
+    unsigned		    ee_delay;	/**< End-to-end delay, in msec.	    */
 };
 
@@ -220,15 +221,31 @@
 
 /**
- * Build a RTCP SR/RR packet to be transmitted to remote RTP peer.
- * @param session The session.
- *
- * @param rtcp_pkt  [output] Upon return, it will contain pointer to the 
+ * Call this function when an RTCP packet is received from remote peer.
+ * This RTCP packet received from remote is used to calculate the end-to-
+ * end delay of the network.
+ *
+ * @param session   RTCP session.
+ * @param rtcp_pkt  The received RTCP packet.
+ * @param size	    Size of the incoming packet.
+ */
+PJ_DECL(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *session,
+				    const void *rtcp_pkt,
+				    pj_size_t size);
+
+
+/**
+ * Build a RTCP SR+RR packet to be transmitted to remote RTP peer.
+ * Note that this function will reset the interval counters (such as
+ * the ones to calculate fraction lost) in the session.
+ *
+ * @param session   The RTCP session.
+ * @param rtcp_pkt  Upon return, it will contain pointer to the 
  *		    RTCP packet.
- * @param len	    [output] Upon return, it will indicate the size of 
+ * @param len	    Upon return, it will indicate the size of 
  *		    the RTCP packet.
  */
 PJ_DECL(void) pjmedia_rtcp_build_rtcp( pjmedia_rtcp_session *session, 
 				       pjmedia_rtcp_pkt **rtcp_pkt, 
-				       int *len );
+				       int *len);
 
 
Index: pjproject/trunk/pjmedia/src/pjmedia/rtcp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/rtcp.c	(revision 382)
+++ pjproject/trunk/pjmedia/src/pjmedia/rtcp.c	(revision 383)
@@ -19,7 +19,8 @@
 #include <pjmedia/rtcp.h>
 #include <pjmedia/errno.h>
-#include <pj/os.h>	/* pj_gettimeofday */
-#include <pj/sock.h>	/* pj_htonx, pj_ntohx */
-#include <pj/string.h>	/* pj_memset */
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/sock.h>
+#include <pj/string.h>
 
 
@@ -28,5 +29,7 @@
 
 
-#define USE_TIMESTAMP	PJ_HAS_HIGH_RES_TIMER
+#if PJ_HAS_HIGH_RES_TIMER==0
+#   error "High resolution timer needs to be enabled"
+#endif
 
 
@@ -34,14 +37,22 @@
  * Get NTP time.
  */
-static void rtcp_get_ntp_time(struct pjmedia_rtcp_ntp_rec *ntp)
+static void rtcp_get_ntp_time(const pjmedia_rtcp_session *s, 
+			      struct pjmedia_rtcp_ntp_rec *ntp)
 {
     pj_time_val tv;
+    pj_timestamp ts;
 
     pj_gettimeofday(&tv);
-    
+    pj_get_timestamp(&ts);
+    
+    /* Fill up the high 32bit part */
     ntp->hi = tv.sec;
-    tv.msec = tv.msec % 1000;
-    ntp->lo = tv.msec * 0xFFFF / 1000;
-    ntp->lo <<= 16;
+    
+    /* Calculate second fractions */
+    ts.u64 %= s->ts_freq.u64;
+    ts.u64 = (ts.u64 << 32) / s->ts_freq.u64;
+
+    /* Fill up the low 32bit part */
+    ntp->lo = ts.u32.lo;
 }
 
@@ -60,5 +71,5 @@
     /* Init time */
     s->rtcp_lsr.hi = s->rtcp_lsr.lo = 0;
-    s->rtcp_lsr_time = 0;
+    s->rtcp_lsr_time.u64 = 0;
     
     /* Init common RTCP header */
@@ -72,10 +83,9 @@
     
     /* Get timestamp frequency */
-#if USE_TIMESTAMP
     pj_get_timestamp_freq(&s->ts_freq);
-#endif
 
     /* RR will be initialized on receipt of the first RTP packet. */
 }
+
 
 PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *session)
@@ -88,6 +98,6 @@
 {
     s->received = 0;
-    s->expected_prior = 0;
-    s->received_prior = 0;
+    s->exp_prior = 0;
+    s->rx_prior = 0;
     s->transit = 0;
     s->jitter = 0;
@@ -100,4 +110,5 @@
 				 pj_uint32_t rtp_ts)
 {   
+    pj_timestamp ts;
     pj_uint32_t arrival;
     pj_int32_t transit;
@@ -117,28 +128,11 @@
 
     /*
-     * Calculate jitter (s->jitter is in timer tick unit)
+     * Calculate jitter (see RFC 3550 section A.8)
      */
-#if USE_TIMESTAMP
-    {
-	pj_timestamp ts;
-
-	pj_get_timestamp(&ts);
-
-	/* Convert timestamp to samples */
-	ts.u64 = ts.u64 * s->clock_rate / s->ts_freq.u64;
-	arrival = (pj_uint32_t)ts.u64;
-    }
-#else
-    {
-	pj_time_val tv;
-	unsigned long timer_tick;
-
-	pj_gettimeofday(&tv);
-	timer_tick = tv.sec * 1000 + tv.msec;
-
-	/* Convert timer tick to samples */
-	arrival = timer_tick * s->clock_rate / 1000;
-    }
-#endif
+    
+    /* Get arrival time and convert timestamp to samples */
+    pj_get_timestamp(&ts);
+    ts.u64 = ts.u64 * s->clock_rate / s->ts_freq.u64;
+    arrival = ts.u32.lo;
 
     transit = arrival - rtp_ts;
@@ -147,5 +141,5 @@
 	s->transit = transit;
     } else {
-	pj_int32_t d, jitter = s->jitter;
+	pj_int32_t d;
 	
 	d = transit - s->transit;
@@ -154,6 +148,5 @@
 	    d = -d;
 	
-	jitter += d - ((jitter + 8) >> 4);
-	s->jitter = jitter;
+	s->jitter += d - ((s->jitter + 8) >> 4);
     }
 }
@@ -163,7 +156,63 @@
 {
     pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;
-    rtcp_pkt->sr.sender_pcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1);
-    rtcp_pkt->sr.sender_bcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size );
-}
+
+    /* Update number of packets */
+    rtcp_pkt->sr.sender_pcount = 
+	pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1);
+
+    /* Update number of bytes */
+    rtcp_pkt->sr.sender_bcount = 
+	pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size );
+}
+
+
+PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *session,
+				   const void *pkt,
+				   pj_size_t size)
+{
+    const struct pjmedia_rtcp_pkt *rtcp = pkt;
+
+    /* Must at least contain SR */
+    pj_assert(size >= sizeof(pjmedia_rtcp_common)+sizeof(pjmedia_rtcp_sr));
+
+    /* Save NTP timestamp */
+    session->rtcp_lsr.hi = pj_ntohl(rtcp->sr.ntp_sec);
+    session->rtcp_lsr.lo = pj_ntohl(rtcp->sr.ntp_frac);
+
+    /* Calculate SR arrival time for DLSR */
+    pj_get_timestamp(&session->rtcp_lsr_time);
+
+    /* Calculate ee_delay if it has RR */
+    if (size >= sizeof(pjmedia_rtcp_pkt)) {
+	
+	/* Can only calculate if LSR and DLSR is present in RR */
+	if (rtcp->rr.lsr && rtcp->rr.dlsr) {
+	    pj_uint32_t lsr, now, dlsr, eedelay;
+	    pjmedia_rtcp_ntp_rec ntp;
+
+	    /* LSR is the middle 32bit of NTP. It has 1/65536 second 
+	     * resolution 
+	     */
+	    lsr = pj_ntohl(rtcp->rr.lsr);
+
+	    /* DLSR is delay since LSR, also in 1/65536 resolution */
+	    dlsr = pj_ntohl(rtcp->rr.dlsr);
+
+	    /* Get current time, and convert to 1/65536 resolution */
+	    rtcp_get_ntp_time(session, &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 msec: 
+	     *   session->ee_delay = (eedelay * 1000) / 65536;
+	     */
+	    session->ee_delay = (eedelay * 1000) >> 16;
+	}
+    }
+}
+
 
 static void rtcp_build_rtcp(pjmedia_rtcp_session *s, 
@@ -185,7 +234,6 @@
     
     /* Total lost. */
-    expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq + 1;
+    expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq;
     u32 = expected - s->received;
-    if (u32 == 1) u32 = 0;
     rtcp_pkt->rr.total_lost_2 = (u32 >> 16) & 0x00FF;
     rtcp_pkt->rr.total_lost_1 = (u32 >> 8) & 0x00FF;
@@ -193,9 +241,9 @@
 
     /* Fraction lost calculation */
-    expected_interval = expected - s->expected_prior;
-    s->expected_prior = expected;
-    
-    received_interval = s->received - s->received_prior;
-    s->received_prior = s->received;
+    expected_interval = expected - s->exp_prior;
+    s->exp_prior = expected;
+    
+    received_interval = s->received - s->rx_prior;
+    s->rx_prior = s->received;
     
     lost_interval = expected_interval - received_interval;
@@ -214,10 +262,9 @@
     pjmedia_rtcp_pkt *rtcp_pkt = &session->rtcp_pkt;
     pjmedia_rtcp_ntp_rec ntp;
-    pj_time_val now;
     
     rtcp_build_rtcp(session, session->peer_ssrc);
     
     /* Get current NTP time. */
-    rtcp_get_ntp_time(&ntp);
+    rtcp_get_ntp_time(session, &ntp);
     
     /* Fill in NTP timestamp in SR. */
@@ -225,9 +272,9 @@
     rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo);
     
-    if (session->rtcp_lsr_time == 0 || session->rtcp_lsr.lo == 0) {
+    if (session->rtcp_lsr_time.u64 == 0 || session->rtcp_lsr.lo == 0) {
 	rtcp_pkt->rr.lsr = 0;
 	rtcp_pkt->rr.dlsr = 0;
     } else {
-	unsigned msec_elapsed;
+	pj_timestamp ts;
 	
 	/* Fill in LSR.
@@ -241,9 +288,14 @@
 	   DLSR is Delay since Last SR, in 1/65536 seconds.
 	 */
-	pj_gettimeofday(&now);
-	msec_elapsed = (now.msec - session->rtcp_lsr_time);
-	rtcp_pkt->rr.dlsr = pj_htonl((msec_elapsed * 65536) / 1000);
-    }
-    
+	pj_get_timestamp(&ts);
+
+	/* Convert interval to 1/65536 seconds value */
+	ts.u64 = ((ts.u64 - session->rtcp_lsr_time.u64) << 16) / 
+		    session->ts_freq.u64;
+
+	rtcp_pkt->rr.dlsr = pj_htonl( (pj_uint32_t)ts.u64 );
+    }
+    
+
     /* Return pointer. */
     *ret_p_pkt = rtcp_pkt;
@@ -251,2 +303,3 @@
 }
 
+ 
Index: pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 382)
+++ pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 383)
@@ -1114,4 +1114,7 @@
 		    pj_memcpy(&strm->rem_rtcp, packet, size);
 		    status = PJ_SUCCESS;
+
+		    /* Report receipt of RTCP to RTCP session */
+		    pjmedia_rtcp_rx_rtcp(&strm->rtcp, packet, size);
 		}
 	    }
@@ -1525,4 +1528,6 @@
 	   );
 
+    printf("              End to end delay: %u ms\n", audio->rtcp.ee_delay);
+
 }
 
