Merged revisions 51311 via svnmerge from
authorRussell Bryant <russell@russellbryant.com>
Fri, 19 Jan 2007 18:06:03 +0000 (18:06 +0000)
committerRussell Bryant <russell@russellbryant.com>
Fri, 19 Jan 2007 18:06:03 +0000 (18:06 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines

Merge the changes from the /team/group/vldtmf_fixup branch.

The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged.  So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio.  However,
since there was no audio coming in, the DTMF_END was never generated.  This
caused DTMF based features to no longer work.

To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf).  If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.

Channel drivers also now get passed the length of the digit to their digit_end
callback.  This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.

(issue #8597, maybe others...)

........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3

19 files changed:
channels/chan_agent.c
channels/chan_alsa.c
channels/chan_features.c
channels/chan_gtalk.c
channels/chan_h323.c
channels/chan_iax2.c
channels/chan_jingle.c
channels/chan_local.c
channels/chan_mgcp.c
channels/chan_misdn.c
channels/chan_oss.c
channels/chan_phone.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_zap.c
include/asterisk/channel.h
main/channel.c
main/frame.c
main/rtp.c

index c83df41..ba36df4 100644 (file)
@@ -230,7 +230,7 @@ static struct ast_channel *agent_request(const char *type, int format, void *dat
 static int agent_devicestate(void *data);
 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
 static int agent_digit_begin(struct ast_channel *ast, char digit);
-static int agent_digit_end(struct ast_channel *ast, char digit);
+static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
 static int agent_hangup(struct ast_channel *ast);
 static int agent_answer(struct ast_channel *ast);
@@ -610,12 +610,12 @@ static int agent_digit_begin(struct ast_channel *ast, char digit)
        return res;
 }
 
-static int agent_digit_end(struct ast_channel *ast, char digit)
+static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct agent_pvt *p = ast->tech_pvt;
        int res = -1;
        ast_mutex_lock(&p->lock);
-       ast_senddigit_end(p->chan, digit);
+       ast_senddigit_end(p->chan, digit, duration);
        ast_mutex_unlock(&p->lock);
        return res;
 }
index 6c52b3c..67c0b66 100644 (file)
@@ -185,7 +185,7 @@ static int nosound = 0;
 
 /* ZZ */
 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause);
-static int alsa_digit(struct ast_channel *c, char digit);
+static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
 static int alsa_text(struct ast_channel *c, const char *text);
 static int alsa_hangup(struct ast_channel *c);
 static int alsa_answer(struct ast_channel *c);
@@ -494,10 +494,11 @@ static int soundcard_init(void)
        return readdev;
 }
 
-static int alsa_digit(struct ast_channel *c, char digit)
+static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
 {
        ast_mutex_lock(&alsalock);
-       ast_verbose(" << Console Received digit %c >> \n", digit);
+       ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
+               digit, duration);
        ast_mutex_unlock(&alsalock);
        return 0;
 }
index 3c1285c..c4d82d7 100644 (file)
@@ -93,7 +93,7 @@ static AST_LIST_HEAD_STATIC(features, feature_pvt);
 
 static struct ast_channel *features_request(const char *type, int format, void *data, int *cause);
 static int features_digit_begin(struct ast_channel *ast, char digit);
-static int features_digit_end(struct ast_channel *ast, char digit);
+static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int features_call(struct ast_channel *ast, char *dest, int timeout);
 static int features_hangup(struct ast_channel *ast);
 static int features_answer(struct ast_channel *ast);
@@ -316,7 +316,7 @@ static int features_digit_begin(struct ast_channel *ast, char digit)
        return res;
 }
 
-static int features_digit_end(struct ast_channel *ast, char digit)
+static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct feature_pvt *p = ast->tech_pvt;
        int res = -1;
@@ -326,7 +326,7 @@ static int features_digit_end(struct ast_channel *ast, char digit)
        ast_mutex_lock(&p->lock);
        x = indexof(p, ast, 0);
        if (!x && p->subchan)
-               res = ast_senddigit_end(p->subchan, digit);
+               res = ast_senddigit_end(p->subchan, digit, duration);
        ast_mutex_unlock(&p->lock);
        return res;
 }
index 456a536..3e6f4d4 100644 (file)
@@ -170,7 +170,9 @@ AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pv
 
 /* Forward declarations */
 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
-static int gtalk_digit(struct ast_channel *ast, char digit);
+static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
+static int gtalk_digit_begin(struct ast_channel *ast, char digit);
+static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
 static int gtalk_hangup(struct ast_channel *ast);
 static int gtalk_answer(struct ast_channel *ast);
@@ -195,8 +197,8 @@ static const struct ast_channel_tech gtalk_tech = {
        .description = "Gtalk Channel Driver",
        .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
        .requester = gtalk_request,
-       .send_digit_begin = gtalk_digit,
-       .send_digit_end = gtalk_digit,
+       .send_digit_begin = gtalk_digit_begin,
+       .send_digit_end = gtalk_digit_end,
        .bridge = ast_rtp_bridge,
        .call = gtalk_call,
        .hangup = gtalk_hangup,
@@ -1338,7 +1340,17 @@ static int gtalk_indicate(struct ast_channel *ast, int condition, const void *da
        return res;
 }
 
-static int gtalk_digit(struct ast_channel *ast, char digit)
+static int gtalk_digit_begin(struct ast_channel *chan, char digit)
+{
+       return gtalk_digit(chan, digit, 0);
+}
+
+static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
+{
+       return gtalk_digit(chan, digit, duration);
+}
+
+static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct gtalk_pvt *p = ast->tech_pvt;
        struct gtalk *client = p->parent;
@@ -1373,8 +1385,8 @@ static int gtalk_digit(struct ast_channel *ast, char digit)
        iks_insert_node(gtalk, dtmf);
 
        ast_mutex_lock(&p->lock);
-       if(ast->dtmff.frametype == AST_FRAME_DTMF) {
-               ast_verbose("Sending 250ms dtmf!\n");
+       if (ast->dtmff.frametype == AST_FRAME_DTMF) {
+               ast_log(LOG_DEBUG, "Sending 250ms dtmf!\n");
        } else if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN) {
                iks_insert_attrib(dtmf, "action", "button-down");
        } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END) {
index ef099eb..8031327 100644 (file)
@@ -235,7 +235,7 @@ static int h323_do_reload(void);
 
 static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause);
 static int oh323_digit_begin(struct ast_channel *c, char digit);
-static int oh323_digit_end(struct ast_channel *c, char digit);
+static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int oh323_call(struct ast_channel *c, char *dest, int timeout);
 static int oh323_hangup(struct ast_channel *c);
 static int oh323_answer(struct ast_channel *c);
@@ -548,7 +548,7 @@ static int oh323_digit_begin(struct ast_channel *c, char digit)
  * Send (play) the specified digit to the channel.
  *
  */
-static int oh323_digit_end(struct ast_channel *c, char digit)
+static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration)
 {
        struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
        char *token;
index 9c62878..1ede22a 100644 (file)
@@ -817,7 +817,7 @@ static int iax2_answer(struct ast_channel *c);
 static int iax2_call(struct ast_channel *c, char *dest, int timeout);
 static int iax2_devicestate(void *data);
 static int iax2_digit_begin(struct ast_channel *c, char digit);
-static int iax2_digit_end(struct ast_channel *c, char digit);
+static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int iax2_do_register(struct iax2_registry *reg);
 static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);
 static int iax2_hangup(struct ast_channel *c);
@@ -2476,7 +2476,7 @@ static int iax2_digit_begin(struct ast_channel *c, char digit)
        return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_BEGIN, digit, 0, NULL, 0, -1);
 }
 
-static int iax2_digit_end(struct ast_channel *c, char digit)
+static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration)
 {
        return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
 }
@@ -6353,7 +6353,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 
        if (packet_len < (sizeof(*meta) + sizeof(*mth))) {
                ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %d min)\n", packet_len,
-                       sizeof(*meta) + sizeof(*mth));
+                       (int) (sizeof(*meta) + sizeof(*mth)));
                return 1;
        }
        mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
@@ -6523,7 +6523,7 @@ static int socket_process(struct iax2_thread *thread)
        memcpy(&sin, &thread->iosin, sizeof(sin));
 
        if (res < sizeof(*mh)) {
-               ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, sizeof(*mh));
+               ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
                return 1;
        }
        if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
@@ -6684,7 +6684,7 @@ static int socket_process(struct iax2_thread *thread)
                }
                /* A full frame */
                if (res < sizeof(*fh)) {
-                       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, sizeof(*fh));
+                       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*fh));
                        ast_mutex_unlock(&iaxsl[fr->callno]);
                        return 1;
                }
index 201f7fe..493c2f1 100644 (file)
@@ -169,7 +169,7 @@ AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_
 /* Forward declarations */
 static struct ast_channel *jingle_request(const char *type, int format, void *data, int *cause);
 static int jingle_digit_begin(struct ast_channel *ast, char digit);
-static int jingle_digit_end(struct ast_channel *ast, char digit);
+static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int jingle_call(struct ast_channel *ast, char *dest, int timeout);
 static int jingle_hangup(struct ast_channel *ast);
 static int jingle_answer(struct ast_channel *ast);
@@ -1182,13 +1182,7 @@ static int jingle_indicate(struct ast_channel *ast, int condition, const void *d
        return res;
 }
 
-static int jingle_digit_begin(struct ast_channel *chan, char digit)
-{
-       /* XXX Does jingle have a concept of the length of a dtmf digit ? */
-       return 0;
-}
-
-static int jingle_digit_end(struct ast_channel *ast, char digit)
+static int jingle_digit(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct jingle_pvt *p = ast->tech_pvt;
        struct jingle *client = p->parent;
@@ -1223,9 +1217,7 @@ static int jingle_digit_end(struct ast_channel *ast, char digit)
        iks_insert_node(jingle, dtmf);
 
        ast_mutex_lock(&p->lock);
-       if(ast->dtmff.frametype == AST_FRAME_DTMF) {
-               ast_verbose("Sending 250ms dtmf!\n");
-       } else if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN) {
+       if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN) {
                iks_insert_attrib(dtmf, "action", "button-down");
        } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END) {
                iks_insert_attrib(dtmf, "action", "button-up");
@@ -1238,6 +1230,16 @@ static int jingle_digit_end(struct ast_channel *ast, char digit)
        return 0;
 }
 
+static int jingle_digit_begin(struct ast_channel *chan, char digit)
+{
+       return jingle_digit(chan, digit, 0);
+}
+
+static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+       return jingle_digit(ast, digit, duration);
+}
+
 static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
 {
        ast_log(LOG_NOTICE, "XXX Implement jingle sendhtml XXX\n");
index b8d112b..8d96327 100644 (file)
@@ -68,7 +68,7 @@ static const char tdesc[] = "Local Proxy Channel Driver";
 
 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
 static int local_digit_begin(struct ast_channel *ast, char digit);
-static int local_digit_end(struct ast_channel *ast, char digit);
+static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int local_call(struct ast_channel *ast, char *dest, int timeout);
 static int local_hangup(struct ast_channel *ast);
 static int local_answer(struct ast_channel *ast);
@@ -368,7 +368,7 @@ static int local_digit_begin(struct ast_channel *ast, char digit)
        return res;
 }
 
-static int local_digit_end(struct ast_channel *ast, char digit)
+static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct local_pvt *p = ast->tech_pvt;
        int res = -1;
@@ -381,6 +381,7 @@ static int local_digit_end(struct ast_channel *ast, char digit)
        ast_mutex_lock(&p->lock);
        isoutbound = IS_OUTBOUND(ast, p);
        f.subclass = digit;
+       f.len = duration;
        res = local_queue_frame(p, isoutbound, &f, ast);
        ast_mutex_unlock(&p->lock);
        
index bdb7047..ce68552 100644 (file)
@@ -428,7 +428,7 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
-static int mgcp_senddigit_end(struct ast_channel *ast, char digit);
+static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int mgcp_devicestate(void *data);
 
 static const struct ast_channel_tech mgcp_tech = {
@@ -1282,7 +1282,7 @@ static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
        return -1;
 }
 
-static int mgcp_senddigit_end(struct ast_channel *ast, char digit)
+static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct mgcp_subchannel *sub = ast->tech_pvt;
        char tmp[4];
index 5a2c8a4..268dee1 100644 (file)
@@ -2067,7 +2067,7 @@ static int misdn_digit_begin(struct ast_channel *chan, char digit)
        return 0;
 }
 
-static int misdn_digit_end(struct ast_channel *ast, char digit )
+static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct chan_list *p;
        
index c762782..fb869cb 100644 (file)
@@ -406,7 +406,7 @@ static int setformat(struct chan_oss_pvt *o, int mode);
 static struct ast_channel *oss_request(const char *type, int format, void *data
 , int *cause);
 static int oss_digit_begin(struct ast_channel *c, char digit);
-static int oss_digit_end(struct ast_channel *c, char digit);
+static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int oss_text(struct ast_channel *c, const char *text);
 static int oss_hangup(struct ast_channel *c);
 static int oss_answer(struct ast_channel *c);
@@ -776,10 +776,11 @@ static int oss_digit_begin(struct ast_channel *c, char digit)
        return 0;
 }
 
-static int oss_digit_end(struct ast_channel *c, char digit)
+static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration)
 {
        /* no better use for received digits than print them */
-       ast_verbose(" << Console Received digit %c >> \n", digit);
+       ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
+               digit, duration);
        return 0;
 }
 
index 20a0cb3..26e6921 100644 (file)
@@ -156,7 +156,7 @@ static char cid_name[AST_MAX_EXTENSION];
 
 static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause);
 static int phone_digit_begin(struct ast_channel *ast, char digit);
-static int phone_digit_end(struct ast_channel *ast, char digit);
+static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int phone_call(struct ast_channel *ast, char *dest, int timeout);
 static int phone_hangup(struct ast_channel *ast);
 static int phone_answer(struct ast_channel *ast);
@@ -244,12 +244,12 @@ static int phone_digit_begin(struct ast_channel *chan, char digit)
        return 0;
 }
 
-static int phone_digit_end(struct ast_channel *ast, char digit)
+static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct phone_pvt *p;
        int outdigit;
        p = ast->tech_pvt;
-       ast_log(LOG_NOTICE, "Dialed %c\n", digit);
+       ast_log(LOG_DEBUG, "Dialed %c\n", digit);
        switch(digit) {
        case '0':
        case '1':
@@ -280,7 +280,7 @@ static int phone_digit_end(struct ast_channel *ast, char digit)
                ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
                return -1;
        }
-       ast_log(LOG_NOTICE, "Dialed %d\n", outdigit);
+       ast_log(LOG_DEBUG, "Dialed %d\n", outdigit);
        ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
        p->lastformat = -1;
        return 0;
@@ -333,7 +333,7 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
                {
                  digit++;
                  while (*digit)
-                   phone_digit_end(ast, *digit++);
+                   phone_digit_end(ast, *digit++, 0);
                }
        }
  
index 833202b..2048682 100644 (file)
@@ -1228,7 +1228,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 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_end(struct ast_channel *ast, char digit);
+static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 
 /*--- Transmitting responses and requests */
 static int sipsock_read(int *id, int fd, short events, void *ignore);
@@ -1250,7 +1250,7 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmit
 static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version);
-static int transmit_info_with_digit(struct sip_pvt *p, const char digit);
+static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
 static int transmit_info_with_vidupdate(struct sip_pvt *p);
 static int transmit_message_with_text(struct sip_pvt *p, const char *text);
 static int transmit_refer(struct sip_pvt *p, const char *dest);
@@ -1495,7 +1495,7 @@ static int add_header(struct sip_request *req, const char *var, const char *valu
 static int add_header_contentLength(struct sip_request *req, int len);
 static int add_line(struct sip_request *req, const char *line);
 static int add_text(struct sip_request *req, const char *text);
-static int add_digit(struct sip_request *req, char digit);
+static int add_digit(struct sip_request *req, char digit, unsigned int duration);
 static int add_vidupdate(struct sip_request *req);
 static void add_route(struct sip_request *req, struct sip_route *route);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -1564,6 +1564,30 @@ static const struct ast_channel_tech sip_tech = {
        .send_text = sip_sendtext,
 };
 
+/*! \brief This version of the sip channel tech has no send_digit_begin
+ *  callback.  This is for use with channels using SIP INFO DTMF so that
+ *  the core knows that the channel doesn't want DTMF BEGIN frames. */
+static const struct ast_channel_tech sip_tech_info = {
+       .type = "SIP",
+       .description = "Session Initiation Protocol (SIP)",
+       .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
+       .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
+       .requester = sip_request_call,
+       .devicestate = sip_devicestate,
+       .call = sip_call,
+       .hangup = sip_hangup,
+       .answer = sip_answer,
+       .read = sip_read,
+       .write = sip_write,
+       .write_video = sip_write,
+       .indicate = sip_indicate,
+       .transfer = sip_transfer,
+       .fixup = sip_fixup,
+       .send_digit_end = sip_senddigit_end,
+       .bridge = ast_rtp_bridge,
+       .send_text = sip_sendtext,
+};
+
 /**--- some list management macros. **/
  
 #define UNLINK(element, head, prev) do {       \
@@ -3688,7 +3712,7 @@ static int sip_senddigit_begin(struct ast_channel *ast, char digit)
 
 /*! \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)
+static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        struct sip_pvt *p = ast->tech_pvt;
        int res = 0;
@@ -3696,7 +3720,7 @@ static int sip_senddigit_end(struct ast_channel *ast, char digit)
        sip_pvt_lock(p);
        switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
        case SIP_DTMF_INFO:
-               transmit_info_with_digit(p, digit);
+               transmit_info_with_digit(p, digit, duration);
                break;
        case SIP_DTMF_RFC2833:
                if (p->rtp)
@@ -3857,7 +3881,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                return NULL;
        }
        sip_pvt_lock(i);
-       tmp->tech = &sip_tech;
+
+       if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO)
+               tmp->tech = &sip_tech_info;
+       else
+               tmp->tech = &sip_tech;
 
        /* Select our native format based on codec preference until we receive
           something from another device to the contrary. */
@@ -5927,11 +5955,11 @@ static int add_text(struct sip_request *req, const char *text)
 
 /*! \brief Add DTMF INFO tone to sip message */
 /* Always adds default duration 250 ms, regardless of what came in over the line */
-static int add_digit(struct sip_request *req, char digit)
+static int add_digit(struct sip_request *req, char digit, unsigned int duration)
 {
        char tmp[256];
 
-       snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=250\r\n", digit);
+       snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=%u\r\n", digit, duration);
        add_header(req, "Content-Type", "application/dtmf-relay");
        add_header_contentLength(req, strlen(tmp));
        add_line(req, tmp);
@@ -7491,12 +7519,12 @@ static int transmit_refer(struct sip_pvt *p, const char *dest)
 
 
 /*! \brief Send SIP INFO dtmf message, see Cisco documentation on cisco.com */
-static int transmit_info_with_digit(struct sip_pvt *p, const char digit)
+static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration)
 {
        struct sip_request req;
 
        reqprep(&req, p, SIP_INFO, 0, 1);
-       add_digit(&req, digit);
+       add_digit(&req, digit, duration);
        return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
@@ -10881,6 +10909,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
        /* Need to check the media/type */
        if (!strcasecmp(c, "application/dtmf-relay") ||
            !strcasecmp(c, "application/vnd.nortelnetworks.digits")) {
+               unsigned int duration = 0;
 
                /* Try getting the "signal=" part */
                if (ast_strlen_zero(c = get_body(req, "Signal")) && ast_strlen_zero(c = get_body(req, "d"))) {
@@ -10890,7 +10919,12 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                } else {
                        ast_copy_string(buf, c, sizeof(buf));
                }
-       
+
+               if (!ast_strlen_zero((c = get_body(req, "Duration"))))
+                       duration = atoi(c);
+               if (!duration)
+                       duration = 100; /* 100 ms */
+
                if (!p->owner) {        /* not a PBX call */
                        transmit_response(p, "481 Call leg/transaction does not exist", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -10928,6 +10962,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                        } else if (event < 16) {
                                f.subclass = 'A' + (event - 12);
                        }
+                       f.len = duration;
                        ast_queue_frame(p->owner, &f);
                        if (sipdebug)
                                ast_verbose("* DTMF-relay event received: %c\n", f.subclass);
@@ -11428,7 +11463,7 @@ static int func_header_read(struct ast_channel *chan, const char *function, char
        }
 
        ast_channel_lock(chan);
-       if (chan->tech != &sip_tech) {
+       if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
                ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
                ast_channel_unlock(chan);
                return -1;
@@ -11603,7 +11638,7 @@ static int function_sipchaninfo_read(struct ast_channel *chan, const char *cmd,
        }
 
        ast_channel_lock(chan);
-       if (chan->tech != &sip_tech) {
+       if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
                ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
                ast_channel_unlock(chan);
                return -1;
@@ -11851,7 +11886,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                                ast_log(LOG_WARNING, "Ooooh.. no tech!  That's REALLY bad\n");
                                break;
                        }
-                       if (bridgepeer->tech == &sip_tech) {
+                       if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
                                bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
                                if (bridgepvt->udptl) {
                                        if (p->t38.state == T38_PEER_REINVITE) {
@@ -13654,7 +13689,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                if ((bridgepeer = ast_bridged_channel(p->owner))) {
                                        /* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
                                        /*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
-                                       if (bridgepeer->tech == &sip_tech) {
+                                       if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
                                                bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
                                                if (bridgepvt->t38.state == T38_DISABLED) {
                                                        if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
@@ -13708,7 +13743,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                struct ast_channel *bridgepeer = NULL;
                                struct sip_pvt *bridgepvt = NULL;
                                if ((bridgepeer = ast_bridged_channel(p->owner))) {
-                                       if (bridgepeer->tech == &sip_tech) {
+                                       if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
                                                bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
                                                /* Does the bridged peer have T38 ? */
                                                if (bridgepvt->t38.state == T38_ENABLED) {
@@ -17015,7 +17050,7 @@ static int sip_dtmfmode(struct ast_channel *chan, void *data)
                return 0;
        }
        ast_channel_lock(chan);
-       if (chan->tech != &sip_tech) {
+       if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
                ast_log(LOG_WARNING, "Call this application only on SIP incoming calls\n");
                ast_channel_unlock(chan);
                return 0;
index 927172e..350db45 100644 (file)
@@ -1028,7 +1028,7 @@ static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
-static int skinny_senddigit_end(struct ast_channel *ast, char digit);
+static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 
 static const struct ast_channel_tech skinny_tech = {
        .type = "Skinny",
@@ -2565,7 +2565,7 @@ static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
        return -1; /* Start inband indications */
 }
 
-static int skinny_senddigit_end(struct ast_channel *ast, char digit)
+static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
 #if 0
        struct skinny_subchannel *sub = ast->tech_pvt;
index ced9769..57d5d2c 100644 (file)
@@ -724,7 +724,7 @@ static struct zt_chan_conf zt_chan_conf_default(void) {
 
 static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
 static int zt_digit_begin(struct ast_channel *ast, char digit);
-static int zt_digit_end(struct ast_channel *ast, char digit);
+static int zt_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int zt_sendtext(struct ast_channel *c, const char *text);
 static int zt_call(struct ast_channel *ast, char *rdest, int timeout);
 static int zt_hangup(struct ast_channel *ast);
@@ -1170,7 +1170,7 @@ out:
        return 0;
 }
 
-static int zt_digit_end(struct ast_channel *chan, char digit)
+static int zt_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
 {
        struct zt_pvt *pvt;
        int res = 0;
index 60b68fe..e969594 100644 (file)
@@ -242,7 +242,7 @@ struct ast_channel_tech {
        int (* const send_digit_begin)(struct ast_channel *chan, char digit);
 
        /*! \brief Stop sending a literal DTMF digit */
-       int (* const send_digit_end)(struct ast_channel *chan, char digit);
+       int (* const send_digit_end)(struct ast_channel *chan, char digit, unsigned int duration);
 
        /*! \brief Call a given phone number (address, etc), but don't
           take longer than timeout seconds to do so.  */
@@ -479,7 +479,8 @@ struct ast_channel {
        struct ast_jb jb;                               /*!< The jitterbuffer state  */
 
        char emulate_dtmf_digit;                        /*!< Digit being emulated */
-       unsigned int emulate_dtmf_samples;              /*!< Number of samples left to emulate DTMF for */
+       unsigned int emulate_dtmf_duration;     /*!< Number of ms left to emulate DTMF for */
+       struct timeval dtmf_begin_tv;       /*!< The time that an in process digit began */
 
        /*! \brief Data stores on the channel */
        AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores;
@@ -498,34 +499,37 @@ enum {
 /*! \brief ast_channel flags */
 enum {
        /*! Queue incoming dtmf, to be released when this flag is turned off */
-       AST_FLAG_DEFER_DTMF =   (1 << 1),
+       AST_FLAG_DEFER_DTMF =    (1 << 1),
        /*! write should be interrupt generator */
-       AST_FLAG_WRITE_INT =    (1 << 2),
+       AST_FLAG_WRITE_INT =     (1 << 2),
        /*! a thread is blocking on this channel */
-       AST_FLAG_BLOCKING =     (1 << 3),
+       AST_FLAG_BLOCKING =      (1 << 3),
        /*! This is a zombie channel */
-       AST_FLAG_ZOMBIE =       (1 << 4),
+       AST_FLAG_ZOMBIE =        (1 << 4),
        /*! There is an exception pending */
-       AST_FLAG_EXCEPTION =    (1 << 5),
+       AST_FLAG_EXCEPTION =     (1 << 5),
        /*! Listening to moh XXX anthm promises me this will disappear XXX */
-       AST_FLAG_MOH =          (1 << 6),
+       AST_FLAG_MOH =           (1 << 6),
        /*! This channel is spying on another channel */
-       AST_FLAG_SPYING =       (1 << 7),
+       AST_FLAG_SPYING =        (1 << 7),
        /*! This channel is in a native bridge */
-       AST_FLAG_NBRIDGE =      (1 << 8),
+       AST_FLAG_NBRIDGE =       (1 << 8),
        /*! the channel is in an auto-incrementing dialplan processor,
         *  so when ->priority is set, it will get incremented before
         *  finding the next priority to run */
-       AST_FLAG_IN_AUTOLOOP =  (1 << 9),
+       AST_FLAG_IN_AUTOLOOP =   (1 << 9),
        /*! This is an outgoing call */
-       AST_FLAG_OUTGOING =     (1 << 10),
+       AST_FLAG_OUTGOING =      (1 << 10),
        /*! This channel is being whispered on */
-       AST_FLAG_WHISPER =      (1 << 11),
+       AST_FLAG_WHISPER =       (1 << 11),
        /*! A DTMF_BEGIN frame has been read from this channel, but not yet an END */
-       AST_FLAG_IN_DTMF =      (1 << 12),
+       AST_FLAG_IN_DTMF =       (1 << 12),
        /*! A DTMF_END was received when not IN_DTMF, so the length of the digit is 
         *  currently being emulated */
-       AST_FLAG_EMULATE_DTMF = (1 << 13),
+       AST_FLAG_EMULATE_DTMF =  (1 << 13),
+       /*! This is set to tell the channel not to generate DTMF begin frames, and
+        *  to instead only generate END frames. */
+       AST_FLAG_END_DTMF_ONLY = (1 << 14),
 };
 
 /*! \brief ast_bridge_config flags */
@@ -934,14 +938,16 @@ int ast_senddigit(struct ast_channel *chan, char digit);
  * \return Returns 0 on success, -1 on failure
  */
 int ast_senddigit_begin(struct ast_channel *chan, char digit);
+
 /*! \brief Send a DTMF digit to a channel
 
  * Send a DTMF digit to a channel.
  * \param chan channel to act upon
  * \param digit the DTMF digit to send, encoded in ASCII
+ * \param duration the duration of the digit ending in ms
  * \return Returns 0 on success, -1 on failure
  */
-int ast_senddigit_end(struct ast_channel *chan, char digit);
+int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration);
 
 /*! \brief Receives a text string from a channel
  * Read a string of text from a channel
index 71af27f..9bedf87 100644 (file)
@@ -101,8 +101,8 @@ unsigned long global_fin, global_fout;
 AST_THREADSTORAGE(state2str_threadbuf);
 #define STATE2STR_BUFSIZE   32
 
-/* XXX 100ms ... this won't work with wideband support */
-#define AST_DEFAULT_EMULATE_DTMF_SAMPLES 800
+/*! 100ms */
+#define AST_DEFAULT_EMULATE_DTMF_DURATION 100
 
 struct chanlist {
        const struct ast_channel_tech *tech;
@@ -2003,14 +2003,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
        if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) && 
            !ast_strlen_zero(chan->dtmfq)) {
                /* We have DTMF that has been deferred.  Return it now */
-               chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN;
                chan->dtmff.subclass = chan->dtmfq[0];
                /* Drop first digit from the buffer */
                memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
                f = &chan->dtmff;
-               ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
-               chan->emulate_dtmf_digit = f->subclass;
-               chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
+               if (ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY))
+                       chan->dtmff.frametype = AST_FRAME_DTMF_END;
+               else {
+                       chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN;
+                       ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
+                       chan->emulate_dtmf_digit = f->subclass;
+                       chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
+                       chan->dtmf_begin_tv = ast_tvnow();
+               }
                goto done;
        }
        
@@ -2128,38 +2133,47 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        break;
                case AST_FRAME_DTMF_END:
                        ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
-                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) {
+                       /* Queue it up if DTMF is deffered, or if DTMF emulation is forced.
+                        * However, only let emulation be forced if the other end cares about BEGIN frames */
+                       if ( ast_test_flag(chan, AST_FLAG_DEFER_DTMF) ||
+                               (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) ) {
                                if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
                                        chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
                                else
                                        ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
                                ast_frfree(f);
                                f = &ast_null_frame;
-                       } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
+                       } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY)) {
                                f->frametype = AST_FRAME_DTMF_BEGIN;
                                ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
                                chan->emulate_dtmf_digit = f->subclass;
-                               if (f->samples)
-                                       chan->emulate_dtmf_samples = f->samples;
+                               chan->dtmf_begin_tv = ast_tvnow();
+                               if (f->len)
+                                       chan->emulate_dtmf_duration = f->len;
                                else
-                                       chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
-                       } else 
+                                       chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
+                       } else {
                                ast_clear_flag(chan, AST_FLAG_IN_DTMF);
+                               if (!f->len)
+                                       f->len = ast_tvdiff_ms(chan->dtmf_begin_tv, ast_tvnow());
+                       }
                        break;
                case AST_FRAME_DTMF_BEGIN:
                        ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
-                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
+                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY)) {
                                ast_frfree(f);
                                f = &ast_null_frame;
-                       } else 
+                       } else {
                                ast_set_flag(chan, AST_FLAG_IN_DTMF);
+                               chan->dtmf_begin_tv = ast_tvnow();
+                       }
                        break;
                case AST_FRAME_VOICE:
                        /* The EMULATE_DTMF flag must be cleared here as opposed to when the samples
                         * first get to zero, because we want to make sure we pass at least one
                         * voice frame through before starting the next digit, to ensure a gap
                         * between DTMF digits. */
-                       if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_samples) {
+                       if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_duration) {
                                ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF);
                                chan->emulate_dtmf_digit = 0;
                        }
@@ -2168,12 +2182,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                ast_frfree(f);
                                f = &ast_null_frame;
                        } else if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) {
-                               if (f->samples >= chan->emulate_dtmf_samples) {
-                                       chan->emulate_dtmf_samples = 0;
+                               if ((f->samples / 8) >= chan->emulate_dtmf_duration) { /* XXX 8kHz */
+                                       chan->emulate_dtmf_duration = 0;
                                        f->frametype = AST_FRAME_DTMF_END;
                                        f->subclass = chan->emulate_dtmf_digit;
                                } else {
-                                       chan->emulate_dtmf_samples -= f->samples;
+                                       chan->emulate_dtmf_duration -= f->samples / 8; /* XXX 8kHz */
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                }
@@ -2448,12 +2462,12 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit)
        return 0;
 }
 
-int ast_senddigit_end(struct ast_channel *chan, char digit)
+int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration)
 {
        int res = -1;
 
        if (chan->tech->send_digit_end)
-               res = chan->tech->send_digit_end(chan, digit);
+               res = chan->tech->send_digit_end(chan, digit, duration);
 
        if (res && chan->generator)
                ast_playtones_stop(chan);
@@ -2463,11 +2477,12 @@ int ast_senddigit_end(struct ast_channel *chan, char digit)
 
 int ast_senddigit(struct ast_channel *chan, char digit)
 {
-       ast_senddigit_begin(chan, digit);
-       
-       ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */
+       if (!ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) {
+               ast_senddigit_begin(chan, digit);
+               ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */
+       }
        
-       return ast_senddigit_end(chan, digit);
+       return ast_senddigit_end(chan, digit, 100);
 }
 
 int ast_prod(struct ast_channel *chan)
@@ -2545,7 +2560,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        case AST_FRAME_DTMF_END:
                ast_clear_flag(chan, AST_FLAG_BLOCKING);
                ast_channel_unlock(chan);
-               res = ast_senddigit_end(chan, fr->subclass);
+               res = ast_senddigit_end(chan, fr->subclass, fr->len);
                ast_channel_lock(chan);
                CHECK_BLOCKING(chan);
                break;
@@ -3841,6 +3856,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        nexteventts = ast_tvsub(nexteventts, ast_samp2tv(config->play_warning, 1000));
        }
 
+       if (!c0->tech->send_digit_begin)
+               ast_set_flag(c1, AST_FLAG_END_DTMF_ONLY);
+       if (!c1->tech->send_digit_begin)
+               ast_set_flag(c0, AST_FLAG_END_DTMF_ONLY);
+
        for (/* ever */;;) {
                struct timeval now = { 0, };
                int to;
@@ -3994,6 +4014,9 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        break;
        }
 
+       ast_clear_flag(c0, AST_FLAG_END_DTMF_ONLY);
+       ast_clear_flag(c1, AST_FLAG_END_DTMF_ONLY);
+
        c0->_bridge = NULL;
        c1->_bridge = NULL;
 
index 6471f19..c089db8 100644 (file)
@@ -501,11 +501,9 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
                strcpy((char *)out->src, f->src);
        }
        out->has_timing_info = f->has_timing_info;
-       if (f->has_timing_info) {
-               out->ts = f->ts;
-               out->len = f->len;
-               out->seqno = f->seqno;
-       }
+       out->ts = f->ts;
+       out->len = f->len;
+       out->seqno = f->seqno;
        return out;
 }
 
index 13c5f57..2273296 100644 (file)
@@ -140,7 +140,7 @@ struct ast_rtp {
        char resp;
        unsigned int lasteventendseqn;
        int dtmfcount;
-       unsigned int dtmfduration;
+       unsigned int dtmfsamples;
        /* DTMF Transmission Variables */
        unsigned int lastdigitts;
        char sending_digit;     /* boolean - are we sending digits */
@@ -431,7 +431,7 @@ static int stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *dat
        
        if (len < sizeof(struct stun_header)) {
                if (option_debug)
-                       ast_log(LOG_DEBUG, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, sizeof(struct stun_header));
+                       ast_log(LOG_DEBUG, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
                return -1;
        }
        if (stundebug)
@@ -446,7 +446,7 @@ static int stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *dat
        while(len) {
                if (len < sizeof(struct stun_attr)) {
                        if (option_debug)
-                               ast_log(LOG_DEBUG, "Runt Attribute (got %d, expecting %d)\n", (int)len, sizeof(struct stun_attr));
+                               ast_log(LOG_DEBUG, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
                        break;
                }
                attr = (struct stun_attr *)data;
@@ -619,7 +619,7 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type
                if (option_debug)
                        ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(rtp->them.sin_addr));
                rtp->resp = 0;
-               rtp->dtmfduration = 0;
+               rtp->dtmfsamples = 0;
                return &ast_null_frame;
        }
        if (option_debug)
@@ -732,14 +732,14 @@ static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *
                /* Why we should care on DTMF compensation at reception? */
                if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
                        f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
-                       rtp->dtmfduration = 0;
+                       rtp->dtmfsamples = 0;
                }
        } else if ((rtp->resp == resp) && !power) {
                f = send_dtmf(rtp, AST_FRAME_DTMF_END);
-               f->samples = rtp->dtmfduration * 8;
+               f->samples = rtp->dtmfsamples * 8;
                rtp->resp = 0;
        } else if (rtp->resp == resp)
-               rtp->dtmfduration += 20 * 8;
+               rtp->dtmfsamples += 20 * 8;
        rtp->dtmfcount = dtmftimeout;
        return f;
 }
@@ -759,18 +759,18 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
 {
        unsigned int event;
        unsigned int event_end;
-       unsigned int duration;
+       unsigned int samples;
        char resp = 0;
        struct ast_frame *f = NULL;
 
-       /* Figure out event, event end, and duration */
+       /* Figure out event, event end, and samples */
        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;
+       samples = ntohl(*((unsigned int *)(data)));
+       samples &= 0xFFFF;
 
        /* Print out debug if turned on */
        if (rtpdebug || option_debug > 2)
@@ -795,19 +795,19 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
                        f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
        } else if (event_end & 0x80 && rtp->lasteventendseqn != seqno && rtp->resp) {
                f = send_dtmf(rtp, AST_FRAME_DTMF_END);
-               f->samples = duration;
+               f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
                rtp->resp = 0;
                rtp->lasteventendseqn = seqno;
        } else if (ast_test_flag(rtp, FLAG_DTMF_COMPENSATE) && event_end & 0x80 && rtp->lasteventendseqn != seqno) {
                rtp->resp = resp;
                f = send_dtmf(rtp, AST_FRAME_DTMF_END);
-               f->samples = duration;
+               f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
                rtp->resp = 0;
                rtp->lasteventendseqn = seqno;
        }
 
        rtp->dtmfcount = dtmftimeout;
-       rtp->dtmfduration = duration;
+       rtp->dtmfsamples = samples;
 
        return f;
 }
@@ -2065,7 +2065,7 @@ void ast_rtp_reset(struct ast_rtp *rtp)
        rtp->lasttxformat = 0;
        rtp->lastrxformat = 0;
        rtp->dtmfcount = 0;
-       rtp->dtmfduration = 0;
+       rtp->dtmfsamples = 0;
        rtp->seqno = 0;
        rtp->rxseqno = 0;
 }
@@ -3281,6 +3281,22 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
                audio_p1_res = AST_RTP_TRY_PARTIAL;
        }
 
+       /* If both sides are not using the same method of DTMF transmission 
+        * (ie: one is RFC2833, other is INFO... then we can not do direct media. 
+        * --------------------------------------------------
+        * | DTMF Mode |  HAS_DTMF  |  Accepts Begin Frames |
+        * |-----------|------------|-----------------------|
+        * | Inband    | False      | True                  |
+        * | RFC2833   | True       | True                  |
+        * | SIP Info  | False      | False                 |
+        * --------------------------------------------------
+        */
+       if ( (ast_test_flag(p0, FLAG_HAS_DTMF) != ast_test_flag(p1, FLAG_HAS_DTMF)) ||
+                (!c0->tech->send_digit_begin != !c1->tech->send_digit_begin)) {
+               audio_p0_res = AST_RTP_TRY_PARTIAL;
+               audio_p1_res = AST_RTP_TRY_PARTIAL;
+       }
+
        /* Get codecs from both sides */
        codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
        codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;