Fixed several bugs in RTCP and tested the compatibility. Fixed bugs: total lost byte order, RTCP RR parsing, normalizing large RTT, RX pkt lost online update.
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@427 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
b17c93b3c5
commit
27071e301e
|
@ -70,9 +70,9 @@ struct pjmedia_rtcp_rr
|
|||
pj_uint32_t total_lost_0:8; /**< Total lost, bit 0-7. */
|
||||
#else
|
||||
pj_uint32_t fract_lost:8; /**< Fraction lost. */
|
||||
pj_uint32_t total_lost_0:8; /**< Total lost, bit 0-7. */
|
||||
pj_uint32_t total_lost_2:8; /**< Total lost, bit 0-7. */
|
||||
pj_uint32_t total_lost_1:8; /**< Total lost, bit 8-15. */
|
||||
pj_uint32_t total_lost_2:8; /**< Total lost, bit 16-23. */
|
||||
pj_uint32_t total_lost_0:8; /**< Total lost, bit 16-23. */
|
||||
#endif
|
||||
pj_uint32_t last_seq; /**< Last sequence number. */
|
||||
pj_uint32_t jitter; /**< Jitter. */
|
||||
|
@ -111,7 +111,9 @@ struct pjmedia_rtcp_common
|
|||
typedef struct pjmedia_rtcp_common pjmedia_rtcp_common;
|
||||
|
||||
/**
|
||||
* RTCP packet.
|
||||
* This structure declares default RTCP packet (SR) that is sent by pjmedia.
|
||||
* Incoming RTCP packet may have different format, and must be parsed
|
||||
* manually by application.
|
||||
*/
|
||||
struct pjmedia_rtcp_pkt
|
||||
{
|
||||
|
|
|
@ -50,7 +50,7 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
|
|||
pjmedia_rtcp_ntp_rec *ntp)
|
||||
{
|
||||
/* Seconds between 1900-01-01 to 1970-01-01 */
|
||||
#define NTP_DIFF ((70 * 365 + 17) * 86400UL)
|
||||
#define JAN_1970 (2208988800UL)
|
||||
pj_timestamp ts;
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -58,7 +58,7 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
|
|||
|
||||
/* Fill up the high 32bit part */
|
||||
ntp->hi = (pj_uint32_t)((ts.u64 - sess->ts_base.u64) / sess->ts_freq.u64)
|
||||
+ sess->tv_base.sec + NTP_DIFF;
|
||||
+ sess->tv_base.sec + JAN_1970;
|
||||
|
||||
/* Calculate seconds fractions */
|
||||
ts.u64 %= sess->ts_freq.u64;
|
||||
|
@ -94,7 +94,7 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
|
|||
|
||||
pj_gettimeofday(&elapsed);
|
||||
|
||||
ts_time.sec = ntp->hi - sess->tv_base.sec - NTP_DIFF;
|
||||
ts_time.sec = ntp->hi - sess->tv_base.sec - JAN_1970;
|
||||
ts_time.msec = (long)(ntp->lo * 1000.0 / 0xFFFFFFFF);
|
||||
|
||||
PJ_TIME_VAL_SUB(elapsed, sess->tv_base);
|
||||
|
@ -113,7 +113,7 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
|
|||
PJ_TIME_VAL_MSEC(diff)));
|
||||
|
||||
|
||||
ntp->hi = elapsed.sec + sess->tv_base.sec + NTP_DIFF;
|
||||
ntp->hi = elapsed.sec + sess->tv_base.sec + JAN_1970;
|
||||
ntp->lo = (elapsed.msec * 65536 / 1000) << 16;
|
||||
}
|
||||
|
||||
|
@ -216,6 +216,9 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Only mark "good" packets */
|
||||
++sess->received;
|
||||
|
||||
/* Calculate loss periods. */
|
||||
if (seq_st.diff > 1) {
|
||||
unsigned count = seq_st.diff - 1;
|
||||
|
@ -224,6 +227,12 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess,
|
|||
period = count * sess->pkt_size * 1000 / sess->clock_rate;
|
||||
period *= 1000;
|
||||
|
||||
/* Update packet lost.
|
||||
* The packet lost number will also be updated when we're sending
|
||||
* outbound RTCP RR.
|
||||
*/
|
||||
sess->stat.rx.loss += (seq_st.diff - 1);
|
||||
|
||||
/* Update loss period stat */
|
||||
if (sess->stat.rx.loss_period.count == 0 ||
|
||||
period < sess->stat.rx.loss_period.min)
|
||||
|
@ -240,10 +249,6 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess,
|
|||
}
|
||||
|
||||
|
||||
/* Only mark "good" packets */
|
||||
++sess->received;
|
||||
|
||||
|
||||
/*
|
||||
* Calculate jitter only when sequence is good (see RFC 3550 section A.8)
|
||||
*/
|
||||
|
@ -303,34 +308,53 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
const void *pkt,
|
||||
pj_size_t size)
|
||||
{
|
||||
const struct pjmedia_rtcp_pkt *rtcp = pkt;
|
||||
const pjmedia_rtcp_common *common = pkt;
|
||||
const pjmedia_rtcp_rr *rr = NULL;
|
||||
const pjmedia_rtcp_sr *sr = NULL;
|
||||
pj_uint32_t last_loss, jitter_samp, jitter;
|
||||
|
||||
/* Must at least contain SR */
|
||||
pj_assert(size >= sizeof(pjmedia_rtcp_common)+sizeof(pjmedia_rtcp_sr));
|
||||
/* Parse RTCP */
|
||||
if (common->pt == RTCP_SR) {
|
||||
sr = (pjmedia_rtcp_sr*) (((char*)pkt) + sizeof(pjmedia_rtcp_common));
|
||||
if (common->count > 0 && size >= (sizeof(pjmedia_rtcp_pkt))) {
|
||||
rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common)
|
||||
+ sizeof(pjmedia_rtcp_sr)));
|
||||
}
|
||||
} else if (common->pt == RTCP_RR && common->count > 0)
|
||||
rr = (pjmedia_rtcp_rr*)(((char*)pkt) +sizeof(pjmedia_rtcp_common) +4);
|
||||
|
||||
/* Save LSR from NTP timestamp of RTCP packet */
|
||||
sess->rx_lsr = ((pj_ntohl(rtcp->sr.ntp_sec) & 0x0000FFFF) << 16) |
|
||||
((pj_ntohl(rtcp->sr.ntp_frac) >> 16) & 0xFFFF);
|
||||
|
||||
/* Calculate SR arrival time for DLSR */
|
||||
pj_get_timestamp(&sess->rx_lsr_time);
|
||||
if (sr) {
|
||||
/* Save LSR from NTP timestamp of RTCP packet */
|
||||
sess->rx_lsr = ((pj_ntohl(sr->ntp_sec) & 0x0000FFFF) << 16) |
|
||||
((pj_ntohl(sr->ntp_frac) >> 16) & 0xFFFF);
|
||||
|
||||
TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p",
|
||||
sess->rx_lsr,
|
||||
(pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64)));
|
||||
/* Calculate SR arrival time for DLSR */
|
||||
pj_get_timestamp(&sess->rx_lsr_time);
|
||||
|
||||
/* Nothing more to do if this is an SR only RTCP packet */
|
||||
if (size < sizeof(pjmedia_rtcp_pkt))
|
||||
TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p",
|
||||
sess->rx_lsr,
|
||||
(pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64)));
|
||||
}
|
||||
|
||||
|
||||
/* Nothing more to do if there's no RR packet */
|
||||
if (rr == NULL)
|
||||
return;
|
||||
|
||||
|
||||
|
||||
last_loss = sess->stat.tx.loss;
|
||||
|
||||
/* Get packet loss */
|
||||
sess->stat.tx.loss = (rtcp->rr.total_lost_2 << 16) +
|
||||
(rtcp->rr.total_lost_1 << 8) +
|
||||
rtcp->rr.total_lost_0;
|
||||
sess->stat.tx.loss = (rr->total_lost_2 << 16) +
|
||||
(rr->total_lost_1 << 8) +
|
||||
rr->total_lost_0;
|
||||
|
||||
TRACE_((sess->name, "Rx RTCP RR: total_lost_2=%x, 1=%x, 0=%x, lost=%d",
|
||||
(int)rr->total_lost_2,
|
||||
(int)rr->total_lost_1,
|
||||
(int)rr->total_lost_0,
|
||||
sess->stat.tx.loss));
|
||||
|
||||
/* We can't calculate the exact loss period for TX, so just give the
|
||||
* best estimation.
|
||||
|
@ -359,7 +383,7 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
}
|
||||
|
||||
/* Get jitter value in usec */
|
||||
jitter_samp = pj_ntohl(rtcp->rr.jitter);
|
||||
jitter_samp = pj_ntohl(rr->jitter);
|
||||
/* Calculate jitter in usec, avoiding overflows */
|
||||
if (jitter_samp <= 4294)
|
||||
jitter = jitter_samp * 1000000 / sess->clock_rate;
|
||||
|
@ -382,7 +406,7 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
|
||||
|
||||
/* Can only calculate if LSR and DLSR is present in RR */
|
||||
if (rtcp->rr.lsr && rtcp->rr.dlsr) {
|
||||
if (rr->lsr && rr->dlsr) {
|
||||
pj_uint32_t lsr, now, dlsr;
|
||||
pj_uint64_t eedelay;
|
||||
pjmedia_rtcp_ntp_rec ntp;
|
||||
|
@ -390,10 +414,10 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
/* LSR is the middle 32bit of NTP. It has 1/65536 second
|
||||
* resolution
|
||||
*/
|
||||
lsr = pj_ntohl(rtcp->rr.lsr);
|
||||
lsr = pj_ntohl(rr->lsr);
|
||||
|
||||
/* DLSR is delay since LSR, also in 1/65536 resolution */
|
||||
dlsr = pj_ntohl(rtcp->rr.dlsr);
|
||||
dlsr = pj_ntohl(rr->dlsr);
|
||||
|
||||
/* Get current time, and convert to 1/65536 resolution */
|
||||
pjmedia_rtcp_get_ntp_time(sess, &ntp);
|
||||
|
@ -424,18 +448,32 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
if (now-dlsr >= lsr) {
|
||||
unsigned rtt = (pj_uint32_t)eedelay;
|
||||
|
||||
TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
|
||||
/* Check that eedelay value really makes sense.
|
||||
* We allow up to 30 seconds RTT!
|
||||
*/
|
||||
if (eedelay > 30 * 1000 * 1000UL) {
|
||||
|
||||
if (rtt >= 1000000) {
|
||||
pjmedia_rtcp_ntp_rec ntp2;
|
||||
pj_thread_sleep(50);
|
||||
pjmedia_rtcp_get_ntp_time(sess, &ntp2);
|
||||
ntp2.lo = ntp2.lo;
|
||||
TRACE_((sess->name, "RTT not making any sense, ignored.."));
|
||||
goto end_rtt_calc;
|
||||
}
|
||||
|
||||
if (sess->stat.rtt_update_cnt == 0)
|
||||
sess->stat.rtt.min = rtt;
|
||||
|
||||
/* "Normalize" rtt value that is exceptionally high.
|
||||
* For such values, "normalize" the rtt to be three times
|
||||
* the average value.
|
||||
*/
|
||||
if (rtt > (sess->stat.rtt.avg*3) && sess->stat.rtt_update_cnt!=0) {
|
||||
unsigned orig_rtt = rtt;
|
||||
rtt = sess->stat.rtt.avg*3;
|
||||
PJ_LOG(5,(sess->name,
|
||||
"RTT value %d usec is normalized to %d usec",
|
||||
orig_rtt, rtt));
|
||||
}
|
||||
|
||||
TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
|
||||
|
||||
if (rtt < sess->stat.rtt.min && rtt)
|
||||
sess->stat.rtt.min = rtt;
|
||||
if (rtt > sess->stat.rtt.max)
|
||||
|
@ -458,6 +496,8 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
|
|||
}
|
||||
}
|
||||
|
||||
end_rtt_calc:
|
||||
|
||||
pj_gettimeofday(&sess->stat.tx.update);
|
||||
sess->stat.tx.update_cnt++;
|
||||
}
|
||||
|
@ -507,6 +547,9 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,
|
|||
expected = pj_ntohl(rtcp_pkt->rr.last_seq) - sess->seq_ctrl.base_seq;
|
||||
if (expected >= sess->received)
|
||||
sess->stat.rx.loss = expected - sess->received;
|
||||
else
|
||||
sess->stat.rx.loss = 0;
|
||||
|
||||
rtcp_pkt->rr.total_lost_2 = (sess->stat.rx.loss >> 16) & 0xFF;
|
||||
rtcp_pkt->rr.total_lost_1 = (sess->stat.rx.loss >> 8) & 0xFF;
|
||||
rtcp_pkt->rr.total_lost_0 = (sess->stat.rx.loss & 0xFF);
|
||||
|
|
Loading…
Reference in New Issue