📄 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 + -