summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorTorrey Searle <torrey@voxbone.com>2017-06-26 14:52:52 +0200
committerGeorge Joseph <gjoseph@digium.com>2017-08-01 15:33:38 -0600
commitc24cdbf4ae677fd3980c91e60a027efad899b63d (patch)
tree7d8a3e482a2ad6d73cee743041fe0b9c5e9ad6fd /channels
parentd056f6b2fe3f417cfd266779c4a458f1be5173dc (diff)
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
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_pjsip.c17
-rw-r--r--channels/pjsip/dialplan_functions.c153
-rw-r--r--channels/pjsip/include/dialplan_functions.h25
3 files changed, 193 insertions, 2 deletions
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 51b5dab5c..ebda6c7ee 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1947,7 +1947,7 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
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 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in
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 @@ static struct ast_custom_function media_offer_function = {
.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,
@@ -2937,6 +2943,11 @@ static int load_module(void)
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;
+ }
+
if (ast_custom_function_register(&session_refresh_function)) {
ast_log(LOG_WARNING, "Unable to register PJSIP_SEND_SESSION_REFRESH dialplan function\n");
goto end;
@@ -2996,6 +3007,7 @@ static int load_module(void)
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 @@ static int unload_module(void)
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 59ca9d791..c89d9ca26 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 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char
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 @@ static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_dat
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 8b80bfa74..731e91d13 100644
--- a/channels/pjsip/include/dialplan_functions.h
+++ b/channels/pjsip/include/dialplan_functions.h
@@ -48,6 +48,31 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data
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