[asterisk-commits] chan pjsip: add a new function PJSIP DTMF MODE (asterisk[master])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jul 27 09:02:23 CDT 2017


Jenkins2 has submitted this change and it was merged. ( https://gerrit.asterisk.org/6088 )

Change subject: chan_pjsip: add a new function PJSIP_DTMF_MODE
......................................................................

chan_pjsip: add a new function PJSIP_DTMF_MODE

This function is a replica of SIPDtmfMode, allowing the DTMF mode of a
PJSIP call to be modified on a per-call basis

ASTERISK-27085 #close

Change-Id: I20eef5da3e5d1d3e58b304416bc79683f87e7612
---
M CHANGES
M channels/chan_pjsip.c
M channels/pjsip/dialplan_functions.c
M channels/pjsip/include/dialplan_functions.h
M include/asterisk/res_pjsip.h
M include/asterisk/res_pjsip_session.h
M res/res_pjsip.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_sdp_rtp.c
M res/res_pjsip_session.c
10 files changed, 294 insertions(+), 37 deletions(-)

Approvals:
  Joshua Colp: Looks good to me, but someone else must approve; Verified
  George Joseph: Looks good to me, approved
  Jenkins2: Approved for Submit



diff --git a/CHANGES b/CHANGES
index 5daa816..1721ed1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -37,6 +37,9 @@
    which sends signals to the application and its descendants directly, or
    "process" which sends signals only to the application itself.
 
+ * New dialplan function PJSIP_DTMF_MODE added to get or change the DTMF mode
+   of a channel on a per-call basis.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------
 ------------------------------------------------------------------------------
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 51b5dab..ebda6c7 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1947,7 +1947,7 @@
 
 	media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
 
-	switch (channel->session->endpoint->dtmf) {
+	switch (channel->session->dtmf) {
 	case AST_SIP_DTMF_RFC_4733:
 		if (!media || !media->rtp) {
 			return -1;
@@ -2068,7 +2068,7 @@
 
 	media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
 
-	switch (channel->session->endpoint->dtmf) {
+	switch (channel->session->dtmf) {
 	case AST_SIP_DTMF_AUTO_INFO:
 	{
 		if (!media || !media->rtp) {
@@ -2893,6 +2893,12 @@
 	.write = pjsip_acf_media_offer_write
 };
 
+static struct ast_custom_function dtmf_mode_function = {
+	.name = "PJSIP_DTMF_MODE",
+	.read = pjsip_acf_dtmf_mode_read,
+	.write = pjsip_acf_dtmf_mode_write
+};
+
 static struct ast_custom_function session_refresh_function = {
 	.name = "PJSIP_SEND_SESSION_REFRESH",
 	.write = pjsip_acf_session_refresh_write,
@@ -2934,6 +2940,11 @@
 
 	if (ast_custom_function_register(&media_offer_function)) {
 		ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
+		goto end;
+	}
+
+	if (ast_custom_function_register(&dtmf_mode_function)) {
+		ast_log(LOG_WARNING, "Unable to register PJSIP_DTMF_MODE dialplan function\n");
 		goto end;
 	}
 
@@ -2996,6 +3007,7 @@
 end:
 	ao2_cleanup(pjsip_uids_onhold);
 	pjsip_uids_onhold = NULL;
+	ast_custom_function_unregister(&dtmf_mode_function);
 	ast_custom_function_unregister(&media_offer_function);
 	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_custom_function_unregister(&session_refresh_function);
@@ -3018,6 +3030,7 @@
 	ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
 	ast_sip_session_unregister_supplement(&call_pickup_supplement);
 
+	ast_custom_function_unregister(&dtmf_mode_function);
 	ast_custom_function_unregister(&media_offer_function);
 	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_custom_function_unregister(&session_refresh_function);
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index 59ca9d7..c89d9ca 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -68,6 +68,18 @@
 		<ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
 	</see-also>
 </function>
+<function name="PJSIP_DTMF_MODE" language="en_US">
+	<synopsis>
+		Get or change the DTMF mode for a SIP call.
+	</synopsis>
+	<syntax>
+	</syntax>
+	<description>
+		<para>When read, returns the current DTMF mode</para>
+		<para>When written, sets the current DTMF mode</para>
+		<para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
+	</description>
+</function>
 <function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
 	<synopsis>
 		W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
@@ -439,6 +451,7 @@
 #include "asterisk/channel.h"
 #include "asterisk/stream.h"
 #include "asterisk/format.h"
+#include "asterisk/dsp.h"
 #include "asterisk/pbx.h"
 #include "asterisk/res_pjsip.h"
 #include "asterisk/res_pjsip_session.h"
@@ -1167,6 +1180,34 @@
 	return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);
 }
 
+int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	struct ast_sip_channel_pvt *channel;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	channel = ast_channel_tech_pvt(chan);
+
+	if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) {
+		ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan));
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	ast_channel_unlock(chan);
+	return 0;
+}
+
 struct refresh_data {
 	struct ast_sip_session *session;
 	enum ast_sip_session_refresh_method method;
@@ -1195,6 +1236,118 @@
 	return 0;
 }
 
+static int dtmf_mode_refresh_cb(void *obj)
+{
+	struct refresh_data *data = obj;
+
+	if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {
+		ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
+
+		ast_sip_session_refresh(data->session, NULL, NULL,
+			sip_session_response_cb, data->method, 1, NULL);
+	}
+
+	return 0;
+}
+
+int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+	struct ast_sip_channel_pvt *channel;
+	struct ast_sip_session_media *media;
+	int dsp_features = 0;
+	int dtmf = -1;
+	struct refresh_data rdata = {
+			.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE,
+		};
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	channel = ast_channel_tech_pvt(chan);
+	rdata.session = channel->session;
+
+	dtmf = ast_sip_str_to_dtmf(value);
+
+	if (dtmf == -1) {
+		ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value,
+			ast_channel_name(chan));
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (channel->session->dtmf == dtmf) {
+		/* DTMF mode unchanged, nothing to do! */
+		ast_channel_unlock(chan);
+		return 0;
+	}
+
+	channel->session->dtmf = dtmf;
+
+	media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
+
+	if (media && media->rtp) {
+		if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {
+			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 1);
+			ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_RFC2833);
+		} else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {
+			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0);
+			ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE);
+		} else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {
+			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0);
+			ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_INBAND);
+		} else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {
+			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0);
+			ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE);
+		} else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {
+			if (ast_rtp_instance_dtmf_mode_get(media->rtp) != AST_RTP_DTMF_MODE_RFC2833) {
+				/* no RFC4733 negotiated, enable inband */
+				ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_INBAND);
+			}
+		} else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
+			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0);
+			if (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND) {
+				/* if inband, switch to INFO */
+				ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE);
+			}
+		}
+	}
+
+	if (channel->session->dsp) {
+		dsp_features = ast_dsp_get_features(channel->session->dsp);
+	}
+	if (channel->session->dtmf == AST_SIP_DTMF_INBAND ||
+		channel->session->dtmf == AST_SIP_DTMF_AUTO) {
+		dsp_features |= DSP_FEATURE_DIGIT_DETECT;
+	} else {
+		dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
+	}
+	if (dsp_features) {
+		if (!channel->session->dsp) {
+			if (!(channel->session->dsp = ast_dsp_new())) {
+				ast_channel_unlock(chan);
+				return 0;
+			}
+		}
+		ast_dsp_set_features(channel->session->dsp, dsp_features);
+	} else if (channel->session->dsp) {
+		ast_dsp_free(channel->session->dsp);
+		channel->session->dsp = NULL;
+	}
+
+	ast_channel_unlock(chan);
+
+	return ast_sip_push_task_synchronous(channel->session->serializer, dtmf_mode_refresh_cb, &rdata);
+}
+
 static int refresh_write_cb(void *obj)
 {
 	struct refresh_data *data = obj;
diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h
index 8b80bfa..731e91d 100644
--- a/channels/pjsip/include/dialplan_functions.h
+++ b/channels/pjsip/include/dialplan_functions.h
@@ -48,6 +48,31 @@
 int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
 
 /*!
+ * \brief PJSIP_DTMF_MODE function read callback
+ * \param chan The channel the function is called on
+ * \param cmd The name of the function
+ * \param data Arguments passed to the function
+ * \param buf Out buffer that should be populated with the data
+ * \param len Size of the buffer
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+
+/*!
+ * \brief PJSIP_DTMF_MODE function write callback
+ * \param chan The channel the function is called on
+ * \param cmd The name of the function
+ * \param data Arguments passed to the function
+ * \param value Value to be set by the function
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
+
+/*!
  * \brief PJSIP_MEDIA_OFFER function read callback
  * \param chan The channel the function is called on
  * \param cmd The name of the function
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index cf366cb..cb77fa3 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -2889,4 +2889,31 @@
 int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg,
 	pjsip_tpselector *selector);
 
+/*!
+ * \brief Convert the DTMF mode enum value into a string
+ * \since 13.18.0
+ *
+ * \param dtmf the dtmf mode
+ * \param buf Buffer to receive dtmf mode string
+ * \param buf_len Buffer length
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ *
+ */
+int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf,
+	char *buf, size_t buf_len);
+
+/*!
+ * \brief Convert the DTMF mode name into an enum
+ * \since 13.18.0
+ *
+ * \param dtmf_mode dtmf mode as a string
+ *
+ * \retval  >= 0 The enum value
+ * \retval -1 Failure
+ *
+ */
+int ast_sip_str_to_dtmf(const char *dtmf_mode);
+
 #endif /* _RES_PJSIP_H */
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index eae11af..caf10db 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -203,6 +203,8 @@
 	unsigned int defer_end:1;
 	/*! Session end (remote hangup) requested while termination deferred */
 	unsigned int ended_while_deferred:1;
+	/*! DTMF mode to use with this session, from endpoint but can change */
+	enum ast_sip_dtmf_mode dtmf;
 };
 
 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 0211211..f3648ac 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -4483,6 +4483,56 @@
 	return NULL;
 }
 
+int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf,
+		        char *buf, size_t buf_len)
+{
+	switch (dtmf) {
+	case AST_SIP_DTMF_NONE:
+		ast_copy_string(buf, "none", buf_len);
+		break;
+	case AST_SIP_DTMF_RFC_4733:
+		ast_copy_string(buf, "rfc4733", buf_len);
+		break;
+	case AST_SIP_DTMF_INBAND:
+		ast_copy_string(buf, "inband", buf_len);
+		break;
+	case AST_SIP_DTMF_INFO:
+		ast_copy_string(buf, "info", buf_len);
+		break;
+	case AST_SIP_DTMF_AUTO:
+		ast_copy_string(buf, "auto", buf_len);
+		break;
+	case AST_SIP_DTMF_AUTO_INFO:
+		ast_copy_string(buf, "auto_info", buf_len);
+		break;
+	default:
+		buf[0] = '\0';
+		return -1;
+	}
+	return 0;
+}
+
+int ast_sip_str_to_dtmf(const char * dtmf_mode)
+{
+	int result = -1;
+
+	if (!strcasecmp(dtmf_mode, "info")) {
+		result = AST_SIP_DTMF_INFO;
+	} else if (!strcasecmp(dtmf_mode, "rfc4733")) {
+		result = AST_SIP_DTMF_RFC_4733;
+	} else if (!strcasecmp(dtmf_mode, "inband")) {
+		result = AST_SIP_DTMF_INBAND;
+	} else if (!strcasecmp(dtmf_mode, "none")) {
+		result = AST_SIP_DTMF_NONE;
+	} else if (!strcasecmp(dtmf_mode, "auto")) {
+		result = AST_SIP_DTMF_AUTO;
+	} else if (!strcasecmp(dtmf_mode, "auto_info")) {
+		result = AST_SIP_DTMF_AUTO_INFO;
+	}
+
+	return result;
+}
+
 /*!
  * \brief Set name and number information on an identity header.
  *
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 9f9de36..4e12b04 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -366,47 +366,29 @@
 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
 	struct ast_sip_endpoint *endpoint = obj;
+	enum ast_sip_dtmf_mode dtmf = ast_sip_str_to_dtmf(var->value);
 
-	if (!strcasecmp(var->value, "rfc4733")) {
-		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")) {
-		endpoint->dtmf = AST_SIP_DTMF_AUTO;
-	} else if (!strcasecmp(var->value, "none")) {
-		endpoint->dtmf = AST_SIP_DTMF_NONE;
-	} else {
+	if (dtmf == -1) {
 		return -1;
 	}
 
+	endpoint->dtmf = dtmf;
 	return 0;
 }
 
 static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
 {
 	const struct ast_sip_endpoint *endpoint = obj;
+	char dtmf_str[20];
+	int result = -1;
 
-	switch (endpoint->dtmf) {
-	case AST_SIP_DTMF_RFC_4733 :
-		*buf = "rfc4733"; break;
-	case AST_SIP_DTMF_INBAND :
-		*buf = "inband"; break;
-	case AST_SIP_DTMF_INFO :
-		*buf = "info"; break;
-	case AST_SIP_DTMF_AUTO :
-		*buf = "auto"; break;
-	case AST_SIP_DTMF_AUTO_INFO :
-		*buf = "auto_info";
-		break;
-	default:
-		*buf = "none";
+	result = ast_sip_dtmf_to_str(endpoint->dtmf, dtmf_str, sizeof(dtmf_str));
+
+	if (result == 0) {
+		*buf = ast_strdup(dtmf_str);
+	} else {
+		*buf = ast_strdup("none");
 	}
-
-	*buf = ast_strdup(*buf);
 	return 0;
 }
 
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a2e7f8f..4ed1f8a 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -207,10 +207,10 @@
 		ice->stop(session_media->rtp);
 	}
 
-	if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) {
+	if (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->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) {
+	} else if (session->dtmf == AST_SIP_DTMF_INBAND) {
 		ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
 	}
 
@@ -293,11 +293,11 @@
 			}
 		}
 	}
-	if (!tel_event && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
+	if (!tel_event && (session->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 (session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
 		if  (tel_event) {
 			ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);
 		} else {
@@ -434,7 +434,7 @@
 			ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
 		}
 
-		if ( ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) || (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) )
+		if ( ((session->dtmf == AST_SIP_DTMF_AUTO) || (session->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);
@@ -1314,7 +1314,7 @@
 	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 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0;
+	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;
 	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 fe3680f..28b209b 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -2007,6 +2007,8 @@
 	session->contact = ao2_bump(contact);
 	session->inv_session = inv_session;
 
+	session->dtmf = endpoint->dtmf;
+
 	if (add_supplements(session)) {
 		/* Release the ref held by session->inv_session */
 		ao2_ref(session, -1);

-- 
To view, visit https://gerrit.asterisk.org/6088
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I20eef5da3e5d1d3e58b304416bc79683f87e7612
Gerrit-Change-Number: 6088
Gerrit-PatchSet: 2
Gerrit-Owner: Torrey Searle <tsearle at gmail.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Jenkins2
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-commits/attachments/20170727/eb20159b/attachment-0001.html>


More information about the asterisk-commits mailing list