aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-01-19 17:49:38 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-01-19 17:49:38 +0000
commitcc3938c1989d0b9f6a907ee2d64f2f66a01b2e29 (patch)
tree3fe50ce72af12ead588e9b25a6bf636f67b0993d /channels/chan_sip.c
parent397418eb0c2c20f83505c9af8d5bb8aa89cab8af (diff)
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: http://svn.digium.com/svn/asterisk/branches/1.4@51311 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c69
1 files changed, 52 insertions, 17 deletions
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;