summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UPGRADE.txt5
-rw-r--r--channels/chan_pjsip.c19
-rw-r--r--contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py63
-rw-r--r--include/asterisk/dsp.h3
-rw-r--r--include/asterisk/res_pjsip.h2
-rw-r--r--main/dsp.c7
-rw-r--r--res/res_pjsip.c4
-rw-r--r--res/res_pjsip/pjsip_configuration.c4
-rw-r--r--res/res_pjsip_sdp_rtp.c32
-rw-r--r--res/res_pjsip_session.c2
10 files changed, 133 insertions, 8 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 19f947c4a..8b848cc8a 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -23,6 +23,11 @@
From 13.3.0 to 13.4.0:
+res_pjsip:
+ - The dtmf_mode now supports a new option, 'auto'. This mode will attempt to
+ detect if the device supports RFC4733 DTMF. If so, it will choose that
+ DTMF type; if not, it will choose 'inband' DTMF.
+
res_pjsip_dlg_options:
- A new module, this handles OPTIONS requests sent in-dialog. This module
should have no adverse effects for those upgrading; this note merely
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index c9d09dbeb..207a7d90b 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -548,7 +548,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
int exists;
/* If we only needed this DSP for fax detection purposes we can just drop it now */
- if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
+ if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) {
ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT);
} else {
ast_dsp_free(session->dsp);
@@ -1473,6 +1473,14 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
}
ast_rtp_instance_dtmf_begin(media->rtp, digit);
+ break;
+ case AST_SIP_DTMF_AUTO:
+ if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_begin(media->rtp, digit);
+ break;
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:
@@ -1576,6 +1584,15 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in
}
ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
+ break;
+ case AST_SIP_DTMF_AUTO:
+ if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
+ break;
+
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:
diff --git a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
new file mode 100644
index 000000000..fd1b6c7d4
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
@@ -0,0 +1,63 @@
+"""Add auto DTMF mode
+
+Revision ID: 31cd4f4891ec
+Revises: 23530d604b96
+Create Date: 2015-04-10 12:36:51.619419
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '31cd4f4891ec'
+down_revision = '23530d604b96'
+
+from alembic import op
+import sqlalchemy as sa
+
+OLD_ENUM = ['rfc4733', 'inband', 'info']
+NEW_ENUM = ['rfc4733', 'inband', 'info', 'auto']
+
+old_type = sa.Enum(*OLD_ENUM, name='pjsip_dtmf_mode_values')
+new_type = sa.Enum(*NEW_ENUM, name='pjsip_dtmf_mode_values_v2')
+
+tcr = sa.sql.table('ps_endpoints', sa.Column('dtmf_mode', new_type,
+ nullable=True))
+
+def upgrade():
+ context = op.get_context()
+
+ # Upgrading to this revision WILL clear your directmedia values.
+ if context.bind.dialect.name != 'postgresql':
+ op.alter_column('ps_endpoints', 'dtmf_mode',
+ type_=new_type,
+ existing_type=old_type)
+ else:
+ enum = ENUM('rfc4733', 'inband', 'info', 'auto',
+ name='pjsip_dtmf_mode_values_v2')
+ enum.create(op.get_bind(), checkfirst=False)
+
+ op.execute('ALTER TABLE ps_endpoints ALTER COLUMN dtmf_mode TYPE'
+ ' pjsip_dtmf_mode_values_v2 USING'
+ ' dtmf_mode::text::pjsip_dtmf_mode_values_v2')
+
+ ENUM(name="pjsip_dtmf_mode_values").drop(op.get_bind(), checkfirst=False)
+
+def downgrade():
+ context = op.get_context()
+
+ op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing')
+ .values(directmedia=None))
+
+ if context.bind.dialect.name != 'postgresql':
+ op.alter_column('ps_endpoints', 'dtmf_mode',
+ type_=old_type,
+ existing_type=new_type)
+ else:
+ enum = ENUM('rfc4733', 'inband', 'info',
+ name='pjsip_dtmf_mode_values')
+ enum.create(op.get_bind(), checkfirst=False)
+
+ op.execute('ALTER TABLE ps_endpoints ALTER COLUMN dtmf_mode TYPE'
+ ' pjsip_dtmf_mode_values USING'
+ ' dtmf_mode::text::pjsip_dtmf_mode_values')
+
+ ENUM(name="pjsip_dtmf_mode_values_v2").drop(op.get_bind(), checkfirst=False)
diff --git a/include/asterisk/dsp.h b/include/asterisk/dsp.h
index 16262c05d..7e84ebe9c 100644
--- a/include/asterisk/dsp.h
+++ b/include/asterisk/dsp.h
@@ -138,6 +138,9 @@ void ast_dsp_digitreset(struct ast_dsp *dsp);
/*! \brief Select feature set */
void ast_dsp_set_features(struct ast_dsp *dsp, int features);
+/*! \brief Get features */
+int ast_dsp_get_features(struct ast_dsp *dsp);
+
/*! \brief Get pending DTMF/MF digits */
int ast_dsp_getdigits(struct ast_dsp *dsp, char *buf, int max);
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index fcad28878..06607cfc4 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -252,6 +252,8 @@ enum ast_sip_dtmf_mode {
AST_SIP_DTMF_INBAND,
/*! Use SIP INFO DTMF (blech) */
AST_SIP_DTMF_INFO,
+ /*! Use SIP 4733 if supported by the other side or INBAND if not */
+ AST_SIP_DTMF_AUTO,
};
/*!
diff --git a/main/dsp.c b/main/dsp.c
index 335fb3db0..087416358 100644
--- a/main/dsp.c
+++ b/main/dsp.c
@@ -1702,6 +1702,13 @@ void ast_dsp_set_features(struct ast_dsp *dsp, int features)
}
}
+
+int ast_dsp_get_features(struct ast_dsp *dsp)
+{
+ return (dsp->features);
+}
+
+
void ast_dsp_free(struct ast_dsp *dsp)
{
ast_free(dsp);
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 448d57ddb..93905d6e9 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -210,6 +210,10 @@
<enum name="info">
<para>DTMF is sent as SIP INFO packets.</para>
</enum>
+ <enum name="auto">
+ <para>DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not.</para>
+ </enum>
+
</enumlist>
</description>
</configOption>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 4f5fc74de..1f38e7729 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -109,6 +109,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var,
endpoint->dtmf = AST_SIP_DTMF_INBAND;
} else if (!strcasecmp(var->value, "info")) {
endpoint->dtmf = AST_SIP_DTMF_INFO;
+ } else if (!strcasecmp(var->value, "auto")) {
+ endpoint->dtmf = AST_SIP_DTMF_AUTO;
} else if (!strcasecmp(var->value, "none")) {
endpoint->dtmf = AST_SIP_DTMF_NONE;
} else {
@@ -129,6 +131,8 @@ static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
*buf = "inband"; break;
case AST_SIP_DTMF_INFO :
*buf = "info"; break;
+ case AST_SIP_DTMF_AUTO :
+ *buf = "auto"; break;
default:
*buf = "none";
}
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index ab801c9e7..f99afb302 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sched.h"
#include "asterisk/acl.h"
#include "asterisk/sdp_srtp.h"
+#include "asterisk/dsp.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
@@ -123,7 +124,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
ice->stop(session_media->rtp);
}
- if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) {
+ if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) {
ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);
ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 1);
} else if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
@@ -143,13 +144,14 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
return 0;
}
-static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs)
+static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs,
+ struct ast_sip_session_media *session_media)
{
pjmedia_sdp_attr *attr;
pjmedia_sdp_rtpmap *rtpmap;
pjmedia_sdp_fmtp fmtp;
struct ast_format *format;
- int i, num = 0;
+ int i, num = 0, tel_event = 0;
char name[256];
char media[20];
char fmt_param[256];
@@ -171,6 +173,9 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
}
ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
+ if (strcmp(name,"telephone-event") == 0) {
+ tel_event++;
+ }
ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]),
media, name, 0, rtpmap->clock_rate);
@@ -200,7 +205,9 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
}
}
}
-
+ if ((tel_event==0) && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
+ ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
+ }
/* Get the packetization, if it exists */
if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) {
unsigned long framing = pj_strtoul(pj_strltrim(&attr->value));
@@ -221,6 +228,7 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
int fmts = 0;
int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
ast_format_cap_count(session->direct_media_cap);
+ int dsp_features = 0;
if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
!(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
@@ -238,7 +246,7 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
}
/* get the capabilities on the peer */
- get_codecs(session, stream, &codecs);
+ get_codecs(session, stream, &codecs, session_media);
ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);
/* get the joint capabilities between peer and endpoint */
@@ -288,6 +296,18 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
ast_channel_nativeformats_set(session->channel, caps);
ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
+ if ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO)
+ && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833)
+ && (session->dsp)) {
+ dsp_features = ast_dsp_get_features(session->dsp);
+ dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
+ if (dsp_features) {
+ ast_dsp_set_features(session->dsp, dsp_features);
+ } else {
+ ast_dsp_free(session->dsp);
+ session->dsp = NULL;
+ }
+ }
ast_channel_unlock(session->channel);
ao2_ref(fmt, -1);
@@ -951,7 +971,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
pj_str_t stmp;
pjmedia_sdp_attr *attr;
int index = 0;
- int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0;
+ int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) ? AST_RTP_DTMF : 0;
int min_packet_size = 0, max_packet_size = 0;
int rtp_code;
RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 4854c51d0..87ce2b0c1 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1283,7 +1283,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
session->inv_session = inv_session;
session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
- if (endpoint->dtmf == AST_SIP_DTMF_INBAND) {
+ if ((endpoint->dtmf == AST_SIP_DTMF_INBAND) || (endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
dsp_features |= DSP_FEATURE_DIGIT_DETECT;
}