diff options
author | Kevin Harwell <kharwell@digium.com> | 2013-08-22 22:09:16 +0000 |
---|---|---|
committer | Kevin Harwell <kharwell@digium.com> | 2013-08-22 22:09:16 +0000 |
commit | aefebebd37add82bbea2d3423a5fc5f28feb2c60 (patch) | |
tree | 0955ad1b8a929c5b6f3269c1548f797d550b048f /res/res_pjsip_dtmf_info.c | |
parent | 6fa4e8e3ab302fc20b7d0fd39c7545c9520882f0 (diff) |
res_sip_dtmf_info: Support sending of 'raw' DTMF
Added the ability to handle 'raw' DTMF within the body of an INFO message.
Also made it so values 10-16 are mapped to valid DTMF values.
(closes issue ASTERISK-22144)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2776/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397484 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip_dtmf_info.c')
-rw-r--r-- | res/res_pjsip_dtmf_info.c | 117 |
1 files changed, 77 insertions, 40 deletions
diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c index 3cd410dae..72f93dc46 100644 --- a/res/res_pjsip_dtmf_info.c +++ b/res/res_pjsip_dtmf_info.c @@ -32,77 +32,114 @@ #include "asterisk/res_pjsip_session.h" #include "asterisk/module.h" -static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) +static int is_media_type(pjsip_rx_data *rdata, char *subtype) { - int res = 0; - pjsip_msg_body *body = rdata->msg_info.msg->body; + return !pj_strcmp2(&rdata->msg_info.ctype->media.type, "application") && + !pj_strcmp2(&rdata->msg_info.ctype->media.subtype, subtype); +} +static void send_response(struct ast_sip_session *session, + struct pjsip_rx_data *rdata, int code) +{ pjsip_tx_data *tdata; + pjsip_dialog *dlg = session->inv_session->dlg; + + if (pjsip_dlg_create_response(dlg, rdata, code, + NULL, &tdata) == PJ_SUCCESS) { + struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); + pjsip_dlg_send_response(dlg, tsx, tdata); + } +} + +static char get_event(const char *c) +{ + unsigned int event; + + if (*c == '!' || *c == '*' || *c == '#' || + ('A' <= *c && *c <= 'D') || + ('a' <= *c && *c <= 'd')) { + return *c; + } + + if ((sscanf(c, "%30u", &event) != 1) || event > 16) { + return '\0'; + } + + if (event < 10) { + return *c; + } + + switch (event) { + case 10: return '*'; + case 11: return '#'; + case 16: return '!'; + } + + return 'A' + (event - 12); +} +static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) +{ + pjsip_msg_body *body = rdata->msg_info.msg->body; char buf[body ? body->len : 0]; char *cur = buf; char *line; char event = '\0'; - unsigned int duration = 0; + unsigned int duration = 100; + + char is_dtmf = is_media_type(rdata, "dtmf"); + + if (!is_dtmf && !is_media_type(rdata, "dtmf-relay")) { + return 0; + } - if (!body || !ast_sip_is_content_type(&body->content_type, "application", "dtmf-relay")) { + if (!body || !body->len) { + /* need to return 200 OK on empty body */ + send_response(session, rdata, 200); return 0; } body->print_body(body, buf, body->len); - while ((line = strsep(&cur, "\r\n"))) { - char *c; + if (is_dtmf) { + /* directly use what is in the message body */ + event = get_event(cur); + } else { /* content type = application/dtmf-relay */ + while ((line = strsep(&cur, "\r\n"))) { + char *c; - if (!(c = strchr(line, '='))) { - continue; - } - *c++ = '\0'; - - c = ast_skip_blanks(c); - - if (!strcasecmp(line, "signal")) { - if (c[0] == '!' || c[0] == '*' || c[0] == '#' || - ('0' <= c[0] && c[0] <= '9') || - ('A' <= c[0] && c[0] <= 'D') || - ('a' <= c[0] && c[0] <= 'd')) { - event = c[0]; - } else { - ast_log(LOG_ERROR, "Invalid DTMF event signal in INFO message.\n"); - res = -1; - break; + if (!(c = strchr(line, '='))) { + continue; } - } else if (!strcasecmp(line, "duration")) { - sscanf(c, "%30u", &duration); - } - } - if (!duration) { - duration = 100; + *c++ = '\0'; + c = ast_skip_blanks(c); + + if (!strcasecmp(line, "signal")) { + if (!(event = get_event(c))) { + break; + } + } else if (!strcasecmp(line, "duration")) { + sscanf(c, "%30u", &duration); + } + } } if (event == '!') { struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } }; - ast_queue_frame(session->channel, &f); } else if (event != '\0') { struct ast_frame f = { AST_FRAME_DTMF, }; f.len = duration; f.subclass.integer = event; - ast_queue_frame(session->channel, &f); } else { - res = -1; - } - - if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, !res ? 200 : 500, NULL, &tdata) == PJ_SUCCESS) { - struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); - - pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata); + ast_log(LOG_ERROR, "Invalid DTMF event signal in INFO message.\n"); } - return res; + send_response(session, rdata, event ? 200 : 500); + return event ? 0 : -1; } static struct ast_sip_session_supplement dtmf_info_supplement = { |