P ROGETTO V.O.C.I. HOWTO IVR RUBRICA TELEFONICA E MENU DI GESTIONE DELLE CHIAMATE N O M E F I L E: Asterisk_IVR_Rubrica_e_Menu_Gestione_Chiamate.doc D A T A: 15/09/2009 A T T I V I T À: S T A T O: U R L: AUTORE/ I : Gruppo VoIP ABSTRACT: Il presente documento contiene l howto relativo all implementazione di un IVR, di una rubrica telefonica e di un menù di selezione basato su IVR per la gestione automatizzata delle chiamate. ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 1/14
INDICE INTRODUZIONE... 3 1. IMPLEMENTAZIONE DI UN IVR... 4 2. IMPLEMENTAZIONE DI UNA RUBRICA TELEFONICA CON SELEZIONE DEL DESTINATARIO IN FORMA DI IVR PER LA PRESENTAZIONE DI CONTATTI MULTIPLI... 9 3. IMPLEMENTAZIONE DI UN MENU DI GESTIONE DELLE CHIAMATE... 12 ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 2/14
INTRODUZIONE Il documento contiene l howto relativo all implementazione di un IVR, di una rubrica telefonica e di un menù di selezione basato su IVR per la gestione automatizzata delle chiamate. Un IVR (Interactive Voice Response) consente di definire delle strutture in forma di menù di selezione per la gestione automatizzata delle chiamate ad esempio in caso di mancata registrazione SIP del chiamato o in caso di mancata risposta alle chiamate entranti. E possibile creare degli IVR usando le applicazioni disponibili in Asterisk oppure definendone nuove. Gli IVR possono essere composti da contesti oppure solo da estensioni. Le configurazioni allegate possono essere applicate alle release Asterisk 1.2.X, 1.4.X, 1.6.X. ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 3/14
1. IMPLEMENTAZIONE DI UN IVR La combinazione dei contesti e delle funzioni native di Asterisk si presta alla generazione di strutture definite tradizionalmente risponditori automatici. Si tratta, nell esempio realizzato, di una disposizione ad albero comprensiva di due sezioni: una appositamente creata per la lingua inglese, l'altra per l'italiano. In ciascun "sottomenu" sono state previste cinque funzionalità come illustrato in Figura 1. Questo è un esempio di IVR realizzato nella Direzione GARR; i pattern ed i file audio sono stati creati appositamente. Occorre precisare che in questo howto è contenuta anche una implementazione per le opzioni evidenziate in rosso presenti nell albero di Figura 1. Figura 1 Struttura del menù IVR Per fini grafici le sottovoci 3.Ora di sistema, 4.Registrazione e riproduzione frase, 5.per test eco, sono state raggruppate, relativamente alla sezione Inglese in un unico macro blocco. Sono possibili varie soluzioni di conversione "text-to-speech" allo scopo di creare audio guide per la notifica al chiamante delle tipologie di servizi disponibili e dei relativi numeri di accesso ad essi associati. L introduzione di audio, all interno del menu IVR, è stata eseguita testando la soluzione Festival. Si tratta di un sintetizzatore Text to Speech sviluppato dalla Soluzione alternativa, è stata la registrazione tramite Asterisk di audio prodotto da sintetizzatori esterni. Nel dialplan è possibile inserire la seguente porzione di codice. exten => 300,1,Record(/tmp/asterisk-recording%d:gsm); press # to stop recording exten => 300,n,Wait(2) exten => 300,n,Hangup() Tabella 1 Estratto del file extensions.conf ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 4/14
Con essa è possibile eseguire la registrazione di audio con formato gsm. Il bisogno di registrare più di un messaggio, ha giustificato l introduzione della opzione %d nel nome del file creato da Asterisk, contenente l audio rilevato. Si introduce, in questo modo, una sezione automaticamente aggiunta costituita da un numero progressivo, all interno del nome file. L introduzione di istruzioni playback(path del file) all interno dell IVR oppure background(path del file) permette l impiego dei file precedentemente creati. La differenza consiste nella possibilità, permessa dalla funzione background, di digitare toni durante l ascolto. In Tabella2 è allegato l estratto del file extensions.conf relativo all IVR. [IVR menu] include => full-capabilities ;menu - 1 ITALIANO, 2 INGLESE exten => 3098,1,Verbose("${SIPDOMAIN}dominio,${ASTERISK_IP},ipasterisk,"${SIPDOMAIN}"="${ASTERIS K_IP}" "${SIPDOMAIN}"="${ASTERISKBal_IP}" "${SIPDOMAIN}"="${ASTERISK_IPVOIP1}", "${SIPDOMAIN}"="${ASTERISK_Domain}" "${SIPDOMAIN}"="${ASTERISKBal_Domain}" "${ SIPDOMAIN}"="${Asterisk_DomainVOIP1}" "${fromh323}"="true"i") exten => 3098,n,GotoIf($["${SIPDOMAIN}"="${ASTERISK_IP}" "${SIPDOMAIN}"="${ASTERISKBal_IP}" "${SIPDOMAIN}"="${ASTERISK_IPVOIP1}" "${SIPDOMAIN}"="${ASTERISK_Domain}" "${S IPDOMAIN}"="${ASTERISKBal_Domain}" "${SIPDOMAIN}"="${Asterisk_DomainVOIP1}" "${fr omh323}"="true" "${DaPSTN}"="true"]?channeldial6:uridial6) exten => 3098,n(channeldial6),Set(CHANNEL(language)=it) exten => 3098,n,Answer() exten => 3098,n,Playback("beep") exten => 3098,n,Background(/root/applicativiAsterisk/Suoni/scelta1itintro) exten => 3098,n,Background(/root/applicativiAsterisk/Suoni/scelta1itintroIT) exten => 3098,n,Background(/root/applicativiAsterisk/Suoni/scelta1itintroEN) exten => 3098,n,WaitExten() exten => 3098,n,Verbose(1 "IVR menu principale") exten => 3098,n(uridial6),Macro(uridial,${EXTEN}@${SIPDOMAIN}) exten => t,1,goto(ivr menu,3098,1) exten => 1,1,Goto(IVR menu IT,300,1) exten => 2,1,Goto(IVR menu EN,400,1) [IVR menu IT] include => full-capabilities ;include => VoiceMail exten => 300,1,Set(CHANNEL(language)=it) ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 5/14
exten => 300,n,Background("beep") exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/salve) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/scelta1itintro) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/uno) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/due) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/tre) exten => 300,n,Playback(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/quattro) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/stopreg) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/cinque) exten => 300,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/it/sei) exten => 300,n,Verbose(1 "IVR menu ITALIANO") exten => 300,n,WaitExten() ;Interno exten => 1,1,Background("vm-enter-num-to-call") exten => 1,n,Playback("beep") exten => 1,n,WaitExten() ;Directory ;exten => 2,1,Macro(dialbyname,"b") ;b = chiamata per cognome [prime tre lettere] exten => 2,1,Macro(dialbynameIVR,"b") exten => 2,n,Playback("beep") exten => 2,n,Background("auth-tankyou") exten => 2,n,Goto(IVR menu300,1) ;Ora Esatta exten => 3,1,SayUnixTime() exten => 3,n,Background("auth-thankyou") exten => 3,n,Goto(IVR menu,300,1) ;record exten => 4,1,Wait(2) ; Record new Sound Files exten => 4,n,Record(/tmp/asterisk-recording:gsm) ; Press # to stop recording exten => 4,n,Wait(2) exten => 4,n,Playback(/tmp/asterisk-recording) ; Listen to your voice exten => 4,n,wait(2) exten => 4,n,Goto(IVR menu,300,1) ;Echo Test exten => 5,1,Echo() exten => 5,n,Wait(10) exten => 5,n,Hangup() ; cattura comportamenti differenti dai previsti exten => t,1,goto(ivr menu IT,300,1) ; in caso di timeout ( t ) exten => 6,1,Background("auth-thankyou") ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 6/14
exten => 6,n,Hangup() ;************************************************************************ [IVR menu EN] include => full-capabilities ;include => VoiceMail exten => 400,1,Set(CHANNEL(language)=en) exten => 400,n,Playback("beep") exten => 400,n,Verbose(1 "IVR menu INGLESE") exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/hi) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/one) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/two) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/three) exten => 400,n,Playback(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/four) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/stopregen) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/five) exten => 400,n,Background(/root/applicativiAsterisk/Suoni/SUONIDIALPLAN/suoniIVR/en/six) exten => 400,n,WaitExten() ;Interno exten => 1,1,Background("enter-ext-of-person") exten => 1,n,Playback("beep") exten => 1,n,WaitExten() ;Director exten => 2,1,Set(CHANNEL(language)=en) exten => 2,n,Set(GLOBAL(in_inglese)=yes) exten => 2,n,Macro(dialbynameIVR,"b") exten => 2,n,Background("auth-tankyou") exten => 2,n,Goto(IVR menu300,1) ;Ora Esatta exten => 3,1,SayUnixTime() exten => 3,n,Background("auth-thankyou") exten => 3,n,Goto(IVR menu,400,1) ;record exten => 4,1,Wait(2) ; Record new Sound Files exten => 4,n,Record(/tmp/asterisk-recording:gsm) ; Press # to stop recording exten => 4,n,Wait(2) exten => 4,n,Playback(/tmp/asterisk-recording) ; Listen to your voic exten => 4,n,wait(2) exten => 4,n,Goto(IVR menu,400,1) ;Echo Test exten => 5,1,Echo() ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 7/14
exten => 5,n,Wait(10) exten => 5,n,Hangup() ; cattura comportamenti differenti dai previsti exten => t,1,goto(ivr menu EN,400,1) ; in caso di timeout ( t ) exten => 6,1,Playback("auth-thankyou") exten => 6,n,Hangup() Tabella 2 IVR introdotto nel file extensions.conf ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 8/14
2. IMPLEMENTAZIONE DI UNA RUBRICA TELEFONICA CON SELEZIONE DEL DESTINATARIO IN FORMA DI IVR PER LA PRESENTAZIONE DI CONTATTI MULTIPLI Nella sezione precedente è presente la funzione Directory. Essa consente di chiamare un estensione digitando le prime tre lettere del cognome della persona cercata. In caso di corrispondenza di più contatti telefonici con le lettere digitate, sono presentate in sequenza tutte le alternative disponibili. La selezione di quella desiderata va eseguita digitando il tasto 1. In caso contrario, è possibile proseguire digitando il tasto *.Questa funzione può essere usata al fin di creare un semplice IVR per la gestione di contatti legacy associati bi univocamente a contatti VoIP. La configurazione commentata in seguito consente ad Asterisk di presentare al chiamante gli interni fisso, VoIP associati al cognome desiderato invitando alla selezione di quello desiderato. A questo punto la chiamata prosegue secondo la selezione fornita. La configurazione è riferita alla struttura di Figura 2 ed è valida anche in presenza di connessioni dirette tra Asterisk e rete PSTN (Public Switched Telephone Network) con PBX (Private Branch Exchange) connesso alla PSTN (Public Switched Telephone Network) attraverso Asterisk. Figura 2 Architettura di riferimento In Figura 2 i telefoni legaci e quelli IP hanno numeri differenti solo per la prima cifra (es. per i legaci i numeri interni sono 2XXX e per gli IPPhone 3XXX ). La configurazione di Asterisk per implementare questa logica può richiedere la associazione tra l estensione chiamata dalla funzione Dialbyname ed una macro presente all interno del dialplan. Stabilito l utente desiderato tramite selezione del cognome, Asterisk genera una chiamata SIP verso l estensione telefonica associata, nel file voicemail.conf, alla coppia Nome Cognome scelta 1. Al fine di aggiungere una seconda fase di selezione del contatto telefonico, sono stati previsti nel dialplan un pattern ed una macro appositi. Il pattern é allegato in Tabella 2 1 Il file voicmemail.conf come spiegato nella sezione Segreteria telefonica e servizio email permette di associare: Cognome<->Nome Cognome<->numero di casella vocale<->pin<->indirizzo_email di ciascun utente. ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 9/14
exten => _1[05]XX,1,Verbose(1 "Call for ${DB(cidname/${EXTEN})}") exten => _1[05]XX,n,Set(GLOBAL(NumeroEstensione)=${EXTEN}) exten => _1[05]XX,n,Verbose(1 "Esecuzione interno") exten => _1[05]XX,n,GotoIf($["${SIPDOMAIN}"="${ASTERISK_IP}" "${SIPDOMAIN}"="${ASTERISKBal_I P}" "${SIPDOMAIN}"="${ASTERISK_IPVOIP1}" "${SIPDOMAIN}"="${ASTERISK_Domain}" "${SIPDOMAIN}"="${ASTERISKBal_Domain}" "${SIPDOMAIN}"="${Asterisk_DomainVOIP1}" "${fromh323}"="true" "${SIPDOMAIN}"="${ASTERISKBal_IP}" "${DaPSTN}"="true"]?channeld ialivr:uridial1) exten => _1[05]XX,n(channeldialIVR),Macro(channeldialIVR,${EXTEN}) exten => _1[05]XX,n,Hangup() exten => _1[05]XX,n(uridial1),Macro(uridial,${EXTEN}@${SIPDOMAIN}) Tabella 3 Pattern di redirezione dal servizio Dialbyname verso la macro di chiamata Il pattern cattura tutte le chiamate generate dalla funzione Directory. Le funzioni ad esso associate eseguono il controllo della componente SIPDOMAIN al fine di stabilire se la chiamata debba essere inoltrata verso server esterni. In caso di chiamata verso utenti interni, la chiamata é gestita invocando la macro channeldialivr allegata in Tabella 4. [macro-channeldialivr] exten => s,1,verbose(1 "Ingresso del sistema IVR ${ARG1}") exten => s,n,set(global(chiamato_ivr)=${arg1}) exten => s,n,verbose(1 "${in_inglese}") exten => s,n,gotoif($[${in_inglese}=yes]?en:it) exten => s,n(en),set(channel(language)=en) exten => s,n,background(/root/applicativiasterisk/suoni/internoen) exten => s,n,background(/root/applicativiasterisk/suoni/interno_fissoen) exten => s,n,saydigits(2${arg1:1}) exten => s,n,background(/root/applicativiasterisk/suoni/interno_voipen) exten => s,n,saydigits(3${arg1:1}) exten => s,n,background(/root/applicativiasterisk/suoni/selezionareen) exten => s,n,verbose(1 "$${chiamato_ivr}") exten => s,n,goto(gestioneutenzeivr,s,1) exten => s,n(it),background(/root/applicativiasterisk/suoni/interno) exten => s,n,background(/root/applicativiasterisk/suoni/interno_fisso) exten => s,n,saydigits(2${arg1:1}) exten => s,n,background(/root/applicativiasterisk/suoni/interno_voip) exten => s,n,saydigits(3${arg1:1}) exten => s,n,background(/root/applicativiasterisk/suoni/selezionare) exten => s,n,background(/root/applicativiasterisk/suoni/selezionare1) exten => s,n,verbose(1 "$${chiamato_ivr}") exten => s,n,goto(gestioneutenzeivr,s,1) exten => t,1,macro(channeldialivr,${arg1}) exten => i,1,hangup() [gestioneutenzeivr] exten => s,1,wait(1) ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 10/14
exten => s,n,background("beep") exten => s,n,waitexten() exten =>_[1 2],1,Goto(gestioneutenzeIVR,${EXTEN},1) exten => 1,1,Goto(full-capabilities,2${chiamato_IVR:1},1) exten => 2,1,Goto(full-capabilities,3${chiamato_IVR:1},1) Tabella 4 Macro di gestione delle chiamate provenienti dalla funzione dialbyname La macro genera le notifiche audio dei numeri telefonici associati alla estensione chiamata. Data la corrispondenza esistente tra i piani di numerazione fisso legacy e VoIP, gli interni sono automaticamente generati tramite espressioni parametriche. La gestione della chiamata prosegue sulla base della logica implementata nel contesto [gestioneutenzeivr]. In esso, sono previste due semplici redirezioni al contesto full-capabilities per l esecuzione delle Dial sui canali corrispondenti alla selezione legacy/voip eseguita dall utente. ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 11/14
3. IMPLEMENTAZIONE DI UN MENU DI GESTIONE DELLE CHIAMATE La gestione delle chiamate entranti nel sistema Asterisk può essere automatizzata prevedendo la presentazione di un menù di scelta al chiamante in caso di non disponibilità (utente non registrato, occupato, problemi sulla connessione VoIP) del chiamato. In Figura 3 é mostrato uno schema logico relativo alle interazioni definite, tramite IVR, tra il server Asterisk ed il chiamante con riferimento all architettura illustrata in Figura 2. La configurazione spiegata è un esempio di gestione delle chiamate entranti che può essere impiegato in presenza di piani di numerazione VoIP associati a numeri legacy PSTN come quello definito per la Direzione GARR nel quale esiste un associazione biunivoca tra gli interni legacy e quelli VoIP. Figura 3 Diagramma logico delle interazioni tra Asterisk ed il chiamante La variabile DialStatus è automaticamente compilata da Asterisk configurandola con il valore relativo allo stato della chiamata in corso. Il suo controllo risulta sufficiente per il livello di dettaglio proposto per l howto. [macro-chiama_interni] ;; ${ARG1} deve contenere il numero telefonico dell interno da chiamare Exten => s,1,verbose(1 Macro di gestione delle chiamate dirette agli interni ) exten => s,n,dial(sip/${arg1},20,t) exten => s,n,verbose(1 "valore dialedtime"${dialedtime}*********${dialstatus}) exten => s,n,gotoif($[${dialstatus}=noanswer ${DIALSTATUS}=CHANUNAVAIL]?s- NOANSWERorCHANUNAVAIL,1) exten => s,n,gotoif($[${dialstatus}=busy]?s-busy,1) exten => s,n,hangup() exten => s,n,macroexit() ; Accede al menu di selezione del comportamento da assumere nel caso in cui il chiamato non avesse risposto (lasciato squillare a vuoto) oppure sia non registrato ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 12/14
exten => s-noanswerorchanunavail,1,macro(selezioneinoltro,${arg2}) ; Accede alla voicemail riservata (utente occupato) exten => s-busy,1,voicemail(${arg1}@default,b) exten => s-busy,n,return Tabella 5 Estratto del file extensions.conf La configurazione del file extensions.conf allegata in Tabella 5 fa riferimento alla impostazione, presente per ciascun utente, all interno del file voicemail.conf descritto nel seguito (Segreteria telefonica e servizio e-mail). La macro di gestione in forma di IVR é allegata in Tabella2. Un IVR consente gestioni automatizzate delle chiamate entranti in seguito alla presentazione di un menù di selezione ed all acquisizione di una scelta. Sulla base di questa, il sistema avvia la esecuzione di una o più operazioni in forma automatizzata. La logica di implementazione di un IVR prevede quindi due sezioni: una prima dedicata alla presentazione delle voci di menù, la seconda di rilevazione e gestione della selezione ricevuta dall'utente. In questo howto sarà mostrato un esempio di IVR prodotto per la presentazione al chiamante di due sole opzioni relative alla prosecuzione della chiamata: 1. su segreteria telefonica, 2. su interno legacy. La gestione é riferita ad una macro. Si tratta di un contesto nel quale é definita una logica che può essere invocata da varie estensioni o contesti nel dialplan. [macro-selezioneinoltro] exten => s,1,verbose(1 "${ARG1}") exten => s,n,background("beep") exten => s,n,background(/root/applicativiasterisk/suoni/suonidialplan/suonigestione/primo) exten => s,n,background(/root/applicativiasterisk/suoni/suonidialplan/suonigestione/secondo) exten => s,n,background(/root/applicativiasterisk/suoni/suonidialplan/suonigestione/terzo) exten => s,n,set(global(internolegacy)=2${arg1:1}) exten => s,n,waitexten() exten =>_[1 2],1,Goto(gestioneutenze,${EXTEN},1) exten => t,1,macro(selezioneinoltro,${arg1}) exten => i,1,hangup() [gestioneutenze] exten => 1,1,Set(CHANNEL(language)=it) exten => 1,n,Verbose("1 ${vmbox}") exten => 1,n,Voicemail(${vmbox}@userAsterisk,u) exten => 1,n,Playback("auth-thankyou") exten => 1,n,Hangup() exten => 2,1,Dial(DAHDI/g1/${InternoLegacy},30,g) exten => 2,n,GotoIf($[${DIALSTATUS}=CONGESTION]?dial2:chiusura) exten => 2,n(dial2), Dial(SIP/${InternoLegacy}@secondary_SIP_server,40,kKtTg) exten => 2,n,Playback("auth-thankyou") ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 13/14
exten => 2,n(chiusura),Hangup() Tabella 6 Estratto del file extensions.conf relativo alla macro di gesitone in forma di IVR La macro allegata consente di presentare al chiamante un menù a due selezioni: 1. inoltro al servizio di segreteria telefonica, 2. chiamata dell'interno legacy associato al chimato. La implementazione presenta l'espressione 2${ARG1:1} con la quale dall'interno VoIP fornito alla macro in forma di argomento (${ARG1}), é calcolato il numero dell'interno legacy ad esso corrispondente. In questo howto si assume che al numero VoIP ${ARG1} sia biunivocamente associato quello legacy 2${ARG1:1}. Il contesto prevede inoltre un esempio di fallback su un eventuale server secondario nel caso in cui il canale DAHDI non potesse essere impegnato. Anche in questo caso, i file audio, le associazioni legacy-voip mostrate corrispondono alla configurazione prodotta in ambito del progetto V.O.C.I.; analoghi file vanno prodotti per la propria architettura ad esempio con sintetizzatori text to speech. ASTERISK_IVR_RUBRICA_E_MENU_GESTIONE_CHIAMATE 14/14