mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-15 22:38:08 +00:00
Merge "channel.c: Resolve issue with receiving SIP INFO packets for DTMF" into 13
This commit is contained in:
105
main/channel.c
105
main/channel.c
@@ -2971,6 +2971,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)) {
|
||||
@@ -2991,6 +3018,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);
|
||||
}
|
||||
|
||||
@@ -3867,6 +3898,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
|
||||
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);
|
||||
|
||||
@@ -3894,10 +3926,26 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
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 */
|
||||
@@ -3935,6 +3983,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
|
||||
/* 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) {
|
||||
@@ -3943,6 +3992,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
* some later time. */
|
||||
|
||||
if ( (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) && skip_dtmf) {
|
||||
skipped_dtmf_frame = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3954,7 +4004,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
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 */
|
||||
@@ -4091,6 +4153,16 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
} 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;
|
||||
@@ -4132,12 +4204,30 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
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;
|
||||
@@ -4191,6 +4281,15 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user