[asterisk-commits] blanchet: branch blanchet/v6 r60454 -
/team/blanchet/v6/main/rtp.c
asterisk-commits at lists.digium.com
asterisk-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 asterisk-commits
mailing list