Simplifying Frequently Changing IVR Menus in Asterisk 1.8

Many organizations use IVR menus in their phone systems. Certainly we've all heard something like "Thank you for calling Robert Morris University. Please press...". One inherent problem with these menus is that they're generally not easy to maintain -- especially the ones that change frequently. The people that have "control" over these menus generally are able to record new files, but the replacement of the sound files is often a manual process.

Using astdb (or any other database engine asterisk can talk to), the process of managing frequently changing sound files can be simplified.

Using some code snippets I found on the web, along with some of my own brain power, I've put together this early working version of a simple IVR menu changing application. Essentially how it works is each sound file in the menus are assigned an ID and passcode. Every user who can record new sound files also is given a username and password in the "ariusers" context in Voicemail.conf. After authenticating as an allowed user, they then must enter the ID and password of the sound file they'd like to change. When recording is finished, the user is able to listen back at the new sound file, accept it, or rerecord it. After that, they're prompted whether or not they'd like to change another file. If not, the system says thank you and hangs up. On hangup it moves the temp audio file into the right place with the right name that is already referenced in the dialplan.

You'll want to insert two kinds of values into the Asterisk database. Auth values and name values. Example:

asterisk -r -x 'database put recname 64101 isc_64101_thankyou'; sleep 1;
asterisk -r -x 'database put recauth 64101 1234'; sleep 1;

Once your values are inserted and matched to sound files, here's the dialplan code to make this work. Any questions or comments, please post them.

[globals]
; Must be writable by the user running the asterisk process... usually "asterisk"
CUSTOM_RECORDINGS=/var/lib/asterisk/sounds/en/custom

; Somewhere in the dialplan
exten => 5000,1,Gosub(RecordPrompt,${EXTEN},1)

; The special subroutine that makes this all work
[RecordPrompt]
; Handles extension changes over time
exten => _[A-Za-z0-9].,1,NoOp()

; Can this user even use this feature?
same => n,Read(UserID,custom/welcome-user-id);
same => n,VMAuthenticate(${UserID}@ariusers,s);

; Get which message they want to change
same => n(getmessage),Read(MessageID,custom/enter-message-id,5,,,1)
same => n,Read(MessagePWD,custom/enter-message-pwd,4)
same => n,Set(ValidMessagePWD=${DB(recauth/${MessageID})})
same => n,GotoIf($['${MessagePWD}' = '${ValidMessagePWD}']?prerec)
same => n,Playback(option-is-invalid)
same => n,Goto(getmessage)

; This will be our filename
same => n(prerec),Set(RecordedFilename=${DB(recname/${MessageID})})
same => n,Set(RandomNumber=${RAND()})

; Record the prompt
same => n(record),Playback(custom/say-message)
same => n,Wait(1)
same => n,Record(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)

; Ask how we want to handle the recording
same => n(handle_recording),Read(ActionItem,vm-review,1)

; Verify we got values we expect
same => n,GotoIf($['${ActionItem}' = '1' | '${ActionItem}' = '2' | '${ActionItem}' = '3']?valid_action)
same => n,Playback(option-is-invalid)
same => n,Goto(handle_recording)

same => n(valid_action),NoOp()
; Handle the recording
; 1 accept, 2 review, 3 re-record
same => n,GotoIf($['${ActionItem}' = '1']?accept) ; keep this recording
same => n,GotoIf($['${ActionItem}' = '3']?record)   ; re-record it

; If we get here they pressed 2
same => n,Playback(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber})
same => n,Goto(handle_recording)

; Recording accepted, move from tmp to permanent
same => n(accept),Verbose(2,Recording accepted!)
same => n,System(mv ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav ${GLOBAL(CUSTOM_RECORDINGS)}/${RecordedFilename}.wav)
same => n,Playback(custom/message-updated)

; Do they want to rerecord another message?
same => n(recordanother),Read(RecordAnother,custom/record-another,1)
same => n,GotoIf($['${RecordAnother}' = '1']?getmessage)
same => n,Playback(option-is-invalid)
same => n,Goto(recordanother)

; On hangup remove the tmp file
exten => h,1,Verbose(2,Cleanup the file)
same => n,System(rm -f ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)

3052 views and 0 responses