summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 = {