Interactive voice response menus Implementing a simple 'push-1, push-2' menu structure The key to creating this menu is to create an Extension (defined as 205 below) to record your menu prompts. This will put the sound file in /tmp/asterisk-recording.gsm. You'll have to move that file each time its created to /var/lib/asterisk/sounds and rename it to something pertinent to your design so it can be called from the dial-plan. Notice the line under [mainmenu] exten => s,5,Background(sai-welcome). The sai-welcome is one of those .gsm sound files. The rest of the dial-plan just defines what happens when each option is pushed. If you want to be able to have regular users update the voice prompts, see asterisk tips phrase recording menu. extensions.conf [mainmenu] exten => s,1,Answer exten => s,2,SetMusicOnHold(default) exten => s,3,DigitTimeout,5 exten => s,4,ResponseTimeout,10 ;SAI menu - 1 for tech support, 2 for voicemail, 3 for echo test exten => s,5,Background(sai-welcome) exten => s,6,Background(sai-choose) ; Tech Support exten => 1,1,AGI(dima-test.agi) exten => 1,2,SetGlobalVar(ACCOUNTCODE=${callerid}) exten => 1,3,SetVar(testcallerid=${callerid}) exten => 1,4,Background(sai-reptech-welcome) exten => 1,5,Queue(rep-tech) ; Leave Voicemail exten => 2,1,VoicemailMain() exten => 2,2,Hangup ; Echo Test exten => 3,1,Playback(demo-echotest) exten => 3,2,Echo exten => 3,3,Playback(demo-echodone) exten => 3,4,Goto(mainmenu,s,6) ; EAGI Test exten => 4,1,Answer() exten => 4,2,Wait(1) exten => 4,3,AGI(sai-repid.agi) exten => 4,4,Wait(1) exten => 4,5,Hangup ; Play Music-on-Hold exten => 5,1,MusicOnHold(default) exten => 5,2,Goto(mainmenu,s,6) ; #=hangup exten => #,1,Playback(sai-thanks) exten => #,2,Hangup exten => t,1,Goto(#,1) ; If they take too long, give up exten => i,1,Playback(invalid) ; "That's not valid, try again" [default] include => mainmenu include => local include => longdistance include => joe-iax include => npi-iax ; Record voice file to /tmp directory exten => 205,1,Wait(2) ; Call 205 to Record new Sound Files exten => 205,2,Record(/tmp/asterisk-recording:gsm) ; Press # to stop recording exten => 205,3,Wait(2) exten => 205,4,Playback(/tmp/asterisk-recording) ; Listen to your voice exten => 205,5,wait(2) exten => 205,6,Hangup Implementing a high-density without wearing out your keyboard Now consider an information delivery IVR, such as a bus schedule. The basic call flow goes something like: Hear initial greeting Hear root menu Descend into to menu 1 Descend into to submenu 2 Play information message at option 4 Return to submenu 2 Descend into to submenu 7 Return to root menu {and so on...} The schedule that prompted creation of this code has 136 possible menu/message combinations. [transit-ivr] exten => s,1,Answer exten => s,2,SetVar(ivrflag=transit) ; Unused at the moment exten => s,3,Background(transit-ivr/grtg-3) ; Play the initial greeting (interruptable) exten => s,4,Goto(transit-ivrmain,s,1) ; Start the menuing system after the message completes exten => _x,1,Goto(transit-ivrmain,s,1) ; Start the menuing system if the user presses any key during the greeting [transit-ivrmain] exten => s,1,NoOp(s,1 - Has ${digitstack} in the digitstack) exten => s,2,GotoIf($[${LEN(${digitstack})} = 0]?s-restart,1) ; If there is nothing in the stack at all then restart the stack exten => s,3,System(/var/lib/asterisk/sounds/transit-ivr/filexists /var/lib/asterisk/sounds/transit-ivr/${digitstack}.gsm) ; test for the existance of this path as a recording exten => s,4,Background(transit-ivr/${digitstack}) exten => s,5,NoOp() ; insert padding to offset s,9 so it in turn is offset cleanly enough for it's n+101 jump exten => s,6,NoOp() exten => s,7,NoOp() exten => s,8,NoOp() exten => s,9,System(/var/lib/asterisk/sounds/transit-ivr/filexists /var/lib/asterisk/sounds/transit-ivr/${digitstack}?.gsm) ; test for the existance of additional recordings underneath the current path exten => s,104,NoOp(we should warn the user they chose an invalid option...) ; Relative to s,3 exten => s,105,SetVar(digitstack=${digitstack:0:$[${LEN(${digitstack})} - 1]}) exten => s,106,Goto(s,1) exten => s,110,NoOp(there aren't any menus below this one, so go back up one level) ; Relative to s,9 exten => s,111,SetVar(digitstack=${digitstack:0:$[${LEN(${digitstack})} - 1]}) exten => s,112,Goto(s,1) exten => s-restart,1,SetVar(digitstack=0) exten => s-restart,2,Goto(s,1) ; Capture keypresses exten => _X,1,SetVar(digitstack=${digitstack}${EXTEN}) exten => _X,2,GotoIf($[${digitstack:$[${LEN(${digitstack})} - 1],1} = 8]?_X,10) exten => _X,3,Goto(s,1) exten => _X,10,SetVar(digitstack=${digitstack:0:$[${LEN(${digitstack})} - 2]}) ; Eight pops two digit off the stack... (including the 8 itself) exten => _X,11,Goto(s,1) '.../transit-ivr/filexists' is a bash script containing: #!/bin/bash # Test for the existance of files based on shell globbing patterns for a in $1; do if [ -f $a ] ; then # there are one or more files that match; exit; else # there aren't any files that match; exit 1; fi; done; Finally, the folder '.../transit-ivr/' contains a collection of .gsm recordings named according to their 'dialing path', thus: 8192 Aug 27 00:53 . 20480 Aug 27 00:53 .. 54285 Aug 25 22:46 0.gsm This is the root menu 66429 Aug 25 22:47 01.gsm This is menu 1 off of the root 17556 Aug 25 22:46 02.gsm This is menu 2 off of the root 17292 Aug 25 22:44 023.gsm This is informational recording 3 off of menu 2 off of the root 115533 Aug 25 22:48 03.gsm This is menu 3 off the root {and so on...} When creating the recordings, any recording that doesn't have another recording 'below' it in 'dialing path' is implicity an informational recording (a leaf on the tree). To work backwards up the tree 8 (or any other key) has to be assigned to 'go back to the previous menu'. Other global keys such as 'exit to operator' and 'end call/hangup' can be assigned similarly using dialplan logic. The next refinement to this model would be to add a filename suffix parser to be able to embed jumps, transfers and out-dials inside the tree by encoding them into the filenames (ie. 029x1235551212.gsm). All of this should be painfully familiar if you've worked with Nortel Norstar NAM3 based StarTalk IVRs before. Advanced IVR Menu Here is a more advanced IVR application that is assumed you know how it works. I found this example in a newsgroup but I don't have the url to reference. It was very helpful for me to see this type of setup different from the ones provided above. This shows the flow between multiple IVR menus and how to control and display the information. I will show the basics of the IVR. [deeper] exten => s,1,Background(demo-nomatch) ;exten => s,1,AGI(festival-script.pl|"deeper menu") exten => s,2,Goto,options|s|1 [options] exten => s,1,Background(demo-instruct) ;exten => s,1,AGI(festival-script.pl|"options menu") exten => 1,1,Goto,deeper|s|1 exten => 2,1,Goto,sales|s|1 [sales] exten => s,1,Background(demo-thanks) ;exten => s,1,AGI(festival-script.pl|"sales menu") exten => 0,1,Goto,from-sip|1000 exten => 1,1,Goto,Menu|s|1 [Menu] exten => s,1,Background(demo-congrats) ;exten => s,1,AGI(festival-script.pl|"menu menu") exten => 1,1,Goto,sales|s|1 exten => 2,1,Goto,options|s|1 exten => i,1,Goto,s exten => t,1,Goto,s ;The specific method to enter the menu is up to you but I used my sip phone to test. [from-sip] exten => 100,1,Answer exten => 100,2,Goto,Menu|s|1 If you have sip configured this should work out of the box. I am not sure if it requires that you have the sample installed to have the default sound files but this is what i have setup above. If you have festival configured on the box then you can use the commented out lise for the festival-script.pl which does not require the running festival server but rather just have the binaries in the path. The important piece that I really didn't realize on this site is the Goto that allow you to go to a context which was a simple piece that I was missing"exten => 100,2,Goto,Menu|s|1" or "exten => 100,2,Goto(Menu,s,1)". So each menu is a context and I can move back and forth through each one for a more advanced IVR setup. Here is a portion of that listed above that accepts the call and plays the message. And accepts a 1 or 2 as menu options to change the option. When the 1 is pressed then the IVR will go to the sales context and when the 2 is pressed then I will go to the options context. [Menu] exten => s,1,Background(demo-congrats) exten => 1,1,Goto,sales|s|1 exten => 2,1,Goto,options|s|1 This may have been clear but from my reading I missed it and thought it should be added to the site. See Also * Asterisk tips phrase recording menu * Asterisk tips and tricks * Dialplan Extension Matching * The Dialplan - extensions.conf * Commands: Playback | Record | DigitTimeout | ResponseTimeout | Wait