Improve DTMF handling in ast_read() even more in response to a discussion on

the asterisk-dev mailing list.  I changed the enforced minimum length of a
digit from 100ms to 80ms.  Furthermore, I made it now enforce a gap of 45ms in
between digits.  These values are not configurable in a configuration file
right now, but they can be easily changed near the top of main/channel.c.


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@61781 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Russell Bryant 18 years ago
parent db55615090
commit 456cad8a47

@ -428,7 +428,7 @@ struct ast_channel {
char emulate_dtmf_digit; /*!< Digit being emulated */
unsigned int emulate_dtmf_duration; /*!< Number of ms left to emulate DTMF for */
struct timeval dtmf_begin_tv; /*!< The time that an in process digit began */
struct timeval dtmf_tv; /*!< The time that an in process digit began, or the last digit ended */
/*! \brief Data stores on the channel */
AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores;

@ -104,9 +104,17 @@ unsigned long global_fin, global_fout;
AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
#define STATE2STR_BUFSIZE 32
/*! 100ms */
/*! Default amount of time to use when emulating a digit as a begin and end
* 100ms */
#define AST_DEFAULT_EMULATE_DTMF_DURATION 100
/*! Minimum allowed digit length - 80ms */
#define AST_MIN_DTMF_DURATION 80
/*! Minimum amount of time between the end of the last digit and the beginning
* of a new one - 45ms */
#define AST_MIN_DTMF_GAP 45
struct chanlist {
const struct ast_channel_tech *tech;
AST_LIST_ENTRY(chanlist) list;
@ -2113,7 +2121,8 @@ 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_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) &&
!ast_strlen_zero(chan->dtmfq)) {
!ast_strlen_zero(chan->dtmfq) &&
(ast_tvzero(chan->dtmf_tv) || ast_tvdiff_ms(ast_tvnow(), chan->dtmf_tv) > AST_MIN_DTMF_GAP) ) {
/* We have DTMF that has been deferred. Return it now */
chan->dtmff.subclass = chan->dtmfq[0];
/* Drop first digit from the buffer */
@ -2126,8 +2135,8 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
chan->dtmf_begin_tv = ast_tvnow();
}
chan->dtmf_tv = ast_tvnow();
goto done;
}
@ -2264,34 +2273,50 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
ast_frfree(f);
f = &ast_null_frame;
} else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY)) {
f->frametype = AST_FRAME_DTMF_BEGIN;
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
chan->dtmf_begin_tv = ast_tvnow();
if (f->len && f->len > AST_DEFAULT_EMULATE_DTMF_DURATION)
chan->emulate_dtmf_duration = f->len;
else
chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
if (!ast_tvzero(chan->dtmf_tv) &&
ast_tvdiff_ms(ast_tvnow(), chan->dtmf_tv) < AST_MIN_DTMF_GAP) {
/* If it hasn't been long enough, defer this digit */
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 {
/* There was no begin, turn this into a begin and send the end later */
f->frametype = AST_FRAME_DTMF_BEGIN;
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
chan->dtmf_tv = ast_tvnow();
if (f->len && f->len > AST_MIN_DTMF_DURATION)
chan->emulate_dtmf_duration = f->len;
else
chan->emulate_dtmf_duration = AST_MIN_DTMF_DURATION;
}
} else {
struct timeval now = ast_tvnow();
ast_clear_flag(chan, AST_FLAG_IN_DTMF);
if (!f->len)
f->len = ast_tvdiff_ms(ast_tvnow(), chan->dtmf_begin_tv);
if (f->len < AST_DEFAULT_EMULATE_DTMF_DURATION) {
f->len = ast_tvdiff_ms(now, chan->dtmf_tv);
if (f->len < AST_MIN_DTMF_DURATION) {
ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
chan->emulate_dtmf_digit = f->subclass;
chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION - f->len;
chan->emulate_dtmf_duration = AST_MIN_DTMF_DURATION - f->len;
f = &ast_null_frame;
}
} else
chan->dtmf_tv = now;
}
break;
case AST_FRAME_DTMF_BEGIN:
ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY)) {
if ( ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY) ||
(!ast_tvzero(chan->dtmf_tv) &&
ast_tvdiff_ms(ast_tvnow(), chan->dtmf_tv) < AST_MIN_DTMF_GAP) ) {
ast_frfree(f);
f = &ast_null_frame;
} else {
ast_set_flag(chan, AST_FLAG_IN_DTMF);
chan->dtmf_begin_tv = ast_tvnow();
chan->dtmf_tv = ast_tvnow();
}
break;
case AST_FRAME_VOICE:
@ -2309,10 +2334,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
f = &ast_null_frame;
} else if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) {
if ((f->samples / 8) >= chan->emulate_dtmf_duration) { /* XXX 8kHz */
struct timeval now = ast_tvnow();
chan->emulate_dtmf_duration = 0;
f->frametype = AST_FRAME_DTMF_END;
f->subclass = chan->emulate_dtmf_digit;
f->len = ast_tvdiff_ms(ast_tvnow(), chan->dtmf_begin_tv);
f->len = ast_tvdiff_ms(now, chan->dtmf_tv);
chan->dtmf_tv = now;
} else {
chan->emulate_dtmf_duration -= f->samples / 8; /* XXX 8kHz */
ast_frfree(f);

Loading…
Cancel
Save