From 406a7843fd00fad656c1673df9cf4f930f6034ee Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Fri, 11 Sep 2026 09:26:43 -0400 Subject: [PATCH] chan_dahdi: Avoid transitioning device state from INUSE to RINGING. By default, DAHDI relies on the Asterisk code to provide most device state, especially for analog lines, in which case it relies entirely on the core. When an incoming call arrives to a DAHDI line, it immediately asks the core to update device state for the channel. This can sometimes lead to unoptimal outcomes; for example, when ringing an FXS line (station), the device state is momentarily "INUSE" and then almost immediately transitions to "RINGING". However, this is incompatible with the state machines of some CPE. For example, Polycom IP phones' BLFs will ignore any "RINGING" received after an "INUSE". This makes sense because a line can't ring after being in use without first being made idle. (The reverse case, RINGING followed by INUSE, is allowed, since one can answer a ringing phone.) Thus, to ensure that BLFs accurately display the status of DAHDI channels, we need to avoid the momentary "INUSE" device state for ringing channels. Resolves: #2159 --- channels/chan_dahdi.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index c7f9244741..b48b98d5d3 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -9826,12 +9826,22 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb ast_jb_configure(tmp, &global_jbconf); /* Set initial device state */ - ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name)); - dashptr = strrchr(device_name, '-'); - if (dashptr) { - *dashptr = '\0'; + if (IS_FXO_SIG(i) && idx == SUB_REAL && state == AST_STATE_RESERVED && !startpbx && requestor) { + /* In the case that an analog line is receiving a call, temporarily suppress device state updates. + * If we updated the device state right now, the calculated device state would be "INUSE", + * even though almost instantly, it will become "RINGING". This is problematic, + * because many IP phones ignore INUSE -> RINGING transitions since that's not technically possible. + * To prevent such a bogus transition, if this line is about to ring and is not already in use, skip the update. + * The next update will correctly start device state at RINGING so everything works as devices expect. */ + ast_debug(3, "Suppressing immediate device state update to prevent INUSE -> RINGING transition\n"); + } else { + ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name)); + dashptr = strrchr(device_name, '-'); + if (dashptr) { + *dashptr = '\0'; + } + ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, device_name); } - ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, device_name); for (v = i->vars ; v ; v = v->next) pbx_builtin_setvar_helper(tmp, v->name, v->value);