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