Merge "channel.c: Resolve issue with receiving SIP INFO packets for DTMF"

pull/18/head
Friendly Automation 6 years ago committed by Gerrit Code Review
commit fd00a2bd10

@ -2819,6 +2819,33 @@ int ast_channel_get_up_time(struct ast_channel *chan)
return (ast_channel_get_up_time_ms(chan) / 1000);
}
/*!
* \brief Determine whether or not we have to trigger dtmf emulating using 50 fps timer events
* especially when no voice frames are received during dtmf processing (direct media or muted
* sender case using SIP INFO)
*/
static inline int should_trigger_dtmf_emulating(struct ast_channel *chan)
{
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) {
/* We're in the middle of emulating a digit, or DTMF has been
* explicitly deferred. Trigger dtmf with periodic 50 pfs timer events, then. */
return 1;
}
if (!ast_tvzero(*ast_channel_dtmf_tv(chan)) &&
ast_tvdiff_ms(ast_tvnow(), *ast_channel_dtmf_tv(chan)) < 2*AST_MIN_DTMF_GAP) {
/*
* We're not in the middle of a digit, but it hasn't been long enough
* since the last digit, so we'll have to trigger DTMF furtheron.
* Using 2 times AST_MIN_DTMF_GAP to trigger readq reading for possible
* buffered next dtmf event
*/
return 1;
}
return 0;
}
static void deactivate_generator_nolock(struct ast_channel *chan)
{
if (ast_channel_generatordata(chan)) {
@ -2839,6 +2866,10 @@ void ast_deactivate_generator(struct ast_channel *chan)
{
ast_channel_lock(chan);
deactivate_generator_nolock(chan);
if (should_trigger_dtmf_emulating(chan)) {
/* if in the middle of dtmf emulation keep 50 tick per sec timer on rolling */
ast_timer_set_rate(ast_channel_timer(chan), 50);
}
ast_channel_unlock(chan);
}
@ -3508,6 +3539,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
if (ast_channel_timingfd(chan) > -1 && ast_channel_fdno(chan) == AST_TIMING_FD) {
enum ast_timer_event res;
int trigger_dtmf_emulating = should_trigger_dtmf_emulating(chan);
ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
@ -3535,10 +3567,26 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
if (got_ref) {
ao2_ref(data, -1);
}
if (trigger_dtmf_emulating) {
/*
* Since we're breaking out of this switch block and not
* returning, we need to re-lock the channel.
*/
ast_channel_lock(chan);
/* generate null frame to trigger dtmf emulating */
f = &ast_null_frame;
break;
}
} else if (trigger_dtmf_emulating) {
/* generate null frame to trigger dtmf emualating */
f = &ast_null_frame;
break;
} else {
ast_timer_set_rate(ast_channel_timer(chan), 0);
ast_channel_fdno_set(chan, -1);
ast_channel_unlock(chan);
/* generate very last null frame to trigger dtmf emulating */
f = &ast_null_frame;
break;
}
/* cannot 'goto done' because the channel is already unlocked */
@ -3576,6 +3624,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
/* Check for pending read queue */
if (!AST_LIST_EMPTY(ast_channel_readq(chan))) {
int skipped_dtmf_frame = 0;
int skip_dtmf = should_skip_dtmf(chan);
AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) {
@ -3584,6 +3633,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
* some later time. */
if ( (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) && skip_dtmf) {
skipped_dtmf_frame = 1;
continue;
}
@ -3595,7 +3645,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
if (!f) {
/* There were no acceptable frames on the readq. */
f = &ast_null_frame;
ast_channel_alert_write(chan);
if (!skipped_dtmf_frame) {
/*
* Do not trigger alert pipe if only buffered dtmf begin or end frames
* are left in the readq.
*/
ast_channel_alert_write(chan);
} else {
/*
* Safely disable continous timer events if only buffered dtmf begin or end
* frames are left in the readq.
*/
ast_timer_disable_continuous(ast_channel_timer(chan));
}
}
/* Interpret hangup and end-of-Q frames to return NULL */
@ -3801,6 +3863,16 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
} else
ast_channel_emulate_dtmf_duration_set(chan, AST_DEFAULT_EMULATE_DTMF_DURATION);
ast_log(LOG_DTMF, "DTMF begin emulation of '%c' with duration %u queued on %s\n", f->subclass.integer, ast_channel_emulate_dtmf_duration(chan), ast_channel_name(chan));
/*
* Start generating 50 fps timer events (null frames) for dtmf emulating
* independently from any existing incoming voice frames.
* If channel generator is already activated in regular mode use these
* timer events to generate null frames.
*/
if (!ast_channel_generator(chan)) {
ast_timer_set_rate(ast_channel_timer(chan), 50);
}
}
if (ast_channel_audiohooks(chan)) {
struct ast_frame *old_frame = f;
@ -3842,12 +3914,30 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
ast_channel_emulate_dtmf_duration_set(chan, option_dtmfminduration - f->len);
ast_frfree(f);
f = &ast_null_frame;
/* Start generating 50 fps timer events (null frames) for dtmf emulating
* independently from any existing incoming voice frames.
* If channel generator is already activated in regular mode use these
* timer events to generate null frames.
*/
if (!ast_channel_generator(chan)) {
ast_timer_set_rate(ast_channel_timer(chan), 50);
}
} else {
ast_log(LOG_DTMF, "DTMF end passthrough '%c' on %s\n", f->subclass.integer, ast_channel_name(chan));
if (f->len < option_dtmfminduration) {
f->len = option_dtmfminduration;
}
ast_channel_dtmf_tv_set(chan, &now);
/* Start generating 50 fps timer events (null frames) for dtmf emulating
* independently from any existing incoming voice frames.
* If channel generator is already activated in regular mode use these
* timer events to generate null frames.
*/
if (!ast_channel_generator(chan)) {
ast_timer_set_rate(ast_channel_timer(chan), 50);
}
}
if (ast_channel_audiohooks(chan)) {
struct ast_frame *old_frame = f;
@ -3901,6 +3991,15 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
ast_frfree(old_frame);
}
}
/* Start generating 50 fps timer events (null frames) for dtmf emulating
* independently from any existing incoming voice frames.
* If channel generator is already activated in regular mode use these
* timer events to generate null frames.
*/
if (!ast_channel_generator(chan)) {
ast_timer_set_rate(ast_channel_timer(chan), 50);
}
}
}
break;

Loading…
Cancel
Save