⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtcp.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $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 + -