]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add DTMF INFO Failback mode
authorTorrey Searle <torrey@voxbone.com>
Thu, 15 Jun 2017 08:12:41 +0000 (10:12 +0200)
committerTorrey Searle <torrey@voxbone.com>
Fri, 23 Jun 2017 07:15:24 +0000 (09:15 +0200)
The existing auto dtmf mode reverts to inband if 4733 fails to be
negotiated.  This patch adds a new mode auto_info which will
switch to INFO instead of inband if 4733 is not available.

ASTERISK-27066 #close

Change-Id: Id185b11e84afd9191a2f269e8443019047765e91

CHANGES
channels/chan_pjsip.c
contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py [new file with mode: 0644]
include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_sdp_rtp.c

diff --git a/CHANGES b/CHANGES
index 1b87dbf0d067d884f44a442fcfd9359a3ded2786..c2a9c8f8af342a3ffa55f1001c61ee4f7eda4362 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -25,6 +25,10 @@ res_pjsip
    whether to notify dialog-info state 'early' or 'confirmed' on Ringing
    when already INUSE.
 
+ * The endpoint option 'dtmf_mode' has a new option 'auto_dtmf' added. This
+   mode works similar to 'auto' except uses DTMF INFO as fallback instead of
+   INBAND.
+
 res_agi
 ------------------
  * The EAGI() application will now look for a dialplan variable named
index 486a237aed5939737ef26db21800d378a8b266a9..d1691b87e5ac15b30424d34163134a3bb701ed59 100644 (file)
@@ -1708,14 +1708,20 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
                }
 
                ast_rtp_instance_dtmf_begin(media->rtp, digit);
-                break;
+               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;
-                }
+               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;
+               ast_rtp_instance_dtmf_begin(media->rtp, digit);
+               break;
+       case AST_SIP_DTMF_AUTO_INFO:
+               if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_NONE)) {
+                       return -1;
+               }
+               ast_rtp_instance_dtmf_begin(media->rtp, digit);
+               break;
        case AST_SIP_DTMF_NONE:
                break;
        case AST_SIP_DTMF_INBAND:
@@ -1816,6 +1822,20 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in
        int res = 0;
 
        switch (channel->session->endpoint->dtmf) {
+       case AST_SIP_DTMF_AUTO_INFO:
+       {
+               if (!media || !media->rtp) {
+                       return -1;
+               }
+               if (ast_rtp_instance_dtmf_mode_get(media->rtp) != AST_RTP_DTMF_MODE_NONE) {
+                       ast_debug(3, "Told to send end of digit on Auto-Info channel %s RFC4733 negotiated so using it.\n", ast_channel_name(ast));
+                       ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
+                       break;
+               }
+               /* If RFC_4733 was not negotiated, fail through to the DTMF_INFO processing */
+               ast_debug(3, "Told to send end of digit on Auto-Info channel %s RFC4733 NOT negotiated using INFO instead.\n", ast_channel_name(ast));
+       }
+
        case AST_SIP_DTMF_INFO:
        {
                struct info_dtmf_data *dtmf_data = info_dtmf_data_alloc(channel->session, digit, duration);
@@ -1848,14 +1868,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;
+               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;
diff --git a/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py b/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py
new file mode 100644 (file)
index 0000000..dbc8ce9
--- /dev/null
@@ -0,0 +1,57 @@
+"""Add auto_info to endpoint dtmf_mode
+
+Revision ID: 164abbd708c
+Revises: 86bb1efa278d
+Create Date: 2017-06-19 13:55:15.354706
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '164abbd708c'
+down_revision = '86bb1efa278d'
+
+from alembic import op
+import sqlalchemy as sa
+
+OLD_ENUM = ['rfc4733', 'inband', 'info', 'auto']
+NEW_ENUM = ['rfc4733', 'inband', 'info', 'auto', 'auto_info']
+
+old_type = sa.Enum(*OLD_ENUM, name='pjsip_dtmf_mode_values_v2')
+new_type = sa.Enum(*NEW_ENUM, name='pjsip_dtmf_mode_values_v3')
+
+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', 'auto_info',
+                    name='pjsip_dtmf_mode_values_v3')
+        enum.create(op.get_bind(), checkfirst=False)
+
+        op.execute('ALTER TABLE ps_endpoints ALTER COLUMN dtmf_mode TYPE'
+                   ' pjsip_dtmf_mode_values_v3 USING'
+                   ' dtmf_mode::text::pjsip_dtmf_mode_values_v3')
+
+        ENUM(name="pjsip_dtmf_mode_values_v2").drop(op.get_bind(), checkfirst=False)
+
+def downgrade():
+    context = op.get_context()
+
+    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', '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 USING'
+                   ' dtmf_mode::text::pjsip_dtmf_mode_values_v2')
+
+        ENUM(name="pjsip_dtmf_mode_values_v3").drop(op.get_bind(), checkfirst=False)
index 04e0c65d0f53a0f82b837a6b465db60d3188ec06..b5a02881d7eb27f67dc43fc24aae3d2ea3e1bcca 100644 (file)
@@ -363,6 +363,8 @@ enum ast_sip_dtmf_mode {
        AST_SIP_DTMF_INFO,
        /*! Use SIP 4733 if supported by the other side or INBAND if not */
        AST_SIP_DTMF_AUTO,
+       /*! Use SIP 4733 if supported by the other side or INFO DTMF (blech) if not */
+       AST_SIP_DTMF_AUTO_INFO,
 };
 
 /*!
index f79ebfd7200cae611f01c65e5a85789fe9234057..057ae33602de8d761f3111ca33b980848c858cf8 100644 (file)
                                                        <enum name="auto">
                                                                <para>DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not.</para>
                                                        </enum>
+                                                       <enum name="auto_info">
+                                                               <para>DTMF is sent as RFC 4733 if the other side supports it or as SIP INFO if not.</para>
+                                                       </enum>
                                                </enumlist>
                                        </description>
                                </configOption>
index d2d1a0c24daa0c4e4008a79081ecc2979cd0c88d..9604ff2ea92cf6ec2ef0c26cd3ca51f7b01c1a4f 100644 (file)
@@ -373,6 +373,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var,
                endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
        } else if (!strcasecmp(var->value, "inband")) {
                endpoint->dtmf = AST_SIP_DTMF_INBAND;
+       } else if (!strcasecmp(var->value, "auto_info")) {
+               endpoint->dtmf = AST_SIP_DTMF_AUTO_INFO;
        } else if (!strcasecmp(var->value, "info")) {
                endpoint->dtmf = AST_SIP_DTMF_INFO;
        } else if (!strcasecmp(var->value, "auto")) {
@@ -397,8 +399,11 @@ 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 :
+       case AST_SIP_DTMF_AUTO :
                *buf = "auto"; break;
+       case AST_SIP_DTMF_AUTO_INFO :
+               *buf = "auto_info";
+               break;
        default:
                *buf = "none";
        }
index d39842f3a8fb726b79beb7aeb13873ff327baa7d..a6bd2d79c06eb18589cb964f1751a75e1bace972 100644 (file)
@@ -246,7 +246,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 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) {
+       if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) {
                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) {
@@ -269,7 +269,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
 }
 
 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)
+       struct ast_sip_session_media *session_media)
 {
        pjmedia_sdp_attr *attr;
        pjmedia_sdp_rtpmap *rtpmap;
@@ -335,6 +335,16 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
        if (!tel_event && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
                ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
        }
+
+       if (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) {
+               if  (tel_event) {
+                       ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);
+               } else {
+                       ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_NONE);
+               }
+       }
+
+
        /* 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));
@@ -429,7 +439,8 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
                        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)
+
+               if ( ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) || (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) )
                    && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833)
                    && (session->dsp)) {
                        dsp_features = ast_dsp_get_features(session->dsp);
@@ -1149,7 +1160,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 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) ? AST_RTP_DTMF : 0;
+       int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ? 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);