summaryrefslogtreecommitdiff
path: root/res/res_pjsip_dtmf_info.c
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2013-08-22 22:09:16 +0000
committerKevin Harwell <kharwell@digium.com>2013-08-22 22:09:16 +0000
commitaefebebd37add82bbea2d3423a5fc5f28feb2c60 (patch)
tree0955ad1b8a929c5b6f3269c1548f797d550b048f /res/res_pjsip_dtmf_info.c
parent6fa4e8e3ab302fc20b7d0fd39c7545c9520882f0 (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.c117
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 = {