Asterisk Speech-Enabled Call Router in Dialplan

A common application in building speech applications for Asterisk is the call router, which asks a user to speak the name of a person and then dial that person's name. This very simple example performs that functionality. Developers should be familiar with basic speech recognition concepts such as writing grammars and interacting with the Asterisk speech dialplan applications like MRCPRecog.

For the sound files used by this application, please download the attached zip file that includes source code, grammars, and the audio prompts. The audio prompts should be placed in your Asterisk sounds directory.

Grammars

The following two grammars are used in the application:

yesno.gram

This grammar allows for some simple yes/no type phrases.

#ABNF 1.0 UTF-8;
language en-US;
mode voice;
tag-format <semantics/1.0>;

root $yesorno;

$yesorno = ($yes|$no){out=rules.latest()};

$yes = (yes [please]|yeah){out="yes"};
$no = (no [thanks] | nope){out="no"};

directory.gram

This grammar contains the list of names that can be spoken and returns an extension when a name is matched:

#ABNF 1.0;
language en-US;
mode voice;
tag-format <semantics/1.0>;
root $company_directory;

$tom = (Tom [Smith]) {out="990"};
$joe = ((Joe | Joseph) [Jones]) {out="991"};
$bob = ((Bob | Robert | Bobby) [Johnson]) {out="992"};

$company_directory = ($tom | $joe | $bob ) {out = rules.latest()};

Dialplan

The dialplan that performs the call routing functionality is:

[voice-callrouter]

exten => s,1,Answer()

; The THRESHOLD variable stores the confirmation threshold that will be used. 
; If the confidence score for an answer is lower than this number, the
; caller will be asked to confirm themselves.
exten => s,n,Set(THRESHOLD=0.65)

; Invoke ASR using MRCPRecog. Be sure the grammar file below exists on disk and that
; you have the sayname sound file in your sounds directory. We also set the timeout to
; 5 seconds, and the confidence threshold (different from the confidence threshold above)
; to 0.4, meaning if the confidence is below 0.4, the ASR will return a no-match.
exten => s,n(Sayname),MRCPRecog(/etc/asterisk/grammars/directory.gram,f=sayname&t=5000&ct=0.4)

; After MRCPRecog returns, we check for an error.
exten => s,n,GotoIf($[ "${RECOGSTATUS}" = "ERROR"]?Error)

; Otherwise we check RECOG_COMPLETION_CAUSE to see whether we got a match, no-match,
; or no-input result.
exten => s,n,GotoIf($[ "${RECOG_COMPLETION_CAUSE}" = "000"]?InputOK) 
exten => s,n,GotoIf($[ "${RECOG_COMPLETION_CAUSE}" = "001"]?BadInput)

; In the event that we got no input, we play the No Input prompt and return to the start.
exten => s,n,Playback(NI)
exten => s,n,Goto(Sayname)

; If we got a match, store the recognized extension in the DIALTHIS variable. We save this
; because we may ask the user to confirm, and in that case the value of RECOG_INSTANCE
; may change after another recognition attempt.
exten => s,n(InputOK),Set(DIALTHIS=${RECOG_INSTANCE(0/0)})
exten => s,n,Verbose(1,The recognized extension was ${RECOG_INSTANCE(0/0)})
exten => s,n,Verbose(1,The score was ${RECOG_CONFIDENCE(0)})
exten => s,n,Verbose(1,The confidence threshold is ${THRESHOLD})

; We compare the returned confidence to the THRESHOLD. If it's higher, we will dial the name
exten => s,n,GotoIf($[ ${RECOG_CONFIDENCE(0)} {>} ${THRESHOLD} ]?Dial)

; Otherwise, we will be launching the confirmation macro and passing in the recognized extension.
exten => s,n,Macro(confirm,${RECOG_INSTANCE(0/0)})

; Return from the macro and check if they said yes or no. Yes means dial, no
; means go back to the start.
exten => s,n,GotoIf($[ "${RECOG_INSTANCE(0/0)}" = "yes"]?Dial:Sayname)

; If we got a no-match we play the no-match prompt and go back to the start.
exten => s,n(BadInput),Playback(didnotunderstand)
exten => s,n,Goto(Sayname)

; If everything worked, we dial the recognized variable.
exten => s,n(Dial),Goto(${DIALTHIS},1)

; Gets called if there was an error. At this point in a real application, you might
; consider falling back to DTMF or transferring to an operator.
exten => s,n(Error),Verbose(1,There was an error initializing ASR)
exten => s,n,Hangup

; Here are the different extensions that can be dialed.
exten => 990,1,Verbose(1,You called Tom Smith)
exten => 990,n,Playback(tomsmithgreeting)
exten => 990,n,Hangup

exten => 991,1,Verbose(1,You called Joe Jones)
exten => 991,n,Playback(joejonesgreeting)
exten => 991,n,Hangup

exten => 992,1,Verbose(1,You called Bob Johnson)
exten => 992,n,Playback(bobjohnsongreeting)
exten => 992,n,Hangup

; The confirmation macro asks the user if they wanted to speak with the
; recognized person.
[macro-confirm]

; Argument 1 is the recognized extension; this gets us confirm+extension
; which is how our confirmation prompts are named. E.g. "Tom Smith" is a file
; called confirm990.gsm, so if "Tom Smith" was reocgnized, CONFIRMPROMPT is confirm990
exten => s,1,Set(CONFIRMPROMPT=$[confirm${ARG1}])

; Play a prompt that says "Did you want to speak with?"
exten => s,n(PlayConfirm),Playback(didyouwant)

; And start speech recognition with the
exten => s,n,MRCPRecog(/etc/asterisk/grammars/yesno.gram,f=${CONFIRMPROMPT}&t=5)

; Make sure we got a match.
exten => s,n,GotoIf($[ "${RECOG_COMPLETION_CAUSE}" = "000"]?EndConfirm)
exten => s,n,Playback(NI)
exten => s,n,Goto(PlayConfirm)

; Exit the macro.
exten => s,n(EndConfirm),NoOp();

Sample Type

Software Type