<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6087">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Sean Bright: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, but someone else must approve; Verified
  George Joseph: Looks good to me, approved
  Jenkins2: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_pjsip: add a new function PJSIP_DTMF_MODE<br><br>This function is a replica of SIPDtmfMode, allowing the DTMF mode of a<br>PJSIP call to be modified on a per-call basis<br><br>ASTERISK-27085 #close<br><br>Change-Id: I20eef5da3e5d1d3e58b304416bc79683f87e7612<br>---<br>M CHANGES<br>M channels/chan_pjsip.c<br>M channels/pjsip/dialplan_functions.c<br>M channels/pjsip/include/dialplan_functions.h<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/res_pjsip_session.h<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_session.c<br>10 files changed, 293 insertions(+), 37 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/CHANGES b/CHANGES<br>index 5907e13..63422b4 100644<br>--- a/CHANGES<br>+++ b/CHANGES<br>@@ -28,6 +28,9 @@<br>    which sends signals to the application and its descendants directly, or<br>    "process" which sends signals only to the application itself.<br> <br>+ * New dialplan function PJSIP_DTMF_MODE added to get or change the DTMF mode<br>+   of a channel on a per-call basis.<br>+<br> ------------------------------------------------------------------------------<br> --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------<br> ------------------------------------------------------------------------------<br>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c<br>index 6a11b59..93e74a5 100644<br>--- a/channels/chan_pjsip.c<br>+++ b/channels/chan_pjsip.c<br>@@ -1749,7 +1749,7 @@<br>     struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];<br>         int res = 0;<br> <br>-      switch (channel->session->endpoint->dtmf) {<br>+ switch (channel->session->dtmf) {<br>       case AST_SIP_DTMF_RFC_4733:<br>           if (!media || !media->rtp) {<br>                       return -1;<br>@@ -1869,7 +1869,7 @@<br>     struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];<br>         int res = 0;<br> <br>-      switch (channel->session->endpoint->dtmf) {<br>+ switch (channel->session->dtmf) {<br>       case AST_SIP_DTMF_AUTO_INFO:<br>  {<br>             if (!media || !media->rtp) {<br>@@ -2681,6 +2681,12 @@<br>       .write = pjsip_acf_media_offer_write<br> };<br> <br>+static struct ast_custom_function dtmf_mode_function = {<br>+      .name = "PJSIP_DTMF_MODE",<br>+ .read = pjsip_acf_dtmf_mode_read,<br>+    .write = pjsip_acf_dtmf_mode_write<br>+};<br>+<br> static struct ast_custom_function session_refresh_function = {<br>   .name = "PJSIP_SEND_SESSION_REFRESH",<br>       .write = pjsip_acf_session_refresh_write,<br>@@ -2722,6 +2728,11 @@<br> <br>  if (ast_custom_function_register(&media_offer_function)) {<br>                ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");<br>+          goto end;<br>+    }<br>+<br>+ if (ast_custom_function_register(&dtmf_mode_function)) {<br>+         ast_log(LOG_WARNING, "Unable to register PJSIP_DTMF_MODE dialplan function\n");<br>             goto end;<br>     }<br> <br>@@ -2784,6 +2795,7 @@<br> end:<br>    ao2_cleanup(pjsip_uids_onhold);<br>       pjsip_uids_onhold = NULL;<br>+    ast_custom_function_unregister(&dtmf_mode_function);<br>      ast_custom_function_unregister(&media_offer_function);<br>    ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);<br>       ast_custom_function_unregister(&session_refresh_function);<br>@@ -2806,6 +2818,7 @@<br>         ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);<br>        ast_sip_session_unregister_supplement(&call_pickup_supplement);<br> <br>+       ast_custom_function_unregister(&dtmf_mode_function);<br>      ast_custom_function_unregister(&media_offer_function);<br>    ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);<br>       ast_custom_function_unregister(&session_refresh_function);<br>diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c<br>index 01081e9..13d9fab 100644<br>--- a/channels/pjsip/dialplan_functions.c<br>+++ b/channels/pjsip/dialplan_functions.c<br>@@ -68,6 +68,18 @@<br>               <ref type="function">PJSIP_SEND_SESSION_REFRESH</ref><br>   </see-also><br> </function><br>+<function name="PJSIP_DTMF_MODE" language="en_US"><br>+ <synopsis><br>+             Get or change the DTMF mode for a SIP call.<br>+  </synopsis><br>+    <syntax><br>+       </syntax><br>+      <description><br>+          <para>When read, returns the current DTMF mode</para><br>+            <para>When written, sets the current DTMF mode</para><br>+            <para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para><br>+  </description><br>+</function><br> <function name="PJSIP_SEND_SESSION_REFRESH" language="en_US"><br>    <synopsis><br>              W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session<br>@@ -440,6 +452,7 @@<br> #include "asterisk/app.h"<br> #include "asterisk/channel.h"<br> #include "asterisk/format.h"<br>+#include "asterisk/dsp.h"<br> #include "asterisk/pbx.h"<br> #include "asterisk/res_pjsip.h"<br> #include "asterisk/res_pjsip_session.h"<br>@@ -1039,6 +1052,34 @@<br>  return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);<br> }<br> <br>+int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)<br>+{<br>+  struct ast_sip_channel_pvt *channel;<br>+<br>+      if (!chan) {<br>+         ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);<br>+            return -1;<br>+   }<br>+<br>+ ast_channel_lock(chan);<br>+      if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {<br>+            ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);<br>+              ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ channel = ast_channel_tech_pvt(chan);<br>+<br>+     if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) {<br>+            ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan));<br>+          ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ ast_channel_unlock(chan);<br>+    return 0;<br>+}<br>+<br> struct refresh_data {<br>      struct ast_sip_session *session;<br>      enum ast_sip_session_refresh_method method;<br>@@ -1067,6 +1108,117 @@<br>  return 0;<br> }<br> <br>+static int dtmf_mode_refresh_cb(void *obj)<br>+{<br>+    struct refresh_data *data = obj;<br>+<br>+  if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {<br>+               ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel));<br>+<br>+               ast_sip_session_refresh(data->session, NULL, NULL,<br>+                        sip_session_response_cb, data->method, 1);<br>+        }<br>+<br>+ return 0;<br>+}<br>+<br>+int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)<br>+{<br>+       struct ast_sip_channel_pvt *channel;<br>+ struct chan_pjsip_pvt *pjsip_pvt;<br>+    int dsp_features = 0;<br>+        int dtmf = -1;<br>+       struct refresh_data rdata = {<br>+                        .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE,<br>+             };<br>+<br>+        if (!chan) {<br>+         ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);<br>+            return -1;<br>+   }<br>+<br>+ ast_channel_lock(chan);<br>+      if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {<br>+            ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);<br>+              ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ channel = ast_channel_tech_pvt(chan);<br>+        rdata.session = channel->session;<br>+<br>+      dtmf = ast_sip_str_to_dtmf(value);<br>+<br>+        if (dtmf == -1) {<br>+            ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value,<br>+                 ast_channel_name(chan));<br>+             ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ if (channel->session->dtmf == dtmf) {<br>+          /* DTMF mode unchanged, nothing to do! */<br>+            ast_channel_unlock(chan);<br>+            return 0;<br>+    }<br>+<br>+ channel->session->dtmf = dtmf;<br>+<br>+      pjsip_pvt = channel->pvt;<br>+ if (pjsip_pvt->media[SIP_MEDIA_AUDIO]  && (pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) {<br>+               if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {<br>+                 ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 1);<br>+                 ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_RFC2833);<br>+           } else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {<br>+                      ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);<br>+                 ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_NONE);<br>+              } else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {<br>+                    ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);<br>+                 ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_INBAND);<br>+            } else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {<br>+                      ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);<br>+                 ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_NONE);<br>+              } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {<br>+                      if (ast_rtp_instance_dtmf_mode_get((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) != AST_RTP_DTMF_MODE_RFC2833) {<br>+                           /* no RFC4733 negotiated, enable inband */<br>+                           ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_INBAND);<br>+                    }<br>+            } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {<br>+                 ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);<br>+                 if (ast_rtp_instance_dtmf_mode_get((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) == AST_RTP_DTMF_MODE_INBAND) {<br>+                            /* if inband, switch to INFO */<br>+                              ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_NONE);<br>+                      }<br>+            }<br>+    }<br>+<br>+ if (channel->session->dsp) {<br>+           dsp_features = ast_dsp_get_features(channel->session->dsp);<br>+    }<br>+    if (channel->session->dtmf == AST_SIP_DTMF_INBAND ||<br>+           channel->session->dtmf == AST_SIP_DTMF_AUTO) {<br>+         dsp_features |= DSP_FEATURE_DIGIT_DETECT;<br>+    } else {<br>+             dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;<br>+       }<br>+    if (dsp_features) {<br>+          if (!channel->session->dsp) {<br>+                  if (!(channel->session->dsp = ast_dsp_new())) {<br>+                                ast_channel_unlock(chan);<br>+                            return 0;<br>+                    }<br>+            }<br>+            ast_dsp_set_features(channel->session->dsp, dsp_features);<br>+     } else if (channel->session->dsp) {<br>+            ast_dsp_free(channel->session->dsp);<br>+           channel->session->dsp = NULL;<br>+  }<br>+<br>+ ast_channel_unlock(chan);<br>+<br>+ return ast_sip_push_task_synchronous(channel->session->serializer, dtmf_mode_refresh_cb, &rdata);<br>+}<br>+<br> static int refresh_write_cb(void *obj)<br> {<br>       struct refresh_data *data = obj;<br>diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h<br>index 8b80bfa..731e91d 100644<br>--- a/channels/pjsip/include/dialplan_functions.h<br>+++ b/channels/pjsip/include/dialplan_functions.h<br>@@ -48,6 +48,31 @@<br> int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);<br> <br> /*!<br>+ * \brief PJSIP_DTMF_MODE function read callback<br>+ * \param chan The channel the function is called on<br>+ * \param cmd The name of the function<br>+ * \param data Arguments passed to the function<br>+ * \param buf Out buffer that should be populated with the data<br>+ * \param len Size of the buffer<br>+ *<br>+ * \retval 0 on success<br>+ * \retval -1 on failure<br>+ */<br>+int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);<br>+<br>+/*!<br>+ * \brief PJSIP_DTMF_MODE function write callback<br>+ * \param chan The channel the function is called on<br>+ * \param cmd The name of the function<br>+ * \param data Arguments passed to the function<br>+ * \param value Value to be set by the function<br>+ *<br>+ * \retval 0 on success<br>+ * \retval -1 on failure<br>+ */<br>+int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);<br>+<br>+/*!<br>  * \brief PJSIP_MEDIA_OFFER function read callback<br>  * \param chan The channel the function is called on<br>  * \param cmd The name of the function<br>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index 9b42527..a674313 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -2859,4 +2859,31 @@<br> int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg,<br>        pjsip_tpselector *selector);<br> <br>+/*!<br>+ * \brief Convert the DTMF mode enum value into a string<br>+ * \since 13.18.0<br>+ *<br>+ * \param dtmf the dtmf mode<br>+ * \param buf Buffer to receive dtmf mode string<br>+ * \param buf_len Buffer length<br>+ *<br>+ * \retval 0 Success<br>+ * \retval -1 Failure<br>+ *<br>+ */<br>+int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf,<br>+    char *buf, size_t buf_len);<br>+<br>+/*!<br>+ * \brief Convert the DTMF mode name into an enum<br>+ * \since 13.18.0<br>+ *<br>+ * \param dtmf_mode dtmf mode as a string<br>+ *<br>+ * \retval  >= 0 The enum value<br>+ * \retval -1 Failure<br>+ *<br>+ */<br>+int ast_sip_str_to_dtmf(const char *dtmf_mode);<br>+<br> #endif /* _RES_PJSIP_H */<br>diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h<br>index e2a9066..ca331cb 100644<br>--- a/include/asterisk/res_pjsip_session.h<br>+++ b/include/asterisk/res_pjsip_session.h<br>@@ -159,6 +159,8 @@<br>     unsigned int defer_end:1;<br>     /*! Session end (remote hangup) requested while termination deferred */<br>       unsigned int ended_while_deferred:1;<br>+ /*! DTMF mode to use with this session, from endpoint but can change */<br>+      enum ast_sip_dtmf_mode dtmf;<br> };<br> <br> typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);<br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index 4fa28a1..e2d2c0a 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -4431,6 +4431,56 @@<br>        return NULL;<br> }<br> <br>+int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf,<br>+                     char *buf, size_t buf_len)<br>+{<br>+       switch (dtmf) {<br>+      case AST_SIP_DTMF_NONE:<br>+              ast_copy_string(buf, "none", buf_len);<br>+             break;<br>+       case AST_SIP_DTMF_RFC_4733:<br>+          ast_copy_string(buf, "rfc4733", buf_len);<br>+          break;<br>+       case AST_SIP_DTMF_INBAND:<br>+            ast_copy_string(buf, "inband", buf_len);<br>+           break;<br>+       case AST_SIP_DTMF_INFO:<br>+              ast_copy_string(buf, "info", buf_len);<br>+             break;<br>+       case AST_SIP_DTMF_AUTO:<br>+              ast_copy_string(buf, "auto", buf_len);<br>+             break;<br>+       case AST_SIP_DTMF_AUTO_INFO:<br>+         ast_copy_string(buf, "auto_info", buf_len);<br>+                break;<br>+       default:<br>+             buf[0] = '\0';<br>+               return -1;<br>+   }<br>+    return 0;<br>+}<br>+<br>+int ast_sip_str_to_dtmf(const char * dtmf_mode)<br>+{<br>+       int result = -1;<br>+<br>+  if (!strcasecmp(dtmf_mode, "info")) {<br>+              result = AST_SIP_DTMF_INFO;<br>+  } else if (!strcasecmp(dtmf_mode, "rfc4733")) {<br>+            result = AST_SIP_DTMF_RFC_4733;<br>+      } else if (!strcasecmp(dtmf_mode, "inband")) {<br>+             result = AST_SIP_DTMF_INBAND;<br>+        } else if (!strcasecmp(dtmf_mode, "none")) {<br>+               result = AST_SIP_DTMF_NONE;<br>+  } else if (!strcasecmp(dtmf_mode, "auto")) {<br>+               result = AST_SIP_DTMF_AUTO;<br>+  } else if (!strcasecmp(dtmf_mode, "auto_info")) {<br>+          result = AST_SIP_DTMF_AUTO_INFO;<br>+     }<br>+<br>+ return result;<br>+}<br>+<br> /*!<br>  * \brief Set name and number information on an identity header.<br>  *<br>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c<br>index 4e501e6..fb15db0 100644<br>--- a/res/res_pjsip/pjsip_configuration.c<br>+++ b/res/res_pjsip/pjsip_configuration.c<br>@@ -365,47 +365,29 @@<br> static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)<br> {<br>      struct ast_sip_endpoint *endpoint = obj;<br>+     enum ast_sip_dtmf_mode dtmf = ast_sip_str_to_dtmf(var->value);<br> <br>- if (!strcasecmp(var->value, "rfc4733")) {<br>-               endpoint->dtmf = AST_SIP_DTMF_RFC_4733;<br>-   } else if (!strcasecmp(var->value, "inband")) {<br>-         endpoint->dtmf = AST_SIP_DTMF_INBAND;<br>-     } else if (!strcasecmp(var->value, "auto_info")) {<br>-              endpoint->dtmf = AST_SIP_DTMF_AUTO_INFO;<br>-  } else if (!strcasecmp(var->value, "info")) {<br>-           endpoint->dtmf = AST_SIP_DTMF_INFO;<br>-       } else if (!strcasecmp(var->value, "auto")) {<br>-           endpoint->dtmf = AST_SIP_DTMF_AUTO;<br>-       } else if (!strcasecmp(var->value, "none")) {<br>-           endpoint->dtmf = AST_SIP_DTMF_NONE;<br>-       } else {<br>+     if (dtmf == -1) {<br>             return -1;<br>    }<br> <br>+ endpoint->dtmf = dtmf;<br>     return 0;<br> }<br> <br> static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)<br> {<br>      const struct ast_sip_endpoint *endpoint = obj;<br>+       char dtmf_str[20];<br>+   int result = -1;<br> <br>-  switch (endpoint->dtmf) {<br>- case AST_SIP_DTMF_RFC_4733 :<br>-         *buf = "rfc4733"; break;<br>-   case AST_SIP_DTMF_INBAND :<br>-           *buf = "inband"; break;<br>-    case AST_SIP_DTMF_INFO :<br>-             *buf = "info"; break;<br>-      case AST_SIP_DTMF_AUTO :<br>-             *buf = "auto"; break;<br>-      case AST_SIP_DTMF_AUTO_INFO :<br>-                *buf = "auto_info";<br>-                break;<br>-       default:<br>-             *buf = "none";<br>+     result = ast_sip_dtmf_to_str(endpoint->dtmf, dtmf_str, sizeof(dtmf_str));<br>+<br>+      if (result == 0) {<br>+           *buf = ast_strdup(dtmf_str);<br>+ } else {<br>+             *buf = ast_strdup("none");<br>  }<br>-<br>- *buf = ast_strdup(*buf);<br>      return 0;<br> }<br> <br>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c<br>index 6b29e79..5fff767 100644<br>--- a/res/res_pjsip_sdp_rtp.c<br>+++ b/res/res_pjsip_sdp_rtp.c<br>@@ -247,10 +247,10 @@<br>          ice->stop(session_media->rtp);<br>  }<br> <br>- if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) {<br>+       if (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->dtmf == AST_SIP_DTMF_AUTO_INFO) {<br>               ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);<br>             ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 1);<br>-  } else if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {<br>+   } else if (session->dtmf == AST_SIP_DTMF_INBAND) {<br>                 ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);<br>      }<br> <br>@@ -333,11 +333,11 @@<br>                   }<br>             }<br>     }<br>-    if (!tel_event && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) {<br>+    if (!tel_event && (session->dtmf == AST_SIP_DTMF_AUTO)) {<br>          ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);<br>      }<br> <br>- if (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) {<br>+       if (session->dtmf == AST_SIP_DTMF_AUTO_INFO) {<br>             if  (tel_event) {<br>                     ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);<br>             } else {<br>@@ -450,7 +450,7 @@<br>                         ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));<br>              }<br> <br>-         if ( ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) || (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) )<br>+            if ( ((session->dtmf == AST_SIP_DTMF_AUTO) || (session->dtmf == AST_SIP_DTMF_AUTO_INFO) )<br>                   && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833)<br>               && (session->dsp)) {<br>                   dsp_features = ast_dsp_get_features(session->dsp);<br>@@ -1178,7 +1178,7 @@<br>  pj_str_t stmp;<br>        pjmedia_sdp_attr *attr;<br>       int index = 0;<br>-       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;<br>+ int noncodec = (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0;<br>         int min_packet_size = 0, max_packet_size = 0;<br>         int rtp_code;<br>         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index aedf3f6..aed047b 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -1481,6 +1481,8 @@<br>       session->contact = ao2_bump(contact);<br>      session->inv_session = inv_session;<br> <br>+    session->dtmf = endpoint->dtmf;<br>+<br>      if (add_supplements(session)) {<br>               /* Release the ref held by session->inv_session */<br>                 ao2_ref(session, -1);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6087">change 6087</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6087"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I20eef5da3e5d1d3e58b304416bc79683f87e7612 </div>
<div style="display:none"> Gerrit-Change-Number: 6087 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Torrey Searle <tsearle@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>