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:
parent
0fcb352fba
commit
3f22aa53af
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
11
main/app.c
11
main/app.c
|
@ -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;
|
||||
|
|
141
main/channel.c
141
main/channel.c
|
@ -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 */
|
||||
|
|
65
main/dsp.c
65
main/dsp.c
|
@ -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--;
|
||||
|
|
|
@ -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);
|
||||
|
|
271
main/rtp.c
271
main/rtp.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Reference in New Issue