📄 rtcp.c
字号:
/* $Id: rtcp.c 974 2007-02-19 01:13:53Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjmedia/rtcp.h>#include <pjmedia/errno.h>#include <pj/assert.h>#include <pj/log.h>#include <pj/os.h>#include <pj/sock.h>#include <pj/string.h>#define THIS_FILE "rtcp.c"#define RTCP_SR 200#define RTCP_RR 201#if PJ_HAS_HIGH_RES_TIMER==0# error "High resolution timer needs to be enabled"#endif#if 0# define TRACE_(x) PJ_LOG(3,x)#else# define TRACE_(x) ;#endif/* * Get NTP time. */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 JAN_1970 (2208988800UL) pj_timestamp ts; pj_status_t status; status = pj_get_timestamp(&ts); /* 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 + JAN_1970; /* Calculate seconds fractions */ ts.u64 %= sess->ts_freq.u64; pj_assert(ts.u64 < sess->ts_freq.u64); ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64; /* Fill up the low 32bit part */ ntp->lo = ts.u32.lo;#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \ (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0) /* On Win32, since we use QueryPerformanceCounter() as the backend * timestamp API, we need to protect against this bug: * Performance counter value may unexpectedly leap forward * http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323 */ { /* * Compare elapsed time reported by timestamp with actual elapsed * time. If the difference is too excessive, then we use system * time instead. */ /* MIN_DIFF needs to be large enough so that "normal" diff caused * by system activity or context switch doesn't trigger the time * correction. */ enum { MIN_DIFF = 400 }; pj_time_val ts_time, elapsed, diff; pj_gettimeofday(&elapsed); 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); if (PJ_TIME_VAL_LT(ts_time, elapsed)) { diff = elapsed; PJ_TIME_VAL_SUB(diff, ts_time); } else { diff = ts_time; PJ_TIME_VAL_SUB(diff, elapsed); } if (PJ_TIME_VAL_MSEC(diff) >= MIN_DIFF) { TRACE_((sess->name, "RTCP NTP timestamp corrected by %d ms", PJ_TIME_VAL_MSEC(diff))); ntp->hi = elapsed.sec + sess->tv_base.sec + JAN_1970; ntp->lo = (elapsed.msec * 65536 / 1000) << 16; } }#endif return status;}PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *sess, char *name, unsigned clock_rate, unsigned samples_per_frame, pj_uint32_t ssrc){ pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; pj_time_val now; /* Memset everything */ pj_bzero(sess, sizeof(pjmedia_rtcp_session)); /* Last RX timestamp in RTP packet */ sess->rtp_last_ts = (unsigned)-1; /* Name */ sess->name = name ? name : THIS_FILE, /* Set clock rate */ sess->clock_rate = clock_rate; sess->pkt_size = samples_per_frame; /* Init common RTCP header */ rtcp_pkt->common.version = 2; rtcp_pkt->common.count = 1; rtcp_pkt->common.pt = RTCP_SR; rtcp_pkt->common.length = pj_htons(12); /* Init SR */ rtcp_pkt->sr.ssrc = pj_htonl(ssrc); /* Get time and timestamp base and frequency */ pj_gettimeofday(&now); sess->tv_base = now; sess->stat.start = now; pj_get_timestamp(&sess->ts_base); pj_get_timestamp_freq(&sess->ts_freq); /* RR will be initialized on receipt of the first RTP packet. */}PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess){ /* Nothing to do. */ PJ_UNUSED_ARG(sess);}static void rtcp_init_seq(pjmedia_rtcp_session *sess){ sess->received = 0; sess->exp_prior = 0; sess->rx_prior = 0; sess->transit = 0; sess->jitter = 0;}PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess, unsigned seq, unsigned rtp_ts, unsigned payload){ pj_timestamp ts; pj_uint32_t arrival; pj_int32_t transit; pjmedia_rtp_status seq_st; unsigned last_seq; if (sess->stat.rx.pkt == 0) { /* Init sequence for the first time. */ pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq); } sess->stat.rx.pkt++; sess->stat.rx.bytes += payload; /* Process the RTP packet. */ last_seq = sess->seq_ctrl.max_seq; pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st); if (seq_st.status.flag.restart) { rtcp_init_seq(sess); } if (seq_st.status.flag.dup) { sess->stat.rx.dup++; TRACE_((sess->name, "Duplicate packet detected")); } if (seq_st.status.flag.outorder && !seq_st.status.flag.probation) { sess->stat.rx.reorder++; TRACE_((sess->name, "Out-of-order packet detected")); } if (seq_st.status.flag.bad) { sess->stat.rx.discard++; TRACE_((sess->name, "Bad packet discarded")); return; } /* Only mark "good" packets */ ++sess->received; /* Calculate loss periods. */ if (seq_st.diff > 1) { unsigned count = seq_st.diff - 1; unsigned period; 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); TRACE_((sess->name, "%d packet(s) lost", seq_st.diff - 1)); /* Update loss period stat */ if (sess->stat.rx.loss_period.count == 0 || period < sess->stat.rx.loss_period.min) { sess->stat.rx.loss_period.min = period; } if (period > sess->stat.rx.loss_period.max) sess->stat.rx.loss_period.max = period; sess->stat.rx.loss_period.avg = (sess->stat.rx.loss_period.avg * sess->stat.rx.loss_period.count + period) / (sess->stat.rx.loss_period.count + 1); sess->stat.rx.loss_period.last = period; ++sess->stat.rx.loss_period.count; } /* * Calculate jitter only when sequence is good (see RFC 3550 section A.8), * AND only when the timestamp is different than the last packet * (see RTP FAQ). */ if (seq_st.diff == 1 && rtp_ts != sess->rtp_last_ts) { /* Get arrival time and convert timestamp to samples */ pj_get_timestamp(&ts); ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64; arrival = ts.u32.lo; transit = arrival - rtp_ts; /* Ignore the first N packets as they normally have bad jitter * due to other threads working to establish the call */ if (sess->transit == 0 || sess->received < PJMEDIA_RTCP_IGNORE_FIRST_PACKETS) { sess->transit = transit; sess->stat.rx.jitter.min = 2000; } else { pj_int32_t d; pj_uint32_t jitter; d = transit - sess->transit; sess->transit = transit; if (d < 0) d = -d; sess->jitter += d - ((sess->jitter + 8) >> 4); /* Get jitter in usec */ if (d < 4294) jitter = d * 1000000 / sess->clock_rate; else { jitter = d * 1000 / sess->clock_rate; jitter *= 1000; } /* Add to average */ sess->avg_jitter = (jitter + sess->avg_jitter * sess->stat.rx.jitter.count) / (sess->stat.rx.jitter.count + 1); sess->stat.rx.jitter.avg = (unsigned)sess->avg_jitter; ++sess->stat.rx.jitter.count; /* Update jitter stat */ if (jitter < sess->stat.rx.jitter.min) sess->stat.rx.jitter.min = jitter; if (jitter > sess->stat.rx.jitter.max) sess->stat.rx.jitter.max = jitter; sess->stat.rx.jitter.last = jitter; } } /* Update timestamp of last RX RTP packet */ sess->rtp_last_ts = rtp_ts;}PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess, unsigned bytes_payload_size){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -