[asterisk-commits] oej: branch oej/rana-dtmf-rtp-duration-1.6.0 r333340 - /team/oej/rana-dtmf-rt...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 26 08:43:25 CDT 2011


Author: oej
Date: Fri Aug 26 08:43:20 2011
New Revision: 333340

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=333340
Log:
- Suppress DTMF continue for feature codes. Since I added support for handling DTMF continue as the first part of DTMF (in case of severe packet loss) I need to suppress it in features.c
- Add the beginnings of the DTMF queue code

Modified:
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/features.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/main/features.c?view=diff&rev=333340&r1=333339&r2=333340
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/main/features.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/main/features.c Fri Aug 26 08:43:20 2011
@@ -2463,6 +2463,12 @@
 				}
 				break;
 			}
+		} else if (f->frametype == AST_FRAME_DTMF_CONTINUE) {
+			if (sendingdtmfdigit == 1) {
+				ast_debug(3, "Passing DTMF Continue through, since it is known not to be a feature code\n");
+				ast_write(other, f);
+			}
+			/* Otherwise, just swallow it. DTMF end will be enough */
 		} else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
 			char *featurecode;
 			int sense;
@@ -2484,7 +2490,7 @@
 				res = ast_feature_detect(chan, sense == FEATURE_SENSE_CHAN ? &(config->features_caller) : &(config->features_callee), featurecode, NULL);
 			}
 
-			if (featurelen == 0 || res == AST_FEATURE_RETURN_PASSDIGITS) {
+			if (featurelen == 0 && res == AST_FEATURE_RETURN_PASSDIGITS) {
 				ast_debug(3, "Passing DTMF through, since it is not a feature code\n");
 				ast_write(other, f);
 				sendingdtmfdigit = 1;

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c?view=diff&rev=333340&r1=333339&r2=333340
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c Fri Aug 26 08:43:20 2011
@@ -84,6 +84,14 @@
 	STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
 	STRICT_RTP_LEARN,    /*! Accept next packet as source */
 	STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
+};
+
+/*! \brief States for an outbound RTP stream that handles DTMF in RFC 2833 mode */
+enum dtmf_send_states {
+	DTMF_NOT_SENDING = 0,	/*! Not sending DTMF this very moment */
+	DTMF_SEND_INIT,		/*! Initializing */
+	DTMF_SEND_INPROGRESS,	/*! Playing DTMF */
+	DTMF_SEND_INPROGRESS_WITH_QUEUE	/*! Playing and having a queue to continue with */
 };
 
 /* Uncomment this to enable more intense native bridging, but note: this is currently buggy */
@@ -142,9 +150,11 @@
 	unsigned int dtmfsamples;
 	/* DTMF Transmission Variables */
 	unsigned int lastdigitts;
-	char sending_digit;	/*!< boolean - are we sending digits */
+	enum dtmf_send_states sending_dtmf;	/*!< - are we sending dtmf */
 	char send_digit;	/*!< digit we are sending */
 	char send_dtmf_frame;	/*!< Number of samples in a frame with the current packetization */
+	AST_LIST_HEAD_NOLOCK(, ast_frame) dtmfqueue;	/*!< Queue for DTMF that we receive while occupied with transmitting
+				   an outbound DTMF */
 	int send_payload;
 	int send_duration;
 	int send_endflag:1;	/*!< We have received END marker but are in waiting mode */
@@ -1455,18 +1465,18 @@
 	struct ast_rtp *bridged = NULL;
 	struct frame_list frames;
 	
-	if (rtp->sending_digit > 1) {
+	if (rtp->sending_dtmf == DTMF_SEND_INPROGRESS || rtp->sending_dtmf == DTMF_SEND_INPROGRESS_WITH_QUEUE) {
 		ast_rtp_senddigit_continuation(rtp);
 	} else {
 		/* Skip the first one due to possible BEGIN retransmits 
-	   	Yes, this is a poor coding solution, more of a bad hack.
-	   	Tests have shown that there's always one CONT packet sent without an incoming CONT
-	   	right after we've sent the BEGIN. Un-needed.
+	   	   Yes, this is a poor coding solution, more of a bad hack.
+	   	   Tests have shown that there's always one CONT packet sent without an incoming CONT
+	   	   right after we've sent the BEGIN. Un-needed.
 		*/
-		if (rtp->sending_digit == 1)  {
-			rtp->sending_digit = 2;
-		}
-		ast_debug(2, "---Skipping sending continue frame Sending_digit = %d\n", rtp->sending_digit);
+		if (rtp->sending_dtmf == DTMF_SEND_INIT)  {
+			rtp->sending_dtmf = DTMF_SEND_INPROGRESS;
+		}
+		ast_debug(2, "---Skipping sending continue frame Sending_digit = %d\n", rtp->sending_dtmf);
 	}
 
 	len = sizeof(sin);
@@ -2596,6 +2606,8 @@
 
 void ast_rtp_destroy(struct ast_rtp *rtp)
 {
+	struct ast_frame *f;
+
 	if (rtcp_debug_test_addr(&rtp->them) || rtcpstats) {
 		/*Print some info on the call here */
 		ast_verbose("  RTP-stats\n");
@@ -2651,6 +2663,11 @@
 		ast_free(rtp->rtcp);
 		rtp->rtcp=NULL;
 	}
+
+	/* Empty the DTMF queue */
+	while ((f = AST_LIST_REMOVE_HEAD(&rtp->dtmfqueue, frame_list))) {
+                ast_frfree(f);
+	}
 #ifdef P2P_INTENSE
 	ast_mutex_destroy(&rtp->bridge_lock);
 #endif
@@ -2676,12 +2693,22 @@
 	return (unsigned int) ms;
 }
 
-/*! \brief Send begin frames for DTMF */
+
+/*! \brief Outbound DTMF: Send begin frames for DTMF */
 int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit)
 {
 	unsigned int *rtpheader;
 	int hdrlen = 12, res = 0, i = 0, payload = 0;
 	char data[256];
+
+	/* If we're sending DTMF already, we will ignore this but raise sending_dtmf with one
+	   to mark that we're busy and can't be disturbed. When we receive an END packet, we will
+	   act on that - either start playing with some delay or stack it up in a dtmfqueue.
+	*/
+	if (rtp->sending_dtmf) {
+		ast_debug(3, "Received DTMF begin while we're playing out DTMF. Ignoring \n");
+		rtp->sending_dtmf = DTMF_SEND_INPROGRESS_WITH_QUEUE;	/* Tell the world that there's an ignored DTMF */
+	}
 
 	if ((digit <= '9') && (digit >= '0'))
 		digit -= '0';
@@ -2732,8 +2759,8 @@
 	}
 
 	/* Since we received a begin, we can safely store the digit and disable any compensation */
-	rtp->sending_digit = 1;
-	ast_debug(3, "OEJ --->>> Sending digit = 1!!!! \n");
+	rtp->sending_dtmf = DTMF_SEND_INIT;
+	ast_debug(3, "OEJ --->>> Sending digit = DTMF_SEND_INIT1!!!! \n");
 	rtp->send_digit = digit;
 	rtp->send_payload = payload;
 
@@ -2748,7 +2775,9 @@
 	ast_log(LOG_DEBUG, "DEBUG DTMF CONTINUE - Duration %d Digit %d Send-digit %d\n", duration, digit, rtp->send_digit);
 
 	/* If we missed the BEGIN, we will have to turn on the flag */
-	rtp->sending_digit = 2;
+	if (!rtp->sending_dtmf) {
+		rtp->sending_dtmf = DTMF_SEND_INPROGRESS;
+	}
 
 	/* Duration is in ms. Calculate the duration in timestamps */
 	if (duration > 0) {
@@ -2769,18 +2798,35 @@
 	return 0;
 }
 
-/*! \brief Send continuation frame for DTMF */
+/*! \brief Send continuation frame for DTMF 
+
+This is called when we get a frame in ast_rtp_read. To keep the timing, because there may be delays through Asterisk
+feature handling and other code, we need to clock the outbound DTMF with the frame size we have on the stream.
+We should not cut short and send a begin then in the next packet an END with a duration that exceeds the
+framesize (in most cases for audio 20 ms) and number of frames. That will seriously cause issues in gateways
+or phones down the path.
+
+An effect of this is that we may get a new DTMF frame while we're transmitting the previous one. For this case,
+we have implemented an DTMF queue that will queue up the dtmf and play out. The alternative would be to skip
+these, which is no good, or cut them short and cause issues with timing for other devices, while we solve our
+own situation. That's generally considered bad behaviour amongst SIP devices.
+*/
 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 || !rtp->them.sin_port)
+	if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port) {
 		return 0;
+	}
 
 	ast_log(LOG_DEBUG, "---- Send duration %d Received duration %d Endflag %d Send-digit %d\n", rtp->send_duration, rtp->received_duration, rtp->send_endflag, rtp->send_digit);
 
+	/*! \todo XXX This code assumes 160 samples, which is for 20 ms of 8000 samples
+		we need to calculate this based on the current sample rate and the rtp 
+		stream packetization
+	 */
 	if (rtp->received_duration == 0 || rtp->send_duration + 160 <= rtp->received_duration) {
 		rtp->send_duration += 160;
 	} else if (rtp->send_endflag) {
@@ -2858,7 +2904,8 @@
 			digit = digit - 'a' + 12;
 		else {
 			ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
-			rtp->sending_digit = 0;
+			rtp->sending_dtmf = DTMF_NOT_SENDING;
+/* SKREP - what are we going to do here? */
 			rtp->send_digit = 0;
 			rtp->received_duration = 0;
 			return 0;
@@ -2898,8 +2945,9 @@
 	}
 	ast_log(LOG_DEBUG, "-- DTMF END: Duration samples sent %d got %d ms (%d samples)\n", rtp->send_duration, duration, dursamples);
 	rtp->lastts += rtp->send_duration;
-	rtp->sending_digit = 0;
-	ast_debug(2, "OEJ ---->>>> Turning off sending_digit\n");
+	rtp->sending_dtmf = DTMF_NOT_SENDING;
+/* SKREP and here */
+	ast_debug(2, "OEJ ---->>>> Turning off sending_dtmf\n");
 	rtp->send_digit = 0;
 	rtp->received_duration = 0;
 
@@ -3213,7 +3261,8 @@
 		f->samples /= 2;
 	}
 
-	if (rtp->sending_digit) {
+	/* If we're sending DTMF, just skip this */
+	if (rtp->sending_dtmf) {
 		return 0;
 	}
 




More information about the asterisk-commits mailing list