A practical multi-carrier stack for FAS detection and trunk isolation
Pair SIP-proxy routing with call-audio classification, then quarantine suspect trunks only after a measured pattern—not a single false answer.
Start audio analysis as soon as the answered channel is available, then route on a returned verdict instead of waiting out a fixed greeting timer.
In an Asterisk answering-machine-detection flow, the avoidable delay is often a timer placed before analysis starts. The channel answers, the dialplan waits for a greeting to finish, and only then does detection begin. That sequence can miss the useful part of the call and leave a live person waiting.
A better pattern is to make the answered audio available to the detector immediately, keep the call in a pending state while a verdict is returned, and route according to that verdict. AMDY.IO supports Asterisk and offers a WebSocket API. The product facts available here do not specify an Asterisk dialplan application, WebSocket message format, or verdict variable, so the example below uses an adapter placeholder rather than inventing one.
The dialplan should make a small number of decisions: start detection, wait for the adapter’s result, then branch to human or machine handling. A separate adapter is responsible for carrying call audio to the detection service and making its result available to Asterisk. Your implementation must follow the current API documentation for the connection and result format.
This separation matters at answer time. In SIP, a 200 OK indicates that the call has been answered; Asterisk’s channel and media handling determine when your dialplan can act on that answer. Start the audio path as soon as the relevant answered channel is available. Do not insert a greeting-length pause before the adapter begins receiving audio.
Also check which channel your context runs on. If you send an upstream answer before the destination has answered, you change call signaling rather than merely starting AMD. Place the logic on the leg that receives the answer you intend to classify.
The following is a control-flow sketch for extensions.conf, not a ready-to-run AMDY.IO command. Replace ADAPTER_START_AND_WAIT with your own integration. It must start streaming promptly, wait for a result, and set AMD_CLASS to a value your dialplan can inspect. Use the exact application or handoff supported by your implementation.
[amd-entry]
exten => _X.,1,NoOp(Start AMD on answered channel)
same => n,Answer()
same => n,Set(AMD_CLASS=PENDING)
same => n,ADAPTER_START_AND_WAIT(${UNIQUEID})
same => n,GotoIf($["${AMD_CLASS}"="HUMAN"]?human)
same => n,GotoIf($["${AMD_CLASS}"="MACHINE"]?machine)
same => n,Goto(unknown)
same => n(human),NoOp(Route human call)
same => n,Goto(agent-route,s,1)
same => n(machine),NoOp(Route machine call)
same => n,Goto(machine-route,s,1)
same => n(unknown),NoOp(Apply local policy to unresolved result)
same => n,Goto(review-route,s,1)
The route names are examples; replace them with contexts in your dialplan. The important detail is the final branch. A missing, late, or unrecognized result should not silently become HUMAN. Define a local fallback for unresolved calls, and record enough information to distinguish a detector result from a timeout or adapter failure.
Starting the stream is not the same as eliminating every audible gap. If Asterisk waits synchronously for a verdict before connecting a person to an agent, that wait may be heard as silence. The dialplan alone cannot promise zero dead air. Design the agent connection and any pre-verdict audio handling around your call flow, then measure the interval from answer to human routing.
AMDY.IO says detection starts in one-eighth of a second and claims 99% AMD accuracy. Those are product claims, not a guarantee that every call will receive a verdict within a fixed interval or that an Asterisk adapter will return it without delay. Measure answer-to-verdict and answer-to-agent separately. That distinction helps locate whether the hold-up is audio delivery, classification, or the dialplan’s next action.
For a deeper look at the placement tradeoff, see how inline and post-connect analysis change where latency lands. The useful question is not simply how fast detection runs; it is whether the audio reaches the detector early enough and what the call does while a verdict is pending.
Use controlled calls to verify the full path: answer supervision arrives, audio begins flowing, the adapter returns a result, and the expected branch runs. Test human speech, a recorded greeting, and calls where no useful speech arrives. Then test an adapter timeout and a disconnected WebSocket. Confirm that each case takes the policy you intended rather than falling through to an agent by default.
Compare timestamps for answer, stream start, verdict, and route execution. If the stream starts late, remove the pre-analysis wait or correct the channel handoff. If the verdict arrives promptly but routing lags, inspect the dialplan’s wait and branch logic. If the answer signal itself looks suspect, investigate that separately: carrier false answers and audio-based human-versus-machine classification are related operational concerns, but they are not the same verdict.
Keep the first deployment narrow. Validate the adapter and fallback behavior on a test route, then extend the context once call traces show that audio starts at answer and every result has an explicit destination. That is the practical route to less avoidable dead air: begin analysis early, make the pending state visible, and never guess what an absent verdict means.
Pair SIP-proxy routing with call-audio classification, then quarantine suspect trunks only after a measured pattern—not a single false answer.
Combine OpenSIPS routing, Asterisk call handling and AMDY.IO detection—then automate trunk quarantine only after your own policy verifies the pattern.
Dead air, fake ringback and early media can all confuse outbound dialers, but they are different signals—and none alone proves a carrier fault.