[asterisk-commits] file: branch group/vldtmf r39453 - in /team/group/vldtmf: ./ channels/ includ...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Aug 8 20:44:19 MST 2006


Author: file
Date: Tue Aug  8 22:44:19 2006
New Revision: 39453

URL: http://svn.digium.com/view/asterisk?rev=39453&view=rev
Log:
Put in what I have so far... basically reception from a regular RFC2833 works for shizzle, and sending from regular should as well. Now we just need to compensate!

Modified:
    team/group/vldtmf/channels/chan_sip.c
    team/group/vldtmf/include/asterisk/rtp.h
    team/group/vldtmf/rtp.c

Modified: team/group/vldtmf/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/group/vldtmf/channels/chan_sip.c?rev=39453&r1=39452&r2=39453&view=diff
==============================================================================
--- team/group/vldtmf/channels/chan_sip.c (original)
+++ team/group/vldtmf/channels/chan_sip.c Tue Aug  8 22:44:19 2006
@@ -740,9 +740,10 @@
 #define SIP_PAGE2_CALL_ONHOLD		(3 << 23)	/*!< Call states */
 #define SIP_PAGE2_CALL_ONHOLD_ONEDIR	(1 << 23)	/*!< 23: One directional hold */
 #define SIP_PAGE2_CALL_ONHOLD_INACTIVE	(2 << 24)	/*!< 24: Inactive  */
+#define SIP_PAGE2_RFC2833_COMPENSATE    (1 << 26)
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
-	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT)
+	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE)
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
@@ -2513,12 +2514,14 @@
 			ast_log(LOG_DEBUG, "Setting NAT on RTP to %s\n", natflags ? "On" : "Off");
 		ast_rtp_setnat(r->rtp, natflags);
 		ast_rtp_setdtmf(r->rtp, ast_test_flag(&r->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
+		ast_rtp_setdtmfcompensate(r->rtp, ast_test_flag(&r->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 	}
 	if (r->vrtp) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", natflags ? "On" : "Off");
 		ast_rtp_setnat(r->vrtp, natflags);
 		ast_rtp_setdtmf(r->vrtp, 0);
+		ast_rtp_setdtmfcompensate(r->vrtp, 0);
 	}
 	if (r->udptl) {
 		if (option_debug)
@@ -3437,12 +3440,14 @@
 	struct sip_pvt *p = ast->tech_pvt;
 	int res = 0;
 
-	/* XXX Implement me, plz, kthx */
-
 	ast_mutex_lock(&p->lock);
 	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
 	case SIP_DTMF_INBAND:
 		res = -1; /* Tell Asterisk to generate inband indications */
+		break;
+	case SIP_DTMF_RFC2833:
+		if (p->rtp)
+			ast_rtp_senddigit_begin(p->rtp, digit);
 		break;
 	default:
 		break;
@@ -3466,7 +3471,7 @@
 		break;
 	case SIP_DTMF_RFC2833:
 		if (p->rtp)
-			ast_rtp_senddigit(p->rtp, digit);
+			ast_rtp_senddigit_end(p->rtp, digit);
 		break;
 	case SIP_DTMF_INBAND:
 		res = -1; /* Tell Asterisk to stop inband indications */
@@ -4063,10 +4068,12 @@
 			return NULL;
 		}
 		ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
+		ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 		ast_rtp_settos(p->rtp, global_tos_audio);
 		if (p->vrtp) {
 			ast_rtp_settos(p->vrtp, global_tos_video);
 			ast_rtp_setdtmf(p->vrtp, 0);
+			ast_rtp_setdtmfcompensate(p->vrtp, 0);
 		}
 		if (p->udptl)
 			ast_udptl_settos(p->udptl, global_tos_audio);
@@ -12827,6 +12834,7 @@
 		extract_uri(p, req);			/* Get the Contact URI */
 		build_contact(p);			/* Build our contact header */
 		ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
+		ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 
 		if (!replace_id && gotdest) {	/* No matching extension found */
 			if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) {
@@ -14843,6 +14851,9 @@
 	} else if (!strcasecmp(v->name, "t38pt_tcp")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_TCP);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_TCP);
+	} else if (!strcasecmp(v->name, "rfc2833compensate")) {
+		ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE);
+		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE);
 	}
 
 	return res;

Modified: team/group/vldtmf/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/team/group/vldtmf/include/asterisk/rtp.h?rev=39453&r1=39452&r2=39453&view=diff
==============================================================================
--- team/group/vldtmf/include/asterisk/rtp.h (original)
+++ team/group/vldtmf/include/asterisk/rtp.h Tue Aug  8 22:44:19 2006
@@ -129,7 +129,9 @@
 
 int ast_rtcp_fd(struct ast_rtp *rtp);
 
-int ast_rtp_senddigit(struct ast_rtp *rtp, char digit);
+int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit);
+
+int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
 
 int ast_rtp_sendcng(struct ast_rtp *rtp, int level);
 
@@ -168,6 +170,9 @@
 /*! \brief Indicate whether this RTP session is carrying DTMF or not */
 void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf);
 
+/*! \brief Compensate for devices that send RFC2833 packets all at once */
+void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate);
+
 int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 
 int ast_rtp_proto_register(struct ast_rtp_protocol *proto);

Modified: team/group/vldtmf/rtp.c
URL: http://svn.digium.com/view/asterisk/team/group/vldtmf/rtp.c?rev=39453&r1=39452&r2=39453&view=diff
==============================================================================
--- team/group/vldtmf/rtp.c (original)
+++ team/group/vldtmf/rtp.c Tue Aug  8 22:44:19 2006
@@ -106,14 +106,12 @@
 /*! \brief RTP session description */
 struct ast_rtp {
 	int s;
-	char resp;
 	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 lastdigitts;
 	unsigned int lastrxts;
 	unsigned int lastividtimestamp;
 	unsigned int lastovidtimestamp;
@@ -128,11 +126,18 @@
 	unsigned int cycles;            /*!< Shifted count of sequence number cycles */
 	double rxjitter;                /*!< Interarrival jitter at the moment */
 	double rxtransit;               /*!< Relative transit time for previous packet */
-	unsigned int lasteventendseqn;
 	int lasttxformat;
 	int lastrxformat;
+	/* DTMF Reception Variables */
+	char resp;
+	unsigned int lasteventendseqn;
 	int dtmfcount;
 	unsigned int dtmfduration;
+	/* DTMF Transmission Variables */
+	unsigned int lastdigitts;
+	char send_digit;
+	int send_compensate;
+	int send_payload;
 	int nat;
 	unsigned int flags;
 	struct sockaddr_in us;		/*!< Socket representation of the local endpoint. */
@@ -169,6 +174,7 @@
 #define FLAG_NAT_INACTIVE		(0 << 1)
 #define FLAG_NAT_INACTIVE_NOWARN	(1 << 1)
 #define FLAG_HAS_DTMF			(1 << 3)
+#define FLAG_DTMF_COMPENSATE            (1 << 4)
 
 /*!
  * \brief Structure defining an RTCP session.
@@ -526,7 +532,12 @@
 	ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF);
 }
 
-static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
+void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate)
+{
+	ast_set2_flag(rtp, compensate ? 1 : 0, FLAG_DTMF_COMPENSATE);
+}
+
+static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type)
 {
 	if (ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
 		if (option_debug)
@@ -541,15 +552,13 @@
 		rtp->f.frametype = AST_FRAME_CONTROL;
 		rtp->f.subclass = AST_CONTROL_FLASH;
 	} else {
-		rtp->f.frametype = AST_FRAME_DTMF;
+		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";
-	rtp->resp = 0;
-	rtp->dtmfduration = 0;
 	return &rtp->f;
 	
 }
@@ -602,7 +611,7 @@
 		resp = 'X';
 	}
 	if (rtp->resp && (rtp->resp != resp)) {
-		f = send_dtmf(rtp);
+		f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
 	}
 	rtp->resp = resp;
 	rtp->dtmfcount = dtmftimeout;
@@ -628,6 +637,7 @@
 	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)));
@@ -635,8 +645,12 @@
 	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) {
@@ -648,25 +662,21 @@
 	} else if (event < 17) {	/* Event 16: Hook flash */
 		resp = 'X';	
 	}
-	if (rtp->resp && (rtp->resp != resp)) {
-		f = send_dtmf(rtp);
-	} else if (event_end & 0x80) {
-		if (rtp->resp) {
-			if (rtp->lasteventendseqn != seqno) {
-				f = send_dtmf(rtp);
-				rtp->lasteventendseqn = seqno;
-			}
-			rtp->resp = 0;
-		}
-		resp = 0;
-		duration = 0;
-	} else if (rtp->resp && rtp->dtmfduration && (duration < rtp->dtmfduration)) {
-		f = send_dtmf(rtp);
-	}
-	if (!(event_end & 0x80))
+
+	if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
 		rtp->resp = resp;
+		/* Only actually send an AST_FRAME_DTMF_BEGIN If we are not compensating */
+		if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE))
+			f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+	} else if ((event_end & 0x80) && rtp->resp && rtp->lasteventendseqn != seqno) {
+		rtp->lasteventendseqn = seqno;
+		f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+		rtp->resp = 0;
+	}
+
 	rtp->dtmfcount = dtmftimeout;
 	rtp->dtmfduration = duration;
+
 	return f;
 }
 
@@ -1082,13 +1092,13 @@
 				duration &= 0xFFFF;
 				ast_verbose("Got  RTP RFC2833 from   %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
 			}
-			if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
+			if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
 				f = process_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->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
+			if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
 				f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
 				rtp->lasteventseqn = seqno;
 			}
@@ -1126,8 +1136,9 @@
 	if (rtp->resp && !rtp->dtmfcount) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Sending pending DTMF\n");
-		return send_dtmf(rtp);
-	}
+		return send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+	}
+
 	rtp->f.mallocd = 0;
 	rtp->f.datalen = res - hdrlen;
 	rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
@@ -1862,29 +1873,36 @@
 	return (unsigned int) ms;
 }
 
-int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
+/* Convert DTMF digit into something usable */
+static int digit_convert(char digit)
+{
+	if ((digit <= '9') && (digit >= '0'))
+                digit -= '0';
+        else if (digit == '*')
+                digit = 10;
+        else if (digit == '#')
+                digit = 11;
+        else if ((digit >= 'A') && (digit <= 'D'))
+                digit = digit - 'A' + 12;
+        else if ((digit >= 'a') && (digit <= 'd'))
+                digit = digit - 'a' + 12;
+        else {
+                ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
+                return -1;
+        }
+	return 0;
+}
+
+/*! \brief Send begin frames for DTMF */
+int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit)
 {
 	unsigned int *rtpheader;
-	int hdrlen = 12;
-	int res;
-	int x;
-	int payload;
+	int hdrlen = 12, res = 0, i = 0, payload = 0;
 	char data[256];
 
-	if ((digit <= '9') && (digit >= '0'))
-		digit -= '0';
-	else if (digit == '*')
-		digit = 10;
-	else if (digit == '#')
-		digit = 11;
-	else if ((digit >= 'A') && (digit <= 'D')) 
-		digit = digit - 'A' + 12;
-	else if ((digit >= 'a') && (digit <= 'd')) 
-		digit = digit - 'a' + 12;
-	else {
-		ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
+	if (digit_convert(digit))
 		return -1;
-	}
+
 	payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
 
 	/* If we have no peer, return immediately */	
@@ -1899,7 +1917,8 @@
 	rtpheader[1] = htonl(rtp->lastdigitts);
 	rtpheader[2] = htonl(rtp->ssrc); 
 	rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
-	for (x = 0; x < 6; x++) {
+
+	for (i = 0; i < 2; i++) {
 		if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
 			res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
 			if (res < 0) 
@@ -1911,39 +1930,115 @@
 					    ast_inet_ntoa(rtp->them.sin_addr),
 					    ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
 		}
-		/* Sequence number of last two end packets does not get incremented */
-		if (x < 3)
-			rtp->seqno++;
+		/* Increment sequence number */
+		rtp->seqno++;
 		/* Clear marker bit and set seqno */
 		rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
-		/* For the last three packets, set the duration and the end bit */
-		if (x == 2) {
-#if 0
-			/* No, this is wrong...  Do not increment lastdigitts, that's not according
-			   to the RFC, as best we can determine */
-			rtp->lastdigitts++; /* or else the SPA3000 will click instead of beeping... */
-			rtpheader[1] = htonl(rtp->lastdigitts);
-#endif			
-			/* Make duration 800 (100ms) */
-			rtpheader[3] |= htonl((800));
-			/* Set the End bit */
-			rtpheader[3] |= htonl((1 << 23));
-		}
-	}
-	/*! \note Increment the digit timestamp by 120ms, to ensure that digits
-	   sent sequentially with no intervening non-digit packets do not
-	   get sent with the same timestamp, and that sequential digits
-	   have some 'dead air' in between them
-	*/
-	rtp->lastdigitts += 960;
-	/* Increment the sequence number to reflect the last packet
-	   that was sent
-	*/
+	}
+
+	/* Since we received a begin, we can safely store the digit and disable any compensation */
+	rtp->send_digit = digit;
+	rtp->send_compensate = 0;
+	rtp->send_payload = payload;
+
+	return 0;
+}
+
+/*! \brief Send continuation frame for DTMF */
+static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp)
+{
+	unsigned int *rtpheader;
+	int hdrlen = 12, res = 0;
+	char data[256];
+
+	if (!rtp->them.sin_addr.s_addr)
+		return 0;
+
+	/* Setup packet to send */
+	rtpheader = (unsigned int *)data;
+        rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
+        rtpheader[1] = htonl(rtp->lastdigitts);
+        rtpheader[2] = htonl(rtp->ssrc);
+        rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (0));
+	rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
+	
+	/* Transmit */
+	if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
+		res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+		if (res < 0)
+			ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
+				ast_inet_ntoa(rtp->them.sin_addr),
+				ntohs(rtp->them.sin_port), strerror(errno));
+		if (rtp_debug_test_addr(&rtp->them))
+			ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+				    ast_inet_ntoa(rtp->them.sin_addr),
+				    ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+	}
+
+	/* Increment sequence number */
 	rtp->seqno++;
+
 	return 0;
 }
 
-/* \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
+/*! \brief Send end packets for DTMF */
+int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit)
+{
+	unsigned int *rtpheader;
+	int hdrlen = 12, res = 0, i = 0;
+	char data[256];
+	char original_digit = digit;
+	
+	/* If no address, then bail out */
+	if (!rtp->them.sin_addr.s_addr)
+		return 0;
+	
+	/* Convert our digit to the crazy RTP way */
+	if (digit_convert(digit))
+		return -1;
+
+	/* If no digit was pressed initially, then we need to compensate */
+	if (!rtp->send_digit || rtp->send_digit != digit) {
+		if ((res = ast_rtp_senddigit_begin(rtp, original_digit)))
+			return res;
+		/* Initialize compensation */
+		rtp->send_compensate = 1;
+	} else {
+		/* We can safely send termination here */
+		rtpheader = (unsigned int *)data;
+		rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
+		rtpheader[1] = htonl(rtp->lastdigitts);
+		rtpheader[2] = htonl(rtp->ssrc);
+		rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
+		/* Send duration to 100ms */
+		rtpheader[3] |= htonl((800));
+		/* Set end bit */
+		rtpheader[3] |= htonl((1 << 23));		
+		/* Send 3 termination packets */
+		for (i = 0; i < 3; i++) {
+			if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
+				res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+				if (res < 0)
+					ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
+						ast_inet_ntoa(rtp->them.sin_addr),
+						ntohs(rtp->them.sin_port), strerror(errno));
+				if (rtp_debug_test_addr(&rtp->them))
+					ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+						    ast_inet_ntoa(rtp->them.sin_addr),
+						    ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+			}
+		}
+		rtp->send_digit = 0;
+		rtp->send_compensate = 0;
+		/* Increment lastdigitts */
+		rtp->lastdigitts += 960;
+		rtp->seqno++;
+	}
+
+	return res;
+}
+
+/*! \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
 int ast_rtcp_send_h261fur(void *data)
 {
 	struct ast_rtp *rtp = data;



More information about the asterisk-commits mailing list