FreeSWITCH answering machine detection with AI
nomoVM adds FreeSWITCH answering machine detection that listens to how a call is answered. A Lua script streams the first seconds of the answered call through mod_audio_stream, and your dialplan gets AMDSTATUS: HUMAN, MACHINE or FALLBACK, in about 2 seconds.
Why FreeSWITCH needs better AMD
FreeSWITCH has no built-in answering machine detection like Asterisk's AMD(). Options are a beep detector (mod_avmd, which finds the voicemail tone after the greeting, not who answered), third-party timing-based modules, or your carrier's detection. nomoVM gives FreeSWITCH dialers and PBXs the same AI model VICIdial users get: it hears the difference between a live "Hello?" and a recording, recognises busy, SIT, fax and ringback tones, and catches recorded hellos played to many numbers. How the AI decides
How it works
The call is answered
Your dialplan runs
nomovm_amd.lua. The script startsmod_audio_streamon the call, which sends the caller's audio (8 kHz, mono) to nomoVM over a secure WebSocket, with your key in the request header.nomoVM decides
After about 2 seconds of audio (3.2 seconds for unclear calls) the service replies with one verdict.
mod_audio_streampasses it back to FreeSWITCH as an event.Your dialplan routes
The script sets
AMDSTATUSandAMDCAUSE, stops the stream and returns. SendHUMANto an agent, drop or leave a message forMACHINE.
mod_audio_stream not loaded), AMDSTATUS is FALLBACK before any audio is used. A timeout after streaming started gives MACHINE / UNKNOWN, so only a confirmed person reaches an agent.Install
1. Load mod_audio_stream
mod_audio_stream is an open-source FreeSWITCH module that streams call audio to a WebSocket. Install it as its README describes (it publishes packages for recent Debian releases with FreeSWITCH from SignalWire's repository), then load it:
fs_cli -x "load mod_audio_stream"
# and to load it at every start, in autoload_configs/modules.conf.xml:
# <load module="mod_audio_stream"/>
mod_audio_stream is a separate project with its own license (AGPL-3.0 with a FreeSWITCH linking exception for the community edition). Check that it suits how you run FreeSWITCH.
2. Install the script
cd /usr/share/freeswitch/scripts # or /etc/freeswitch/scripts on some installs
curl -fsSLO https://nomovm.com/assets/nomovm_amd.lua
mod_lua ships with FreeSWITCH. The script has no other dependencies.
3. Create a key
Sign up free and create a WS key on the WS keys page (one per FreeSWITCH server is easiest to follow in the dashboard).
Dialplan
Send answered outbound calls to an extension that runs the script, then route on the result. In dialplan/default.xml (or your own context):
<extension name="nomovm_amd">
<condition field="destination_number" expression="^nomovm_amd$">
<action application="lua" data="nomovm_amd.lua wss://amd.nomovm.com/ YOUR_KEY 4500"/>
<action application="transfer" data="amd_${AMDSTATUS} XML default"/>
</condition>
</extension>
<extension name="amd_human">
<condition field="destination_number" expression="^amd_HUMAN$">
<action application="transfer" data="agents XML default"/> <!-- your agent queue -->
</condition>
</extension>
<extension name="amd_machine">
<condition field="destination_number" expression="^amd_MACHINE$">
<action application="hangup"/> <!-- or play a voicemail message first -->
</condition>
</extension>
<extension name="amd_fallback">
<condition field="destination_number" expression="^amd_FALLBACK$">
<action application="transfer" data="agents XML default"/> <!-- or your previous detection -->
</condition>
</extension>
Variables in action data are filled in when the action runs, so amd_${AMDSTATUS} becomes amd_HUMAN, amd_MACHINE or amd_FALLBACK after the script has decided. AMDCAUSE tells you why (SCREENING, TONE, BUSY, SILENCE...) if you want separate routes.
Outbound calls
Have your dialer place each call into that extension, so detection starts the moment the call is answered:
originate {origination_caller_id_number=15550001111}sofia/gateway/my_carrier/15551234567 nomovm_amd XML default
Dialers that use the event socket can do the same with bgapi originate. The extension runs only after the callee answers, which is when AMD should start.
Test
- Check the module answers:
fs_cli -x "uuid_audio_stream"should print its usage, not "command not found". - Place a test call to your own mobile and let it go to voicemail: the log line shows
MACHINE. Answer it yourself:HUMAN. - Open the nomoVM dashboard: each call is listed with its verdict, cause, timing and the audio the model heard.
FreeSWITCH questions
Does it work with FusionPBX and other FreeSWITCH-based systems?
Yes, if you can load mod_audio_stream and add a dialplan extension. FusionPBX lets you add dialplan entries from its admin screens.
What audio does nomoVM receive?
Only the caller's side ("mono"), 8 kHz, 16-bit, from answer until the verdict, usually 2 to 3.2 seconds. The script stops the stream as soon as the verdict arrives.
How is the key sent?
As an Authorization header on the WebSocket handshake (mod_audio_stream's STREAM_EXTRA_HEADERS), over TLS. It never appears in the URL.
Can I use mod_avmd as well?
Yes. mod_avmd detects the voicemail beep, which is useful for timing a voicemail drop after nomoVM has said MACHINE.
Not using mod_audio_stream?
Any module or application that can stream 8 kHz, 16-bit audio to a WebSocket can use the WebSocket API directly.
Stop sending voicemail to your agents
30,000 calls a month free. No card, no setup fee. Your dialer falls back to Asterisk AMD() on its own if anything goes wrong.