📄 rtcp.c
字号:
/* Update statistics */ sess->stat.tx.pkt++; sess->stat.tx.bytes += bytes_payload_size;}PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess, const void *pkt, pj_size_t size){ 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; /* 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); 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); /* Calculate SR arrival time for DLSR */ pj_get_timestamp(&sess->rx_lsr_time); 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 = (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. */ if (sess->stat.tx.loss > last_loss) { unsigned period; /* Loss period in msec */ period = (sess->stat.tx.loss - last_loss) * sess->pkt_size * 1000 / sess->clock_rate; /* Loss period in usec */ period *= 1000; if (sess->stat.tx.update_cnt==0||sess->stat.tx.loss_period.min==0) sess->stat.tx.loss_period.min = period; if (period < sess->stat.tx.loss_period.min) sess->stat.tx.loss_period.min = period; if (period > sess->stat.tx.loss_period.max) sess->stat.tx.loss_period.max = period; sess->stat.tx.loss_period.avg = (sess->stat.tx.loss_period.avg*sess->stat.tx.update_cnt+period) / (sess->stat.tx.update_cnt + 1); sess->stat.tx.loss_period.last = period; } /* Get jitter value in usec */ jitter_samp = pj_ntohl(rr->jitter); /* Calculate jitter in usec, avoiding overflows */ if (jitter_samp <= 4294) jitter = jitter_samp * 1000000 / sess->clock_rate; else { jitter = jitter_samp * 1000 / sess->clock_rate; jitter *= 1000; } /* Update jitter statistics */ if (sess->stat.tx.jitter.count == 0) sess->stat.tx.jitter.min = jitter; if (jitter < sess->stat.tx.jitter.min && jitter) sess->stat.tx.jitter.min = jitter; if (jitter > sess->stat.tx.jitter.max) sess->stat.tx.jitter.max = jitter; sess->stat.tx.jitter.avg = (sess->stat.tx.jitter.avg * sess->stat.tx.jitter.count + jitter) / (sess->stat.tx.jitter.count + 1); ++sess->stat.tx.jitter.count; sess->stat.tx.jitter.last = jitter; /* Can only calculate if LSR and DLSR is present in RR */ if (rr->lsr && rr->dlsr) { pj_uint32_t lsr, now, dlsr; pj_uint64_t eedelay; pjmedia_rtcp_ntp_rec ntp; /* LSR is the middle 32bit of NTP. It has 1/65536 second * resolution */ lsr = pj_ntohl(rr->lsr); /* DLSR is delay since LSR, also in 1/65536 resolution */ dlsr = pj_ntohl(rr->dlsr); /* Get current time, and convert to 1/65536 resolution */ pjmedia_rtcp_get_ntp_time(sess, &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 usec (keeping the calculation in * 64bit space):: * sess->ee_delay = (eedelay * 1000) / 65536; */ if (eedelay < 4294) { eedelay = (eedelay * 1000000) >> 16; } else { eedelay = (eedelay * 1000) >> 16; eedelay *= 1000; } TRACE_((sess->name, "Rx RTCP RR: lsr=%p, dlsr=%p (%d:%03dms), " "now=%p, rtt=%p", lsr, dlsr, dlsr/65536, (dlsr%65536)*1000/65536, now, (pj_uint32_t)eedelay)); /* Only save calculation if "now" is greater than lsr, or * otherwise rtt will be invalid */ if (now-dlsr >= lsr) { unsigned rtt = (pj_uint32_t)eedelay; /* Check that eedelay value really makes sense. * We allow up to 30 seconds RTT! */ if (eedelay > 30 * 1000 * 1000UL) { 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) sess->stat.rtt.max = rtt; sess->stat.rtt.avg = (sess->stat.rtt.avg * sess->stat.rtt_update_cnt + rtt) / (sess->stat.rtt_update_cnt + 1); sess->stat.rtt.last = rtt; sess->stat.rtt_update_cnt++; } else { PJ_LOG(5, (sess->name, "Internal RTCP NTP clock skew detected: " "lsr=%p, now=%p, dlsr=%p (%d:%03dms), " "diff=%d", lsr, now, dlsr, dlsr/65536, (dlsr%65536)*1000/65536, dlsr-(now-lsr))); } }end_rtt_calc: pj_gettimeofday(&sess->stat.tx.update); sess->stat.tx.update_cnt++;}PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess, pjmedia_rtcp_pkt **ret_p_pkt, int *len){ pj_uint32_t expected, expected_interval, received_interval, lost_interval; pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; pj_timestamp ts_now; pjmedia_rtcp_ntp_rec ntp; /* Packet count */ rtcp_pkt->sr.sender_pcount = pj_htonl(sess->stat.tx.pkt); /* Octets count */ rtcp_pkt->sr.sender_bcount = pj_htonl(sess->stat.tx.bytes); /* SSRC and last_seq */ rtcp_pkt->rr.ssrc = pj_htonl(sess->peer_ssrc); rtcp_pkt->rr.last_seq = (sess->seq_ctrl.cycles & 0xFFFF0000L); rtcp_pkt->rr.last_seq += sess->seq_ctrl.max_seq; rtcp_pkt->rr.last_seq = pj_htonl(rtcp_pkt->rr.last_seq); /* Jitter */ rtcp_pkt->rr.jitter = pj_htonl(sess->jitter >> 4); /* Total lost. */ expected = pj_ntohl(rtcp_pkt->rr.last_seq) - sess->seq_ctrl.base_seq; /* This is bug: total lost already calculated on each incoming RTP! 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); /* Fraction lost calculation */ expected_interval = expected - sess->exp_prior; sess->exp_prior = expected; received_interval = sess->received - sess->rx_prior; sess->rx_prior = sess->received; lost_interval = expected_interval - received_interval; if (expected_interval==0 || lost_interval == 0) { rtcp_pkt->rr.fract_lost = 0; } else { rtcp_pkt->rr.fract_lost = (lost_interval << 8) / expected_interval; } /* Get current NTP time. */ pj_get_timestamp(&ts_now); pjmedia_rtcp_get_ntp_time(sess, &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); TRACE_((sess->name, "TX RTCP SR: ntp_ts=%p", ((ntp.hi & 0xFFFF) << 16) + ((ntp.lo & 0xFFFF0000) >> 16))); if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) { rtcp_pkt->rr.lsr = 0; rtcp_pkt->rr.dlsr = 0; } else { pj_timestamp ts; pj_uint32_t lsr = sess->rx_lsr; pj_uint64_t lsr_time = sess->rx_lsr_time.u64; pj_uint32_t dlsr; /* Convert LSR time to 1/65536 seconds resolution */ lsr_time = (lsr_time << 16) / sess->ts_freq.u64; /* Fill in LSR. LSR is the middle 32bit of the last SR NTP time received. */ rtcp_pkt->rr.lsr = pj_htonl(lsr); /* Fill in DLSR. DLSR is Delay since Last SR, in 1/65536 seconds. */ ts.u64 = ts_now.u64; /* Convert interval to 1/65536 seconds value */ ts.u64 = (ts.u64 << 16) / sess->ts_freq.u64; /* Get DLSR */ dlsr = (pj_uint32_t)(ts.u64 - lsr_time); rtcp_pkt->rr.dlsr = pj_htonl(dlsr); TRACE_((sess->name,"Tx RTCP RR: lsr=%p, lsr_time=%p, now=%p, dlsr=%p" "(%ds:%03dms)", lsr, (pj_uint32_t)lsr_time, (pj_uint32_t)ts.u64, dlsr, dlsr/65536, (dlsr%65536)*1000/65536 )); } /* Update counter */ pj_gettimeofday(&sess->stat.rx.update); sess->stat.rx.update_cnt++; /* Return pointer. */ *ret_p_pkt = rtcp_pkt; *len = sizeof(pjmedia_rtcp_pkt);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -