aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--channels/chan_agent.c6
-rw-r--r--channels/chan_alsa.c7
-rw-r--r--channels/chan_features.c6
-rw-r--r--channels/chan_gtalk.c24
-rw-r--r--channels/chan_h323.c4
-rw-r--r--channels/chan_iax2.c4
-rw-r--r--channels/chan_local.c5
-rw-r--r--channels/chan_mgcp.c4
-rw-r--r--channels/chan_misdn.c2
-rw-r--r--channels/chan_oss.c7
-rw-r--r--channels/chan_phone.c10
-rw-r--r--channels/chan_sip.c69
-rw-r--r--channels/chan_skinny.c4
-rw-r--r--channels/chan_zap.c4
-rw-r--r--include/asterisk/channel.h36
-rw-r--r--main/channel.c73
-rw-r--r--main/frame.c8
-rw-r--r--main/rtp.c36
18 files changed, 200 insertions, 109 deletions
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 484f33333..5f3e3bc5d 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -238,7 +238,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);
@@ -617,12 +617,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 3d819bb32..e74df21cb 100644
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -187,7 +187,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);
@@ -487,10 +487,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 b41867fa2..89fe1f903 100644
--- a/channels/chan_features.c
+++ b/channels/chan_features.c
@@ -96,7 +96,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);
@@ -318,7 +318,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;
@@ -328,7 +328,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 59f40cc61..530af5b25 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -173,7 +173,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);
@@ -198,8 +200,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,
@@ -1341,7 +1343,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;
@@ -1376,8 +1388,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 294d1b59e..cf4e89f64 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -234,7 +234,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);
@@ -545,7 +545,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 c13ab667a..6204dcc23 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -776,7 +776,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);
@@ -2388,7 +2388,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);
}
diff --git a/channels/chan_local.c b/channels/chan_local.c
index e4c7612cf..4f4b75c5f 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 ff6087156..78d1948f0 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 = {
@@ -1276,7 +1276,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 20a70590f..28cf4e9cb 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -2068,7 +2068,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 4971321aa..06a287957 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -408,7 +408,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);
@@ -769,10 +769,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 73113d57e..44d79c25a 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -159,7 +159,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);
@@ -246,12 +246,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':
@@ -282,7 +282,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;
@@ -335,7 +335,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 d767ebe8f..a313c8dc5 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1207,7 +1207,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);
@@ -1229,7 +1229,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);
-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);
@@ -1481,7 +1481,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);
@@ -1550,6 +1550,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 { \
@@ -3574,7 +3598,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;
@@ -3582,7 +3606,7 @@ static int sip_senddigit_end(struct ast_channel *ast, char digit)
ast_mutex_lock(&p->lock);
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)
@@ -3742,7 +3766,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
return NULL;
}
ast_mutex_lock(&i->lock);
- 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. */
@@ -5821,11 +5849,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);
@@ -7389,12 +7417,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);
}
@@ -10655,6 +10683,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"))) {
@@ -10664,7 +10693,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);
@@ -10702,6 +10736,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);
@@ -11230,7 +11265,7 @@ static int func_header_read(struct ast_channel *chan, char *function, char *data
}
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;
@@ -11405,7 +11440,7 @@ static int function_sipchaninfo_read(struct ast_channel *chan, char *cmd, 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;
@@ -11653,7 +11688,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) {
@@ -13446,7 +13481,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 */
@@ -13500,7 +13535,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) {
@@ -16781,7 +16816,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 0552a5c84..9b8faf55e 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1032,7 +1032,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",
@@ -2566,7 +2566,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 4d1935202..bbec9c182 100644
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -673,7 +673,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);
@@ -1059,7 +1059,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 431f57144..efa06bafb 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -204,7 +204,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. */
@@ -427,7 +427,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;
@@ -446,34 +447,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 */
@@ -887,7 +891,7 @@ 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);
+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 21007b7f6..925d5d363 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -104,8 +104,8 @@ unsigned long global_fin, global_fout;
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
+/*! 100ms */
+#define AST_DEFAULT_EMULATE_DTMF_DURATION 100
struct chanlist {
const struct ast_channel_tech *tech;
@@ -2086,14 +2086,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;
}
@@ -2211,38 +2216,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;
}
@@ -2251,12 +2265,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;
}
@@ -2531,12 +2545,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);
@@ -2546,11 +2560,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)
@@ -2628,7 +2643,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;
@@ -3917,6 +3932,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;
@@ -4070,6 +4090,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 83599fff8..0cd0b03fb 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -496,11 +496,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 9b4431d06..dc6efbd81 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 */
@@ -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)
@@ -709,18 +709,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)
@@ -745,19 +745,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;
}
@@ -2000,7 +2000,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;
}
@@ -3180,6 +3180,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;