summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-04-05 12:53:42 +0000
committerBenny Prijono <bennylp@teluu.com>2006-04-05 12:53:42 +0000
commitb314eb0d0223a4c629b8c5a97877a413f1e14e3d (patch)
tree395a62b3e570e7f9c69272a2e06445c564b769da
parentee48033d397909ffc4d88048f8a1f3d0dd62a2a6 (diff)
Added RTCP end to end delay calculation
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@383 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/rtcp.h57
-rw-r--r--pjmedia/src/pjmedia/rtcp.c161
-rw-r--r--pjsip-apps/src/samples/siprtp.c5
3 files changed, 149 insertions, 74 deletions
diff --git a/pjmedia/include/pjmedia/rtcp.h b/pjmedia/include/pjmedia/rtcp.h
index 96f135e3..1ce8362b 100644
--- a/pjmedia/include/pjmedia/rtcp.h
+++ b/pjmedia/include/pjmedia/rtcp.h
@@ -116,8 +116,8 @@ typedef struct pjmedia_rtcp_common pjmedia_rtcp_common;
struct pjmedia_rtcp_pkt
{
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 */
};
/**
@@ -146,7 +146,8 @@ typedef struct pjmedia_rtcp_ntp_rec pjmedia_rtcp_ntp_rec;
/**
- * 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
{
@@ -154,18 +155,18 @@ struct pjmedia_rtcp_session
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. */
};
/**
@@ -219,17 +220,33 @@ PJ_DECL(void) pjmedia_rtcp_tx_rtp( pjmedia_rtcp_session *session,
/**
- * Build a RTCP SR/RR packet to be transmitted to remote RTP peer.
- * @param session The session.
+ * 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 rtcp_pkt [output] Upon return, it will contain pointer to the
+ * @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);
/**
diff --git a/pjmedia/src/pjmedia/rtcp.c b/pjmedia/src/pjmedia/rtcp.c
index 3ce2783e..bb5666e9 100644
--- a/pjmedia/src/pjmedia/rtcp.c
+++ b/pjmedia/src/pjmedia/rtcp.c
@@ -18,31 +18,42 @@
*/
#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>
#define RTCP_SR 200
#define RTCP_RR 201
-#define USE_TIMESTAMP PJ_HAS_HIGH_RES_TIMER
+#if PJ_HAS_HIGH_RES_TIMER==0
+# error "High resolution timer needs to be enabled"
+#endif
/*
* 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;
}
@@ -59,7 +70,7 @@ PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *s,
/* 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 */
rtcp_pkt->common.version = 2;
@@ -71,13 +82,12 @@ PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *s,
rtcp_pkt->sr.ssrc = pj_htonl(ssrc);
/* 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)
{
/* Nothing to do. */
@@ -87,8 +97,8 @@ PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *session)
static void rtcp_init_seq(pjmedia_rtcp_session *s, pj_uint16_t seq)
{
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;
@@ -99,6 +109,7 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *s,
pj_uint16_t seq,
pj_uint32_t rtp_ts)
{
+ pj_timestamp ts;
pj_uint32_t arrival;
pj_int32_t transit;
int status;
@@ -116,45 +127,27 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *s,
++s->received;
/*
- * 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;
if (s->transit == 0) {
s->transit = transit;
} else {
- pj_int32_t d, jitter = s->jitter;
+ pj_int32_t d;
d = transit - s->transit;
s->transit = transit;
if (d < 0)
d = -d;
- jitter += d - ((jitter + 8) >> 4);
- s->jitter = jitter;
+ s->jitter += d - ((s->jitter + 8) >> 4);
}
}
@@ -162,10 +155,66 @@ PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *s,
pj_uint16_t bytes_payload_size)
{
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,
pj_uint32_t receiver_ssrc)
{
@@ -184,19 +233,18 @@ static void rtcp_build_rtcp(pjmedia_rtcp_session *s,
rtcp_pkt->rr.jitter = pj_htonl(s->jitter >> 4);
/* 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;
rtcp_pkt->rr.total_lost_0 = u32 & 0x00FF;
/* Fraction lost calculation */
- expected_interval = expected - s->expected_prior;
- s->expected_prior = expected;
+ expected_interval = expected - s->exp_prior;
+ s->exp_prior = expected;
- received_interval = s->received - s->received_prior;
- s->received_prior = s->received;
+ received_interval = s->received - s->rx_prior;
+ s->rx_prior = s->received;
lost_interval = expected_interval - received_interval;
@@ -213,22 +261,21 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *session,
{
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. */
rtcp_pkt->sr.ntp_sec = pj_htonl(ntp.hi);
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.
LSR is the middle 32bit of the last SR NTP time received.
@@ -240,13 +287,19 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *session,
/* Fill in DLSR.
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;
*len = sizeof(pjmedia_rtcp_pkt);
}
+ \ No newline at end of file
diff --git a/pjsip-apps/src/samples/siprtp.c b/pjsip-apps/src/samples/siprtp.c
index d80656a5..c7764499 100644
--- a/pjsip-apps/src/samples/siprtp.c
+++ b/pjsip-apps/src/samples/siprtp.c
@@ -1113,6 +1113,9 @@ static int media_thread(void *arg)
} else {
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);
}
}
@@ -1524,6 +1527,8 @@ static void print_call(int call_index)
""
);
+ printf(" End to end delay: %u ms\n", audio->rtcp.ee_delay);
+
}