dect
/
asterisk
Archived
13
0
Fork 0

Merge in VLDTMF support with Zaptel/Core done by the ever great Darumkilla Russell Bryant and the RTP portion done by myself, Muffinlicious Joshua Colp. This has gone through so many discussions/revisions it's not funny but we finally have it!

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@41507 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
file 2006-08-31 01:59:02 +00:00
parent 0fcb352fba
commit 3f22aa53af
29 changed files with 744 additions and 365 deletions

View File

@ -303,6 +303,12 @@ The SIP channel:
option in sip.conf is removed to osp.conf as authpolicy. allowguest option
in sip.conf cannot be set as osp anymore.
* The Asterisk RTP stack has been changed in regards to RFC2833 reception
and transmission. Packets will now be sent with proper duration instead of all
at once. If you are receiving calls from a pre-1.4 Asterisk installation you
will want to turn on the rfc2833compensate option. Without this option your
DTMF reception may act poorly.
* The $SIPUSERAGENT dialplan variable is deprecated and will be removed
in coming versions of Asterisk. Please use the dialplan function
SIPCHANINFO(useragent) instead.

View File

@ -71,19 +71,13 @@ static int echo_exec(struct ast_channel *chan, void *data)
f->delivery.tv_usec = 0;
switch (f->frametype) {
case AST_FRAME_DTMF:
case AST_FRAME_DTMF_END:
if (f->subclass == '#') {
res = 0;
ast_frfree(f);
goto end;
}
/* fall through */
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_VOICE:
case AST_FRAME_VIDEO:
case AST_FRAME_TEXT:
case AST_FRAME_HTML:
case AST_FRAME_IMAGE:
default:
if (ast_write(chan, f)) {
ast_frfree(f);
goto end;

View File

@ -238,7 +238,8 @@ static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (l
static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
static int agent_devicestate(void *data);
static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
static int agent_digit(struct ast_channel *ast, char digit);
static int agent_digit_begin(struct ast_channel *ast, char digit);
static int agent_digit_end(struct ast_channel *ast, char digit);
static int agent_call(struct ast_channel *ast, char *dest, int timeout);
static int agent_hangup(struct ast_channel *ast);
static int agent_answer(struct ast_channel *ast);
@ -258,7 +259,8 @@ static const struct ast_channel_tech agent_tech = {
.capabilities = -1,
.requester = agent_request,
.devicestate = agent_devicestate,
.send_digit = agent_digit,
.send_digit_begin = agent_digit_begin,
.send_digit_end = agent_digit_end,
.call = agent_call,
.hangup = agent_hangup,
.answer = agent_answer,
@ -491,7 +493,8 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
}
}
break;
case AST_FRAME_DTMF:
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_DTMF_END:
if (!p->acknowledged && (f->subclass == '#')) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
@ -511,7 +514,9 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
ast_frfree(f);
f = &ast_null_frame;
}
break;
default:
/* pass everything else on through */
break;
}
}
@ -603,15 +608,22 @@ static int agent_indicate(struct ast_channel *ast, int condition, const void *da
return res;
}
static int agent_digit(struct ast_channel *ast, char digit)
static int agent_digit_begin(struct ast_channel *ast, char digit)
{
struct agent_pvt *p = ast->tech_pvt;
int res = -1;
ast_mutex_lock(&p->lock);
if (p->chan)
res = p->chan->tech->send_digit(p->chan, digit);
else
res = 0;
ast_senddigit_begin(p->chan, digit);
ast_mutex_unlock(&p->lock);
return res;
}
static int agent_digit_end(struct ast_channel *ast, char digit)
{
struct agent_pvt *p = ast->tech_pvt;
int res = -1;
ast_mutex_lock(&p->lock);
ast_senddigit_end(p->chan, digit);
ast_mutex_unlock(&p->lock);
return res;
}

View File

@ -203,7 +203,7 @@ static const struct ast_channel_tech alsa_tech = {
.description = tdesc,
.capabilities = AST_FORMAT_SLINEAR,
.requester = alsa_request,
.send_digit = alsa_digit,
.send_digit_end = alsa_digit,
.send_text = alsa_text,
.hangup = alsa_hangup,
.answer = alsa_answer,

View File

@ -95,7 +95,8 @@ static AST_LIST_HEAD_STATIC(features, feature_pvt);
#define SUB_THREEWAY 2 /* Three-way call */
static struct ast_channel *features_request(const char *type, int format, void *data, int *cause);
static int features_digit(struct ast_channel *ast, char digit);
static int features_digit_begin(struct ast_channel *ast, char digit);
static int features_digit_end(struct ast_channel *ast, char digit);
static int features_call(struct ast_channel *ast, char *dest, int timeout);
static int features_hangup(struct ast_channel *ast);
static int features_answer(struct ast_channel *ast);
@ -109,7 +110,8 @@ static const struct ast_channel_tech features_tech = {
.description = tdesc,
.capabilities = -1,
.requester = features_request,
.send_digit = features_digit,
.send_digit_begin = features_digit_begin,
.send_digit_end = features_digit_end,
.call = features_call,
.hangup = features_hangup,
.answer = features_answer,
@ -300,7 +302,7 @@ static int features_indicate(struct ast_channel *ast, int condition, const void
return res;
}
static int features_digit(struct ast_channel *ast, char digit)
static int features_digit_begin(struct ast_channel *ast, char digit)
{
struct feature_pvt *p = ast->tech_pvt;
int res = -1;
@ -310,7 +312,23 @@ static int features_digit(struct ast_channel *ast, char digit)
ast_mutex_lock(&p->lock);
x = indexof(p, ast, 0);
if (!x && p->subchan)
res = ast_senddigit(p->subchan, digit);
res = ast_senddigit_begin(p->subchan, digit);
ast_mutex_unlock(&p->lock);
return res;
}
static int features_digit_end(struct ast_channel *ast, char digit)
{
struct feature_pvt *p = ast->tech_pvt;
int res = -1;
int x;
/* Queue up a frame representing the indication as a control frame */
ast_mutex_lock(&p->lock);
x = indexof(p, ast, 0);
if (!x && p->subchan)
res = ast_senddigit_end(p->subchan, digit);
ast_mutex_unlock(&p->lock);
return res;
}

View File

@ -220,7 +220,8 @@ static int restart_monitor(void);
static int h323_do_reload(void);
static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause);
static int oh323_digit(struct ast_channel *c, char digit);
static int oh323_digit_begin(struct ast_channel *c, char digit);
static int oh323_digit_end(struct ast_channel *c, char digit);
static int oh323_call(struct ast_channel *c, char *dest, int timeout);
static int oh323_hangup(struct ast_channel *c);
static int oh323_answer(struct ast_channel *c);
@ -235,7 +236,8 @@ static const struct ast_channel_tech oh323_tech = {
.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
.requester = oh323_request,
.send_digit = oh323_digit,
.send_digit_begin = oh323_digit_begin,
.send_digit_end = oh323_digit_end,
.call = oh323_call,
.hangup = oh323_hangup,
.answer = oh323_answer,
@ -381,11 +383,17 @@ static void oh323_destroy(struct oh323_pvt *pvt)
ast_mutex_unlock(&iflock);
}
static int oh323_digit_begin(struct ast_channel *chan, char digit)
{
/* XXX Implement me, plz, kthx */
return 0;
}
/**
* Send (play) the specified digit to the channel.
*
*/
static int oh323_digit(struct ast_channel *c, char digit)
static int oh323_digit_end(struct ast_channel *c, char digit)
{
struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
char *token;

View File

@ -776,7 +776,8 @@ static int expire_registry(void *data);
static int iax2_answer(struct ast_channel *c);
static int iax2_call(struct ast_channel *c, char *dest, int timeout);
static int iax2_devicestate(void *data);
static int iax2_digit(struct ast_channel *c, char digit);
static int iax2_digit_begin(struct ast_channel *c, char digit);
static int iax2_digit_end(struct ast_channel *c, char digit);
static int iax2_do_register(struct iax2_registry *reg);
static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);
static int iax2_hangup(struct ast_channel *c);
@ -809,7 +810,8 @@ static const struct ast_channel_tech iax2_tech = {
.properties = AST_CHAN_TP_WANTSJITTER,
.requester = iax2_request,
.devicestate = iax2_devicestate,
.send_digit = iax2_digit,
.send_digit_begin = iax2_digit_begin,
.send_digit_end = iax2_digit_end,
.send_text = iax2_sendtext,
.send_image = iax2_sendimage,
.send_html = iax2_sendhtml,
@ -2379,9 +2381,14 @@ static int iax2_transmit(struct iax_frame *fr)
static int iax2_digit(struct ast_channel *c, char digit)
static int iax2_digit_begin(struct ast_channel *c, char digit)
{
return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_BEGIN, digit, 0, NULL, 0, -1);
}
static int iax2_digit_end(struct ast_channel *c, char digit)
{
return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
}
static int iax2_sendtext(struct ast_channel *c, const char *text)

View File

@ -171,7 +171,8 @@ AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_
/* Forward declarations */
static struct ast_channel *jingle_request(const char *type, int format, void *data, int *cause);
static int jingle_digit(struct ast_channel *ast, char digit);
static int jingle_digit_begin(struct ast_channel *ast, char digit);
static int jingle_digit_end(struct ast_channel *ast, char digit);
static int jingle_call(struct ast_channel *ast, char *dest, int timeout);
static int jingle_hangup(struct ast_channel *ast);
static int jingle_answer(struct ast_channel *ast);
@ -194,7 +195,8 @@ static const struct ast_channel_tech jingle_tech = {
.description = "Jingle Channel Driver",
.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
.requester = jingle_request,
.send_digit = jingle_digit,
.send_digit_begin = jingle_digit_begin,
.send_digit_end = jingle_digit_end,
.bridge = ast_rtp_bridge,
.call = jingle_call,
.hangup = jingle_hangup,
@ -1181,7 +1183,13 @@ static int jingle_indicate(struct ast_channel *ast, int condition, const void *d
return res;
}
static int jingle_digit(struct ast_channel *ast, char digit)
static int jingle_digit_begin(struct ast_channel *chan, char digit)
{
/* XXX Does jingle have a concept of the length of a dtmf digit ? */
return 0;
}
static int jingle_digit_end(struct ast_channel *ast, char digit)
{
struct jingle_pvt *p = ast->tech_pvt;
struct jingle *client = p->parent;

View File

@ -67,7 +67,8 @@ static const char tdesc[] = "Local Proxy Channel Driver";
#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
static int local_digit(struct ast_channel *ast, char digit);
static int local_digit_begin(struct ast_channel *ast, char digit);
static int local_digit_end(struct ast_channel *ast, char digit);
static int local_call(struct ast_channel *ast, char *dest, int timeout);
static int local_hangup(struct ast_channel *ast);
static int local_answer(struct ast_channel *ast);
@ -85,7 +86,8 @@ static const struct ast_channel_tech local_tech = {
.description = tdesc,
.capabilities = -1,
.requester = local_request,
.send_digit = local_digit,
.send_digit_begin = local_digit_begin,
.send_digit_end = local_digit_end,
.call = local_call,
.hangup = local_hangup,
.answer = local_answer,
@ -327,11 +329,11 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da
return res;
}
static int local_digit(struct ast_channel *ast, char digit)
static int local_digit_begin(struct ast_channel *ast, char digit)
{
struct local_pvt *p = ast->tech_pvt;
int res = -1;
struct ast_frame f = { AST_FRAME_DTMF, };
struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
int isoutbound;
ast_mutex_lock(&p->lock);
@ -339,6 +341,23 @@ static int local_digit(struct ast_channel *ast, char digit)
f.subclass = digit;
res = local_queue_frame(p, isoutbound, &f, ast);
ast_mutex_unlock(&p->lock);
return res;
}
static int local_digit_end(struct ast_channel *ast, char digit)
{
struct local_pvt *p = ast->tech_pvt;
int res = -1;
struct ast_frame f = { AST_FRAME_DTMF_END, };
int isoutbound;
ast_mutex_lock(&p->lock);
isoutbound = IS_OUTBOUND(ast, p);
f.subclass = digit;
res = local_queue_frame(p, isoutbound, &f, ast);
ast_mutex_unlock(&p->lock);
return res;
}

View File

@ -427,7 +427,8 @@ static struct ast_frame *mgcp_read(struct ast_channel *ast);
static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int mgcp_senddigit(struct ast_channel *ast, char digit);
static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
static int mgcp_senddigit_end(struct ast_channel *ast, char digit);
static int mgcp_devicestate(void *data);
static const struct ast_channel_tech mgcp_tech = {
@ -444,7 +445,8 @@ static const struct ast_channel_tech mgcp_tech = {
.write = mgcp_write,
.indicate = mgcp_indicate,
.fixup = mgcp_fixup,
.send_digit = mgcp_senddigit,
.send_digit_begin = mgcp_senddigit_begin,
.send_digit_end = mgcp_senddigit_end,
.bridge = ast_rtp_bridge,
};
@ -1221,7 +1223,13 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
return 0;
}
static int mgcp_senddigit(struct ast_channel *ast, char digit)
static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
{
/* Let asterisk play inband indications */
return -1;
}
static int mgcp_senddigit_end(struct ast_channel *ast, char digit)
{
struct mgcp_subchannel *sub = ast->tech_pvt;
char tmp[4];
@ -1233,7 +1241,7 @@ static int mgcp_senddigit(struct ast_channel *ast, char digit)
ast_mutex_lock(&sub->lock);
transmit_notify_request(sub, tmp);
ast_mutex_unlock(&sub->lock);
return -1;
return -1; /* Return non-zero so that Asterisk will stop the inband indications */
}
/*!

View File

@ -2006,7 +2006,13 @@ static int misdn_answer(struct ast_channel *ast)
return 0;
}
static int misdn_digit(struct ast_channel *ast, char digit )
static int misdn_digit_begin(struct ast_channel *chan, char digit)
{
/* XXX Modify this callback to support Asterisk controlling the length of DTMF */
return 0;
}
static int misdn_digit_end(struct ast_channel *ast, char digit )
{
struct chan_list *p;
@ -2983,7 +2989,8 @@ static struct ast_channel_tech misdn_tech = {
.description="Channel driver for mISDN Support (Bri/Pri)",
.capabilities= AST_FORMAT_ALAW ,
.requester=misdn_request,
.send_digit=misdn_digit,
.send_digit_begin=misdn_digit_begin,
.send_digit_end=misdn_digit_end,
.call=misdn_call,
.bridge=misdn_bridge,
.hangup=misdn_hangup,
@ -3001,7 +3008,8 @@ static struct ast_channel_tech misdn_tech_wo_bridge = {
.description="Channel driver for mISDN Support (Bri/Pri)",
.capabilities=AST_FORMAT_ALAW ,
.requester=misdn_request,
.send_digit=misdn_digit,
.send_digit_begin=misdn_digit_begin,
.send_digit_end=misdn_digit_end,
.call=misdn_call,
.hangup=misdn_hangup,
.answer=misdn_answer,

View File

@ -407,7 +407,8 @@ static int setformat(struct chan_oss_pvt *o, int mode);
static struct ast_channel *oss_request(const char *type, int format, void *data
, int *cause);
static int oss_digit(struct ast_channel *c, char digit);
static int oss_digit_begin(struct ast_channel *c, char digit);
static int oss_digit_end(struct ast_channel *c, char digit);
static int oss_text(struct ast_channel *c, const char *text);
static int oss_hangup(struct ast_channel *c);
static int oss_answer(struct ast_channel *c);
@ -423,7 +424,8 @@ static const struct ast_channel_tech oss_tech = {
.description = tdesc,
.capabilities = AST_FORMAT_SLINEAR,
.requester = oss_request,
.send_digit = oss_digit,
.send_digit_begin = oss_digit_begin,
.send_digit_end = oss_digit_end,
.send_text = oss_text,
.hangup = oss_hangup,
.answer = oss_answer,
@ -757,7 +759,12 @@ static int setformat(struct chan_oss_pvt *o, int mode)
/*
* some of the standard methods supported by channels.
*/
static int oss_digit(struct ast_channel *c, char digit)
static int oss_digit_begin(struct ast_channel *c, char digit)
{
return 0;
}
static int oss_digit_end(struct ast_channel *c, char digit)
{
/* no better use for received digits than print them */
ast_verbose( " << Console Received digit %c >> \n", digit);

View File

@ -161,7 +161,8 @@ static char cid_num[AST_MAX_EXTENSION];
static char cid_name[AST_MAX_EXTENSION];
static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause);
static int phone_digit(struct ast_channel *ast, char digit);
static int phone_digit_begin(struct ast_channel *ast, char digit);
static int phone_digit_end(struct ast_channel *ast, char digit);
static int phone_call(struct ast_channel *ast, char *dest, int timeout);
static int phone_hangup(struct ast_channel *ast);
static int phone_answer(struct ast_channel *ast);
@ -177,7 +178,8 @@ static const struct ast_channel_tech phone_tech = {
.description = tdesc,
.capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
.requester = phone_request,
.send_digit = phone_digit,
.send_digit_begin = phone_digit_begin,
.send_digit_end = phone_digit_end,
.call = phone_call,
.hangup = phone_hangup,
.answer = phone_answer,
@ -192,7 +194,8 @@ static struct ast_channel_tech phone_tech_fxs = {
.type = "Phone",
.description = tdesc,
.requester = phone_request,
.send_digit = phone_digit,
.send_digit_begin = phone_digit_begin,
.send_digit_end = phone_digit_end,
.call = phone_call,
.hangup = phone_hangup,
.answer = phone_answer,
@ -240,7 +243,13 @@ static int phone_fixup(struct ast_channel *old, struct ast_channel *new)
return 0;
}
static int phone_digit(struct ast_channel *ast, char digit)
static int phone_digit_begin(struct ast_channel *chan, char digit)
{
/* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
return 0;
}
static int phone_digit_end(struct ast_channel *ast, char digit)
{
struct phone_pvt *p;
int outdigit;
@ -329,7 +338,7 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
{
digit++;
while (*digit)
phone_digit(ast, *digit++);
phone_digit_end(ast, *digit++);
}
}

View File

@ -743,9 +743,10 @@ struct sip_auth {
#define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< Call states */
#define SIP_PAGE2_CALL_ONHOLD_ONEDIR (1 << 23) /*!< 23: One directional hold */
#define SIP_PAGE2_CALL_ONHOLD_INACTIVE (2 << 24) /*!< 24: Inactive */
#define SIP_PAGE2_RFC2833_COMPENSATE (1 << 26)
#define SIP_PAGE2_FLAGS_TO_COPY \
(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT)
(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE)
/* SIP packet flags */
#define SIP_PKT_DEBUG (1 << 0) /*!< Debug this packet */
@ -1161,7 +1162,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
static int sip_transfer(struct ast_channel *ast, const char *dest);
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int sip_senddigit(struct ast_channel *ast, char digit);
static int sip_senddigit_begin(struct ast_channel *ast, char digit);
static int sip_senddigit_end(struct ast_channel *ast, char digit);
/*--- Transmitting responses and requests */
static int sipsock_read(int *id, int fd, short events, void *ignore);
@ -1512,7 +1514,8 @@ static const struct ast_channel_tech sip_tech = {
.indicate = sip_indicate,
.transfer = sip_transfer,
.fixup = sip_fixup,
.send_digit = sip_senddigit,
.send_digit_begin = sip_senddigit_begin,
.send_digit_end = sip_senddigit_end,
.bridge = ast_rtp_bridge,
.send_text = sip_sendtext,
};
@ -2515,12 +2518,14 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer)
ast_log(LOG_DEBUG, "Setting NAT on RTP to %s\n", natflags ? "On" : "Off");
ast_rtp_setnat(r->rtp, natflags);
ast_rtp_setdtmf(r->rtp, ast_test_flag(&r->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
ast_rtp_setdtmfcompensate(r->rtp, ast_test_flag(&r->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
}
if (r->vrtp) {
if (option_debug)
ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", natflags ? "On" : "Off");
ast_rtp_setnat(r->vrtp, natflags);
ast_rtp_setdtmf(r->vrtp, 0);
ast_rtp_setdtmfcompensate(r->vrtp, 0);
}
if (r->udptl) {
if (option_debug)
@ -3441,9 +3446,31 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
return ret;
}
static int sip_senddigit_begin(struct ast_channel *ast, char digit)
{
struct sip_pvt *p = ast->tech_pvt;
int res = 0;
ast_mutex_lock(&p->lock);
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
case SIP_DTMF_INBAND:
res = -1; /* Tell Asterisk to generate inband indications */
break;
case SIP_DTMF_RFC2833:
if (p->rtp)
ast_rtp_senddigit_begin(p->rtp, digit);
break;
default:
break;
}
ast_mutex_unlock(&p->lock);
return res;
}
/*! \brief Send DTMF character on SIP channel
within one call, we're able to transmit in many methods simultaneously */
static int sip_senddigit(struct ast_channel *ast, char digit)
static int sip_senddigit_end(struct ast_channel *ast, char digit)
{
struct sip_pvt *p = ast->tech_pvt;
int res = 0;
@ -3455,13 +3482,14 @@ static int sip_senddigit(struct ast_channel *ast, char digit)
break;
case SIP_DTMF_RFC2833:
if (p->rtp)
ast_rtp_senddigit(p->rtp, digit);
ast_rtp_senddigit_end(p->rtp, digit);
break;
case SIP_DTMF_INBAND:
res = -1;
res = -1; /* Tell Asterisk to stop inband indications */
break;
}
ast_mutex_unlock(&p->lock);
return res;
}
@ -4049,10 +4077,12 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
return NULL;
}
ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
ast_rtp_settos(p->rtp, global_tos_audio);
if (p->vrtp) {
ast_rtp_settos(p->vrtp, global_tos_video);
ast_rtp_setdtmf(p->vrtp, 0);
ast_rtp_setdtmfcompensate(p->vrtp, 0);
}
if (p->udptl)
ast_udptl_settos(p->udptl, global_tos_audio);
@ -12835,6 +12865,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
extract_uri(p, req); /* Get the Contact URI */
build_contact(p); /* Build our contact header */
ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
if (!replace_id && gotdest) { /* No matching extension found */
if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) {
@ -14856,6 +14887,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
} else if (!strcasecmp(v->name, "t38pt_tcp")) {
ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_TCP);
ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_TCP);
} else if (!strcasecmp(v->name, "rfc2833compensate")) {
ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE);
ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE);
}
return res;

View File

@ -1013,7 +1013,8 @@ static struct ast_frame *skinny_read(struct ast_channel *ast);
static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int skinny_senddigit(struct ast_channel *ast, char digit);
static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
static int skinny_senddigit_end(struct ast_channel *ast, char digit);
static const struct ast_channel_tech skinny_tech = {
.type = "Skinny",
@ -1028,7 +1029,8 @@ static const struct ast_channel_tech skinny_tech = {
.write = skinny_write,
.indicate = skinny_indicate,
.fixup = skinny_fixup,
.send_digit = skinny_senddigit,
.send_digit_begin = skinny_senddigit_begin,
.send_digit_end = skinny_senddigit_end,
/* .bridge = ast_rtp_bridge, */
};
@ -2467,7 +2469,12 @@ static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
return 0;
}
static int skinny_senddigit(struct ast_channel *ast, char digit)
static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
{
return -1; /* Start inband indications */
}
static int skinny_senddigit_end(struct ast_channel *ast, char digit)
{
#if 0
struct skinny_subchannel *sub = ast->tech_pvt;
@ -2478,7 +2485,7 @@ static int skinny_senddigit(struct ast_channel *ast, char digit)
sprintf(tmp, "%d", digit);
transmit_tone(d->session, digit);
#endif
return -1;
return -1; /* Stop inband indications */
}
static char *control2str(int ind) {

View File

@ -341,9 +341,9 @@ static struct vpb_pvt {
static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, char *context);
static void *do_chanreads(void *pvt);
static struct ast_channel *vpb_request(const char *type, int format, void *data, int *cause);
static int vpb_digit(struct ast_channel *ast, char digit);
static int vpb_digit_begin(struct ast_channel *ast, char digit);
static int vpb_digit_end(struct ast_channel *ast, char digit);
static int vpb_call(struct ast_channel *ast, char *dest, int timeout);
static int vpb_hangup(struct ast_channel *ast);
static int vpb_answer(struct ast_channel *ast);
@ -360,9 +360,8 @@ static struct ast_channel_tech vpb_tech = {
properties: 0,
requester: vpb_request,
devicestate: NULL,
send_digit: vpb_digit,
send_digit_begin: NULL,
send_digit_end: NULL,
send_digit_begin: vpb_digit_begin,
send_digit_end: vpb_digit_end,
call: vpb_call,
hangup: vpb_hangup,
answer: vpb_answer,
@ -389,9 +388,8 @@ static struct ast_channel_tech vpb_tech_indicate = {
properties: 0,
requester: vpb_request,
devicestate: NULL,
send_digit: vpb_digit,
send_digit_begin: NULL,
send_digit_end: NULL,
send_digit_begin: vpb_digit_begin,
send_digit_end: vpb_digit_end,
call: vpb_call,
hangup: vpb_hangup,
answer: vpb_answer,
@ -863,11 +861,11 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
vpb_timer_stop(p->ring_timer);
vpb_timer_start(p->ring_timer);
} else
f.frametype = -1; /* ignore ring on station port. */
f.frametype = AST_FRAME_NULL; /* ignore ring on station port. */
break;
case VPB_RING_OFF:
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
break;
case VPB_TIMEREXP:
@ -876,12 +874,12 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
p->state = VPB_STATE_PLAYBUSY;
vpb_timer_stop(p->busy_timer);
vpb_timer_start(p->busy_timer);
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
} else if (e->data == p->ringback_timer_id) {
playtone(p->handle, &Ringbacktone);
vpb_timer_stop(p->ringback_timer);
vpb_timer_start(p->ringback_timer);
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
} else if (e->data == p->ring_timer_id) {
/* We didnt get another ring in time! */
if (p->owner->_state != AST_STATE_UP) {
@ -890,23 +888,23 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
f.subclass = AST_CONTROL_HANGUP;
} else {
vpb_timer_stop(p->ring_timer);
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
}
} else {
f.frametype = -1; /* Ignore. */
f.frametype = AST_FRAME_NULL; /* Ignore. */
}
break;
case VPB_DTMF_DOWN:
case VPB_DTMF:
if (use_ast_dtmfdet){
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
} else if (p->owner->_state == AST_STATE_UP) {
f.frametype = AST_FRAME_DTMF;
f.subclass = e->data;
} else
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
break;
case VPB_TONEDETECT:
@ -950,11 +948,11 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
f.subclass = AST_CONTROL_HANGUP;
} else {
p->lastgrunt = ast_tvnow();
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
}
}
else {
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
}
break;
@ -970,7 +968,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
f.subclass = AST_CONTROL_HANGUP;
#else
ast_log(LOG_NOTICE,"%s: Got call progress callback but blind dialing \n", p->dev);
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
#endif
break;
@ -983,14 +981,14 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
if (p->owner->_state == AST_STATE_UP)
f.subclass = AST_CONTROL_HANGUP;
else
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
}
break;
case VPB_LOOP_ONHOOK:
if (p->owner->_state == AST_STATE_UP)
f.subclass = AST_CONTROL_HANGUP;
else
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
break;
case VPB_STATION_ONHOOK:
f.subclass = AST_CONTROL_HANGUP;
@ -1009,22 +1007,22 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "%s: Dialend\n", p->dev);
} else {
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
}
break;
case VPB_PLAY_UNDERFLOW:
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
vpb_reset_play_fifo_alarm(p->handle);
break;
case VPB_RECORD_OVERFLOW:
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
vpb_reset_record_fifo_alarm(p->handle);
break;
default:
f.frametype = -1;
f.frametype = AST_FRAME_NULL;
break;
}
@ -1831,7 +1829,12 @@ static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
return 0;
}
static int vpb_digit(struct ast_channel *ast, char digit)
static int vpb_digit_begin(struct ast_channel *ast, char digit)
{
/* XXX Modify this callback to let Asterisk control the length of DTMF */
return 0;
}
static int vpb_digit_end(struct ast_channel *ast, char digit)
{
struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
char s[2];

View File

@ -690,10 +690,12 @@ static struct zt_pvt {
#endif
int polarity;
int dsp_features;
char begindigit;
} *iflist = NULL, *ifend = NULL;
static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
static int zt_digit(struct ast_channel *ast, char digit);
static int zt_digit_begin(struct ast_channel *ast, char digit);
static int zt_digit_end(struct ast_channel *ast, char digit);
static int zt_sendtext(struct ast_channel *c, const char *text);
static int zt_call(struct ast_channel *ast, char *rdest, int timeout);
static int zt_hangup(struct ast_channel *ast);
@ -711,7 +713,8 @@ static const struct ast_channel_tech zap_tech = {
.description = tdesc,
.capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
.requester = zt_request,
.send_digit = zt_digit,
.send_digit_begin = zt_digit_begin,
.send_digit_end = zt_digit_end,
.send_text = zt_sendtext,
.call = zt_call,
.hangup = zt_hangup,
@ -1002,45 +1005,113 @@ static int unalloc_sub(struct zt_pvt *p, int x)
return 0;
}
static int zt_digit(struct ast_channel *ast, char digit)
static int digit_to_dtmfindex(char digit)
{
ZT_DIAL_OPERATION zo;
struct zt_pvt *p;
if (isdigit(digit))
return ZT_TONE_DTMF_BASE + (digit - '0');
else if (digit >= 'A' && digit <= 'D')
return ZT_TONE_DTMF_A + (digit - 'A');
else if (digit >= 'a' && digit <= 'd')
return ZT_TONE_DTMF_A + (digit - 'a');
else if (digit == '*')
return ZT_TONE_DTMF_s;
else if (digit == '#')
return ZT_TONE_DTMF_p;
else
return -1;
}
static int zt_digit_begin(struct ast_channel *chan, char digit)
{
struct zt_pvt *pvt;
int index;
int dtmf = -1;
pvt = chan->tech_pvt;
ast_mutex_lock(&pvt->lock);
index = zt_get_index(chan, pvt, 0);
if ((index != SUB_REAL) || !pvt->owner)
goto out;
#ifdef HAVE_PRI
if ((pvt->sig == SIG_PRI) && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
if (pvt->setup_ack) {
if (!pri_grab(pvt, pvt->pri)) {
pri_information(pvt->pri->pri, pvt->call, digit);
pri_rel(pvt->pri);
} else
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
} else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
int res;
ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
res = strlen(pvt->dialdest);
pvt->dialdest[res++] = digit;
pvt->dialdest[res] = '\0';
}
goto out;
}
#endif
if ((dtmf = digit_to_dtmfindex(digit)) == -1)
goto out;
if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].zfd, ZT_SENDTONE, &dtmf)) {
int res;
ZT_DIAL_OPERATION zo = {
.op = ZT_DIAL_OP_APPEND,
.dialstr[0] = 'T',
.dialstr[1] = digit,
.dialstr[2] = 0,
};
if ((res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
else
pvt->dialing = 1;
} else {
ast_log(LOG_DEBUG, "Started VLDTMF digit '%c'\n", digit);
pvt->dialing = 1;
pvt->begindigit = digit;
}
out:
ast_mutex_unlock(&pvt->lock);
return 0; /* Tell Asterisk not to generate inband indications */
}
static int zt_digit_end(struct ast_channel *chan, char digit)
{
struct zt_pvt *pvt;
int res = 0;
int index;
p = ast->tech_pvt;
ast_mutex_lock(&p->lock);
index = zt_get_index(ast, p, 0);
if ((index == SUB_REAL) && p->owner) {
pvt = chan->tech_pvt;
ast_mutex_lock(&pvt->lock);
index = zt_get_index(chan, pvt, 0);
if ((index != SUB_REAL) || !pvt->owner || pvt->pulse)
goto out;
#ifdef HAVE_PRI
if ((p->sig == SIG_PRI) && (ast->_state == AST_STATE_DIALING) && !p->proceeding) {
if (p->setup_ack) {
if (!pri_grab(p, p->pri)) {
pri_information(p->pri->pri,p->call,digit);
pri_rel(p->pri);
} else
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
} else if (strlen(p->dialdest) < sizeof(p->dialdest) - 1) {
ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
res = strlen(p->dialdest);
p->dialdest[res++] = digit;
p->dialdest[res] = '\0';
}
} else {
#else
{
/* This means that the digit was already sent via PRI signalling */
if (pvt->sig == SIG_PRI && !pvt->begindigit)
goto out;
#endif
zo.op = ZT_DIAL_OP_APPEND;
zo.dialstr[0] = 'T';
zo.dialstr[1] = digit;
zo.dialstr[2] = 0;
if ((res = ioctl(p->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
else
p->dialing = 1;
}
if (pvt->begindigit) {
ast_log(LOG_DEBUG, "Ending VLDTMF digit '%c'\n", digit);
res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_SENDTONE, -1);
pvt->dialing = 0;
pvt->begindigit = 0;
}
ast_mutex_unlock(&p->lock);
out:
ast_mutex_unlock(&pvt->lock);
return res;
}
@ -3543,21 +3614,14 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
ast_log(LOG_DEBUG, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
if (res & (ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFUP)) {
if (res & ZT_EVENT_PULSEDIGIT)
p->pulsedial = 1;
else
p->pulsedial = 0;
p->pulsedial = (res & ZT_EVENT_PULSEDIGIT) ? 1 : 0;
ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
#ifdef HAVE_PRI
if (!p->proceeding && p->sig == SIG_PRI && p->pri && p->pri->overlapdial) {
/* absorb event */
} else {
#endif
/* Send a DTMF event for 'legacy' channels and all applications,
and a DTMF_BEGIN event for channels that handle variable duration
DTMF events
*/
p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
p->subs[index].f.frametype = AST_FRAME_DTMF_END;
p->subs[index].f.subclass = res & 0xff;
#ifdef HAVE_PRI
}
@ -3571,9 +3635,6 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
/* Mute conference */
zt_confmute(p, 1);
/* Send a DTMF_BEGIN event for devices that want variable
duration DTMF events
*/
p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
p->subs[index].f.subclass = res & 0xff;
return &p->subs[index].f;

View File

@ -395,7 +395,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
{
const char *frames[] = {
"(0?)",
"DTMF ",
"DTMF_E ",
"VOICE ",
"VIDEO ",
"CONTROL",
@ -404,7 +404,10 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
"TEXT ",
"IMAGE ",
"HTML ",
"CNG " };
"CNG ",
"MODEM ",
"DTMF_B ",
};
const char *iaxs[] = {
"(0?)",
"NEW ",
@ -508,7 +511,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
} else {
class = frames[(int)fh->type];
}
if (fh->type == AST_FRAME_DTMF) {
if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
sprintf(subclass2, "%c", fh->csub);
subclass = subclass2;
} else if (fh->type == AST_FRAME_IAX) {

View File

@ -417,7 +417,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; subscribecontext subscribecontext
; videosupport videosupport
; maxcallbitrate maxcallbitrate
; mailbox
; rfc2833compensate mailbox
; username
; template
; fromdomain
@ -431,6 +431,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; rtpholdtimeout
; sendrpid
; outboundproxy
; rfc2833compensate
;[sip_proxy]
; For incoming calls only. Example: FWD (Free World Dialup)
@ -587,3 +588,9 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; Normally you do NOT need to set this parameter
;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
;[pre14-asterisk]
;type=friend
;secret=digium
;host=dynamic
;rfc2833compensate=yes ; Compensate for pre-1.4 DTMF transmission from another Asterisk machine.
; You must have this turned on or DTMF reception will work improperly.

View File

@ -200,13 +200,11 @@ struct ast_channel_tech {
int (* const devicestate)(void *data); /*!< Devicestate call back */
int (* const send_digit)(struct ast_channel *chan, char digit); /*!< Send a literal DTMF digit */
/*! \brief Start sending a literal DTMF digit */
int (* const send_digit_begin)(struct ast_channel *chan, char digit);
/*! \brief Stop sending the last literal DTMF digit */
int (* const send_digit_end)(struct ast_channel *chan);
/*! \brief Stop sending a literal DTMF digit */
int (* const send_digit_end)(struct ast_channel *chan, char digit);
/*! \brief Call a given phone number (address, etc), but don't
take longer than timeout seconds to do so. */
@ -424,8 +422,12 @@ struct ast_channel {
struct ast_channel_spy_list *spies; /*!< Chan Spy stuff */
struct ast_channel_whisper_buffer *whisper; /*!< Whisper Paging buffer */
AST_LIST_ENTRY(ast_channel) chan_list; /*!< For easy linking */
struct ast_jb jb; /*!< The jitterbuffer state */
char emulate_dtmf_digit; /*!< Digit being emulated */
unsigned int emulate_dtmf_samples; /*!< Number of samples left to emulate DTMF for */
/*! \brief Data stores on the channel */
AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores;
};
@ -443,29 +445,34 @@ enum {
/*! \brief ast_channel flags */
enum {
/*! Queue incoming dtmf, to be released when this flag is turned off */
AST_FLAG_DEFER_DTMF = (1 << 1),
AST_FLAG_DEFER_DTMF = (1 << 1),
/*! write should be interrupt generator */
AST_FLAG_WRITE_INT = (1 << 2),
AST_FLAG_WRITE_INT = (1 << 2),
/*! a thread is blocking on this channel */
AST_FLAG_BLOCKING = (1 << 3),
AST_FLAG_BLOCKING = (1 << 3),
/*! This is a zombie channel */
AST_FLAG_ZOMBIE = (1 << 4),
AST_FLAG_ZOMBIE = (1 << 4),
/*! There is an exception pending */
AST_FLAG_EXCEPTION = (1 << 5),
AST_FLAG_EXCEPTION = (1 << 5),
/*! Listening to moh XXX anthm promises me this will disappear XXX */
AST_FLAG_MOH = (1 << 6),
AST_FLAG_MOH = (1 << 6),
/*! This channel is spying on another channel */
AST_FLAG_SPYING = (1 << 7),
AST_FLAG_SPYING = (1 << 7),
/*! This channel is in a native bridge */
AST_FLAG_NBRIDGE = (1 << 8),
AST_FLAG_NBRIDGE = (1 << 8),
/*! the channel is in an auto-incrementing dialplan processor,
* so when ->priority is set, it will get incremented before
* finding the next priority to run */
AST_FLAG_IN_AUTOLOOP = (1 << 9),
AST_FLAG_IN_AUTOLOOP = (1 << 9),
/*! This is an outgoing call */
AST_FLAG_OUTGOING = (1 << 10),
AST_FLAG_OUTGOING = (1 << 10),
/*! This channel is being whispered on */
AST_FLAG_WHISPER = (1 << 11),
AST_FLAG_WHISPER = (1 << 11),
/*! A DTMF_BEGIN frame has been read from this channel, but not yet an END */
AST_FLAG_IN_DTMF = (1 << 12),
/*! A DTMF_END was received when not IN_DTMF, so the length of the digit is
* currently being emulated */
AST_FLAG_EMULATE_DTMF = (1 << 13),
};
/*! \brief ast_bridge_config flags */
@ -876,6 +883,9 @@ int ast_recvchar(struct ast_channel *chan, int timeout);
*/
int ast_senddigit(struct ast_channel *chan, char digit);
int ast_senddigit_begin(struct ast_channel *chan, char digit);
int ast_senddigit_end(struct ast_channel *chan, char digit);
/*! \brief Receives a text string from a channel
* Read a string of text from a channel
* \param chan channel to act upon

View File

@ -85,11 +85,46 @@ struct ast_codec_pref {
*/
/*!
* \brief Frame types
*
* \note It is important that the values of each frame type are never changed,
* because it will break backwards compatability with older versions.
*/
enum ast_frame_type {
/*! DTMF end event, subclass is the digit */
AST_FRAME_DTMF_END = 1,
/*! Voice data, subclass is AST_FORMAT_* */
AST_FRAME_VOICE,
/*! Video frame, maybe?? :) */
AST_FRAME_VIDEO,
/*! A control frame, subclass is AST_CONTROL_* */
AST_FRAME_CONTROL,
/*! An empty, useless frame */
AST_FRAME_NULL,
/*! Inter Asterisk Exchange private frame type */
AST_FRAME_IAX,
/*! Text messages */
AST_FRAME_TEXT,
/*! Image Frames */
AST_FRAME_IMAGE,
/*! HTML Frame */
AST_FRAME_HTML,
/*! Comfort Noise frame (subclass is level of CNG in -dBov),
body may include zero or more 8-bit quantization coefficients */
AST_FRAME_CNG,
/*! Modem-over-IP data streams */
AST_FRAME_MODEM,
/*! DTMF begin event, subclass is the digit */
AST_FRAME_DTMF_BEGIN,
};
#define AST_FRAME_DTMF AST_FRAME_DTMF_END
/*! \brief Data structure associated with a single frame of data
*/
struct ast_frame {
/*! Kind of frame */
int frametype;
enum ast_frame_type frametype;
/*! Subclass, frame dependent */
int subclass;
/*! Length of data */
@ -151,35 +186,6 @@ extern struct ast_frame ast_null_frame;
/*! Need the source be free'd? (haha!) */
#define AST_MALLOCD_SRC (1 << 2)
/* Frame types */
/*! A DTMF digit, subclass is the digit */
#define AST_FRAME_DTMF 1
/*! Voice data, subclass is AST_FORMAT_* */
#define AST_FRAME_VOICE 2
/*! Video frame, maybe?? :) */
#define AST_FRAME_VIDEO 3
/*! A control frame, subclass is AST_CONTROL_* */
#define AST_FRAME_CONTROL 4
/*! An empty, useless frame */
#define AST_FRAME_NULL 5
/*! Inter Asterisk Exchange private frame type */
#define AST_FRAME_IAX 6
/*! Text messages */
#define AST_FRAME_TEXT 7
/*! Image Frames */
#define AST_FRAME_IMAGE 8
/*! HTML Frame */
#define AST_FRAME_HTML 9
/*! Comfort Noise frame (subclass is level of CNG in -dBov),
body may include zero or more 8-bit quantization coefficients */
#define AST_FRAME_CNG 10
/*! Modem-over-IP data streams */
#define AST_FRAME_MODEM 11
/*! DTMF begin event, subclass is the digit */
#define AST_FRAME_DTMF_BEGIN 12
/*! DTMF end event, subclass is the digit */
#define AST_FRAME_DTMF_END 13
/* MODEM subclasses */
/*! T.38 Fax-over-IP */
#define AST_MODEM_T38 1

View File

@ -142,7 +142,9 @@ int ast_rtp_fd(struct ast_rtp *rtp);
int ast_rtcp_fd(struct ast_rtp *rtp);
int ast_rtp_senddigit(struct ast_rtp *rtp, char digit);
int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit);
int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
int ast_rtp_sendcng(struct ast_rtp *rtp, int level);
@ -181,6 +183,9 @@ void ast_rtp_setnat(struct ast_rtp *rtp, int nat);
/*! \brief Indicate whether this RTP session is carrying DTMF or not */
void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf);
/*! \brief Compensate for devices that send RFC2833 packets all at once */
void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate);
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
int ast_rtp_proto_register(struct ast_rtp_protocol *proto);

View File

@ -212,10 +212,6 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
{
const char *ptr;
int res = 0;
struct ast_frame f = {
.frametype = AST_FRAME_DTMF,
.src = "ast_dtmf_stream"
};
if (!between)
between = 100;
@ -240,11 +236,8 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
if (*ptr == 'f' || *ptr == 'F') {
/* ignore return values if not supported by channel */
ast_indicate(chan, AST_CONTROL_FLASH);
} else {
f.subclass = *ptr;
if ((res = ast_write(chan, &f)))
break;
}
} else
ast_senddigit(chan, *ptr);
/* pause between digits */
if ((res = ast_safe_sleep(chan, between)))
break;

View File

@ -102,6 +102,9 @@ unsigned long global_fin = 0, global_fout = 0;
AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
#define STATE2STR_BUFSIZE 32
/* XXX 100ms ... this won't work with wideband support */
#define AST_DEFAULT_EMULATE_DTMF_SAMPLES 800
struct chanlist {
const struct ast_channel_tech *tech;
AST_LIST_ENTRY(chanlist) list;
@ -240,7 +243,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
" Indication: %s\n"
" Transfer : %s\n"
" Capabilities: %d\n"
" Send Digit: %s\n"
" Digit Begin: %s\n"
" Digit End: %s\n"
" Send HTML : %s\n"
" Image Support: %s\n"
" Text Support: %s\n",
@ -249,7 +253,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
(cl->tech->indicate) ? "yes" : "no",
(cl->tech->transfer) ? "yes" : "no",
(cl->tech->capabilities) ? cl->tech->capabilities : -1,
(cl->tech->send_digit) ? "yes" : "no",
(cl->tech->send_digit_begin) ? "yes" : "no",
(cl->tech->send_digit_end) ? "yes" : "no",
(cl->tech->send_html) ? "yes" : "no",
(cl->tech->send_image) ? "yes" : "no",
(cl->tech->send_text) ? "yes" : "no"
@ -1862,8 +1867,10 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
/* Write audio if appropriate */
if (audiofd > -1)
write(audiofd, f->data, f->datalen);
default:
/* Ignore */
break;
}
/* Ignore */
ast_frfree(f);
}
}
@ -1881,11 +1888,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
*/
ast_channel_lock(chan);
if (chan->masq) {
if (ast_do_masquerade(chan)) {
if (ast_do_masquerade(chan))
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
} else {
else
f = &ast_null_frame;
}
goto done;
}
@ -1897,13 +1903,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
prestate = chan->_state;
if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF) && !ast_strlen_zero(chan->dtmfq)) {
if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) &&
!ast_strlen_zero(chan->dtmfq)) {
/* We have DTMF that has been deferred. Return it now */
chan->dtmff.frametype = AST_FRAME_DTMF;
chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN;
chan->dtmff.subclass = chan->dtmfq[0];
/* Drop first digit from the buffer */
memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
f = &chan->dtmff;
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
goto done;
}
@ -2017,27 +2027,57 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
}
break;
case AST_FRAME_DTMF:
ast_log(LOG_DTMF, "DTMF '%c' received on %s\n", f->subclass, chan->name);
if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
case AST_FRAME_DTMF_END:
ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) {
if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
else
ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
ast_frfree(f);
f = &ast_null_frame;
}
} else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
f->frametype = AST_FRAME_DTMF_BEGIN;
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
if (f->samples)
chan->emulate_dtmf_samples = f->samples;
else
chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
} else
ast_clear_flag(chan, AST_FLAG_IN_DTMF);
break;
case AST_FRAME_DTMF_BEGIN:
ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
break;
case AST_FRAME_DTMF_END:
ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
break;
case AST_FRAME_VOICE:
if (dropaudio) {
if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
ast_frfree(f);
f = &ast_null_frame;
} else
ast_set_flag(chan, AST_FLAG_IN_DTMF);
break;
case AST_FRAME_VOICE:
/* The EMULATE_DTMF flag must be cleared here as opposed to when the samples
* first get to zero, because we want to make sure we pass at least one
* voice frame through before starting the next digit, to ensure a gap
* between DTMF digits. */
if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_samples) {
ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = 0;
}
if (dropaudio || ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
ast_frfree(f);
f = &ast_null_frame;
} else if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) {
if (f->samples >= chan->emulate_dtmf_samples) {
chan->emulate_dtmf_samples = 0;
f->frametype = AST_FRAME_DTMF_END;
f->subclass = chan->emulate_dtmf_digit;
} else {
chan->emulate_dtmf_samples -= f->samples;
ast_frfree(f);
f = &ast_null_frame;
}
} else if (!(f->subclass & chan->nativeformats)) {
/* This frame can't be from the current native formats -- drop it on the
floor */
@ -2106,6 +2146,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
}
}
default:
/* Just pass it on! */
break;
}
} else {
/* Make sure we always return NULL in the future */
@ -2258,12 +2301,13 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
return res;
}
static int do_senddigit(struct ast_channel *chan, char digit)
int ast_senddigit_begin(struct ast_channel *chan, char digit)
{
int res = -1;
if (chan->tech->send_digit)
res = chan->tech->send_digit(chan, digit);
if (chan->tech->send_digit_begin)
res = chan->tech->send_digit_begin(chan, digit);
if (res) {
/*
* Device does not support DTMF tones, lets fake
@ -2299,12 +2343,30 @@ static int do_senddigit(struct ast_channel *chan, char digit)
ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
}
}
return 0;
}
int ast_senddigit_end(struct ast_channel *chan, char digit)
{
int res = -1;
if (chan->tech->send_digit_end)
res = chan->tech->send_digit_end(chan, digit);
if (res && chan->generator)
ast_playtones_stop(chan);
return 0;
}
int ast_senddigit(struct ast_channel *chan, char digit)
{
return do_senddigit(chan, digit);
ast_senddigit_begin(chan, digit);
ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */
return ast_senddigit_end(chan, digit);
}
int ast_prod(struct ast_channel *chan)
@ -2372,17 +2434,16 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
chan->tech->indicate(chan, fr->subclass, fr->data, fr->datalen);
break;
case AST_FRAME_DTMF_BEGIN:
res = (chan->tech->send_digit_begin == NULL) ? 0 :
chan->tech->send_digit_begin(chan, fr->subclass);
break;
case AST_FRAME_DTMF_END:
res = (chan->tech->send_digit_end == NULL) ? 0 :
chan->tech->send_digit_end(chan);
break;
case AST_FRAME_DTMF:
ast_clear_flag(chan, AST_FLAG_BLOCKING);
ast_channel_unlock(chan);
res = do_senddigit(chan,fr->subclass);
res = ast_senddigit_begin(chan, fr->subclass);
ast_channel_lock(chan);
CHECK_BLOCKING(chan);
break;
case AST_FRAME_DTMF_END:
ast_clear_flag(chan, AST_FLAG_BLOCKING);
ast_channel_unlock(chan);
res = ast_senddigit_end(chan, fr->subclass);
ast_channel_lock(chan);
CHECK_BLOCKING(chan);
break;
@ -2467,7 +2528,14 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
res = chan->tech->write(chan, f);
}
break;
break;
case AST_FRAME_NULL:
case AST_FRAME_IAX:
/* Ignore these */
break;
default:
res = chan->tech->write(chan, f);
break;
}
if (f && f != fr)
@ -3496,6 +3564,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
break;
}
if ((f->frametype == AST_FRAME_VOICE) ||
(f->frametype == AST_FRAME_DTMF_BEGIN) ||
(f->frametype == AST_FRAME_DTMF) ||
(f->frametype == AST_FRAME_VIDEO) ||
(f->frametype == AST_FRAME_IMAGE) ||
@ -3505,10 +3574,14 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
/* monitored dtmf causes exit from bridge */
int monitored_source = (who == c0) ? watch_c0_dtmf : watch_c1_dtmf;
if (f->frametype == AST_FRAME_DTMF && monitored_source) {
if (monitored_source &&
(f->frametype == AST_FRAME_DTMF_END ||
f->frametype == AST_FRAME_DTMF_BEGIN)) {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "Got DTMF on channel (%s)\n", who->name);
ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n",
f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
who->name);
break;
}
/* Write immediately frames, not passed through jb */

View File

@ -1497,42 +1497,45 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
} else {
if (digit) {
/* Thought we saw one last time. Pretty sure we really have now */
if (dsp->thinkdigit) {
if ((dsp->thinkdigit != 'x') && (dsp->thinkdigit != digit)) {
/* If we found a digit, and we're changing digits, go
ahead and send this one, but DON'T stop confmute because
we're detecting something else, too... */
memset(&dsp->f, 0, sizeof(dsp->f));
dsp->f.frametype = AST_FRAME_DTMF;
dsp->f.subclass = dsp->thinkdigit;
FIX_INF(af);
if (chan)
ast_queue_frame(chan, af);
ast_frfree(af);
}
dsp->thinkdigit = digit;
return &dsp->f;
}
dsp->thinkdigit = digit;
} else {
if (dsp->thinkdigit) {
if ((dsp->thinkdigit != 'x') && (dsp->thinkdigit != digit)) {
/* If we found a digit, and we're changing digits, go
ahead and send this one, but DON'T stop confmute because
we're detecting something else, too... */
memset(&dsp->f, 0, sizeof(dsp->f));
if (dsp->thinkdigit != 'x') {
/* If we found a digit, send it now */
dsp->f.frametype = AST_FRAME_DTMF;
dsp->f.subclass = dsp->thinkdigit;
dsp->thinkdigit = 0;
} else {
dsp->f.frametype = AST_FRAME_DTMF;
dsp->f.subclass = 'u';
dsp->thinkdigit = 0;
}
dsp->f.frametype = AST_FRAME_DTMF_END;
dsp->f.subclass = dsp->thinkdigit;
FIX_INF(af);
if (chan)
ast_queue_frame(chan, af);
ast_frfree(af);
} else {
dsp->thinkdigit = digit;
memset(&dsp->f, 0, sizeof(dsp->f));
dsp->f.frametype = AST_FRAME_DTMF_BEGIN;
dsp->f.subclass = dsp->thinkdigit;
FIX_INF(af);
if (chan)
ast_queue_frame(chan, af);
ast_frfree(af);
return &dsp->f;
}
return &dsp->f;
} else {
memset(&dsp->f, 0, sizeof(dsp->f));
if (dsp->thinkdigit != 'x') {
/* If we found a digit, send it now */
dsp->f.frametype = AST_FRAME_DTMF_END;
dsp->f.subclass = dsp->thinkdigit;
dsp->thinkdigit = 0;
} else {
dsp->f.frametype = AST_FRAME_DTMF;
dsp->f.subclass = 'u';
dsp->thinkdigit = 0;
}
FIX_INF(af);
if (chan)
ast_queue_frame(chan, af);
ast_frfree(af);
return &dsp->f;
}
}
} else if (!digit) {
@ -1553,7 +1556,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
} else {
if (dsp->td.dtmf.current_digits) {
memset(&dsp->f, 0, sizeof(dsp->f));
dsp->f.frametype = AST_FRAME_DTMF;
dsp->f.frametype = AST_FRAME_DTMF_END;
dsp->f.subclass = dsp->td.dtmf.digits[0];
memmove(dsp->td.dtmf.digits, dsp->td.dtmf.digits + 1, dsp->td.dtmf.current_digits);
dsp->td.dtmf.current_digits--;

View File

@ -1029,7 +1029,8 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
if (!fr)
return -1;
switch(fr->frametype) {
case AST_FRAME_DTMF:
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_DTMF_END:
if (context) {
const char exten[2] = { fr->subclass, '\0' };
if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
@ -1065,8 +1066,10 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
/* Write audio if appropriate */
if (audiofd > -1)
write(audiofd, fr->data, fr->datalen);
default:
/* Ignore all others */
break;
}
/* Ignore all others */
ast_frfree(fr);
}
ast_sched_runq(c->sched);

View File

@ -106,14 +106,12 @@ struct rtpPayloadType {
/*! \brief RTP session description */
struct ast_rtp {
int s;
char resp;
struct ast_frame f;
unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */
unsigned int themssrc; /*!< Their SSRC */
unsigned int rxssrc;
unsigned int lastts;
unsigned int lastdigitts;
unsigned int lastrxts;
unsigned int lastividtimestamp;
unsigned int lastovidtimestamp;
@ -128,11 +126,17 @@ struct ast_rtp {
unsigned int cycles; /*!< Shifted count of sequence number cycles */
double rxjitter; /*!< Interarrival jitter at the moment */
double rxtransit; /*!< Relative transit time for previous packet */
unsigned int lasteventendseqn;
int lasttxformat;
int lastrxformat;
/* DTMF Reception Variables */
char resp;
unsigned int lasteventendseqn;
int dtmfcount;
unsigned int dtmfduration;
/* DTMF Transmission Variables */
unsigned int lastdigitts;
char send_digit;
int send_payload;
int nat;
unsigned int flags;
struct sockaddr_in us; /*!< Socket representation of the local endpoint. */
@ -164,6 +168,8 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
static int ast_rtcp_write_sr(void *data);
static int ast_rtcp_write_rr(void *data);
static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp);
int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
static int bridge_p2p_rtcp_write(struct ast_rtp *rtp, unsigned int *rtcpheader, int len);
#define FLAG_3389_WARNING (1 << 0)
@ -174,6 +180,7 @@ static int bridge_p2p_rtcp_write(struct ast_rtp *rtp, unsigned int *rtcpheader,
#define FLAG_P2P_SENT_MARK (1 << 4)
#define FLAG_P2P_NEED_DTMF (1 << 5)
#define FLAG_CALLBACK_MODE (1 << 6)
#define FLAG_DTMF_COMPENSATE (1 << 7)
/*!
* \brief Structure defining an RTCP session.
@ -531,7 +538,12 @@ void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf)
ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF);
}
static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate)
{
ast_set2_flag(rtp, compensate ? 1 : 0, FLAG_DTMF_COMPENSATE);
}
static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type)
{
if (ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
if (option_debug)
@ -546,15 +558,13 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
rtp->f.frametype = AST_FRAME_CONTROL;
rtp->f.subclass = AST_CONTROL_FLASH;
} else {
rtp->f.frametype = AST_FRAME_DTMF;
rtp->f.frametype = type;
rtp->f.subclass = rtp->resp;
}
rtp->f.datalen = 0;
rtp->f.samples = 0;
rtp->f.mallocd = 0;
rtp->f.src = "RTP";
rtp->resp = 0;
rtp->dtmfduration = 0;
return &rtp->f;
}
@ -607,7 +617,7 @@ static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *
resp = 'X';
}
if (rtp->resp && (rtp->resp != resp)) {
f = send_dtmf(rtp);
f = send_dtmf(rtp, AST_FRAME_DTMF_END);
}
rtp->resp = resp;
rtp->dtmfcount = dtmftimeout;
@ -633,6 +643,7 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
char resp = 0;
struct ast_frame *f = NULL;
/* Figure out event, event end, and duration */
event = ntohl(*((unsigned int *)(data)));
event >>= 24;
event_end = ntohl(*((unsigned int *)(data)));
@ -640,8 +651,12 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
event_end >>= 24;
duration = ntohl(*((unsigned int *)(data)));
duration &= 0xFFFF;
/* Print out debug if turned on */
if (rtpdebug || option_debug > 2)
ast_log(LOG_DEBUG, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
/* Figure out what digit was pressed */
if (event < 10) {
resp = '0' + event;
} else if (event < 11) {
@ -653,25 +668,21 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
} else if (event < 17) { /* Event 16: Hook flash */
resp = 'X';
}
if (rtp->resp && (rtp->resp != resp)) {
f = send_dtmf(rtp);
} else if (event_end & 0x80) {
if (rtp->resp) {
if (rtp->lasteventendseqn != seqno) {
f = send_dtmf(rtp);
rtp->lasteventendseqn = seqno;
}
rtp->resp = 0;
}
resp = 0;
duration = 0;
} else if (rtp->resp && rtp->dtmfduration && (duration < rtp->dtmfduration)) {
f = send_dtmf(rtp);
}
if (!(event_end & 0x80))
if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
rtp->resp = resp;
if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE))
f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
} else if (event_end & 0x80 && rtp->lasteventendseqn != seqno && rtp->resp) {
f = send_dtmf(rtp, AST_FRAME_DTMF_END);
f->samples = duration;
rtp->resp = 0;
rtp->lasteventendseqn = seqno;
}
rtp->dtmfcount = dtmftimeout;
rtp->dtmfduration = duration;
return f;
}
@ -1030,6 +1041,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
unsigned int *rtpheader;
struct rtpPayloadType rtpPT;
/* If time is up, kill it */
if (rtp->send_digit)
ast_rtp_senddigit_continuation(rtp);
len = sizeof(sin);
/* Cache where the header will go */
@ -1172,13 +1187,13 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
duration &= 0xFFFF;
ast_verbose("Got RTP RFC2833 from %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
}
if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno);
rtp->lasteventseqn = seqno;
}
} else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
/* It's really special -- process it the Cisco way */
if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
if (rtp->lasteventseqn <= seqno || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
rtp->lasteventseqn = seqno;
}
@ -1198,26 +1213,9 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
rtp->rxseqno = seqno;
if (rtp->dtmfcount) {
#if 0
printf("dtmfcount was %d\n", rtp->dtmfcount);
#endif
rtp->dtmfcount -= (timestamp - rtp->lastrxts);
if (rtp->dtmfcount < 0)
rtp->dtmfcount = 0;
#if 0
if (dtmftimeout != rtp->dtmfcount)
printf("dtmfcount is %d\n", rtp->dtmfcount);
#endif
}
/* Record received timestamp as last received now */
rtp->lastrxts = timestamp;
/* Send any pending DTMF */
if (rtp->resp && !rtp->dtmfcount) {
if (option_debug)
ast_log(LOG_DEBUG, "Sending pending DTMF\n");
return send_dtmf(rtp);
}
rtp->f.mallocd = 0;
rtp->f.datalen = res - hdrlen;
rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
@ -1962,35 +1960,42 @@ static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
return (unsigned int) ms;
}
int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
/* Convert DTMF digit into something usable */
static int digit_convert(char digit)
{
if ((digit <= '9') && (digit >= '0'))
digit -= '0';
else if (digit == '*')
digit = 10;
else if (digit == '#')
digit = 11;
else if ((digit >= 'A') && (digit <= 'D'))
digit = digit - 'A' + 12;
else if ((digit >= 'a') && (digit <= 'd'))
digit = digit - 'a' + 12;
else {
ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
return -1;
}
return 0;
}
/*! \brief Send begin frames for DTMF */
int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit)
{
unsigned int *rtpheader;
int hdrlen = 12;
int res;
int x;
int payload;
int hdrlen = 12, res = 0, i = 0, payload = 0;
char data[256];
if ((digit <= '9') && (digit >= '0'))
digit -= '0';
else if (digit == '*')
digit = 10;
else if (digit == '#')
digit = 11;
else if ((digit >= 'A') && (digit <= 'D'))
digit = digit - 'A' + 12;
else if ((digit >= 'a') && (digit <= 'd'))
digit = digit - 'a' + 12;
else {
ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
if (digit_convert(digit))
return -1;
}
payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
/* If we have no peer, return immediately */
if (!rtp->them.sin_addr.s_addr)
if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
return 0;
payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
/* Get a pointer to the header */
@ -1999,51 +2004,111 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
for (x = 0; x < 6; x++) {
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
if (res < 0)
ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), strerror(errno));
if (rtp_debug_test_addr(&rtp->them))
ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
/* Sequence number of last two end packets does not get incremented */
if (x < 3)
rtp->seqno++;
for (i = 0; i < 2; i++) {
res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
if (res < 0)
ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), strerror(errno));
if (rtp_debug_test_addr(&rtp->them))
ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
/* Increment sequence number */
rtp->seqno++;
/* Clear marker bit and set seqno */
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
/* For the last three packets, set the duration and the end bit */
if (x == 2) {
#if 0
/* No, this is wrong... Do not increment lastdigitts, that's not according
to the RFC, as best we can determine */
rtp->lastdigitts++; /* or else the SPA3000 will click instead of beeping... */
rtpheader[1] = htonl(rtp->lastdigitts);
#endif
/* Make duration 800 (100ms) */
rtpheader[3] |= htonl((800));
/* Set the End bit */
rtpheader[3] |= htonl((1 << 23));
}
}
/*! \note Increment the digit timestamp by 120ms, to ensure that digits
sent sequentially with no intervening non-digit packets do not
get sent with the same timestamp, and that sequential digits
have some 'dead air' in between them
*/
rtp->lastdigitts += 960;
/* Increment the sequence number to reflect the last packet
that was sent
*/
rtp->seqno++;
/* Since we received a begin, we can safely store the digit and disable any compensation */
rtp->send_digit = digit;
rtp->send_payload = payload;
return 0;
}
/* \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
/*! \brief Send continuation frame for DTMF */
static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp)
{
unsigned int *rtpheader;
int hdrlen = 12, res = 0;
char data[256];
if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
return 0;
/* Setup packet to send */
rtpheader = (unsigned int *)data;
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (0));
rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
/* Transmit */
res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
if (res < 0)
ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), strerror(errno));
if (rtp_debug_test_addr(&rtp->them))
ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
/* Increment sequence number */
rtp->seqno++;
return 0;
}
/*! \brief Send end packets for DTMF */
int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit)
{
unsigned int *rtpheader;
int hdrlen = 12, res = 0, i = 0;
char data[256];
/* If no address, then bail out */
if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
return 0;
/* Convert our digit to the crazy RTP way */
if (digit_convert(digit))
return -1;
rtpheader = (unsigned int *)data;
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
/* Send duration to 100ms */
rtpheader[3] |= htonl((800));
/* Set end bit */
rtpheader[3] |= htonl((1 << 23));
rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
/* Send 3 termination packets */
for (i = 0; i < 3; i++) {
res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
if (res < 0)
ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), strerror(errno));
if (rtp_debug_test_addr(&rtp->them))
ast_verbose("Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_inet_ntoa(rtp->them.sin_addr),
ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
rtp->send_digit = 0;
/* Increment lastdigitts */
rtp->lastdigitts += 960;
rtp->seqno++;
return res;
}
/*! \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
int ast_rtcp_send_h261fur(void *data)
{
struct ast_rtp *rtp = data;

View File

@ -1016,6 +1016,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
break;
case AST_FRAME_VIDEO:
ast_writestream(fs, f);
default:
/* Ignore all other frames */
break;
}
ast_frfree(f);

View File

@ -1439,9 +1439,9 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
}
}
/* check for '*', if we find it it's time to disconnect */
if (f->frametype == AST_FRAME_DTMF) {
} else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
/* eat it */
} else if (f->frametype == AST_FRAME_DTMF) {
char *featurecode;
int sense;