9780596517342
asterisk-IVR.html

Chapter 17. Interactive Voice Response

One day Alice came to a fork in the road and saw a Cheshire cat in a tree. “Which road do I take?” she asked.

“Where do you want to go?” was his response.

“I don’t know,” Alice answered.

“Then,” said the cat, “it doesn’t matter.”

--Lewis Carroll

In this chapter we will talk about IVR. If what you want is an automated attendant, we have written a chapter for that as well (Chapter 15, The Automated Attendant). The term IVR is often misused to refer to an automated attendant, but the two are very different things.[150]

What Is IVR?

The purpose of an Interactive Voice Response (IVR) system is to take input from a caller, perform an action based on that input (commonly, looking up data in an external system such as a database), and return a result to the caller.[151] Traditionally, IVR systems have been complex, expensive, and annoying to implement. Asterisk changes all that.

Caution

Asterisk blurs the lines between traditional PBXs and IVR systems. The power and flexibility of the Asterisk dialplan results in a system where nearly every extension could be considered an IVR in the traditional sense of the term.

Components of an IVR

The most basic elements of an IVR are quite similar to those of an automated attendant, though the goal is different. We need at least one prompt to tell the caller what the IVR expects from him, a method of receiving input from the caller, logic to verify that the caller’s response is valid input, logic to determine what the next step of the IVR should be, and finally, a storage mechanism for the responses, if applicable. We might think of an IVR as a decision tree, although it need not have any branches. For example, a survey may present exactly the same set of prompts to each caller, regardless of what choices the callers make, and the only routing logic involved is whether the responses given are valid for the questions.

From the caller’s perspective, every IVR needs to start with a prompt. This initial prompt will tell the caller what the IVR is for and ask the caller to provide the first input. We discussed prompts in the automated attendant in Chapter 15, The Automated Attendant. Later, we’ll create a dialplan that will allow you to better manage multiple voice prompts.

The second component of an IVR is a method for receiving input from the caller. Recall that in Chapter 15, The Automated Attendant we discussed the Background() and WaitExten() applications for receiving a new extension. While you could create an IVR using Background() and WaitExten(), it is generally easier and more practical to use the Read() application, which handles both the prompt and the capture of the response. The Read() application was designed specifically for use with IVR systems. Its syntax is as follows:

Read(variable[,filename[&filename2...]][,maxdigits][,option][,attempts][,timeout])

The arguments are described in Table 17.1, “The Read() application”.

Table 17.1. The Read() application

ArgumentPurpose
variable The variable into which the caller’s response is stored. It is best practice to give each variable in your IVR a name that is similar to the prompt associated with that variable. This will help later if, for business reasons or ease of use, you need to reorder the steps of the IVR. Naming your variables var1, var2, etc. may seem easy in the short term, but later in your life cycle it will make fixing bugs more difficult.
prompt A file (or list of files, joined together with the & character) to play for the caller, requesting input. Remember to omit the format extension on the end of each filename.
maxdigits The maximum number of characters to allow as input. In the case of yes/no and multiple choice questions, it’s best practice to limit this value to 1. In the case of larger lengths, the caller may always terminate input by pressing the pound key.
options s (skip)Exit immediately if the channel has not been answered.
i (indication)Rather than playing a prompt, play an indication tone of some sort (such as the dialtone).
n (noanswer)Read digits from the caller, even if the line is not yet answered.
attempts The number of times to play the prompt. If the caller fails to enter anything, the Read() application can automatically re-prompt the user. The default is one attempt.
timeout The number of seconds the caller has to enter his input. The default value in Asterisk is 10 seconds, although it can be altered for a single prompt using this option, or for the entire session by assigning a value using the dialplan function TIMEOUT(response).

Once the input is received, it must be validated. If you do not validate the input, you are most likely going to find your callers complaining of an unstable application. It is not enough to handle the inputs you are expecting; you also need to handle inputs you do not expect. For example, callers may get frustrated and dial 0 when in your IVR; if you’ve done a good job, you will handle this gracefully and connect them to somebody who can help them, or provide a useful alternative. A well-designed IVR (just like any program) will try to anticipate every possible input and provide mechanisms to gracefully handle that input.

Once the input is validated, you can submit it to an external resource for processing. This could be done via a database query, a submission to a URI, an AGI program, or many other things. This external application should produce a result, which you will want to relay back to the caller. This could be a detailed result, such as “Your account balance is…,” or a simple confirmation, such as “Your account has been updated.” We can’t think of any case where some sort of result returned to the caller is not required.

Sometimes the IVR may have multiple steps, and therefore a result might include a request for more information from the caller in order to move to the next step of the IVR application.

It is possible to design very complex IVR systems, with dozens or even hundreds of possible paths. We’ve said it before and we’ll say it again: people don’t like talking to your phone system, regardless of how clever it is. Keep your IVR simple for your callers, and they are much more likely to get some benefit from it.

IVR Design Considerations

When designing your own IVR, there are some important things to keep in mind. We’ve put together this list of some things to do, and things not to do in your IVR.

Do

  • Keep it simple.

  • Have an option to dial 0 to reach a live person.

  • Handle errors gracefully.

Don’t

  • Think that an IVR can completely replace people.

  • Use your IVR to show people how clever you are.

  • Try to replicate your website with an IVR.

  • Bother building an IVR if you can’t take numeric input. Nobody wants to have to spell her name on the dialpad of her phone.[152]

  • Force your callers to listen to advertising. Remember that they can hang up at any moment they wish.

Asterisk Modules for Building IVRs

The “front end” of the IVR (the parts that interact with the callers) can be handled in the dialplan. In theory, it might be possible to build an IVR system using the dialplan alone (perhaps with the astdb to store and retrieve data). In practice, your IVR is going to need to communicate with something external to Asterisk.

CURL

The CURL() dialplan function in Asterisk allows you to span entire web applications with a single line of dialplan code. We’ll use it in our sample IVR later in this chapter.

While you’ll find CURL() itself to be quite simple to use, the creation of the web application will require experience with web development.

func_odbc

Using func_odbc, it is possible to develop extremely complex applications in Asterisk using nothing more than dialplan code and database lookups. If you are not a strong programmer but are very adept with Asterisk dialplans and databases, you’ll love func_odbc just as much as we do. Check it out in Chapter 16, Relational Database Integration.

AGI

The Asterisk Gateway Interface is such an important part of integrating external applications with Asterisk that we gave it its own chapter. You can find more information in Chapter 21, Asterisk Gateway Interface (AGI).

AMI

The Asterisk Manager Interface is a socket interface that you can use to get configuration and status information, request actions to be performed, and get notified about things happening to calls. We’ve written an entire chapter on AMI, as well. You can find more information in Chapter 20, Asterisk Manager Interface (AMI).

A Simple IVR Using CURL

The GNU/Linux program cURL is useful for retrieving data from a URI. In Asterisk, CURL() is a dialplan function.

We’re going to use CURL() as an example of what an extremely simple IVR can look like. We’re going to request our external IP address from the website http://www.whatismyip.org.

Important

In reality, most IVR applications are going to be far more complex. Even most uses of CURL() will tend to be complex, since a URI can return a massive and highly variable amount of data, the vast majority of which will be incomprehensible to Asterisk. The point being that an IVR is not just about the dialplan; it is also very much about the external applications that are triggered by the dialplan, which are doing the real work of the IVR.

Before you can use CURL(), you have to ensure it is installed.

Installing the cURL Module

Installing cURL is easy. If it was not on your system when you last compiled Asterisk, after installing it you’ll need to recompile Asterisk so that it can locate the cURL dependencies and compile the func_curl.so module.

On CentOS:

$ sudo yum -y install libcurl-devel

On Ubuntu:

$ sudo apt-get install libcurl4-openssl-dev

The Dialplan

The dialplan for our example IVR is very simple. The CURL() function will retrieve our IP address from http://www.whatismyip.org, and then SayAlpha() will speak the results to the caller:

exten => *764,1,Verbose(2, Run CURL to get IP address from whatismyip.org)
    same => n,Answer()
    same => n,Set(MyIPAddressIs=${CURL(http://www.whatismyip.org/)})
    same => n,SayAlpha(${MyIPAddressIs})
    same => n,Hangup()

The simplicity of this is impossibly cool. In a traditional IVR system, this sort of thing could take days to program.

A Prompt-Recording Application

In Chapter 15, The Automated Attendant we created a simple bit of dialplan to record prompts. It was fairly limited in that it only recorded one filename, and thus for each prompt the file needed to be copied before a new prompt could be recorded. Here, we expand upon that to create a complete menu for recording prompts:

[prompts]
exten => s,1,Answer
exten => s,n,Set(step1count=0) ; Initialize counters

; If we get no response after 3 times, we stop asking
   same => n(beginning),GotoIf($[${step1count} > 2]?end)
   same => n,Read(which,prompt-instructions,3)
   same => n,Set(step1count=$[${step1count} + 1])

; All prompts must be 3 digits in length
   same => n,GotoIf($[${LEN(${which})} < 3]?beginning) 
   same => n,Set(step1count=0) ; We have a successful response, so reset our counters
   same => n,Set(step2count=0)

   same => n(step2),Set(step2count=$[${step2count} + 1])
   same => n,GotoIf($[${step2count} > 2]?beginning) ; No response after 3 tries

; If the file doesn't exist, then don't ask whether to play it
   same => n,GotoIf($[${STAT(f,${which}.wav)} = 0]?recordonly) 
   same => n,Background(prompt-tolisten)

   same => n(recordonly),Background(prompt-torecord)
   same => n,WaitExten(10) ; Wait 10 seconds for a response
   same => n,Goto(step2)

exten => 1,1,Set(step2count=0)
   same => n,Background(${which})
   same => n,Goto(s,step2)

exten => 2,1,Set(step2count=0)
   same => n,Playback(prompt-waitforbeep)
   same => n,Record(${CHANNEL(uniqueid)}.wav)

   same => n(listen),Playback(${CHANNEL(uniqueid)})
   same => n,Set(step3count=0)
   same => n,Read(saveornot,prompt-1tolisten-2tosave-3todiscard,1)
   same => n,GotoIf($["${saveornot}" = "1"]?listen)
   same => n,GotoIf($["${saveornot}" = "2"]?saveit)
   same => n,System(rm -f /var/lib/asterisk/sounds/${CHANNEL(uniqueid)}.wav)
   same => n,Goto(s,beginning)

   same => n(saveit),System(mv -f ${CHANNEL(uniqueid)}.wav ${which}.wav)
   same => n,Playback(prompt-saved)
   same => n,Goto(s,beginning)

In this system, the name of the prompt is no longer descriptive, but rather it is a number. This means that you can record a far greater variety of prompts using the same mechanism, but the tradeoff is that your prompts will no longer have descriptive names.

Speech Recognition and Text-to-Speech

Although in most cases an IVR system presents prerecorded prompts to the caller and accepts input by way of the dialpad, it is also possible to: a) generate prompts artificially, popularly known as text-to-speech; and b) accept verbal inputs through a speech recognition engine.

While the concept of being able to have an intelligent conversation with a machine is something sci-fi authors have been promising us for many long years, the actual science of this remains complex and error-prone. Despite their amazing capabilities, computers are ill-suited to the task of appreciating the subtle nuances of human speech.

Having said that, it should be noted that over the last 50 years or so, amazing advances have been made in both text-to-speech and speech recognition. A well-designed system created for a very specific purpose can work very well indeed.

Despite what the marketing people will say, your computer still can’t talk to you, and you need to bear this in mind if you are contemplating any sort of system that combines your telephone system with these technologies.

Text-to-Speech

Text-to-speech (also known as speech synthesis) requires that a system be able to artificially construct speech from stored data. While it would be nice if we could simply assign a sound to a letter and have the computer produce each sound as it reads the letters, the written English language is not totally phonetic.

While on the surface, the idea of a speaking computer is very attractive, the reality is that it has limited usefulness. More information about integration of text-to-speech with Asterisk can be found in Chapter 18, External Services.

Speech Recognition

As soon as we’ve convinced computers to talk to us, we will naturally want to be able to talk to them.[153] Anyone who has tried to learn a foreign language can begin to recognize the complexity of teaching a computer to understand words; however, speech recognition also has to take into account the fact that before a computer can even attempt the task of understanding the words, it must first convert the audio into a digital format. This challenge is larger than one might at first think. For example, as humans we are naturally able to recognize speech as distinct from, say, the sound of a barking dog or a car horn. For a computer, this is a very complicated thing. Additionally, for a telephone-based speech recognition system, the audio that is received is always going to be of very low fidelity, and thus the computer will have that much less information to work with.[154]

Asterisk does not have speech recognition built in, but there are many third-party speech recognition packages that integrate with Asterisk.

Conclusion

Asterisk has become extremely popular as an IVR platform. While the media only really pays attention to Asterisk as a “free PBX,” the reality is that Asterisk is quietly taking the IVR industry by storm. Within any respectable-sized organization, it is very likely that the Linux system administrators are using Asterisk to solve telecom problems that previously were either unsolvable or impossibly expensive to solve. This is a stealthy revolution, but no less significant for its relative obscurity.

If you are in the IVR business, you need to get to know Asterisk.



[150] We suspect this is because “IVR” is much easier to say than “automated attendant.”

[151] In contrast to an auto attendant, the purpose of which is to route calls.

[152] Especially if it’s something like Van Meggelen.

[153] Actually, most of us talk to our computers, but this is seldom polite.

[154] If the speech recognition has to happen from a cell phone in a noisy conference hall, it becomes near-impossible.

Site last updated on: September 27, 2011 at 10:30:41 AM PDT
Cover for Asterisk: The Definitive Guide

                        View 2 comments

                        1. Eames,Jay – Posted Nov. 15, 2010

                          "your account balance is ...", or it or it may return nothing more than

                          Duplication of "or it"

                          The author has indicated that the issue raised in this comment has been resolved.

                        2. Russell Bryant – Posted Nov. 24, 2010

                          Thanks! This has been fixed.

                          The author has indicated that the issue raised in this comment has been resolved.