]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add an 'auto' option for DTMF Mode
authorMatthew Jordan <mjordan@digium.com>
Fri, 10 Apr 2015 17:53:44 +0000 (17:53 +0000)
committerMatthew Jordan <mjordan@digium.com>
Fri, 10 Apr 2015 17:53:44 +0000 (17:53 +0000)
This patch adds support for automatically detecting the type of DTMF that a
PJSIP endpoint supports. When the 'dtmf_mode' endpoint option is set to 'auto',
the channel created for an endpoint will attempt to determine if RFC 4733
DTMF is supported. If so, it will use that DTMF type. If not, the DTMF type
for the channel will be set to inband.

Review: https://reviewboard.asterisk.org/r/4438

ASTERISK-24706 #close
Reported by: yaron nahum
patches:
  yaron_patch_3_Feb.diff submitted by yaron nahum (License 6676)

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@434637 65c4cc65-6c06-0410-ace0-fbb531ad65f3

UPGRADE.txt
channels/chan_pjsip.c
contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py [new file with mode: 0644]
include/asterisk/dsp.h
include/asterisk/res_pjsip.h
main/dsp.c
res/res_pjsip.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_sdp_rtp.c
res/res_pjsip_session.c

index 19f947c4a144228dc45477ab7ed9315bb41109a3..8b848cc8aac80890bd62edc86b6f49c4a3a534d3 100644 (file)
 
 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
index c9d09dbeb17c491d5048db4644f950f0e5e730be..207a7d90b6880a937dac8f8fc44378b1d2d54bbf 100644 (file)
@@ -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 (file)
index 0000000..fd1b6c7
--- /dev/null
@@ -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)
index 16262c05d468dd49c6d95ea36dcd9fb6911885ad..7e84ebe9caa11bc41a0e8b43836fae11f6e408c6 100644 (file)
@@ -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);
 
index fcad28878902918273d05fd51a70dc255222991e..06607cfc47c125feb97d709329ae50ed92a60d61 100644 (file)
@@ -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,
 };
 
 /*!
index 335fb3db0ff76ca9ff78da4c33a2d504c768362f..087416358e3609789a651d3c68589675e4eff8ef 100644 (file)
@@ -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);
index 448d57ddbcf2594050aee0e6e9b92569983ff75a..93905d6e966b374eb1980467796c36a190f0578d 100644 (file)
                                                        <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>
index 4f5fc74deb8bad6dac6eacf0ce5f197f16f18631..1f38e77299e692b2c91fe0037cd94657bdd6b374 100644 (file)
@@ -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";
        }
index ab801c9e7aef27f30195ce0cd093225fcd5704ad..f99afb302cb0bb15a96cda5e90628bc3f7375809 100644 (file)
@@ -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);
index 4854c51d03a0f8e51935e54ad93904e07e1a8290..87ce2b0c1b31b5d43b9107bf8b2614438865ce4b 100644 (file)
@@ -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;
        }