diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-04-05 12:53:42 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-04-05 12:53:42 +0000 |
commit | b314eb0d0223a4c629b8c5a97877a413f1e14e3d (patch) | |
tree | 395a62b3e570e7f9c69272a2e06445c564b769da | |
parent | ee48033d397909ffc4d88048f8a1f3d0dd62a2a6 (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.h | 57 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/rtcp.c | 161 | ||||
-rw-r--r-- | pjsip-apps/src/samples/siprtp.c | 5 |
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); + } |