Merge in VLDTMF support with Zaptel/Core done by the ever great Darumkilla Russell...
authorJoshua Colp <jcolp@digium.com>
Thu, 31 Aug 2006 01:59:02 +0000 (01:59 +0000)
committerJoshua Colp <jcolp@digium.com>
Thu, 31 Aug 2006 01:59:02 +0000 (01:59 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@41507 65c4cc65-6c06-0410-ace0-fbb531ad65f3

29 files changed:
UPGRADE.txt
apps/app_echo.c
channels/chan_agent.c
channels/chan_alsa.c
channels/chan_features.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_vpb.cc
channels/chan_zap.c
channels/iax2-parser.c
configs/sip.conf.sample
include/asterisk/channel.h
include/asterisk/frame.h
include/asterisk/rtp.h
main/app.c
main/channel.c
main/dsp.c
main/file.c
main/rtp.c
res/res_agi.c
res/res_features.c

index 9a75748..f0e7246 100644 (file)
@@ -303,6 +303,12 @@ The SIP channel:
   option in sip.conf is removed to osp.conf as authpolicy. allowguest option
   in sip.conf cannot be set as osp anymore. 
 
+* The Asterisk RTP stack has been changed in regards to RFC2833 reception
+  and transmission. Packets will now be sent with proper duration instead of all
+  at once. If you are receiving calls from a pre-1.4 Asterisk installation you
+  will want to turn on the rfc2833compensate option. Without this option your
+  DTMF reception may act poorly.
+
 * The $SIPUSERAGENT dialplan variable is deprecated and will be removed
   in coming versions of Asterisk. Please use the dialplan function
   SIPCHANINFO(useragent) instead.
index 19a8638..4b2c940 100644 (file)
@@ -71,19 +71,13 @@ static int echo_exec(struct ast_channel *chan, void *data)
                f->delivery.tv_usec = 0;
                switch (f->frametype) {
                case AST_FRAME_DTMF:
-               case AST_FRAME_DTMF_END:
                        if (f->subclass == '#') {
                                res = 0;
                                ast_frfree(f);
                                goto end;
                        }
                        /* fall through */
-               case AST_FRAME_DTMF_BEGIN:
-               case AST_FRAME_VOICE:
-               case AST_FRAME_VIDEO:
-               case AST_FRAME_TEXT:
-               case AST_FRAME_HTML:
-               case AST_FRAME_IMAGE:
+               default:
                        if (ast_write(chan, f)) {
                                ast_frfree(f);
                                goto end;
index 0a9b890..4eeffe9 100644 (file)
@@ -238,7 +238,8 @@ static AST_LIST_HEAD_STATIC(agents, agent_pvt);     /*!< Holds the list of agents (l
 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
 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(struct ast_channel *ast, char digit);
+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_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);
@@ -258,7 +259,8 @@ static const struct ast_channel_tech agent_tech = {
        .capabilities = -1,
        .requester = agent_request,
        .devicestate = agent_devicestate,
-       .send_digit = agent_digit,
+       .send_digit_begin = agent_digit_begin,
+       .send_digit_end = agent_digit_end,
        .call = agent_call,
        .hangup = agent_hangup,
        .answer = agent_answer,
@@ -491,7 +493,8 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
                                }
                        }
                        break;
-               case AST_FRAME_DTMF:
+               case AST_FRAME_DTMF_BEGIN:
+               case AST_FRAME_DTMF_END:
                        if (!p->acknowledged && (f->subclass == '#')) {
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
@@ -511,7 +514,9 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
                                ast_frfree(f);
                                f = &ast_null_frame;
                        }
-                       break;
+               default:
+                       /* pass everything else on through */
+                       break;
                }
        }
 
@@ -603,15 +608,22 @@ static int agent_indicate(struct ast_channel *ast, int condition, const void *da
        return res;
 }
 
-static int agent_digit(struct ast_channel *ast, char digit)
+static int agent_digit_begin(struct ast_channel *ast, char digit)
 {
        struct agent_pvt *p = ast->tech_pvt;
        int res = -1;
        ast_mutex_lock(&p->lock);
-       if (p->chan)
-               res = p->chan->tech->send_digit(p->chan, digit);
-       else
-               res = 0;
+       ast_senddigit_begin(p->chan, digit);
+       ast_mutex_unlock(&p->lock);
+       return res;
+}
+
+static int agent_digit_end(struct ast_channel *ast, char digit)
+{
+       struct agent_pvt *p = ast->tech_pvt;
+       int res = -1;
+       ast_mutex_lock(&p->lock);
+       ast_senddigit_end(p->chan, digit);
        ast_mutex_unlock(&p->lock);
        return res;
 }
index 5a4d627..4237ba8 100644 (file)
@@ -203,7 +203,7 @@ static const struct ast_channel_tech alsa_tech = {
        .description = tdesc,
        .capabilities = AST_FORMAT_SLINEAR,
        .requester = alsa_request,
-       .send_digit = alsa_digit,
+       .send_digit_end = alsa_digit,
        .send_text = alsa_text,
        .hangup = alsa_hangup,
        .answer = alsa_answer,
index d1feadb..66b6da3 100644 (file)
@@ -95,7 +95,8 @@ static AST_LIST_HEAD_STATIC(features, feature_pvt);
 #define SUB_THREEWAY   2                       /* Three-way call */
 
 static struct ast_channel *features_request(const char *type, int format, void *data, int *cause);
-static int features_digit(struct ast_channel *ast, char digit);
+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_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);
@@ -109,7 +110,8 @@ static const struct ast_channel_tech features_tech = {
        .description = tdesc,
        .capabilities = -1,
        .requester = features_request,
-       .send_digit = features_digit,
+       .send_digit_begin = features_digit_begin,
+       .send_digit_end = features_digit_end,
        .call = features_call,
        .hangup = features_hangup,
        .answer = features_answer,
@@ -300,7 +302,7 @@ static int features_indicate(struct ast_channel *ast, int condition, const void
        return res;
 }
 
-static int features_digit(struct ast_channel *ast, char digit)
+static int features_digit_begin(struct ast_channel *ast, char digit)
 {
        struct feature_pvt *p = ast->tech_pvt;
        int res = -1;
@@ -310,7 +312,23 @@ static int features_digit(struct ast_channel *ast, char digit)
        ast_mutex_lock(&p->lock);
        x = indexof(p, ast, 0);
        if (!x && p->subchan)
-               res = ast_senddigit(p->subchan, digit);
+               res = ast_senddigit_begin(p->subchan, digit);
+       ast_mutex_unlock(&p->lock);
+
+       return res;
+}
+
+static int features_digit_end(struct ast_channel *ast, char digit)
+{
+       struct feature_pvt *p = ast->tech_pvt;
+       int res = -1;
+       int x;
+
+       /* Queue up a frame representing the indication as a control frame */
+       ast_mutex_lock(&p->lock);
+       x = indexof(p, ast, 0);
+       if (!x && p->subchan)
+               res = ast_senddigit_end(p->subchan, digit);
        ast_mutex_unlock(&p->lock);
        return res;
 }
index 6b956e5..dc498a2 100644 (file)
@@ -220,7 +220,8 @@ static int restart_monitor(void);
 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(struct ast_channel *c, char digit);
+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_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);
@@ -235,7 +236,8 @@ static const struct ast_channel_tech oh323_tech = {
        .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
        .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
        .requester = oh323_request,
-       .send_digit = oh323_digit,
+       .send_digit_begin = oh323_digit_begin,
+       .send_digit_end = oh323_digit_end,
        .call = oh323_call,
        .hangup = oh323_hangup,
        .answer = oh323_answer,
@@ -381,11 +383,17 @@ static void oh323_destroy(struct oh323_pvt *pvt)
        ast_mutex_unlock(&iflock);
 }
 
+static int oh323_digit_begin(struct ast_channel *chan, char digit)
+{
+       /* XXX Implement me, plz, kthx */
+       return 0;
+}
+
 /**
  * Send (play) the specified digit to the channel.
  * 
  */
-static int oh323_digit(struct ast_channel *c, char digit)
+static int oh323_digit_end(struct ast_channel *c, char digit)
 {
        struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
        char *token;
index 1d404c3..60841e0 100644 (file)
@@ -776,7 +776,8 @@ static int expire_registry(void *data);
 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(struct ast_channel *c, char digit);
+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_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);
@@ -809,7 +810,8 @@ static const struct ast_channel_tech iax2_tech = {
        .properties = AST_CHAN_TP_WANTSJITTER,
        .requester = iax2_request,
        .devicestate = iax2_devicestate,
-       .send_digit = iax2_digit,
+       .send_digit_begin = iax2_digit_begin,
+       .send_digit_end = iax2_digit_end,
        .send_text = iax2_sendtext,
        .send_image = iax2_sendimage,
        .send_html = iax2_sendhtml,
@@ -2379,9 +2381,14 @@ static int iax2_transmit(struct iax_frame *fr)
 
 
 
-static int iax2_digit(struct ast_channel *c, char digit)
+static int iax2_digit_begin(struct ast_channel *c, char digit)
 {
-       return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
+       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)
+{
+       return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
 }
 
 static int iax2_sendtext(struct ast_channel *c, const char *text)
index b3d7ea6..a44b420 100644 (file)
@@ -171,7 +171,8 @@ 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(struct ast_channel *ast, char digit);
+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_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);
@@ -194,7 +195,8 @@ static const struct ast_channel_tech jingle_tech = {
        .description = "Jingle Channel Driver",
        .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
        .requester = jingle_request,
-       .send_digit = jingle_digit,
+       .send_digit_begin = jingle_digit_begin,
+       .send_digit_end = jingle_digit_end,
        .bridge = ast_rtp_bridge,
        .call = jingle_call,
        .hangup = jingle_hangup,
@@ -1181,7 +1183,13 @@ static int jingle_indicate(struct ast_channel *ast, int condition, const void *d
        return res;
 }
 
-static int jingle_digit(struct ast_channel *ast, char digit)
+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)
 {
        struct jingle_pvt *p = ast->tech_pvt;
        struct jingle *client = p->parent;
index a9b0582..fec9c62 100644 (file)
@@ -67,7 +67,8 @@ static const char tdesc[] = "Local Proxy Channel Driver";
 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
 
 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
-static int local_digit(struct ast_channel *ast, char digit);
+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_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);
@@ -85,7 +86,8 @@ static const struct ast_channel_tech local_tech = {
        .description = tdesc,
        .capabilities = -1,
        .requester = local_request,
-       .send_digit = local_digit,
+       .send_digit_begin = local_digit_begin,
+       .send_digit_end = local_digit_end,
        .call = local_call,
        .hangup = local_hangup,
        .answer = local_answer,
@@ -327,11 +329,11 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da
        return res;
 }
 
-static int local_digit(struct ast_channel *ast, char digit)
+static int local_digit_begin(struct ast_channel *ast, char digit)
 {
        struct local_pvt *p = ast->tech_pvt;
        int res = -1;
-       struct ast_frame f = { AST_FRAME_DTMF, };
+       struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
        int isoutbound;
 
        ast_mutex_lock(&p->lock);
@@ -339,6 +341,23 @@ static int local_digit(struct ast_channel *ast, char digit)
        f.subclass = digit;
        res = local_queue_frame(p, isoutbound, &f, ast);
        ast_mutex_unlock(&p->lock);
+
+       return res;
+}
+
+static int local_digit_end(struct ast_channel *ast, char digit)
+{
+       struct local_pvt *p = ast->tech_pvt;
+       int res = -1;
+       struct ast_frame f = { AST_FRAME_DTMF_END, };
+       int isoutbound;
+
+       ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
+       f.subclass = digit;
+       res = local_queue_frame(p, isoutbound, &f, ast);
+       ast_mutex_unlock(&p->lock);
+       
        return res;
 }
 
index c77b8a6..05ab81e 100644 (file)
@@ -427,7 +427,8 @@ static struct ast_frame *mgcp_read(struct ast_channel *ast);
 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(struct ast_channel *ast, char digit);
+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_devicestate(void *data);
 
 static const struct ast_channel_tech mgcp_tech = {
@@ -444,7 +445,8 @@ static const struct ast_channel_tech mgcp_tech = {
        .write = mgcp_write,
        .indicate = mgcp_indicate,
        .fixup = mgcp_fixup,
-       .send_digit = mgcp_senddigit,
+       .send_digit_begin = mgcp_senddigit_begin,
+       .send_digit_end = mgcp_senddigit_end,
        .bridge = ast_rtp_bridge,
 };
 
@@ -1221,7 +1223,13 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        return 0;
 }
 
-static int mgcp_senddigit(struct ast_channel *ast, char digit)
+static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
+{
+       /* Let asterisk play inband indications */
+       return -1;
+}
+
+static int mgcp_senddigit_end(struct ast_channel *ast, char digit)
 {
        struct mgcp_subchannel *sub = ast->tech_pvt;
        char tmp[4];
@@ -1233,7 +1241,7 @@ static int mgcp_senddigit(struct ast_channel *ast, char digit)
        ast_mutex_lock(&sub->lock);
        transmit_notify_request(sub, tmp);
        ast_mutex_unlock(&sub->lock);
-       return -1;
+       return -1; /* Return non-zero so that Asterisk will stop the inband indications */
 }
 
 /*!
index 9631a8c..201d38c 100644 (file)
@@ -2006,7 +2006,13 @@ static int misdn_answer(struct ast_channel *ast)
        return 0;
 }
 
-static int misdn_digit(struct ast_channel *ast, char digit )
+static int misdn_digit_begin(struct ast_channel *chan, char digit)
+{
+       /* XXX Modify this callback to support Asterisk controlling the length of DTMF */
+       return 0;
+}
+
+static int misdn_digit_end(struct ast_channel *ast, char digit )
 {
        struct chan_list *p;
        
@@ -2983,7 +2989,8 @@ static struct ast_channel_tech misdn_tech = {
        .description="Channel driver for mISDN Support (Bri/Pri)",
        .capabilities= AST_FORMAT_ALAW ,
        .requester=misdn_request,
-       .send_digit=misdn_digit,
+       .send_digit_begin=misdn_digit_begin,
+       .send_digit_end=misdn_digit_end,
        .call=misdn_call,
        .bridge=misdn_bridge, 
        .hangup=misdn_hangup,
@@ -3001,7 +3008,8 @@ static struct ast_channel_tech misdn_tech_wo_bridge = {
        .description="Channel driver for mISDN Support (Bri/Pri)",
        .capabilities=AST_FORMAT_ALAW ,
        .requester=misdn_request,
-       .send_digit=misdn_digit,
+       .send_digit_begin=misdn_digit_begin,
+       .send_digit_end=misdn_digit_end,
        .call=misdn_call,
        .hangup=misdn_hangup,
        .answer=misdn_answer,
index b298146..e40aacb 100644 (file)
@@ -407,7 +407,8 @@ 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(struct ast_channel *c, char digit);
+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_text(struct ast_channel *c, const char *text);
 static int oss_hangup(struct ast_channel *c);
 static int oss_answer(struct ast_channel *c);
@@ -423,7 +424,8 @@ static const struct ast_channel_tech oss_tech = {
        .description =  tdesc,
        .capabilities = AST_FORMAT_SLINEAR,
        .requester = oss_request,
-       .send_digit = oss_digit,
+       .send_digit_begin = oss_digit_begin,
+       .send_digit_end = oss_digit_end,
        .send_text = oss_text,
        .hangup = oss_hangup,
        .answer = oss_answer,
@@ -757,7 +759,12 @@ static int setformat(struct chan_oss_pvt *o, int mode)
 /*
  * some of the standard methods supported by channels.
  */
-static int oss_digit(struct ast_channel *c, char digit)
+static int oss_digit_begin(struct ast_channel *c, char digit)
+{
+       return 0;
+}
+
+static int oss_digit_end(struct ast_channel *c, char digit)
 {
        /* no better use for received digits than print them */
        ast_verbose( " << Console Received digit %c >> \n", digit);
index 87e971a..bb31eba 100644 (file)
@@ -161,7 +161,8 @@ static char cid_num[AST_MAX_EXTENSION];
 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(struct ast_channel *ast, char digit);
+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_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);
@@ -177,7 +178,8 @@ static const struct ast_channel_tech phone_tech = {
        .description = tdesc,
        .capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
        .requester = phone_request,
-       .send_digit = phone_digit,
+       .send_digit_begin = phone_digit_begin,
+       .send_digit_end = phone_digit_end,
        .call = phone_call,
        .hangup = phone_hangup,
        .answer = phone_answer,
@@ -192,7 +194,8 @@ static struct ast_channel_tech phone_tech_fxs = {
        .type = "Phone",
        .description = tdesc,
        .requester = phone_request,
-       .send_digit = phone_digit,
+       .send_digit_begin = phone_digit_begin,
+       .send_digit_end = phone_digit_end,
        .call = phone_call,
        .hangup = phone_hangup,
        .answer = phone_answer,
@@ -240,7 +243,13 @@ static int phone_fixup(struct ast_channel *old, struct ast_channel *new)
        return 0;
 }
 
-static int phone_digit(struct ast_channel *ast, char digit)
+static int phone_digit_begin(struct ast_channel *chan, char digit)
+{
+       /* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
+       return 0;
+}
+
+static int phone_digit_end(struct ast_channel *ast, char digit)
 {
        struct phone_pvt *p;
        int outdigit;
@@ -329,7 +338,7 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
                {
                  digit++;
                  while (*digit)
-                   phone_digit(ast, *digit++);
+                   phone_digit_end(ast, *digit++);
                }
        }
  
index 948dc3b..aed8b58 100644 (file)
@@ -743,9 +743,10 @@ struct sip_auth {
 #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 */
@@ -1161,7 +1162,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
 static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
 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(struct ast_channel *ast, char digit);
+static int sip_senddigit_begin(struct ast_channel *ast, char digit);
+static int sip_senddigit_end(struct ast_channel *ast, char digit);
 
 /*--- Transmitting responses and requests */
 static int sipsock_read(int *id, int fd, short events, void *ignore);
@@ -1512,7 +1514,8 @@ static const struct ast_channel_tech sip_tech = {
        .indicate = sip_indicate,
        .transfer = sip_transfer,
        .fixup = sip_fixup,
-       .send_digit = sip_senddigit,
+       .send_digit_begin = sip_senddigit_begin,
+       .send_digit_end = sip_senddigit_end,
        .bridge = ast_rtp_bridge,
        .send_text = sip_sendtext,
 };
@@ -2515,12 +2518,14 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer)
                        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)
@@ -3441,9 +3446,31 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        return ret;
 }
 
+static int sip_senddigit_begin(struct ast_channel *ast, char digit)
+{
+       struct sip_pvt *p = ast->tech_pvt;
+       int res = 0;
+
+       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;
+       }
+       ast_mutex_unlock(&p->lock);
+
+       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(struct ast_channel *ast, char digit)
+static int sip_senddigit_end(struct ast_channel *ast, char digit)
 {
        struct sip_pvt *p = ast->tech_pvt;
        int res = 0;
@@ -3455,13 +3482,14 @@ static int sip_senddigit(struct ast_channel *ast, char digit)
                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;
+               res = -1; /* Tell Asterisk to stop inband indications */
                break;
        }
        ast_mutex_unlock(&p->lock);
+
        return res;
 }
 
@@ -4049,10 +4077,12 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
                        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);
@@ -12835,6 +12865,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                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)) {
@@ -14856,6 +14887,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
        } 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;
index b05fabb..97c1245 100644 (file)
@@ -1013,7 +1013,8 @@ static struct ast_frame *skinny_read(struct ast_channel *ast);
 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(struct ast_channel *ast, char digit);
+static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
+static int skinny_senddigit_end(struct ast_channel *ast, char digit);
 
 static const struct ast_channel_tech skinny_tech = {
        .type = "Skinny",
@@ -1028,7 +1029,8 @@ static const struct ast_channel_tech skinny_tech = {
        .write = skinny_write,
        .indicate = skinny_indicate,
        .fixup = skinny_fixup,
-       .send_digit = skinny_senddigit,
+       .send_digit_begin = skinny_senddigit_begin,
+       .send_digit_end = skinny_senddigit_end,
 /*     .bridge = ast_rtp_bridge, */
 };
 
@@ -2467,7 +2469,12 @@ static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
        return 0;
 }
 
-static int skinny_senddigit(struct ast_channel *ast, char digit)
+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)
 {
 #if 0
        struct skinny_subchannel *sub = ast->tech_pvt;
@@ -2478,7 +2485,7 @@ static int skinny_senddigit(struct ast_channel *ast, char digit)
        sprintf(tmp, "%d", digit);
        transmit_tone(d->session, digit);
 #endif
-       return -1;
+       return -1; /* Stop inband indications */
 }
 
 static char *control2str(int ind) {
index 0a98590..26e1bee 100644 (file)
@@ -341,9 +341,9 @@ static struct vpb_pvt {
 
 static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, char *context);
 static void *do_chanreads(void *pvt);
-
 static struct ast_channel *vpb_request(const char *type, int format, void *data, int *cause);
-static int vpb_digit(struct ast_channel *ast, char digit);
+static int vpb_digit_begin(struct ast_channel *ast, char digit);
+static int vpb_digit_end(struct ast_channel *ast, char digit);
 static int vpb_call(struct ast_channel *ast, char *dest, int timeout);
 static int vpb_hangup(struct ast_channel *ast);
 static int vpb_answer(struct ast_channel *ast);
@@ -360,9 +360,8 @@ static struct ast_channel_tech vpb_tech = {
        properties: 0,
        requester: vpb_request,
        devicestate: NULL,
-       send_digit: vpb_digit,
-       send_digit_begin: NULL,
-       send_digit_end: NULL,
+       send_digit_begin: vpb_digit_begin,
+       send_digit_end: vpb_digit_end,
        call: vpb_call,
        hangup: vpb_hangup,
        answer: vpb_answer,
@@ -389,9 +388,8 @@ static struct ast_channel_tech vpb_tech_indicate = {
        properties: 0,
        requester: vpb_request,
        devicestate: NULL,
-       send_digit: vpb_digit,
-       send_digit_begin: NULL,
-       send_digit_end: NULL,
+       send_digit_begin: vpb_digit_begin,
+       send_digit_end: vpb_digit_end,
        call: vpb_call,
        hangup: vpb_hangup,
        answer: vpb_answer,
@@ -863,11 +861,11 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                vpb_timer_stop(p->ring_timer);
                                vpb_timer_start(p->ring_timer);
                        } else
-                               f.frametype = -1; /* ignore ring on station port. */
+                               f.frametype = AST_FRAME_NULL; /* ignore ring on station port. */
                        break;
 
                case VPB_RING_OFF:
-                       f.frametype = -1;
+                       f.frametype = AST_FRAME_NULL;
                        break;
 
                case VPB_TIMEREXP:
@@ -876,12 +874,12 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                p->state = VPB_STATE_PLAYBUSY;
                                vpb_timer_stop(p->busy_timer);
                                vpb_timer_start(p->busy_timer);
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        } else if (e->data == p->ringback_timer_id) {
                                playtone(p->handle, &Ringbacktone);
                                vpb_timer_stop(p->ringback_timer);
                                vpb_timer_start(p->ringback_timer);
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        } else if (e->data == p->ring_timer_id) {
                                /* We didnt get another ring in time! */
                                if (p->owner->_state != AST_STATE_UP)  {
@@ -890,23 +888,23 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                        f.subclass = AST_CONTROL_HANGUP;
                                } else {
                                        vpb_timer_stop(p->ring_timer);
-                                       f.frametype = -1;
+                                       f.frametype = AST_FRAME_NULL;
                                }
                                
                        } else {
-                               f.frametype = -1; /* Ignore. */
+                               f.frametype = AST_FRAME_NULL; /* Ignore. */
                        }
                        break;
 
                case VPB_DTMF_DOWN:
                case VPB_DTMF:
                        if (use_ast_dtmfdet){
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        } else if (p->owner->_state == AST_STATE_UP) {
                                        f.frametype = AST_FRAME_DTMF;
                                        f.subclass = e->data;
                        } else
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        break;
 
                case VPB_TONEDETECT:
@@ -950,11 +948,11 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                        f.subclass = AST_CONTROL_HANGUP;
                                } else {
                                        p->lastgrunt = ast_tvnow();
-                                       f.frametype = -1;
+                                       f.frametype = AST_FRAME_NULL;
                                }
                        } 
                        else {
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        }
                        break;
 
@@ -970,7 +968,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                f.subclass = AST_CONTROL_HANGUP;
                        #else
                        ast_log(LOG_NOTICE,"%s: Got call progress callback but blind dialing \n", p->dev); 
-                       f.frametype = -1;
+                       f.frametype = AST_FRAME_NULL;
                        #endif
                        break;
 
@@ -983,14 +981,14 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                if (p->owner->_state == AST_STATE_UP) 
                                        f.subclass = AST_CONTROL_HANGUP;
                                else
-                                       f.frametype = -1;
+                                       f.frametype = AST_FRAME_NULL;
                        }
                        break;
                case VPB_LOOP_ONHOOK:
                        if (p->owner->_state == AST_STATE_UP)
                                f.subclass = AST_CONTROL_HANGUP;
                        else
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        break;
                case VPB_STATION_ONHOOK:
                        f.subclass = AST_CONTROL_HANGUP;
@@ -1009,22 +1007,22 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                if (option_verbose > 1) 
                                        ast_verbose(VERBOSE_PREFIX_2 "%s: Dialend\n", p->dev);
                        } else {
-                               f.frametype = -1;
+                               f.frametype = AST_FRAME_NULL;
                        }
                        break;
 
                case VPB_PLAY_UNDERFLOW:
-                       f.frametype = -1;
+                       f.frametype = AST_FRAME_NULL;
                        vpb_reset_play_fifo_alarm(p->handle);
                        break;
 
                case VPB_RECORD_OVERFLOW:
-                       f.frametype = -1;
+                       f.frametype = AST_FRAME_NULL;
                        vpb_reset_record_fifo_alarm(p->handle);
                        break;
 
                default:
-                       f.frametype = -1;
+                       f.frametype = AST_FRAME_NULL;
                        break;
        }
 
@@ -1831,7 +1829,12 @@ static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        return 0;
 }
 
-static int vpb_digit(struct ast_channel *ast, char digit)
+static int vpb_digit_begin(struct ast_channel *ast, char digit)
+{
+       /* XXX Modify this callback to let Asterisk control the length of DTMF */
+       return 0;
+}
+static int vpb_digit_end(struct ast_channel *ast, char digit)
 {
        struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        char s[2];
index ae3e942..7c860ff 100644 (file)
@@ -690,10 +690,12 @@ static struct zt_pvt {
 #endif 
        int polarity;
        int dsp_features;
+       char begindigit;
 } *iflist = NULL, *ifend = NULL;
 
 static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
-static int zt_digit(struct ast_channel *ast, char digit);
+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_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);
@@ -711,7 +713,8 @@ static const struct ast_channel_tech zap_tech = {
        .description = tdesc,
        .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
        .requester = zt_request,
-       .send_digit = zt_digit,
+       .send_digit_begin = zt_digit_begin,
+       .send_digit_end = zt_digit_end,
        .send_text = zt_sendtext,
        .call = zt_call,
        .hangup = zt_hangup,
@@ -1002,45 +1005,113 @@ static int unalloc_sub(struct zt_pvt *p, int x)
        return 0;
 }
 
-static int zt_digit(struct ast_channel *ast, char digit)
+static int digit_to_dtmfindex(char digit)
 {
-       ZT_DIAL_OPERATION zo;
-       struct zt_pvt *p;
+       if (isdigit(digit))
+               return ZT_TONE_DTMF_BASE + (digit - '0');
+       else if (digit >= 'A' && digit <= 'D')
+               return ZT_TONE_DTMF_A + (digit - 'A');
+       else if (digit >= 'a' && digit <= 'd')
+               return ZT_TONE_DTMF_A + (digit - 'a');
+       else if (digit == '*')
+               return ZT_TONE_DTMF_s;
+       else if (digit == '#')
+               return ZT_TONE_DTMF_p;
+       else
+               return -1;
+}
+
+static int zt_digit_begin(struct ast_channel *chan, char digit)
+{
+       struct zt_pvt *pvt;
+       int index;
+       int dtmf = -1;
+       
+       pvt = chan->tech_pvt;
+
+       ast_mutex_lock(&pvt->lock);
+
+       index = zt_get_index(chan, pvt, 0);
+
+       if ((index != SUB_REAL) || !pvt->owner)
+               goto out;
+
+#ifdef HAVE_PRI
+       if ((pvt->sig == SIG_PRI) && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
+               if (pvt->setup_ack) {
+                       if (!pri_grab(pvt, pvt->pri)) {
+                               pri_information(pvt->pri->pri, pvt->call, digit);
+                               pri_rel(pvt->pri);
+                       } else
+                               ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
+               } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
+                       int res;
+                       ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
+                       res = strlen(pvt->dialdest);
+                       pvt->dialdest[res++] = digit;
+                       pvt->dialdest[res] = '\0';
+               }
+               goto out;
+       }
+#endif
+       if ((dtmf = digit_to_dtmfindex(digit)) == -1)
+               goto out;
+
+       if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].zfd, ZT_SENDTONE, &dtmf)) {
+               int res;
+               ZT_DIAL_OPERATION zo = {
+                       .op = ZT_DIAL_OP_APPEND,
+                       .dialstr[0] = 'T',
+                       .dialstr[1] = digit,
+                       .dialstr[2] = 0,
+               };
+               if ((res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
+                       ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
+               else
+                       pvt->dialing = 1;
+       } else {
+               ast_log(LOG_DEBUG, "Started VLDTMF digit '%c'\n", digit);
+               pvt->dialing = 1;
+               pvt->begindigit = digit;
+       }
+
+out:
+       ast_mutex_unlock(&pvt->lock);
+
+       return 0; /* Tell Asterisk not to generate inband indications */
+}
+
+static int zt_digit_end(struct ast_channel *chan, char digit)
+{
+       struct zt_pvt *pvt;
        int res = 0;
        int index;
-       p = ast->tech_pvt;
-       ast_mutex_lock(&p->lock);
-       index = zt_get_index(ast, p, 0);
-       if ((index == SUB_REAL) && p->owner) {
+       
+       pvt = chan->tech_pvt;
+
+       ast_mutex_lock(&pvt->lock);
+       
+       index = zt_get_index(chan, pvt, 0);
+
+       if ((index != SUB_REAL) || !pvt->owner || pvt->pulse)
+               goto out;
+
 #ifdef HAVE_PRI
-               if ((p->sig == SIG_PRI) && (ast->_state == AST_STATE_DIALING) && !p->proceeding) {
-                       if (p->setup_ack) {
-                               if (!pri_grab(p, p->pri)) {
-                                       pri_information(p->pri->pri,p->call,digit);
-                                       pri_rel(p->pri);
-                               } else
-                                       ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
-                       } else if (strlen(p->dialdest) < sizeof(p->dialdest) - 1) {
-                               ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
-                               res = strlen(p->dialdest);
-                               p->dialdest[res++] = digit;
-                               p->dialdest[res] = '\0';
-                       }
-               } else {
-#else
-               {
+       /* This means that the digit was already sent via PRI signalling */
+       if (pvt->sig == SIG_PRI && !pvt->begindigit)
+               goto out;
 #endif
-                       zo.op = ZT_DIAL_OP_APPEND;
-                       zo.dialstr[0] = 'T';
-                       zo.dialstr[1] = digit;
-                       zo.dialstr[2] = 0;
-                       if ((res = ioctl(p->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
-                               ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
-                       else
-                               p->dialing = 1;
-               }
+
+       if (pvt->begindigit) {
+               ast_log(LOG_DEBUG, "Ending VLDTMF digit '%c'\n", digit);
+               res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_SENDTONE, -1);
+               pvt->dialing = 0;
+               pvt->begindigit = 0;
        }
-       ast_mutex_unlock(&p->lock);
+
+out:
+       ast_mutex_unlock(&pvt->lock);
+
        return res;
 }
 
@@ -3543,21 +3614,14 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
        ast_log(LOG_DEBUG, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
 
        if (res & (ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFUP)) {
-               if (res & ZT_EVENT_PULSEDIGIT)
-                       p->pulsedial = 1;
-               else
-                       p->pulsedial = 0;
+               p->pulsedial =  (res & ZT_EVENT_PULSEDIGIT) ? 1 : 0;
                ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
 #ifdef HAVE_PRI
                if (!p->proceeding && p->sig == SIG_PRI && p->pri && p->pri->overlapdial) {
                        /* absorb event */
                } else {
 #endif
-                       /* Send a DTMF event for 'legacy' channels and all applications,
-                          and a DTMF_BEGIN event for channels that handle variable duration
-                          DTMF events
-                       */
-                       p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
+                       p->subs[index].f.frametype = AST_FRAME_DTMF_END;
                        p->subs[index].f.subclass = res & 0xff;
 #ifdef HAVE_PRI
                }
@@ -3571,9 +3635,6 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
                /* Mute conference */
                zt_confmute(p, 1);
-               /* Send a DTMF_BEGIN event for devices that want variable
-                  duration DTMF events
-               */
                p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
                p->subs[index].f.subclass = res & 0xff;
                return &p->subs[index].f;
index 94aaf4c..56c45e2 100644 (file)
@@ -395,7 +395,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
 {
        const char *frames[] = {
                "(0?)",
-               "DTMF   ",
+               "DTMF_E ",
                "VOICE  ",
                "VIDEO  ",
                "CONTROL",
@@ -404,7 +404,10 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
                "TEXT   ",
                "IMAGE  ",
                "HTML   ",
-               "CNG    " };
+               "CNG    ",
+               "MODEM  ",
+               "DTMF_B ",
+       };
        const char *iaxs[] = {
                "(0?)",
                "NEW    ",
@@ -508,7 +511,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
        } else {
                class = frames[(int)fh->type];
        }
-       if (fh->type == AST_FRAME_DTMF) {
+       if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
                sprintf(subclass2, "%c", fh->csub);
                subclass = subclass2;
        } else if (fh->type == AST_FRAME_IAX) {
index 3f24034..b04c60e 100644 (file)
@@ -417,7 +417,7 @@ srvlookup=yes                       ; Enable DNS SRV lookups on outbound calls
 ; subscribecontext           subscribecontext
 ; videosupport               videosupport
 ; maxcallbitrate             maxcallbitrate
-;                             mailbox
+; rfc2833compensate           mailbox
 ;                             username
 ;                             template
 ;                             fromdomain
@@ -431,6 +431,7 @@ srvlookup=yes                       ; Enable DNS SRV lookups on outbound calls
 ;                             rtpholdtimeout
 ;                             sendrpid
 ;                             outboundproxy
+;                             rfc2833compensate
 
 ;[sip_proxy]
 ; For incoming calls only. Example: FWD (Free World Dialup)
@@ -587,3 +588,9 @@ srvlookup=yes                       ; Enable DNS SRV lookups on outbound calls
                                ; Normally you do NOT need to set this parameter
 ;setvar=CUSTID=5678            ; Channel variable to be set for all calls from this device
 
+;[pre14-asterisk]
+;type=friend
+;secret=digium
+;host=dynamic
+;rfc2833compensate=yes         ; Compensate for pre-1.4 DTMF transmission from another Asterisk machine.
+                               ; You must have this turned on or DTMF reception will work improperly.
index 95cb319..d54a1bd 100644 (file)
@@ -200,13 +200,11 @@ struct ast_channel_tech {
 
        int (* const devicestate)(void *data);  /*!< Devicestate call back */
 
-       int (* const send_digit)(struct ast_channel *chan, char digit); /*!< Send a literal DTMF digit */
-
        /*! \brief Start sending a literal DTMF digit */
        int (* const send_digit_begin)(struct ast_channel *chan, char digit);
 
-       /*! \brief Stop sending the last literal DTMF digit */
-       int (* const send_digit_end)(struct ast_channel *chan);
+       /*! \brief Stop sending a literal DTMF digit */
+       int (* const send_digit_end)(struct ast_channel *chan, char digit);
 
        /*! \brief Call a given phone number (address, etc), but don't
           take longer than timeout seconds to do so.  */
@@ -424,8 +422,12 @@ struct ast_channel {
        struct ast_channel_spy_list *spies;             /*!< Chan Spy stuff */
        struct ast_channel_whisper_buffer *whisper;     /*!< Whisper Paging buffer */
        AST_LIST_ENTRY(ast_channel) chan_list;          /*!< For easy linking */
+       
        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 */
+
        /*! \brief Data stores on the channel */
        AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores;
 };
@@ -443,29 +445,34 @@ 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),
+       /*! 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),
 };
 
 /*! \brief ast_bridge_config flags */
@@ -876,6 +883,9 @@ int ast_recvchar(struct ast_channel *chan, int timeout);
  */
 int ast_senddigit(struct ast_channel *chan, char digit);
 
+int ast_senddigit_begin(struct ast_channel *chan, char digit);
+int ast_senddigit_end(struct ast_channel *chan, char digit);
+
 /*! \brief Receives a text string from a channel
  * Read a string of text from a channel
  * \param chan channel to act upon
index 0c9c651..bc7273a 100644 (file)
@@ -85,11 +85,46 @@ struct ast_codec_pref {
 
 */
 
+/*!
+ * \brief Frame types 
+ *
+ * \note It is important that the values of each frame type are never changed,
+ *       because it will break backwards compatability with older versions.
+ */
+enum ast_frame_type {
+       /*! DTMF end event, subclass is the digit */
+       AST_FRAME_DTMF_END = 1,
+       /*! Voice data, subclass is AST_FORMAT_* */
+       AST_FRAME_VOICE,
+       /*! Video frame, maybe?? :) */
+       AST_FRAME_VIDEO,
+       /*! A control frame, subclass is AST_CONTROL_* */
+       AST_FRAME_CONTROL,
+       /*! An empty, useless frame */
+       AST_FRAME_NULL,
+       /*! Inter Asterisk Exchange private frame type */
+       AST_FRAME_IAX,
+       /*! Text messages */
+       AST_FRAME_TEXT,
+       /*! Image Frames */
+       AST_FRAME_IMAGE,
+       /*! HTML Frame */
+       AST_FRAME_HTML,
+       /*! Comfort Noise frame (subclass is level of CNG in -dBov), 
+           body may include zero or more 8-bit quantization coefficients */
+       AST_FRAME_CNG,
+       /*! Modem-over-IP data streams */
+       AST_FRAME_MODEM,        
+       /*! DTMF begin event, subclass is the digit */
+       AST_FRAME_DTMF_BEGIN,
+};
+#define AST_FRAME_DTMF AST_FRAME_DTMF_END
+
 /*! \brief Data structure associated with a single frame of data
  */
 struct ast_frame {
        /*! Kind of frame */
-       int frametype;                          
+       enum ast_frame_type frametype;                          
        /*! Subclass, frame dependent */
        int subclass;                           
        /*! Length of data */
@@ -151,35 +186,6 @@ extern struct ast_frame ast_null_frame;
 /*! Need the source be free'd? (haha!) */
 #define AST_MALLOCD_SRC                (1 << 2)
 
-/* Frame types */
-/*! A DTMF digit, subclass is the digit */
-#define AST_FRAME_DTMF         1
-/*! Voice data, subclass is AST_FORMAT_* */
-#define AST_FRAME_VOICE                2
-/*! Video frame, maybe?? :) */
-#define AST_FRAME_VIDEO                3
-/*! A control frame, subclass is AST_CONTROL_* */
-#define AST_FRAME_CONTROL      4
-/*! An empty, useless frame */
-#define AST_FRAME_NULL         5
-/*! Inter Asterisk Exchange private frame type */
-#define AST_FRAME_IAX          6
-/*! Text messages */
-#define AST_FRAME_TEXT         7
-/*! Image Frames */
-#define AST_FRAME_IMAGE                8
-/*! HTML Frame */
-#define AST_FRAME_HTML         9
-/*! Comfort Noise frame (subclass is level of CNG in -dBov), 
-    body may include zero or more 8-bit quantization coefficients */
-#define AST_FRAME_CNG          10
-/*! Modem-over-IP data streams */
-#define AST_FRAME_MODEM                11
-/*! DTMF begin event, subclass is the digit */
-#define AST_FRAME_DTMF_BEGIN   12
-/*! DTMF end event, subclass is the digit */
-#define AST_FRAME_DTMF_END     13
-
 /* MODEM subclasses */
 /*! T.38 Fax-over-IP */
 #define AST_MODEM_T38          1
index f99d4de..6780c2a 100644 (file)
@@ -142,7 +142,9 @@ int ast_rtp_fd(struct ast_rtp *rtp);
 
 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);
 
@@ -181,6 +183,9 @@ void ast_rtp_setnat(struct ast_rtp *rtp, int nat);
 /*! \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);
index 1099fea..b6a7f73 100644 (file)
@@ -212,10 +212,6 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
 {
        const char *ptr;
        int res = 0;
-       struct ast_frame f = {
-               .frametype = AST_FRAME_DTMF,
-               .src = "ast_dtmf_stream"
-       };
 
        if (!between)
                between = 100;
@@ -240,11 +236,8 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
                        if (*ptr == 'f' || *ptr == 'F') {
                                /* ignore return values if not supported by channel */
                                ast_indicate(chan, AST_CONTROL_FLASH);
-                       } else {
-                               f.subclass = *ptr;
-                               if ((res = ast_write(chan, &f)))
-                                       break;
-                       }
+                       } else
+                               ast_senddigit(chan, *ptr);
                        /* pause between digits */
                        if ((res = ast_safe_sleep(chan, between)))
                                break;
index 61df3d2..6ba79ee 100644 (file)
@@ -102,6 +102,9 @@ unsigned long global_fin = 0, global_fout = 0;
 AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
 #define STATE2STR_BUFSIZE   32
 
+/* XXX 100ms ... this won't work with wideband support */
+#define AST_DEFAULT_EMULATE_DTMF_SAMPLES 800
+
 struct chanlist {
        const struct ast_channel_tech *tech;
        AST_LIST_ENTRY(chanlist) list;
@@ -240,7 +243,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
                "    Indication: %s\n"
                "     Transfer : %s\n"
                "  Capabilities: %d\n"
-               "    Send Digit: %s\n"
+               "   Digit Begin: %s\n"
+               "     Digit End: %s\n"
                "    Send HTML : %s\n"
                " Image Support: %s\n"
                "  Text Support: %s\n",
@@ -249,7 +253,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
                (cl->tech->indicate) ? "yes" : "no",
                (cl->tech->transfer) ? "yes" : "no",
                (cl->tech->capabilities) ? cl->tech->capabilities : -1,
-               (cl->tech->send_digit) ? "yes" : "no",
+               (cl->tech->send_digit_begin) ? "yes" : "no",
+               (cl->tech->send_digit_end) ? "yes" : "no",
                (cl->tech->send_html) ? "yes" : "no",
                (cl->tech->send_image) ? "yes" : "no",
                (cl->tech->send_text) ? "yes" : "no"
@@ -1862,8 +1867,10 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
                                /* Write audio if appropriate */
                                if (audiofd > -1)
                                        write(audiofd, f->data, f->datalen);
+                       default:
+                               /* Ignore */
+                               break;
                        }
-                       /* Ignore */
                        ast_frfree(f);
                }
        }
@@ -1881,11 +1888,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
         */
        ast_channel_lock(chan);
        if (chan->masq) {
-               if (ast_do_masquerade(chan)) {
+               if (ast_do_masquerade(chan))
                        ast_log(LOG_WARNING, "Failed to perform masquerade\n");
-               } else {
+               else
                        f =  &ast_null_frame;
-               }
                goto done;
        }
 
@@ -1897,13 +1903,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
        }
        prestate = chan->_state;
 
-       if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF) && !ast_strlen_zero(chan->dtmfq)) {
+       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;
+               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;
                goto done;
        }
        
@@ -2017,27 +2027,57 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                }
                        }
                        break;
-               case AST_FRAME_DTMF:
-                       ast_log(LOG_DTMF, "DTMF '%c' received on %s\n", f->subclass, chan->name);
-                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
+               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)) {
                                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)) {
+                               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;
+                               else
+                                       chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
+                       } else 
+                               ast_clear_flag(chan, AST_FLAG_IN_DTMF);
                        break;
                case AST_FRAME_DTMF_BEGIN:
                        ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
-                       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_frfree(f);
+                               f = &ast_null_frame;
+                       } else 
+                               ast_set_flag(chan, AST_FLAG_IN_DTMF);
                        break;
                case AST_FRAME_VOICE:
-                       if (dropaudio) {
+                       /* 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) {
+                               ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF);
+                               chan->emulate_dtmf_digit = 0;
+                       }
+
+                       if (dropaudio || ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
                                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;
+                                       f->frametype = AST_FRAME_DTMF_END;
+                                       f->subclass = chan->emulate_dtmf_digit;
+                               } else {
+                                       chan->emulate_dtmf_samples -= f->samples;
+                                       ast_frfree(f);
+                                       f = &ast_null_frame;
+                               }
                        } else if (!(f->subclass & chan->nativeformats)) {
                                /* This frame can't be from the current native formats -- drop it on the
                                   floor */
@@ -2106,6 +2146,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                        }
                                }
                        }
+               default:
+                       /* Just pass it on! */
+                       break;
                }
        } else {
                /* Make sure we always return NULL in the future */
@@ -2258,12 +2301,13 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
        return res;
 }
 
-static int do_senddigit(struct ast_channel *chan, char digit)
+int ast_senddigit_begin(struct ast_channel *chan, char digit)
 {
        int res = -1;
 
-       if (chan->tech->send_digit)
-               res = chan->tech->send_digit(chan, digit);
+       if (chan->tech->send_digit_begin)
+               res = chan->tech->send_digit_begin(chan, digit);
+
        if (res) {
                /*
                 * Device does not support DTMF tones, lets fake
@@ -2299,12 +2343,30 @@ static int do_senddigit(struct ast_channel *chan, char digit)
                        ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
                }
        }
+
+       return 0;
+}
+
+int ast_senddigit_end(struct ast_channel *chan, char digit)
+{
+       int res = -1;
+
+       if (chan->tech->send_digit_end)
+               res = chan->tech->send_digit_end(chan, digit);
+
+       if (res && chan->generator)
+               ast_playtones_stop(chan);
+       
        return 0;
 }
 
 int ast_senddigit(struct ast_channel *chan, char digit)
 {
-       return do_senddigit(chan, digit);
+       ast_senddigit_begin(chan, digit);
+       
+       ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */
+       
+       return ast_senddigit_end(chan, digit);
 }
 
 int ast_prod(struct ast_channel *chan)
@@ -2372,17 +2434,16 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                        chan->tech->indicate(chan, fr->subclass, fr->data, fr->datalen);
                break;
        case AST_FRAME_DTMF_BEGIN:
-               res = (chan->tech->send_digit_begin == NULL) ? 0 :
-                       chan->tech->send_digit_begin(chan, fr->subclass);
+               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_END:
-               res = (chan->tech->send_digit_end == NULL) ? 0 :
-                       chan->tech->send_digit_end(chan);
-               break;
-       case AST_FRAME_DTMF:
                ast_clear_flag(chan, AST_FLAG_BLOCKING);
                ast_channel_unlock(chan);
-               res = do_senddigit(chan,fr->subclass);
+               res = ast_senddigit_end(chan, fr->subclass);
                ast_channel_lock(chan);
                CHECK_BLOCKING(chan);
                break;
@@ -2467,7 +2528,14 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 
                        res = chan->tech->write(chan, f);
                }
-               break;  
+               break;
+       case AST_FRAME_NULL:
+       case AST_FRAME_IAX:
+               /* Ignore these */
+               break;
+       default:
+               res = chan->tech->write(chan, f);
+               break;
        }
 
        if (f && f != fr)
@@ -3496,6 +3564,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                                break;
                }
                if ((f->frametype == AST_FRAME_VOICE) ||
+                   (f->frametype == AST_FRAME_DTMF_BEGIN) ||
                    (f->frametype == AST_FRAME_DTMF) ||
                    (f->frametype == AST_FRAME_VIDEO) ||
                    (f->frametype == AST_FRAME_IMAGE) ||
@@ -3505,10 +3574,14 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                        /* monitored dtmf causes exit from bridge */
                        int monitored_source = (who == c0) ? watch_c0_dtmf : watch_c1_dtmf;
 
-                       if (f->frametype == AST_FRAME_DTMF && monitored_source) {
+                       if (monitored_source && 
+                               (f->frametype == AST_FRAME_DTMF_END || 
+                               f->frametype == AST_FRAME_DTMF_BEGIN)) {
                                *fo = f;
                                *rc = who;
-                               ast_log(LOG_DEBUG, "Got DTMF on channel (%s)\n", who->name);
+                               ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n", 
+                                       f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
+                                       who->name);
                                break;
                        }
                        /* Write immediately frames, not passed through jb */
index 7e62c8b..2992031 100644 (file)
@@ -1497,42 +1497,45 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                        } else {
                                if (digit) {
                                        /* Thought we saw one last time.  Pretty sure we really have now */
-                                       if (dsp->thinkdigit) {
-                                               if ((dsp->thinkdigit != 'x') && (dsp->thinkdigit != digit)) {
-                                                       /* If we found a digit, and we're changing digits, go
-                                                          ahead and send this one, but DON'T stop confmute because
-                                                          we're detecting something else, too... */
-                                                       memset(&dsp->f, 0, sizeof(dsp->f));
-                                                       dsp->f.frametype = AST_FRAME_DTMF;
-                                                       dsp->f.subclass = dsp->thinkdigit;
-                                                       FIX_INF(af);
-                                                       if (chan)
-                                                               ast_queue_frame(chan, af);
-                                                       ast_frfree(af);
-                                               }
+                                       if ((dsp->thinkdigit != 'x') && (dsp->thinkdigit != digit)) {
+                                               /* If we found a digit, and we're changing digits, go
+                                                  ahead and send this one, but DON'T stop confmute because
+                                                  we're detecting something else, too... */
+                                               memset(&dsp->f, 0, sizeof(dsp->f));
+                                               dsp->f.frametype = AST_FRAME_DTMF_END;
+                                               dsp->f.subclass = dsp->thinkdigit;
+                                               FIX_INF(af);
+                                               if (chan)
+                                                       ast_queue_frame(chan, af);
+                                               ast_frfree(af);
+                                       } else {
                                                dsp->thinkdigit = digit;
-                                               return &dsp->f;
-                                       }
-                                       dsp->thinkdigit = digit;
-                               } else {
-                                       if (dsp->thinkdigit) {
                                                memset(&dsp->f, 0, sizeof(dsp->f));
-                                               if (dsp->thinkdigit != 'x') {
-                                                       /* If we found a digit, send it now */
-                                                       dsp->f.frametype = AST_FRAME_DTMF;
-                                                       dsp->f.subclass = dsp->thinkdigit;
-                                                       dsp->thinkdigit = 0;
-                                               } else {
-                                                       dsp->f.frametype = AST_FRAME_DTMF;
-                                                       dsp->f.subclass = 'u';
-                                                       dsp->thinkdigit = 0;
-                                               }
+                                               dsp->f.frametype = AST_FRAME_DTMF_BEGIN;
+                                               dsp->f.subclass = dsp->thinkdigit;
                                                FIX_INF(af);
                                                if (chan)
                                                        ast_queue_frame(chan, af);
                                                ast_frfree(af);
-                                               return &dsp->f;
                                        }
+                                       return &dsp->f;
+                               } else {
+                                       memset(&dsp->f, 0, sizeof(dsp->f));
+                                       if (dsp->thinkdigit != 'x') {
+                                               /* If we found a digit, send it now */
+                                               dsp->f.frametype = AST_FRAME_DTMF_END;
+                                               dsp->f.subclass = dsp->thinkdigit;
+                                               dsp->thinkdigit = 0;
+                                       } else {
+                                               dsp->f.frametype = AST_FRAME_DTMF;
+                                               dsp->f.subclass = 'u';
+                                               dsp->thinkdigit = 0;
+                                       }
+                                       FIX_INF(af);
+                                       if (chan)
+                                               ast_queue_frame(chan, af);
+                                       ast_frfree(af);
+                                       return &dsp->f;
                                }
                        }
                } else if (!digit) {
@@ -1553,7 +1556,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                        } else {
                                if (dsp->td.dtmf.current_digits) {
                                        memset(&dsp->f, 0, sizeof(dsp->f));
-                                       dsp->f.frametype = AST_FRAME_DTMF;
+                                       dsp->f.frametype = AST_FRAME_DTMF_END;
                                        dsp->f.subclass = dsp->td.dtmf.digits[0];
                                        memmove(dsp->td.dtmf.digits, dsp->td.dtmf.digits + 1, dsp->td.dtmf.current_digits);
                                        dsp->td.dtmf.current_digits--;
index 365d233..48c1660 100644 (file)
@@ -1029,7 +1029,8 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                        if (!fr)
                                return -1;
                        switch(fr->frametype) {
-                       case AST_FRAME_DTMF:
+                       case AST_FRAME_DTMF_BEGIN:
+                       case AST_FRAME_DTMF_END:
                                if (context) {
                                        const char exten[2] = { fr->subclass, '\0' };
                                        if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
@@ -1065,8 +1066,10 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                                /* Write audio if appropriate */
                                if (audiofd > -1)
                                        write(audiofd, fr->data, fr->datalen);
+                       default:
+                               /* Ignore all others */
+                               break;
                        }
-                       /* Ignore all others */
                        ast_frfree(fr);
                }
                ast_sched_runq(c->sched);
index 5703d71..b53ad40 100644 (file)
@@ -106,14 +106,12 @@ struct rtpPayloadType {
 /*! \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,17 @@ struct ast_rtp {
        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_payload;
        int nat;
        unsigned int flags;
        struct sockaddr_in us;          /*!< Socket representation of the local endpoint. */
@@ -164,6 +168,8 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
 static int ast_rtcp_write_sr(void *data);
 static int ast_rtcp_write_rr(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);
 static int bridge_p2p_rtcp_write(struct ast_rtp *rtp, unsigned int *rtcpheader, int len);
 
 #define FLAG_3389_WARNING              (1 << 0)
@@ -174,6 +180,7 @@ static int bridge_p2p_rtcp_write(struct ast_rtp *rtp, unsigned int *rtcpheader,
 #define FLAG_P2P_SENT_MARK              (1 << 4)
 #define FLAG_P2P_NEED_DTMF              (1 << 5)
 #define FLAG_CALLBACK_MODE              (1 << 6)
+#define FLAG_DTMF_COMPENSATE            (1 << 7)
 
 /*!
  * \brief Structure defining an RTCP session.
@@ -531,7 +538,12 @@ void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf)
        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)
@@ -546,15 +558,13 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
                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;
        
 }
@@ -607,7 +617,7 @@ static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *
                resp = 'X';
        }
        if (rtp->resp && (rtp->resp != resp)) {
-               f = send_dtmf(rtp);
+               f = send_dtmf(rtp, AST_FRAME_DTMF_END);
        }
        rtp->resp = resp;
        rtp->dtmfcount = dtmftimeout;
@@ -633,6 +643,7 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
        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)));
@@ -640,8 +651,12 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
        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) {
@@ -653,25 +668,21 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
        } 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;
+               if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE))
+                       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;
+               rtp->resp = 0;
+               rtp->lasteventendseqn = seqno;
+       }
+
        rtp->dtmfcount = dtmftimeout;
        rtp->dtmfduration = duration;
+
        return f;
 }
 
@@ -1030,6 +1041,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
        unsigned int *rtpheader;
        struct rtpPayloadType rtpPT;
        
+       /* If time is up, kill it */
+       if (rtp->send_digit)
+               ast_rtp_senddigit_continuation(rtp);
+
        len = sizeof(sin);
        
        /* Cache where the header will go */
@@ -1172,13 +1187,13 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                                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;
                        }
@@ -1198,26 +1213,9 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 
        rtp->rxseqno = seqno;
 
-       if (rtp->dtmfcount) {
-#if 0
-               printf("dtmfcount was %d\n", rtp->dtmfcount);
-#endif         
-               rtp->dtmfcount -= (timestamp - rtp->lastrxts);
-               if (rtp->dtmfcount < 0)
-                       rtp->dtmfcount = 0;
-#if 0
-               if (dtmftimeout != rtp->dtmfcount)
-                       printf("dtmfcount is %d\n", rtp->dtmfcount);
-#endif
-       }
+       /* Record received timestamp as last received now */
        rtp->lastrxts = timestamp;
 
-       /* Send any pending DTMF */
-       if (rtp->resp && !rtp->dtmfcount) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Sending pending DTMF\n");
-               return send_dtmf(rtp);
-       }
        rtp->f.mallocd = 0;
        rtp->f.datalen = res - hdrlen;
        rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
@@ -1962,35 +1960,42 @@ static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
        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 */    
-       if (!rtp->them.sin_addr.s_addr)
+       if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
                return 0;
 
+       payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
+
        rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
        
        /* Get a pointer to the header */
@@ -1999,51 +2004,111 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
        rtpheader[1] = htonl(rtp->lastdigitts);
        rtpheader[2] = htonl(rtp->ssrc); 
        rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
-       for (x = 0; x < 6; x++) {
-               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), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
-               }
-               /* Sequence number of last two end packets does not get incremented */
-               if (x < 3)
-                       rtp->seqno++;
+
+       for (i = 0; i < 2; i++) {
+               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), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+               /* 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_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 || !rtp->them.sin_port)
+               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 */
+       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];
+       
+       /* If no address, then bail out */
+       if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+               return 0;
+       
+       /* Convert our digit to the crazy RTP way */
+       if (digit_convert(digit))
+               return -1;
+
+       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));
+       rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
+       /* Send 3 termination packets */
+       for (i = 0; i < 3; i++) {
+               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;
+       /* 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;
index a050d1c..bf51946 100644 (file)
@@ -1016,6 +1016,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
                                break;
                        case AST_FRAME_VIDEO:
                                ast_writestream(fs, f);
+                       default:
+                               /* Ignore all other frames */
                                break;
                        }
                        ast_frfree(f);
index 10faf00..aba923f 100644 (file)
@@ -1439,9 +1439,9 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
                                if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
                                        ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
                        }
-               }
-               /* check for '*', if we find it it's time to disconnect */
-               if (f->frametype == AST_FRAME_DTMF) {
+               } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
+                       /* eat it */
+               } else if (f->frametype == AST_FRAME_DTMF) {
                        char *featurecode;
                        int sense;