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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Feb 2 04:39:57 CST 2011


Author: oej
Date: Wed Feb  2 04:39:51 2011
New Revision: 305743

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=305743
Log:
Code to fix the DTMF issues in RTP channels

Added:
    team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration   (with props)
Modified:
    team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_meetme.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_senddtmf.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_h323.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_mgcp.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_sip.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/channel.h
    team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/frame.h
    team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/rtp.h
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/autoservice.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/channel.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/frame.c
    team/oej/rana-dtmf-rtp-duration-1.6.0/main/rtp.c

Added: team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration?view=auto&rev=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration (added)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration Wed Feb  2 04:39:51 2011
@@ -1,0 +1,22 @@
+EDVINA AB
+Olle E. Johansson
+
+
+This branch is trying to focus on DTMF in the RTP channel. Asterisk 1.4 and later
+doesn't send the proper DTMF duration on the outbound call leg. If we receive
+a DTMF with a duration of 480 samples, we might end up sending 1440 samples out.
+
+In order to handle this a lot of bugs was fixed. We also added a new control
+frame to update the outbound channel with the latest duration from the inbound,
+in order to try to prevent the outbound channel to run ahead of the inbound.
+
+The outbound channel sends a packet for every incoming RTP packet. As usual,
+the inbound and outbond channels are not synchronized at all. So the outbound
+always clocks dtmf in 160 samples /20 ms, something which will break wideband
+codecs. (another fix required for that).
+
+With this code, the outbound channel sends outbound DTMF for the duration of
+the inbound dtmf tone, a bit adjusted to match 160 samples per outbound
+transmission. We do not break outbound DTMF when we receive inbound
+DTMF end, we continue until we have reached the duration of the DTMF that
+we received on the inbound channel.

Propchange: team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/rana-dtmf-rtp-duration-1.6.0/README.rana-dtmf-rtp-duration
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_meetme.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_meetme.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_meetme.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_meetme.c Wed Feb  2 04:39:51 2011
@@ -2668,7 +2668,7 @@
 					ret = 0;
 					ast_frfree(f);
 					break;
-				} else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
+				} else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_CONTINUE || f->frametype == AST_FRAME_DTMF_END)
 					&& confflags & CONFFLAG_PASS_DTMF) {
 					conf_queue_dtmf(conf, user, f);
 				} else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_senddtmf.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_senddtmf.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_senddtmf.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/apps/app_senddtmf.c Wed Feb  2 04:39:51 2011
@@ -80,13 +80,17 @@
 "Description: Plays a dtmf digit on the specified channel.\n"
 "Variables: (all are required)\n"
 "	Channel: Channel name to send digit to\n"
+"	Duration: The length of the tone (100 MS default, optional)\n"
 "	Digit: The dtmf digit to play\n";
 
 static int manager_play_dtmf(struct mansession *s, const struct message *m)
 {
 	const char *channel = astman_get_header(m, "Channel");
 	const char *digit = astman_get_header(m, "Digit");
+	const char *duration = astman_get_header(m, "Duration");
 	struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
+
+	int dtmfduration = 0;
 	
 	if (!chan) {
 		astman_send_error(s, m, "Channel not specified");
@@ -97,8 +101,11 @@
 		ast_channel_unlock(chan);
 		return 0;
 	}
+	if (!ast_strlen_zero(duration)) {
+		dtmfduration = atoi(duration);
+	}
 
-	ast_senddigit(chan, *digit, 0);
+	ast_senddigit(chan, *digit, dtmfduration);
 
 	ast_channel_unlock(chan);
 	astman_send_ack(s, m, "DTMF successfully queued");

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_h323.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_h323.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_h323.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_h323.c Wed Feb  2 04:39:51 2011
@@ -557,7 +557,7 @@
 		if (h323debug) {
 			ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, c->name, duration);
 		}
-		ast_rtp_senddigit_end(pvt->rtp, digit);
+		ast_rtp_senddigit_end(pvt->rtp, digit, duration);
 		ast_mutex_unlock(&pvt->lock);
 	} else {
 		/* in-band DTMF */

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_mgcp.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_mgcp.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_mgcp.c Wed Feb  2 04:39:51 2011
@@ -1348,7 +1348,7 @@
 		tmp[2] = digit;
 		tmp[3] = '\0';
 		transmit_notify_request(sub, tmp);
-                ast_rtp_senddigit_end(sub->rtp, digit);
+                ast_rtp_senddigit_end(sub->rtp, digit, duration);
 	} else {
 		ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
 	}

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_sip.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_sip.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/channels/chan_sip.c Wed Feb  2 04:39:51 2011
@@ -1731,6 +1731,7 @@
 static int sip_transfer(struct ast_channel *ast, const char *dest);
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int sip_senddigit_begin(struct ast_channel *ast, char digit);
+static int sip_senddigit_continue(struct ast_channel *ast, char digit, unsigned int duration);
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
 static const char *sip_get_callid(struct ast_channel *chan);
@@ -2135,6 +2136,7 @@
 	.transfer = sip_transfer,		/* called with chan locked */
 	.fixup = sip_fixup,			/* called with chan locked */
 	.send_digit_begin = sip_senddigit_begin,	/* called with chan unlocked */
+	.send_digit_continue = sip_senddigit_continue,	/* called with chan unlocked */
 	.send_digit_end = sip_senddigit_end,
 	.bridge = ast_rtp_bridge,			/* XXX chan unlocked ? */
 	.early_bridge = ast_rtp_early_bridge,
@@ -5497,6 +5499,26 @@
 	return res;
 }
 
+/*! \brief Update DTMF character on SIP channel
+	within one call, we're able to transmit in many methods simultaneously */
+static int sip_senddigit_continue(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct sip_pvt *p = ast->tech_pvt;
+	int res = 0;
+
+	ast_log(LOG_DEBUG, " DTMF CONTINUE HERE!!! \n");
+
+	sip_pvt_lock(p);
+	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
+	case SIP_DTMF_RFC2833:
+		if (p->rtp)
+			ast_rtp_senddigit_continue(p->rtp, digit, duration);
+		break;
+	}
+	sip_pvt_unlock(p);
+
+	return res;
+}
 /*! \brief Send DTMF character on SIP channel
 	within one call, we're able to transmit in many methods simultaneously */
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
@@ -5512,7 +5534,7 @@
 		break;
 	case SIP_DTMF_RFC2833:
 		if (p->rtp)
-			ast_rtp_senddigit_end(p->rtp, digit);
+			ast_rtp_senddigit_end(p->rtp, digit, duration);
 		break;
 	case SIP_DTMF_INBAND:
 		res = -1; /* Tell Asterisk to stop inband indications */

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/channel.h?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/channel.h (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/channel.h Wed Feb  2 04:39:51 2011
@@ -271,6 +271,13 @@
 	 * \note The channel is not locked when this function gets called. 
 	 */
 	int (* const send_digit_begin)(struct ast_channel *chan, char digit);
+
+	/*! 
+	 * \brief Continue sending a literal DTMF digit 
+	 *
+	 * \note The channel is not locked when this function gets called. 
+	 */
+	int (* const send_digit_continue)(struct ast_channel *chan, char digit, unsigned int duration);
 
 	/*! 
 	 * \brief Stop sending a literal DTMF digit 
@@ -1254,6 +1261,15 @@
  */
 int ast_senddigit_begin(struct ast_channel *chan, char digit);
 
+/*! \brief Continue to send a DTMF digit to a channel
+ * used on RTP bridges mainly (to get the duration correct)
+ * Send a DTMF digit to a channel.
+ * \param chan channel to act upon
+ * \param digit the DTMF digit to send, encoded in ASCII
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_senddigit_continue(struct ast_channel *chan, char digit, unsigned int duration);
+
 /*! \brief Send a DTMF digit to a channel
 
  * Send a DTMF digit to a channel.

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/frame.h?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/frame.h (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/frame.h Wed Feb  2 04:39:51 2011
@@ -121,6 +121,8 @@
 	AST_FRAME_MODEM,	
 	/*! DTMF begin event, subclass is the digit */
 	AST_FRAME_DTMF_BEGIN,
+	/*! DTMF continue event, subclass is the digit */
+	AST_FRAME_DTMF_CONTINUE,
 };
 #define AST_FRAME_DTMF AST_FRAME_DTMF_END
 

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/rtp.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/rtp.h?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/rtp.h (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/include/asterisk/rtp.h Wed Feb  2 04:39:51 2011
@@ -181,7 +181,9 @@
 
 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_senddigit_continue(struct ast_rtp *rtp, char digit, unsigned int duration);
+
+int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit, unsigned int duration);
 
 int ast_rtp_sendcng(struct ast_rtp *rtp, int level);
 

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/main/autoservice.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/main/autoservice.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/main/autoservice.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/main/autoservice.c Wed Feb  2 04:39:51 2011
@@ -146,6 +146,7 @@
 
 			/* Throw these frames away */
 			case AST_FRAME_DTMF_BEGIN:
+			case AST_FRAME_DTMF_CONTINUE:
 			case AST_FRAME_VOICE:
 			case AST_FRAME_VIDEO:
 			case AST_FRAME_NULL:

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/main/channel.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/main/channel.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/main/channel.c Wed Feb  2 04:39:51 2011
@@ -1902,6 +1902,7 @@
 				case AST_FRAME_VIDEO:
 				case AST_FRAME_TEXT:
 				case AST_FRAME_DTMF_BEGIN:
+				case AST_FRAME_DTMF_CONTINUE:
 				case AST_FRAME_DTMF_END:
 				case AST_FRAME_IMAGE:
 				case AST_FRAME_HTML:
@@ -2454,6 +2455,7 @@
 
 			switch (f->frametype) {
 			case AST_FRAME_DTMF_BEGIN:
+			case AST_FRAME_DTMF_CONTINUE:
 				break;
 			case AST_FRAME_DTMF_END:
 				res = f->subclass;
@@ -2750,7 +2752,7 @@
 			 * there are cases where we want to leave DTMF frames on the queue until
 			 * some later time. */
 
-			if ( (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) && skip_dtmf) {
+			if ( (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_CONTINUE || f->frametype == AST_FRAME_DTMF_END) && skip_dtmf) {
 				continue;
 			}
 
@@ -2903,6 +2905,13 @@
 				}
 			}
 			break;
+		case AST_FRAME_DTMF_CONTINUE:
+			/* No manager event at this point
+				send_dtmf_event(chan, "Received", f->subclass, "Yes", "No");
+			*/
+			ast_log(LOG_DTMF, "DTMF continue '%c' received on %s\n", f->subclass, chan->name);
+			ast_log(LOG_DEBUG, "---DEBUG--- DTMF continue '%c' received on %s\n", f->subclass, chan->name);
+			break;
 		case AST_FRAME_DTMF_BEGIN:
 			send_dtmf_event(chan, "Received", f->subclass, "Yes", "No");
 			ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
@@ -3345,6 +3354,17 @@
 	return 0;
 }
 
+int ast_senddigit_continue(struct ast_channel *chan, char digit, unsigned int duration)
+{
+	int res = -1;
+
+	ast_log(LOG_DEBUG, "DEBUG --- COntinue frame passed on to tech for %s\n", chan->name);
+	if (chan->tech->send_digit_continue)
+		res = chan->tech->send_digit_continue(chan, digit, duration);
+
+	return 0;
+}
+
 int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration)
 {
 	int res = -1;
@@ -3466,6 +3486,22 @@
 		ast_clear_flag(chan, AST_FLAG_BLOCKING);
 		ast_channel_unlock(chan);
 		res = ast_senddigit_begin(chan, fr->subclass);
+		ast_channel_lock(chan);
+		CHECK_BLOCKING(chan);
+		break;
+	case AST_FRAME_DTMF_CONTINUE:
+		if (chan->audiohooks) {
+			struct ast_frame *old_frame = fr;
+			fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
+			if (old_frame != fr)
+				f = fr;
+		}
+		ast_log(LOG_DEBUG, "---Continue FRAME received, forwarding to channel %s", chan->name);
+		// Skip manager for continue events (at least for now)
+		//send_dtmf_event(chan, "Sent", fr->subclass, "Yes", "No");
+		ast_clear_flag(chan, AST_FLAG_BLOCKING);
+		ast_channel_unlock(chan);
+		res = ast_senddigit_continue(chan, fr->subclass, fr->len);
 		ast_channel_lock(chan);
 		CHECK_BLOCKING(chan);
 		break;
@@ -4904,6 +4940,7 @@
 		}
 		if ((f->frametype == AST_FRAME_VOICE) ||
 		    (f->frametype == AST_FRAME_DTMF_BEGIN) ||
+		    (f->frametype == AST_FRAME_DTMF_CONTINUE) ||
 		    (f->frametype == AST_FRAME_DTMF) ||
 		    (f->frametype == AST_FRAME_VIDEO) ||
 		    (f->frametype == AST_FRAME_IMAGE) ||
@@ -4919,7 +4956,7 @@
 				*fo = f;
 				*rc = who;
 				ast_debug(1, "Got DTMF %s on channel (%s)\n", 
-					f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
+					f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",	/* BUG for continue. Ignored now. OEJ */
 					who->name);
 
 				break;

Modified: team/oej/rana-dtmf-rtp-duration-1.6.0/main/frame.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/rana-dtmf-rtp-duration-1.6.0/main/frame.c?view=diff&rev=305743&r1=305742&r2=305743
==============================================================================
--- team/oej/rana-dtmf-rtp-duration-1.6.0/main/frame.c (original)
+++ team/oej/rana-dtmf-rtp-duration-1.6.0/main/frame.c Wed Feb  2 04:39:51 2011
@@ -769,6 +769,11 @@
 		subclass[0] = f->subclass;
 		subclass[1] = '\0';
 		break;
+	case AST_FRAME_DTMF_CONTINUE:
+		strcpy(ftype, "DTMF Continue");
+		subclass[0] = f->subclass;
+		subclass[1] = '\0';
+		break;
 	case AST_FRAME_DTMF_END:
 		strcpy(ftype, "DTMF End");
 		subclass[0] = f->subclass;

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=305743&r1=305742&r2=305743
==============================================================================
--- 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 Wed Feb  2 04:39:51 2011
@@ -146,6 +146,8 @@
 	char send_digit;	/*!< digit we are sending */
 	int send_payload;
 	int send_duration;
+	int send_endflag:1;	/*!< We have received END marker but are in waiting mode */
+	unsigned int received_duration;	/*!< Received duration (according to control frames) */
 	int nat;
 	unsigned int flags;
 	struct sockaddr_in us;		/*!< Socket representation of the local endpoint. */
@@ -190,7 +192,6 @@
 static int ast_rtcp_write_rr(const void *data);
 static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
 static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp);
-int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
 
 #define FLAG_3389_WARNING		(1 << 0)
 #define FLAG_NAT_ACTIVE			(3 << 1)
@@ -805,7 +806,7 @@
 		rtp->dtmfsamples = 0;
 		return &ast_null_frame;
 	}
-	ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(rtp->them.sin_addr));
+	ast_debug(1, "Sending dtmf: %d (%c), at %s \n", rtp->resp, rtp->resp, ast_inet_ntoa(rtp->them.sin_addr));
 	if (rtp->resp == 'X') {
 		rtp->f.frametype = AST_FRAME_CONTROL;
 		rtp->f.subclass = AST_CONTROL_FLASH;
@@ -1014,6 +1015,7 @@
 				f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_END));
 				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
 				rtp->resp = 0;
+				ast_log(LOG_DEBUG, "--GOT DTMF END message. Duration samples %d\n", rtp->dtmf_duration);
 				rtp->dtmf_duration = rtp->dtmf_timeout = 0;
 				AST_LIST_INSERT_TAIL(frames, f, frame_list);
 			}
@@ -1033,6 +1035,10 @@
 			if (rtp->resp) {
 				/* Digit continues */
 				rtp->dtmf_duration = new_duration;
+				f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_CONTINUE));
+				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
+				AST_LIST_INSERT_TAIL(frames, f, frame_list);
+				ast_log(LOG_DEBUG, "Queued frame AST_FRAME_DTMF_CONTINUE, Samples %d Ms %d\n", rtp->dtmf_duration, (int)f->len);
 			} else {
 				/* New digit began */
 				rtp->resp = resp;
@@ -1448,9 +1454,18 @@
 	struct ast_rtp *bridged = NULL;
 	struct frame_list frames;
 	
-	/* If time is up, kill it */
-	if (rtp->sending_digit)
+	if (rtp->sending_digit > 1) {
 		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.
+		*/
+		if (rtp->sending_digit == 1)  {
+			rtp->sending_digit = 2;
+		}
+	}
 
 	len = sizeof(sin);
 	
@@ -2710,17 +2725,44 @@
 				    ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
 		/* Increment sequence number */
 		rtp->seqno++;
-		/* Increment duration */
-		rtp->send_duration += 160;
 		/* Clear marker bit and set seqno */
 		rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
 	}
+	/* Increment duration */
+	rtp->send_duration += 160;
 
 	/* Since we received a begin, we can safely store the digit and disable any compensation */
 	rtp->sending_digit = 1;
 	rtp->send_digit = digit;
 	rtp->send_payload = payload;
 
+	ast_log(LOG_DEBUG, "DEBUG DTMF BEGIN - Digit %d send-digit %d\n", digit, rtp->send_digit);
+
+	return 0;
+}
+
+/*! \brief Get notification of duration updates */
+int ast_rtp_senddigit_continue(struct ast_rtp *rtp, char digit, unsigned int duration)
+{
+	ast_log(LOG_DEBUG, "DEBUG DTMF CONTINUE - Duration %d Digit %d Send-digit %d\n", duration, digit, rtp->send_digit);
+
+	/* Duration is in ms. Calculate the duration in timestamps */
+	if (duration > 0) {
+		/* We have an incoming duration from the incoming channel. This needs
+		   to be matched with our outbound pacing. The inbound can be paced
+		   in either 50 ms or whatever packetization that is used on that channel,
+		   so we can't assume 20 ms (160 units in 8000 hz audio).
+		*/
+		// int dursamples =  duration * (rtp_get_rate(f->subclass) / 1000)
+		int dursamples =  duration * (8000 / 1000);	/* How do we get the sample rate for the primary media in this call? */
+		// f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
+
+		ast_log(LOG_DEBUG, "DTMF CONTINUE : %d ms %d samples\n", duration, dursamples);
+		rtp->received_duration = dursamples;
+	} else {
+		ast_log(LOG_DEBUG, "DTMF CONTINUE : Missing duration!!!!!!!\n");
+		
+	}
 	return 0;
 }
 
@@ -2733,6 +2775,18 @@
 
 	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);
+	if (rtp->send_duration + 160 < rtp->received_duration) {
+		rtp->send_duration += 160;
+	} else if (rtp->send_endflag) {
+		ast_log(LOG_DEBUG, "---- Send duration %d Received duration %d - sending END packet\n", rtp->send_duration, rtp->received_duration);
+		rtp->send_duration += 160;
+		/* We are done, ready to send end flag */
+		rtp->send_endflag = 0;
+		return ast_rtp_senddigit_end(rtp, 0, rtp->received_duration);
+	}
+
 
 	/* Setup packet to send */
 	rtpheader = (unsigned int *)data;
@@ -2755,39 +2809,60 @@
 
 	/* Increment sequence number */
 	rtp->seqno++;
-	/* Increment duration */
-	rtp->send_duration += 160;
 
 	return 0;
 }
 
 /*! \brief Send end packets for DTMF */
-int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit)
+int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit, unsigned int duration)
 {
 	unsigned int *rtpheader;
 	int hdrlen = 12, res = 0, i = 0;
 	char data[256];
+	int dursamples =  duration * (8000 / 1000);	/* How do we get the sample rate for the primary media in this call? */
 	
 	/* If no address, then bail out */
 	if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
 		return 0;
-	
-	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 0;
+
+
+	ast_log(LOG_DEBUG, "---- Send duration %d Received duration %d Endflag %d Digit %d Send-digit %d\n", rtp->send_duration, rtp->received_duration, rtp->send_endflag, digit, rtp->send_digit);
+
+	if (!rtp->send_endflag && rtp->send_duration + 160 < rtp->received_duration) {
+		/* We still have to send DTMF continuation, because otherwise we will end prematurely. Set end flag to indicate
+		   that we will have to end ourselves when we're done with the actual duration
+		 */
+		ast_log(LOG_DEBUG, "---- Send duration %d Received duration %d - Avoiding sending END packet\n", rtp->send_duration, rtp->received_duration);
+		rtp->send_endflag = 1;
+		return ast_rtp_senddigit_continuation(rtp);
+	}
+
+	if (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);
+			rtp->sending_digit = 0;
+			rtp->send_digit = 0;
+			rtp->received_duration = 0;
+			return 0;
+		}
+	} else {
+		digit = rtp->send_digit;
 	}
 
 	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
+
+	//rtp->send_duration = rtp->received_duration;	/* Compensate for the last CONT packet */
+	rtp->send_duration = dursamples;	/* Compensate for the last CONT packet */
 
 	rtpheader = (unsigned int *)data;
 	rtpheader[1] = htonl(rtp->lastdigitts);
@@ -2810,9 +2885,11 @@
 				    ast_inet_ntoa(rtp->them.sin_addr),
 				    ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
 	}
+	ast_log(LOG_DEBUG, "-- DTMF END: Duration samples %d ms %d\n", rtp->send_duration, duration);
 	rtp->lastts += rtp->send_duration;
 	rtp->sending_digit = 0;
 	rtp->send_digit = 0;
+	rtp->received_duration = 0;
 
 	return res;
 }




More information about the asterisk-commits mailing list