[svn-commits] blanchet: branch blanchet/v6 r60454 - /team/blanchet/v6/main/rtp.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Fri Apr 6 09:19:42 MST 2007


Author: blanchet
Date: Fri Apr  6 11:19:41 2007
New Revision: 60454

URL: http://svn.digium.com/view/asterisk?view=rev&rev=60454
Log:
- new definitions of ast_virtp routines and definitions for IP version independe
nt routines.  vi = version independent. This means it supports both IPv4 and IPv6 transport.
- see README-IPV6.txt to see the reasoning on why duplicating code and using ano
ther namespace: it enables incremental conversion of channels to IPv6. But has d
rawbacks.
- note well: this RTP code was tested successfully over both Ipv4 and Ipv6, but 
with a full blown 2000 tests setup. So use at your own risk...


Modified:
    team/blanchet/v6/main/rtp.c

Modified: team/blanchet/v6/main/rtp.c
URL: http://svn.digium.com/view/asterisk/team/blanchet/v6/main/rtp.c?view=diff&rev=60454&r1=60453&r2=60454
==============================================================================
--- team/blanchet/v6/main/rtp.c (original)
+++ team/blanchet/v6/main/rtp.c Fri Apr  6 11:19:41 2007
@@ -24,6 +24,13 @@
  * \author Mark Spencer <markster at digium.com>
  * 
  * \note RTP is defined in RFC 3550.
+ *
+ * New versions of rtp/rtcp routines for IP version independence(IPv4 and IPv6)
+ * new routines start with ast_virtp, ast_virtcp
+ * vi = version independent
+ * For IPv6 port:
+ * \author Marc Blanchet <marc.blanchet at viagenie.ca>
+ * \author Frederick Lefebvre <frederick.lefebvre at viagenie.ca>
  */
 
 #include "asterisk.h"
@@ -664,7 +671,6 @@
 	}
 	return 1;
 }
-
 
 static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *data, int len)
 {
@@ -3580,6 +3586,12 @@
 	stun_no_debug, NULL,
 	NULL };
 
+/* temporary forward declaration for IP version independent */
+static int virtp_do_debug(int fd, int argc, char *argv[]);
+static int virtp_do_debug_ip(int fd, int argc, char *argv[]);
+static int virtcp_do_debug(int fd, int argc, char *argv[]);
+static int virtcp_do_debug_ip(int fd, int argc, char *argv[]);
+
 static struct ast_cli_entry cli_rtp[] = {
 	{ { "rtp", "debug", "ip", NULL },
 	rtp_do_debug, "Enable RTP debugging on IP",
@@ -3620,6 +3632,23 @@
 	{ { "stun", "debug", "off", NULL },
 	stun_no_debug, "Disable STUN debugging",
 	stun_no_debug_usage, NULL, &cli_stun_no_debug_deprecated },
+
+/* temporary separate cli entries to debug ipv6 */
+	{ { "rtp", "videbug", "ip", NULL }, 
+	virtp_do_debug, "Enable RTP debugging on IP", 
+	debug_usage },
+
+	{ { "rtp", "videbug", NULL }, 
+	virtp_do_debug, "Enable RTP debugging", 
+	debug_usage },
+
+	{ { "rtp", "rtcp", "videbug", "ip", NULL }, 
+	virtcp_do_debug, "Enable RTCP debugging on IP", 
+	rtcp_debug_usage },
+
+	{ { "rtp", "rtcp", "videbug", NULL }, 
+	virtcp_do_debug, "Enable RTCP debugging", 
+	rtcp_debug_usage },
 };
 
 int ast_rtp_reload(void)
@@ -3693,3 +3722,3068 @@
 	ast_rtp_reload();
 }
 
+/* IP version independent (IPv4 and IPv6) version of RTP 
+ * using a new namespace to avoid conflict with current code
+ * so any channel and module can transition to IPv6 one at a time.
+ * duplicate code however is not automatically synched with changes in ast_rtp
+ *
+ * \author Marc Blanchet <marc.blanchet at viagenie.ca>
+ * \author Frederick Lefebvre/ <frederick.lefebvre at viagenie.ca>
+ * Copyright (C) 2006, Viagenie, Inc.
+ */
+
+#include "asterisk/netsock.h"
+
+static struct sockaddr_storage virtpdebugaddr;	/*!< Debug packets to/from this host */
+static socklen_t virtpdebugaddr_len = 0;
+static struct sockaddr_storage virtcpdebugaddr;	/*!< Debug RTCP packets to/from this host */
+static socklen_t virtcpdebugaddr_len = 0;
+
+/*! \brief RTP session description */
+struct ast_virtp {
+	int s;
+	struct ast_frame f;
+	unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
+	unsigned int ssrc;		/*!< Synchronization source, RFC 3550, page 10. */
+	unsigned int themssrc;		/*!< Their SSRC */
+	unsigned int rxssrc;
+	unsigned int lastts;
+	unsigned int lastrxts;
+	unsigned int lastividtimestamp;
+	unsigned int lastovidtimestamp;
+	unsigned int lasteventseqn;
+	int lastrxseqno;                /*!< Last received sequence number */
+	unsigned short seedrxseqno;     /*!< What sequence number did they start with?*/
+	unsigned int seedrxts;          /*!< What RTP timestamp did they start with? */
+	unsigned int rxcount;           /*!< How many packets have we received? */
+	unsigned int rxoctetcount;      /*!< How many octets have we received? should be rxcount *160*/
+	unsigned int txcount;           /*!< How many packets have we sent? */
+	unsigned int txoctetcount;      /*!< How many octets have we sent? (txcount*160)*/
+	unsigned int cycles;            /*!< Shifted count of sequence number cycles */
+	double rxjitter;                /*!< Interarrival jitter at the moment */
+	double rxtransit;               /*!< Relative transit time for previous packet */
+	int lasttxformat;
+	int lastrxformat;
+
+	int rtptimeout;		/*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
+	int rtpholdtimeout;	/*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
+	int rtpkeepalive;	/*!< Send RTP comfort noice packets for keepalive */
+
+	/* DTMF Reception Variables */
+	char resp;
+	unsigned int lasteventendseqn;
+	int dtmfcount;
+	unsigned int dtmfduration;
+	/* DTMF Transmission Variables */
+	unsigned int lastdigitts;
+	char send_digit;
+	int send_payload;
+	int send_duration;
+	int nat;
+	unsigned int flags;
+	struct sockaddr_storage us;	/*!< Socket representation of the local endpoint. */
+	socklen_t us_len;
+	struct sockaddr_storage them;	/*!< Socket representation of the remote endpoint. */
+	socklen_t them_len;
+	struct timeval rxcore;
+	struct timeval txcore;
+	double drxcore;                 /*!< The double representation of the first received packet */
+	struct timeval lastrx;          /*!< timeval when we last received a packet */
+	struct timeval dtmfmute;
+	struct ast_smoother *smoother;
+	int *ioid;
+	unsigned short seqno;		/*!< Sequence number, RFC 3550, page 13. */
+	unsigned short rxseqno;
+	struct sched_context *sched;
+	struct io_context *io;
+	void *data;
+	ast_virtp_callback callback;
+	ast_mutex_t bridge_lock;
+	struct rtpPayloadType current_RTP_PT[MAX_RTP_PT];
+	int rtp_lookup_code_cache_isAstFormat; /*!< a cache for the result of rtp_lookup_code(): */
+	int rtp_lookup_code_cache_code;
+	int rtp_lookup_code_cache_result;
+	struct ast_virtcp *rtcp;
+	struct ast_codec_pref pref;
+	struct ast_virtp *bridged;        /*!< Who we are Packet bridged to */
+};
+
+/* Forward declarations */
+static int ast_virtcp_write(void *data);
+static int ast_virtcp_write_sr(void *data);
+static int ast_virtcp_write_rr(void *data);
+static unsigned int ast_virtcp_calc_interval(struct ast_virtp *rtp);
+static int ast_virtp_senddigit_continuation(struct ast_virtp *rtp);
+int ast_virtp_senddigit_end(struct ast_virtp *rtp, char digit);
+static int bridge_p2p_virtcp_write(struct ast_virtp *rtp, unsigned int *rtcpheader, int len);
+
+struct ast_virtcp {
+	int s;				/*!< Socket */
+	struct sockaddr_storage us;	/*!< Socket representation of the local endpoint. */
+	socklen_t us_len;
+	struct sockaddr_storage them;	/*!< Socket representation of the remote endpoint. */
+	socklen_t them_len;
+	unsigned int soc;		/*!< What they told us */
+	unsigned int spc;		/*!< What they told us */
+	unsigned int themrxlsr;		/*!< The middle 32 bits of the NTP timestamp in the last received SR*/
+	struct timeval rxlsr;		/*!< Time when we got their last SR */
+	struct timeval txlsr;		/*!< Time when we sent or last SR*/
+	unsigned int expected_prior;	/*!< no. packets in previous interval */
+	unsigned int received_prior;	/*!< no. packets received in previous interval */
+	int schedid;			/*!< Schedid returned from ast_sched_add() to schedule RTCP-transmissions*/
+	unsigned int rr_count;		/*!< number of RRs we've sent, not including report blocks in SR's */
+	unsigned int sr_count;		/*!< number of SRs we've sent */
+	unsigned int lastsrtxcount;     /*!< Transmit packet count when last SR sent */
+	double accumulated_transit;	/*!< accumulated a-dlsr-lsr */
+	double rtt;			/*!< Last reported rtt */
+	unsigned int reported_jitter;	/*!< The contents of their last jitter entry in the RR */
+	unsigned int reported_lost;	/*!< Reported lost packets in their RR */
+	char quality[AST_MAX_USER_FIELD];
+	double maxrxjitter;
+	double minrxjitter;
+	double maxrtt;
+	double minrtt;
+	int sendfur;
+};
+
+
+/* to be verified:
+struct stun_addr {
+	unsigned int addr;
+static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
+static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
+void ast_virtp_stun_request(struct ast_virtp *rtp, struct sockaddr_in *suggestion, const char *username)
+*/
+static AST_LIST_HEAD_STATIC(viprotos, ast_virtp_protocol);
+
+size_t ast_virtp_alloc_size(void)
+{
+        return sizeof(struct ast_virtp);
+}
+
+static int vistun_handle_packet(int s, struct sockaddr *src, socklen_t srclen,
+			      unsigned char *data, size_t len)
+{
+	struct stun_header *resp, *hdr = (struct stun_header *)data;
+	struct stun_attr *attr;
+	struct stun_state st;
+	int ret = STUN_IGNORE;	
+	unsigned char respdata[1024];
+	int resplen, respleft;
+	
+	if (len < sizeof(struct stun_header)) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Runt STUN packet (only %zd, wanting at least %zd)\n", len, sizeof(struct stun_header));
+		return -1;
+	}
+	if (!ast_vinetsock_sa_is_ipv4((struct sockaddr*)src))
+		return ret;
+	if (stundebug)
+		ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), ntohs(hdr->msglen));
+	if (ntohs(hdr->msglen) > len - sizeof(struct stun_header)) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Scrambled STUN packet length (got %d, expecting %zd)\n", ntohs(hdr->msglen), len - sizeof(struct stun_header));
+	} else
+		len = ntohs(hdr->msglen);
+	data += sizeof(struct stun_header);
+	memset(&st, 0, sizeof(st));
+	while(len) {
+		if (len < sizeof(struct stun_attr)) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Runt Attribute (got %zd, expecting %zd)\n", len, sizeof(struct stun_attr));
+			break;
+		}
+		attr = (struct stun_attr *)data;
+		if (ntohs(attr->len) > len) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Inconsistent Attribute (length %d exceeds remaining msg len %zd)\n", ntohs(attr->len), len);
+			break;
+		}
+		if (stun_process_attr(&st, attr)) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
+			break;
+		}
+		/* Clear attribute in case previous entry was a string */
+		attr->attr = 0;
+		data += ntohs(attr->len) + sizeof(struct stun_attr);
+		len -= ntohs(attr->len) + sizeof(struct stun_attr);
+	}
+	/* Null terminate any string */
+	*data = '\0';
+	resp = (struct stun_header *)respdata;
+	resplen = 0;
+	respleft = sizeof(respdata) - sizeof(struct stun_header);
+	resp->id = hdr->id;
+	resp->msgtype = 0;
+	resp->msglen = 0;
+	attr = (struct stun_attr *)resp->ies;
+	if (!len) {
+		switch(ntohs(hdr->msgtype)) {
+		case STUN_BINDREQ:
+			if (stundebug)
+				ast_verbose("STUN Bind Request, username: %s\n", 
+					st.username ? st.username : "<none>");
+			if (st.username)
+				append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
+			append_attr_address(&attr, STUN_MAPPED_ADDRESS, (struct sockaddr_in*)src, &resplen, &respleft);
+			resp->msglen = htons(resplen);
+			resp->msgtype = htons(STUN_BINDRESP);
+			stun_send(s, (struct sockaddr_in*)src, resp);
+			ret = STUN_ACCEPT;
+			break;
+		default:
+			if (stundebug)
+				ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
+		}
+	}
+	return ret;
+}
+
+int ast_virtp_fd(struct ast_virtp *rtp)
+{
+	return rtp->s;
+}
+
+int ast_virtcp_fd(struct ast_virtp *rtp)
+{
+	if (rtp->rtcp)
+		return rtp->rtcp->s;
+	return -1;
+}
+
+unsigned int ast_virtcp_calc_interval(struct ast_virtp *rtp)
+{
+	unsigned int interval;
+	/*! \todo XXX Do a more reasonable calculation on this one
+	* Look in RFC 3550 Section A.7 for an example*/
+	interval = rtcpinterval;
+	return interval;
+}
+
+/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
+void ast_virtp_set_rtptimers_onhold(struct ast_virtp *rtp)
+{
+        rtp->rtptimeout = (-1) * rtp->rtptimeout;
+        rtp->rtpholdtimeout = (-1) * rtp->rtpholdtimeout;
+}
+
+/*! \brief Set rtp timeout */
+void ast_virtp_set_rtptimeout(struct ast_virtp *rtp, int timeout)
+{
+        rtp->rtptimeout = timeout;
+}
+
+/*! \brief Set rtp hold timeout */
+void ast_virtp_set_rtpholdtimeout(struct ast_virtp *rtp, int timeout)
+{
+        rtp->rtpholdtimeout = timeout;
+}
+
+
+/*! \brief set RTP keepalive interval */
+void ast_virtp_set_rtpkeepalive(struct ast_virtp *rtp, int period)
+{
+	rtp->rtpkeepalive = period;
+}
+
+/*! \brief Get rtp timeout */
+int ast_virtp_get_rtptimeout(struct ast_virtp *rtp)
+{
+	if (rtp->rtptimeout < 0)	/* We're not checking, but remembering the setting (during T.38 transmission) */
+		return 0;
+	return rtp->rtptimeout;
+}
+
+/*! \brief Get rtp hold timeout */
+int ast_virtp_get_rtpholdtimeout(struct ast_virtp *rtp)
+{
+	if (rtp->rtptimeout < 0)	/* We're not checking, but remembering the setting (during T.38 transmission) */
+		return 0;
+	return rtp->rtpholdtimeout;
+}
+
+/*! \brief Get RTP keepalive interval */
+int ast_virtp_get_rtpkeepalive(struct ast_virtp *rtp)
+{
+	return rtp->rtpkeepalive;
+}
+
+void ast_virtp_set_data(struct ast_virtp *rtp, void *data)
+{
+	rtp->data = data;
+}
+
+void ast_virtp_set_callback(struct ast_virtp *rtp, ast_virtp_callback callback)
+{
+	rtp->callback = callback;
+}
+
+void ast_virtp_setnat(struct ast_virtp *rtp, int nat)
+{
+	rtp->nat = nat;
+}
+
+
+int ast_virtp_getnat(struct ast_virtp *rtp)
+{
+	return ast_test_flag(rtp, FLAG_NAT_ACTIVE);
+}
+
+void ast_virtp_setdtmf(struct ast_virtp *rtp, int dtmf)
+{
+	ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF);
+}
+
+void ast_virtp_setdtmfcompensate(struct ast_virtp *rtp, int compensate)
+{
+	ast_set2_flag(rtp, compensate ? 1 : 0, FLAG_DTMF_COMPENSATE);
+}
+
+static struct ast_frame *visend_dtmf(struct ast_virtp *rtp, enum ast_frame_type type)
+{
+	char hostport[NI_MAXHOST];
+
+	ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->them,
+				      rtp->them_len, hostport, sizeof(NI_MAXHOST));
+	if (((ast_test_flag(rtp, FLAG_DTMF_COMPENSATE) && type == AST_FRAME_DTMF_END) ||
+	     (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", hostport);
+		rtp->resp = 0;
+		rtp->dtmfduration = 0;
+		return &ast_null_frame;
+	}
+	if (option_debug)
+		ast_log(LOG_DEBUG, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, hostport);
+	if (rtp->resp == 'X') {
+		rtp->f.frametype = AST_FRAME_CONTROL;
+		rtp->f.subclass = AST_CONTROL_FLASH;
+	} else {
+		rtp->f.frametype = type;
+		rtp->f.subclass = rtp->resp;
+	}
+	rtp->f.datalen = 0;
+	rtp->f.samples = 0;
+	rtp->f.mallocd = 0;
+	rtp->f.src = "RTP";
+	return &rtp->f;
+	
+}
+
+static inline int virtp_debug_test_addr(struct sockaddr *addr, socklen_t addrlen)
+{
+	if (rtpdebug == 0)
+		return 0;
+	if (virtpdebugaddr_len) {
+		if (((ast_vinetsock_sa_getport((struct sockaddr*)&virtpdebugaddr, 
+					       virtpdebugaddr_len) != 0)
+		     && ast_vinetsock_sacmp_port((struct sockaddr*)&virtpdebugaddr, 
+						 virtpdebugaddr_len, addr, addrlen))
+		    || ast_vinetsock_sacmp((struct sockaddr*)&virtpdebugaddr, 
+					   virtpdebugaddr_len, addr, addrlen,1))
+		return 0;
+	}
+	return 1;
+}
+
+static inline int virtcp_debug_test_addr(struct sockaddr *addr, socklen_t addrlen)
+{
+	if (rtcpdebug == 0)
+		return 0;
+	if (virtcpdebugaddr_len) {
+		if (((ast_vinetsock_sa_getport((struct sockaddr*)&virtcpdebugaddr, 
+					       virtcpdebugaddr_len) != 0)
+		     && ast_vinetsock_sacmp_port((struct sockaddr*)&virtcpdebugaddr, 
+						 virtcpdebugaddr_len, addr, addrlen))
+		    || ast_vinetsock_sacmp((struct sockaddr*)&virtcpdebugaddr, 
+					   virtcpdebugaddr_len, addr, addrlen,1))
+		return 0;
+	}
+	return 1;
+}
+
+
+static struct ast_frame *viprocess_cisco_dtmf(struct ast_virtp *rtp, unsigned char *data, int len)
+{
+	unsigned int event;
+	char resp = 0;
+	struct ast_frame *f = NULL;
+	event = ntohl(*((unsigned int *)(data)));
+	event &= 0x001F;
+	if (option_debug > 2 || rtpdebug)
+		ast_log(LOG_DEBUG, "Cisco DTMF Digit: %08x (len = %d)\n", event, len);
+	if (event < 10) {
+		resp = '0' + event;
+	} else if (event < 11) {
+		resp = '*';
+	} else if (event < 12) {
+		resp = '#';
+	} else if (event < 16) {
+		resp = 'A' + (event - 12);
+	} else if (event < 17) {
+		resp = 'X';
+	}
+	if (rtp->resp && (rtp->resp != resp)) {
+		f = visend_dtmf(rtp, AST_FRAME_DTMF_END);
+	}
+	rtp->resp = resp;
+	rtp->dtmfcount = dtmftimeout;
+	return f;
+}
+
+/*! 
+ * \brief Process RTP DTMF and events according to RFC 2833.
+ * 
+ * RFC 2833 is "RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals".
+ * 
+ * \param rtp
+ * \param data
+ * \param len
+ * \param seqno
+ * \returns
+ */
+static struct ast_frame *viprocess_rfc2833(struct ast_virtp *rtp, unsigned char *data, int len, unsigned int seqno)
+{
+	unsigned int event;
+	unsigned int event_end;
+	unsigned int duration;
+	char resp = 0;
+	struct ast_frame *f = NULL;
+
+	/* Figure out event, event end, and duration */
+	event = ntohl(*((unsigned int *)(data)));
+	event >>= 24;
+	event_end = ntohl(*((unsigned int *)(data)));
+	event_end <<= 8;
+	event_end >>= 24;
+	duration = ntohl(*((unsigned int *)(data)));
+	duration &= 0xFFFF;
+
+	/* Print out debug if turned on */
+	if (rtpdebug || option_debug > 2)
+		ast_log(LOG_DEBUG, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
+
+	/* Figure out what digit was pressed */
+	if (event < 10) {
+		resp = '0' + event;
+	} else if (event < 11) {
+		resp = '*';
+	} else if (event < 12) {
+		resp = '#';
+	} else if (event < 16) {
+		resp = 'A' + (event - 12);
+	} else if (event < 17) {	/* Event 16: Hook flash */
+		resp = 'X';	
+	}
+
+	if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
+		rtp->resp = resp;
+		if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE))
+			f = visend_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+	} else if (event_end & 0x80 && rtp->lasteventendseqn != seqno && rtp->resp) {
+		f = visend_dtmf(rtp, AST_FRAME_DTMF_END);
+		f->samples = duration;
+		rtp->resp = 0;
+		rtp->lasteventendseqn = seqno;
+	}
+
+	rtp->dtmfcount = dtmftimeout;
+	rtp->dtmfduration = duration;
+
+	return f;
+}
+
+/*!
+ * \brief Process Comfort Noise RTP.
+ * 
+ * This is incomplete at the moment.
+ * 
+*/
+static struct ast_frame *viprocess_rfc3389(struct ast_virtp *rtp, unsigned char *data, int len)
+{
+	struct ast_frame *f = NULL;
+	char iabuf[NI_MAXHOST];
+
+	/* Convert comfort noise into audio with various codecs.  Unfortunately this doesn't
+	   totally help us out becuase we don't have an engine to keep it going and we are not
+	   guaranteed to have it every 20ms or anything */
+	if (rtpdebug)
+		ast_log(LOG_DEBUG, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", rtp->lastrxformat, len);
+
+	if (!(ast_test_flag(rtp, FLAG_3389_WARNING))) {
+		ast_vinetsock_sa_getaddr((struct sockaddr*)&rtp->them, 
+					 rtp->them_len, iabuf, sizeof(iabuf));
+		ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s\n",
+			iabuf);
+		ast_set_flag(rtp, FLAG_3389_WARNING);
+	}
+
+	/* Must have at least one byte */
+	if (!len)
+		return NULL;
+	if (len < 24) {
+		rtp->f.data = rtp->rawdata + AST_FRIENDLY_OFFSET;
+		rtp->f.datalen = len - 1;
+		rtp->f.offset = AST_FRIENDLY_OFFSET;
+		memcpy(rtp->f.data, data + 1, len - 1);
+	} else {
+		rtp->f.data = NULL;
+		rtp->f.offset = 0;
+		rtp->f.datalen = 0;
+	}
+	rtp->f.frametype = AST_FRAME_CNG;
+	rtp->f.subclass = data[0] & 0x7f;
+	rtp->f.datalen = len - 1;
+	rtp->f.samples = 0;
+	rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
+	f = &rtp->f;
+	return f;
+}
+
+static int virtpread(int *id, int fd, short events, void *cbdata)
+{
+	struct ast_virtp *rtp = cbdata;
+	struct ast_frame *f;
+	f = ast_virtp_read(rtp);
+	if (f) {
+		if (rtp->callback)
+			rtp->callback(rtp, f, rtp->data);
+	}
+	return 1;
+}
+
+struct ast_frame *ast_virtcp_read(struct ast_virtp *rtp)
+{
+	int position, i, packetwords;
+	int res;
+	struct sockaddr_storage sin;
+	socklen_t sinlen;
+	unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
+	unsigned int *rtcpheader;
+	int pt;
+	struct timeval now;
+	unsigned int length;
+	int rc;
+	double rtt = 0;
+	double a;
+	double dlsr;
+	double lsr;
+	unsigned int msw;
+	unsigned int lsw;
+	unsigned int comp;
+	struct ast_frame *f = &ast_null_frame;
+	char hostport[NI_MAXHOST];
+	
+	if (!rtp || !rtp->rtcp)
+		return &ast_null_frame;
+
+	sinlen = sizeof(sin);
+	
+	res = recvfrom(rtp->rtcp->s, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
+					0, (struct sockaddr *)&sin, &sinlen);
+	rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
+	
+	if (res < 0) {
+		if (errno != EAGAIN)
+			ast_log(LOG_WARNING, "RTCP Read error: %s\n", strerror(errno));
+		if (errno == EBADF)
+			CRASH;
+		return &ast_null_frame;
+	}
+
+	packetwords = res / 4;
+	
+	if (rtp->nat) {
+		/* Send to whoever sent to us */
+		if (ast_vinetsock_sacmp((struct sockaddr*)&rtp->rtcp->them, 
+					rtp->rtcp->them_len, (struct sockaddr*)&sin, 
+					sinlen, 0)) {
+			memcpy(&rtp->rtcp->them, &sin, sinlen);
+			if (option_debug || rtpdebug) {
+				ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->rtcp->them,
+							      rtp->rtcp->them_len, hostport,
+							      sizeof(hostport));
+				ast_log(LOG_DEBUG, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", 
+					hostport);
+			}
+		}
+	}
+
+	/* If we are P2P bridged to another RTP stream, send it directly over */
+	if (ast_virtp_get_bridged(rtp) && !bridge_p2p_virtcp_write(rtp, rtcpheader, res))
+		return &ast_null_frame;
+
+	if (option_debug)
+		ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
+
+	/* Process a compound packet */
+	position = 0;
+	while (position < packetwords) {
+		i = position;
+		length = ntohl(rtcpheader[i]);
+		pt = (length & 0xff0000) >> 16;
+		rc = (length & 0x1f000000) >> 24;
+		length &= 0xffff;
+    
+		if ((i + length) > packetwords) {
+			ast_log(LOG_WARNING, "RTCP Read too short\n");
+			return &ast_null_frame;
+		}
+		
+		if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen)) {
+			ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->rtcp->them,
+						      rtp->rtcp->them_len, hostport,
+						      sizeof(hostport));
+		  	ast_verbose("\n\nGot RTCP from %s\n", hostport);
+		  	ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
+		  	ast_verbose("Reception reports: %d\n", rc);
+		  	ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
+		}
+    
+		i += 2; /* Advance past header and ssrc */
+		
+		switch (pt) {
+		case RTCP_PT_SR:
+			gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
+			rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
+			rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
+			rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff) >> 16); /* Going to LSR in RR*/
+    
+			if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen)) {
+				ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
+				ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
+				ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
+			}
+			i += 5;
+			if (rc < 1)
+				break;
+			/* Intentional fall through */
+		case RTCP_PT_RR:
+			/* This is the place to calculate RTT */
+			/* Don't handle multiple reception reports (rc > 1) yet */
+			gettimeofday(&now, NULL);
+			timeval2ntp(now, &msw, &lsw);
+			/* Use the one we sent them in our SR instead, rtcp->txlsr could have been rewritten if the dlsr is large */
+			if (ntohl(rtcpheader[i + 4])) { /* We must have the LSR */
+				comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
+				a = (double)((comp & 0xffff0000) >> 16) + (double)((double)(comp & 0xffff)/1000000.);
+				lsr = (double)((ntohl(rtcpheader[i + 4]) & 0xffff0000) >> 16) + (double)((double)(ntohl(rtcpheader[i + 4]) & 0xffff) / 1000000.);
+				dlsr = (double)(ntohl(rtcpheader[i + 5])/65536.);
+				rtt = a - dlsr - lsr;
+				rtp->rtcp->accumulated_transit += rtt;
+				rtp->rtcp->rtt = rtt;
+				if (rtp->rtcp->maxrtt<rtt)
+					rtp->rtcp->maxrtt = rtt;
+				if (rtp->rtcp->minrtt>rtt)
+				rtp->rtcp->minrtt = rtt;
+			}
+			rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
+			rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
+			if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen)) {
+				ast_verbose("Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
+				ast_verbose("Packets lost so far: %d\n", rtp->rtcp->reported_lost);
+				ast_verbose("Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
+				ast_verbose("Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16);
+				ast_verbose("Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
+				ast_verbose("Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
+				ast_verbose("DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
+				if (rtt)
+					ast_verbose("RTT: %f(sec)\n", rtt);
+			}
+			break;
+		case RTCP_PT_FUR:
+		  if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen))
+				ast_verbose("Received an RTCP Fast Update Request\n");
+			rtp->f.frametype = AST_FRAME_CONTROL;
+			rtp->f.subclass = AST_CONTROL_VIDUPDATE;
+			rtp->f.datalen = 0;
+			rtp->f.samples = 0;
+			rtp->f.mallocd = 0;
+			rtp->f.src = "RTP";
+			f = &rtp->f;
+			break;
+		case RTCP_PT_SDES:
+			ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->rtcp->them,
+						      rtp->rtcp->them_len, hostport,
+						      sizeof(hostport));
+			if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen))
+				ast_verbose("Received an SDES from %s\n", hostport);
+			break;
+		case RTCP_PT_BYE:
+			ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->rtcp->them,
+						      rtp->rtcp->them_len, hostport,
+						      sizeof(hostport));
+			if (virtcp_debug_test_addr((struct sockaddr*)&sin, sinlen))
+				ast_verbose("Received a BYE from %s\n", hostport);
+			break;
+		default:
+			ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->rtcp->them,
+						      rtp->rtcp->them_len, hostport,
+						      sizeof(hostport));
+			ast_log(LOG_NOTICE, "Unknown RTCP packet (pt=%d) received from %s\n",
+				pt, hostport);
+			break;
+		}
+		position += (length + 1);
+	}
+			
+	return f;
+}
+
+static void vicalc_rxstamp(struct timeval *tv, struct ast_virtp *rtp, unsigned int timestamp, int mark)
+{
+	struct timeval now;
+	double transit;
+	double current_time;
+	double d;
+	double dtv;
+	double prog;
+	
+	if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
+		gettimeofday(&rtp->rxcore, NULL);
+		rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
+		/* map timestamp to a real time */
+		rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
+		rtp->rxcore.tv_sec -= timestamp / 8000;
+		rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
+		/* Round to 0.1ms for nice, pretty timestamps */
+		rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
+		if (rtp->rxcore.tv_usec < 0) {
+			/* Adjust appropriately if necessary */
+			rtp->rxcore.tv_usec += 1000000;
+			rtp->rxcore.tv_sec -= 1;
+		}
+	}
+
+	gettimeofday(&now,NULL);
+	/* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
+	tv->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
+	tv->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec += 1;
+	}
+	prog = (double)((timestamp-rtp->seedrxts)/8000.);
+	dtv = (double)rtp->drxcore + (double)(prog);
+	current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;
+	transit = current_time - dtv;
+	d = transit - rtp->rxtransit;
+	rtp->rxtransit = transit;
+	if (d<0)
+		d=-d;
+	rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
+	if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
+		rtp->rtcp->maxrxjitter = rtp->rxjitter;
+	if (rtp->rxjitter < rtp->rtcp->minrxjitter)
+		rtp->rtcp->minrxjitter = rtp->rxjitter;
+}
+
+/*! \brief Perform a Packet2Packet RTCP write */
+static int bridge_p2p_virtcp_write(struct ast_virtp *rtp, unsigned int *rtcpheader, int len)
+{
+	struct ast_virtp *bridged = ast_virtp_get_bridged(rtp);
+	int res = 0;
+	char hostport[NI_MAXHOST];
+
+	/* If RTCP is not present on the bridged RTP session, then ignore this */
+	if (!bridged->rtcp)
+		return 0;
+
+	/* Send the data out */
+	res = sendto(bridged->rtcp->s, (void *)rtcpheader, len, 0, (struct sockaddr *)&bridged->rtcp->them, bridged->rtcp->them_len);
+	ast_vinetsock_sa_get_hostport((struct sockaddr*)&bridged->rtcp->them, 
+				      bridged->rtcp->them_len, hostport, sizeof(hostport));
+	if (res < 0) {
+		if (!bridged->nat || (bridged->nat && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE)))
+			ast_log(LOG_DEBUG, "RTCP Transmission error of packet to %s: %s\n", hostport, strerror(errno));
+		else if ((((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug)) && (option_debug || rtpdebug))
+			ast_log(LOG_DEBUG, "RTCP NAT: Can't write RTCP to private address %s, waiting for other end to send first...\n", hostport);
+	} else if (virtp_debug_test_addr((struct sockaddr*)&bridged->rtcp->them, bridged->rtcp->them_len))
+		ast_verbose("Sent RTCP P2P packet to %s (len %-6.6u)\n", hostport, len);
+
+	return 0;
+}
+
+/*! \brief Perform a Packet2Packet RTP write */
+static int bridge_p2p_virtp_write(struct ast_virtp *rtp, unsigned int *rtpheader, int len, int hdrlen)
+{
+	struct ast_virtp *bridged = ast_virtp_get_bridged(rtp);
+	int res = 0, payload = 0, bridged_payload = 0, version, padding, mark, ext;
+	struct rtpPayloadType rtpPT;
+	unsigned int seqno;
+	char hostport[NI_MAXHOST];
+
+	/* Get fields from packet */
+	seqno = ntohl(rtpheader[0]);
+	version = (seqno & 0xC0000000) >> 30;
+	payload = (seqno & 0x7f0000) >> 16;
+	padding = seqno & (1 << 29);
+	mark = seqno & (1 << 23);
+	ext = seqno & (1 << 28);
+	seqno &= 0xffff;
+
+	/* Check what the payload value should be */
+	rtpPT = ast_virtp_lookup_pt(rtp, payload);
+
+	/* If the payload is DTMF, and we are listening for DTMF - then feed it into the core */
+	if (ast_test_flag(rtp, FLAG_P2P_NEED_DTMF) && !rtpPT.isAstFormat && rtpPT.code == AST_RTP_DTMF)
+		return -1;
+
+	/* Otherwise adjust bridged payload to match */
+	bridged_payload = ast_virtp_lookup_code(bridged, rtpPT.isAstFormat, rtpPT.code);
+
+	/* If the mark bit has not been sent yet... do it now */
+	if (!ast_test_flag(rtp, FLAG_P2P_SENT_MARK)) {
+		mark = 1;
+		ast_set_flag(rtp, FLAG_P2P_SENT_MARK);
+	}
+
+	/* Reconstruct part of the packet */
+	rtpheader[0] = htonl((version << 30) | (mark << 23) | (bridged_payload << 16) | (seqno));
+
+	/* Send the packet back out */
+	res = sendto(bridged->s, (void *)rtpheader, len, 0, (struct sockaddr *)&bridged->them, bridged->them_len);
+	ast_vinetsock_sa_get_hostport((struct sockaddr*)&bridged->them, 
+				      bridged->them_len, hostport, sizeof(hostport));
+	if (res < 0) {
+		if (!bridged->nat || (bridged->nat && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
+			ast_log(LOG_DEBUG, "RTP Transmission error of packet to %s: %s\n", hostport, strerror(errno));
+		} else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
+			if (option_debug || rtpdebug)
+				ast_log(LOG_DEBUG, "RTP NAT: Can't write RTP to private address %s, waiting for other end to send audio...\n", hostport);
+			ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
+		}
+		return -1;
+	} else if (virtp_debug_test_addr((struct sockaddr*)&bridged->them, bridged->them_len))
+			ast_verbose("Sent RTP P2P packet to %s (type %-2.2d, len %-6.6u)\n", hostport, bridged_payload, len - hdrlen);
+
+	return -1;
+}
+
+struct ast_frame *ast_virtp_read(struct ast_virtp *rtp)
+{
+	int res;
+	struct sockaddr_storage sin;
+	socklen_t sinlen;
+	unsigned int seqno;
+	int version;
+	int payloadtype;
+	int tseqno;
+	int hdrlen = 12;
+	int padding;
+	int mark;
+	int ext;
+	unsigned int ssrc;
+	unsigned int timestamp;
+	unsigned int *rtpheader;
+	struct rtpPayloadType rtpPT;
+	char hostport[NI_MAXHOST];
+	
+	/* If time is up, kill it */
+	if (rtp->send_digit)
+		ast_virtp_senddigit_continuation(rtp);
+
+	sinlen = sizeof(sin);
+	
+	/* Cache where the header will go */
+	res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
+					0, (struct sockaddr *)&sin, &sinlen);
+
+	rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
+	if (res < 0) {
+		if (errno != EAGAIN)
+			ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
+		if (errno == EBADF)
+			CRASH;
+		return &ast_null_frame;
+	}
+	
+	if (res < hdrlen) {
+		ast_log(LOG_WARNING, "RTP Read too short\n");
+		return &ast_null_frame;
+	}
+
+	/* Get fields */
+	seqno = ntohl(rtpheader[0]);
+
+	/* Check RTP version */
+	version = (seqno & 0xC0000000) >> 30;
+	if (!version) {
+		if ((vistun_handle_packet(rtp->s, (struct sockaddr*)&sin, sinlen, rtp->rawdata + AST_FRIENDLY_OFFSET, res) == STUN_ACCEPT) &&
+		    (!rtp->them_len)) {
+			memcpy(&rtp->them, &sin, sizeof(rtp->them));
+			rtp->them_len = sinlen;
+		}
+		return &ast_null_frame;
+	}
+
+	/* If we don't have the other side's address, then ignore this */
+	if (!rtp->them_len)
+		return &ast_null_frame;
+
+	/* Send to whoever send to us if NAT is turned on */
+	if (rtp->nat) {
+		if (ast_vinetsock_sacmp((struct sockaddr*)&rtp->them, rtp->them_len, 
+					(struct sockaddr*)&sin, sinlen, 0)) {
+			memcpy(&rtp->them, &sin, sinlen);
+			rtp->them_len = sinlen;
+			if (rtp->rtcp) {
+				int port = 0;
+				memcpy(&rtp->rtcp->them, &sin, sinlen);
+				rtp->rtcp->them_len = sinlen;
+				port = ast_vinetsock_sa_getport((struct sockaddr*)&sin,
+								sinlen);
+				ast_vinetsock_sa_setport((struct sockaddr*)&rtp->rtcp->them,
+							 ++port);
+			}
+			rtp->rxseqno = 0;
+			ast_set_flag(rtp, FLAG_NAT_ACTIVE);
+			if (option_debug || rtpdebug) {
+				ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->them,
+							      rtp->them_len, hostport,
+							      sizeof(hostport));
+				ast_log(LOG_DEBUG, "RTP NAT: Got audio from other end. Now sending to address %s\n", hostport);
+			}
+		}
+	}
+
+	/* If we are bridged to another RTP stream, send direct */
+	if (ast_virtp_get_bridged(rtp) && !bridge_p2p_virtp_write(rtp, rtpheader, res, hdrlen))
+		return &ast_null_frame;
+
+	if (version != 2)
+		return &ast_null_frame;
+
+	payloadtype = (seqno & 0x7f0000) >> 16;
+	padding = seqno & (1 << 29);
+	mark = seqno & (1 << 23);
+	ext = seqno & (1 << 28);
+	seqno &= 0xffff;
+	timestamp = ntohl(rtpheader[1]);
+	ssrc = ntohl(rtpheader[2]);
+	
+	if (!mark && rtp->rxssrc && rtp->rxssrc != ssrc) {
+		if (option_debug || rtpdebug)
+			ast_log(LOG_DEBUG, "Forcing Marker bit, because SSRC has changed\n");
+		mark = 1;
+	}
+
+	rtp->rxssrc = ssrc;
+	
+	if (padding) {
+		/* Remove padding bytes */
+		res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
+	}
+	
+	if (ext) {
+		/* RTP Extension present */
+		hdrlen += 4;
+		hdrlen += (ntohl(rtpheader[3]) & 0xffff) << 2;
+	}
+
+	if (res < hdrlen) {
+		ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d)\n", res, hdrlen);
+		return &ast_null_frame;
+	}
+
+	rtp->rxcount++; /* Only count reasonably valid packets, this'll make the rtcp stats more accurate */
+
+	tseqno = rtp->lastrxseqno +1;
+
+	if (rtp->rxcount==1) {
+		/* This is the first RTP packet successfully received from source */
+		rtp->seedrxseqno = seqno;
+	}
+
+	if (rtp->rtcp && rtp->rtcp->schedid < 1) {
+		/* Schedule transmission of Receiver Report */
+		rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_virtcp_calc_interval(rtp), ast_virtcp_write, rtp);
+	}
+
+	if (tseqno > RTP_SEQ_MOD) { /* if tseqno is greater than RTP_SEQ_MOD it would indicate that the sender cycled */
+		rtp->cycles += RTP_SEQ_MOD;
+		ast_verbose("SEQNO cycled: %u\t%d\n", rtp->cycles, seqno);
+	}
+
+	rtp->lastrxseqno = seqno;
+	
+	if (rtp->themssrc==0)
+		rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
+	
+	if (virtp_debug_test_addr((struct sockaddr*)&sin, sinlen)) {
+		ast_vinetsock_sa_get_hostport((struct sockaddr*)&sin,
+					      sinlen, hostport,
+					      sizeof(hostport));
+		ast_verbose("Got  RTP packet from    %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+			hostport, payloadtype, seqno, timestamp,res - hdrlen);
+	}
+	rtpPT = ast_virtp_lookup_pt(rtp, payloadtype);
+	if (!rtpPT.isAstFormat) {
+		struct ast_frame *f = NULL;
+
+		/* This is special in-band data that's not one of our codecs */
+		if (rtpPT.code == AST_RTP_DTMF) {
+			/* It's special -- rfc2833 process it */
+			if (virtp_debug_test_addr((struct sockaddr*)&sin, sinlen)) {
+				unsigned char *data;
+				unsigned int event;
+				unsigned int event_end;
+				unsigned int duration;
+				char* hostport = ast_calloc(1, NI_MAXHOST);
+				ast_vinetsock_sa_get_hostport((struct sockaddr*)&sin,
+							      sinlen, hostport,
+							      sizeof(hostport));
+				data = rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen;
+				event = ntohl(*((unsigned int *)(data)));
+				event >>= 24;
+				event_end = ntohl(*((unsigned int *)(data)));
+				event_end <<= 8;
+				event_end >>= 24;
+				duration = ntohl(*((unsigned int *)(data)));
+				duration &= 0xFFFF;
+				ast_verbose("Got  RTP RFC2833 from   %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n",
+					    hostport, payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
+			}
+			if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
+				f = viprocess_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno);
+				rtp->lasteventseqn = seqno;
+			}
+		} else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
+			/* It's really special -- process it the Cisco way */
+			if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
+				f = viprocess_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+				rtp->lasteventseqn = seqno;
+			}
+		} else if (rtpPT.code == AST_RTP_CN) {
+			/* Comfort Noise */
+			f = viprocess_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+		} else {
+			char* hostport = ast_calloc(1, NI_MAXHOST);
+			ast_vinetsock_sa_get_hostport((struct sockaddr*)&rtp->them,
+						      rtp->them_len, hostport,
+						      sizeof(hostport));
+			ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, hostport);
+		}
+		return f ? f : &ast_null_frame;
+	}
+	rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
+	rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : AST_FRAME_VIDEO;
+
+	if (!rtp->lastrxts)
+		rtp->lastrxts = timestamp;
+
+	rtp->rxseqno = seqno;
+
+	/* Record received timestamp as last received now */
+	rtp->lastrxts = timestamp;
+
+	rtp->f.mallocd = 0;
+	rtp->f.datalen = res - hdrlen;

[... 2008 lines stripped ...]


More information about the svn-commits mailing list