res_pjsip: Add an 'auto' option for DTMF Mode

This patch adds support for automatically detecting the type of DTMF that a
PJSIP endpoint supports. When the 'dtmf_mode' endpoint option is set to 'auto',
the channel created for an endpoint will attempt to determine if RFC 4733
DTMF is supported. If so, it will use that DTMF type. If not, the DTMF type
for the channel will be set to inband.

Review: https://reviewboard.asterisk.org/r/4438

ASTERISK-24706 #close
Reported by: yaron nahum
patches:
  yaron_patch_3_Feb.diff submitted by yaron nahum (License 6676)
........

Merged revisions 434637 from http://svn.asterisk.org/svn/asterisk/branches/13


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@434638 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/42/42/1
Matthew Jordan 10 years ago
parent f69e46de25
commit 8bae18ab93

@ -548,7 +548,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
int exists;
/* If we only needed this DSP for fax detection purposes we can just drop it now */
if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) {
ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT);
} else {
ast_dsp_free(session->dsp);
@ -1522,6 +1522,14 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
}
ast_rtp_instance_dtmf_begin(media->rtp, digit);
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_begin(media->rtp, digit);
break;
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:
@ -1625,6 +1633,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;
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:

@ -0,0 +1,63 @@
"""Add auto DTMF mode
Revision ID: 31cd4f4891ec
Revises: 23530d604b96
Create Date: 2015-04-10 12:36:51.619419
"""
# revision identifiers, used by Alembic.
revision = '31cd4f4891ec'
down_revision = '23530d604b96'
from alembic import op
import sqlalchemy as sa
OLD_ENUM = ['rfc4733', 'inband', 'info']
NEW_ENUM = ['rfc4733', 'inband', 'info', 'auto']
old_type = sa.Enum(*OLD_ENUM, name='pjsip_dtmf_mode_values')
new_type = sa.Enum(*NEW_ENUM, name='pjsip_dtmf_mode_values_v2')
tcr = sa.sql.table('ps_endpoints', sa.Column('dtmf_mode', new_type,
nullable=True))
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',
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_v2 USING'
' dtmf_mode::text::pjsip_dtmf_mode_values_v2')
ENUM(name="pjsip_dtmf_mode_values").drop(op.get_bind(), checkfirst=False)
def downgrade():
context = op.get_context()
op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing')
.values(directmedia=None))
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',
name='pjsip_dtmf_mode_values')
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')
ENUM(name="pjsip_dtmf_mode_values_v2").drop(op.get_bind(), checkfirst=False)

@ -138,6 +138,9 @@ void ast_dsp_digitreset(struct ast_dsp *dsp);
/*! \brief Select feature set */
void ast_dsp_set_features(struct ast_dsp *dsp, int features);
/*! \brief Get features */
int ast_dsp_get_features(struct ast_dsp *dsp);
/*! \brief Get pending DTMF/MF digits */
int ast_dsp_getdigits(struct ast_dsp *dsp, char *buf, int max);

@ -252,6 +252,8 @@ enum ast_sip_dtmf_mode {
AST_SIP_DTMF_INBAND,
/*! Use SIP INFO DTMF (blech) */
AST_SIP_DTMF_INFO,
/*! Use SIP 4733 if supported by the other side or INBAND if not */
AST_SIP_DTMF_AUTO,
};
/*!

@ -1702,6 +1702,13 @@ void ast_dsp_set_features(struct ast_dsp *dsp, int features)
}
}
int ast_dsp_get_features(struct ast_dsp *dsp)
{
return (dsp->features);
}
void ast_dsp_free(struct ast_dsp *dsp)
{
ast_free(dsp);

@ -210,6 +210,10 @@
<enum name="info">
<para>DTMF is sent as SIP INFO packets.</para>
</enum>
<enum name="auto">
<para>DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not.</para>
</enum>
</enumlist>
</description>
</configOption>

@ -109,6 +109,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var,
endpoint->dtmf = AST_SIP_DTMF_INBAND;
} 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 {
@ -129,6 +131,8 @@ 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 :
*buf = "auto"; break;
default:
*buf = "none";
}

@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sched.h"
#include "asterisk/acl.h"
#include "asterisk/sdp_srtp.h"
#include "asterisk/dsp.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
@ -123,7 +124,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) {
if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) {
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) {
@ -143,13 +144,14 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
return 0;
}
static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs)
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)
{
pjmedia_sdp_attr *attr;
pjmedia_sdp_rtpmap *rtpmap;
pjmedia_sdp_fmtp fmtp;
struct ast_format *format;
int i, num = 0;
int i, num = 0, tel_event = 0;
char name[256];
char media[20];
char fmt_param[256];
@ -171,6 +173,9 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
}
ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
if (strcmp(name,"telephone-event") == 0) {
tel_event++;
}
ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]),
media, name, 0, rtpmap->clock_rate);
@ -200,7 +205,9 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
}
}
}
if ((tel_event==0) && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
}
/* 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));
@ -221,6 +228,7 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
int fmts = 0;
int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
ast_format_cap_count(session->direct_media_cap);
int dsp_features = 0;
if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
!(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
@ -238,7 +246,7 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
}
/* get the capabilities on the peer */
get_codecs(session, stream, &codecs);
get_codecs(session, stream, &codecs, session_media);
ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);
/* get the joint capabilities between peer and endpoint */
@ -288,6 +296,18 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
ast_channel_nativeformats_set(session->channel, caps);
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)
&& (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833)
&& (session->dsp)) {
dsp_features = ast_dsp_get_features(session->dsp);
dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
if (dsp_features) {
ast_dsp_set_features(session->dsp, dsp_features);
} else {
ast_dsp_free(session->dsp);
session->dsp = NULL;
}
}
ast_channel_unlock(session->channel);
ao2_ref(fmt, -1);
@ -952,7 +972,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) ? AST_RTP_DTMF : 0;
int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) ? 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);

@ -1283,7 +1283,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
session->inv_session = inv_session;
session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (endpoint->dtmf == AST_SIP_DTMF_INBAND) {
if ((endpoint->dtmf == AST_SIP_DTMF_INBAND) || (endpoint->dtmf == AST_SIP_DTMF_AUTO)) {
dsp_features |= DSP_FEATURE_DIGIT_DETECT;
}

Loading…
Cancel
Save