mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
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
This commit is contained in:
committed by
George Joseph
parent
c16000f201
commit
423d01cf16
@@ -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
|
||||
@@ -440,6 +452,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/format.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/res_pjsip.h"
|
||||
#include "asterisk/res_pjsip_session.h"
|
||||
@@ -1039,6 +1052,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;
|
||||
@@ -1067,6 +1108,117 @@ 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);
|
||||
}
|
||||
|
||||
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 chan_pjsip_pvt *pjsip_pvt;
|
||||
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;
|
||||
|
||||
pjsip_pvt = channel->pvt;
|
||||
if (pjsip_pvt->media[SIP_MEDIA_AUDIO] && (pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) {
|
||||
if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {
|
||||
ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 1);
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_RFC2833);
|
||||
} else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {
|
||||
ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_NONE);
|
||||
} else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {
|
||||
ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_INBAND);
|
||||
} else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {
|
||||
ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_NONE);
|
||||
} else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {
|
||||
if (ast_rtp_instance_dtmf_mode_get((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) != AST_RTP_DTMF_MODE_RFC2833) {
|
||||
/* no RFC4733 negotiated, enable inband */
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_DTMF_MODE_INBAND);
|
||||
}
|
||||
} else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
|
||||
ast_rtp_instance_set_prop((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp, AST_RTP_PROPERTY_DTMF, 0);
|
||||
if (ast_rtp_instance_dtmf_mode_get((pjsip_pvt->media[SIP_MEDIA_AUDIO])->rtp) == AST_RTP_DTMF_MODE_INBAND) {
|
||||
/* if inband, switch to INFO */
|
||||
ast_rtp_instance_dtmf_mode_set((pjsip_pvt->media[SIP_MEDIA_AUDIO])->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;
|
||||
|
Reference in New Issue
Block a user