summaryrefslogtreecommitdiff
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
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
-rw-r--r--res/res_pjsip.c8
-rw-r--r--res/res_pjsip_dtmf_info.c117
2 files changed, 81 insertions, 44 deletions
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 645dcb54a..9b5727fb5 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -685,7 +685,7 @@
Signifies that a domain is an alias. If the domain on a session is
not found to match an AoR then this object is used to see if we have
an alias for the AoR to which the endpoint is binding. This objects
- name as defined in configuration should be the domain alias and a
+ name as defined in configuration should be the domain alias and a
config option is provided to specify the domain to be aliased.
</para></description>
<configOption name="type">
@@ -851,7 +851,7 @@
This must be used in conjuction with the <literal>PJSIP_DIAL_CONTACTS</literal>.
</para><para>
Registrations: For Asterisk to match an inbound registration to an endpoint,
- the AoR object name must match the user portion of the SIP URI in the "To:"
+ the AoR object name must match the user portion of the SIP URI in the "To:"
header of the inbound SIP registration. That will usually be equivalent
to the "user name" set in your hard or soft phones configuration.
</para></description>
@@ -935,7 +935,7 @@
<description><para>
The settings in this section are global. In addition to being global, the values will
not be re-evaluated when a reload is performed. This is because the values must be set
- before the SIP stack is initialized. The only way to reset these values is to either
+ before the SIP stack is initialized. The only way to reset these values is to either
restart Asterisk, or unload res_pjsip.so and then load it again.
</para></description>
<configOption name="timert1" default="500">
@@ -1724,7 +1724,7 @@ int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *su
pjsip_media_type_init2(&compare, type, subtype);
- return pjsip_media_type_cmp(content_type, &compare, 0) ? -1 : 0;
+ return pjsip_media_type_cmp(content_type, &compare, 0) ? 0 : -1;
}
pj_caching_pool caching_pool;
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 = {