IVR with voice recognition on Asterisk - fast, easy, free

  • Tutorial
Creating an IVR based on Asterisk, with recognition of DTMF and employee names (based on Voicer from a respected antirek ) and connecting to an existing PBX.

The upcoming new year brought to the company where I work (not) good news - an ancient server with an IVR system and a PCI card for 4 analog ports from Dialogic died. Suddenly, it turned out that modern systems do not have PCI slots, the old ones are not friendly with new versions of the OS and it is not known how long they will live, and there is a license only for a specific old version of the program.
So the idea was born to raise IVR without a fee (and for free) in a virtual machine with Asterisk.

Total, we need:

  • Existing PBX with subscribers
  • The virtual machine (in the example, ubuntu 18.04 lts).
  • Registration for any of the voice recognition services: wit.ai, google or Yandex
  • Minimal knowledge of Linux systems
  • Desire to deal with Asterisk

If all items successfully completed - you can proceed. The first step is to install asterisk itself, voice prompts for the test, as well as nodejs and npm.

apt install nodejs asterisk npm asterisk-core-sounds-ru-gsm

Next, we need the voicer and process manager recognition service itself to start it:

npm install voicer -g
npm install pm2 -g

Create folders and configuration for voicer:

mkdir -p /etc/voicer/data

And we will write down the configuration in the /etc/voicer/config.js file, adding our login / password and key (developer_key) to the desired service. In my case, wit.ai was chosen - free, accurate enough for our tasks.

module.exports = {
    agi: {
        port: 3000
    web: {
        port: 3100,
        auth: true,
        username: 'ИМЯ_ПОЛЬЗОВАТЕЛЯ',
        password: 'ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ',
        realm: 'НАЗВАНИЕ_КОМПАНИИ'
    processing: {
        totalAttempts: 2,
        playGreeting: true,
        playBeepBeforeRecording: false//use system beep
    asterisk: {
        sounds: {
            onErrorBeforeFinish: 'invalid',
            onErrorBeforeRepeat: 'invalid',
            greeting: 'beep'
        recognitionDialplanVars: {
            status: 'RECOGNITION_RESULT',
            target: 'RECOGNITION_TARGET'
    record: {
            directory: '/tmp',
            type: 'wav',
            duration: 3,
    recognize: {
            directory: '/tmp',
        type: 'witai',    // ['yandex', 'google', 'witai']
        options: {
            developer_key: 'XXXXXXXXXXXXXXXXXXX'
    lookup: {
        type: 'file',
        options: {
            dataFile: '/etc/voicer/data/peernames.json'
    logger: {
        console: {
            colorize: true
        file: {
            filename: '/var/log/voicer.log',
            json: false

Next we need to create a service to start voicer. This will be the /etc/init.d/voicer file:

### BEGIN INIT INFO# Provides:          voicer# Required-Start:    $network $syslog $named# Required-Stop:     $network $syslog $named# Default-Start:     2 3 4 5# Default-Stop:      0 1 6# Short-Description: Start/stop voicer### END INIT INFOset -e
if [ -z "$1" ] ; thenecho"Usage: $0 [start|stop|restart]"exit 0
fiif [ "$1" = "start" ] ; then
     VOICER_CONFIGFILE=/etc/voicer/config pm2 start voicer
elif [ "$1" = "stop" ] ; then
    pm2 stop voicer
elif [ "$1" = "restart" ] ; then$0 stop
    sleep 5
    $0 start

Well, activate it:

systemctl daemon-reload
systemctl enable voicer
systemctl start voicer

It should be noted that voicer will add the recorded files to the / tmp folder and it would be nice to clean it periodically. Create a simple script for this and add it to /etc/cron.daily


rm /tmp/*.wav

Well, now there is a more difficult part - to configure asterisk itself. Since we already have PBX and all clients use it, we do not need most of the configuration. We delete (or store in a dark cool dry place — optional) from the / etc / asterisk folder everything except asterisk.conf, modules.conf and sip.conf. And we add the sip.conf configuration in the following lines, adding the values ​​we need for:

  • fromdomain - server address with asterisk
  • host - PBX address
  • fromuser: secret and defaultuser: remotesecret - login: password pairs that are exchanged between asterisk and PBX


Here you should pay attention to the mode in which the dtmf commands work in your PBX. Consider that they can be processed by different methods for external calls of PBX (for example, from the city or from a mobile phone) and internal calls between subscribers of your PBX. In my case, in the first version it was inband dtmf signals, in the second - rfc2833. But auto handled it. Also, you can expect interesting features of interaction with your PBX - you will have to find out by personal experience what is required, for example, to save caller ID of the calling (external) subscriber when returning a call from IVR to PBX (sendrpid line).

And there was one more configuration file. The most important. Dialplan, he's extensions.conf. In it, you definitely need to specify your external number (which people will call), the secretary’s number (which will take the default calls) and the way to your voice prompts.

exten => ВАШ_ВНЕШНИЙ_НОМЕР,1,Goto(ivr_tree,s,1)
;allow direct dialing to internal users
exten => _40XX,1,Background(custom/common/SoedinyauVas)
;check user voice existance
same => n,Set(exists=${STAT(e,${ASTDATADIR}/sounds/custom/${EXTEN}.vox)})
same => n,Playback(custom/${IF($[ ${exists} = 1 ] ? ${EXTEN} : Sotrudnik)})
same => n,Transfer(SIP/${EXTEN}@АДРЕС_СТАНЦИИ)
;start intro
exten => s,1,Answer()
same => n,Set(CHANNEL(language)=ru)
same => n,Background(custom/common/Welcome)
;start recognition
same => n,AGI(agi://localhost:3000)
same => n,GotoIf($[${RECOGNITION_RESULT}=SUCCESS]?:default)
same => n,Background(custom/common/SoedinyauVas)
;check user voice existance
same => n,Set(exists=${STAT(e,${ASTDATADIR}/sounds/custom/${RECOGNITION_TARGET}.vox)})
;play user name or default name
same => n,Playback(custom/${IF($[ ${exists} = 1 ] ? ${RECOGNITION_TARGET} : Sotrudnik)})
same => n,Hangup()
;default route
same => n(default),Transfer(SIP/4001@АДРЕС_СТАНЦИИ)

This example uses entries with a greeting, employee names, and the phrase “connect you.” At the same time, a hint for an employee is searched by his number, and if it is not there, it is simply pronounced “with an employee”. I recommend these kind of hints to order studios - speech synthesis systems, alas, are not perfect and their pronunciation of your company name and the names of the employees is only suitable for entertainment. 40XX - numbers in the company, 4001 - secretary.

The peculiarity of this situation is that our PBX deals with calls. Thus, instead of the usual Dial command, we use the Transfer command - and then the incoming call after the IVR completely leaves the asterisk and releases the PBX sip channels (their number is often fixed by the license). In most cases, the Transfer team is advised to use the name of the direction (main_link), but for my PBX it was only a direct indication of the station address.

It's time to add users to the recognition system. To do this, go to the address of our server and port 3100, after which we register there the names, surnames and numbers of employees.

Now our asterisk can receive incoming calls, recognize DTMF signals, recognize employees and redirect to their internal numbers. It remains only to convince the station that it needs to send incoming calls to our server. Depending on the manufacturer, these settings may be completely diverse, but the desired path will contain the words ARS and call routing. But that's another story.

Also popular now: