Zwirtualizowana centrala głosowa na MikroTiku (Asterisk + rozpoznawanie mowy + metaROUTER)
Posted in Sieci komputerowe By Blogtech On Grudzień 10, 2019Od dłuższego czasu poszukiwałem rozwiązania, które umożliwiałoby szybko oraz niewielkim nakładem finansowym uruchamiać rozwiązanie centrali głosowej klientom biznesowym. Istnieją oczywiście na rynku rozwiązania, które spełniają moje wymagania dla nieskomplikowanych zastosowań – np. Slican ITS-0286, Platan Prima Mini i parę innych, ale przy głębszym zastanowieniu są one zbyt drogie jak na oferowane funkcjonalności, nie są skalowalne i uruchomienie na nich bardziej skomplikowanych scenariuszy jest niemożliwe. Ponadto oddając usługę klientowi zakładamy wejście do niego włóknem, wstawienie switcha zarządzalnego i w określonych przypadkach routera oraz centrali głosowej. Ilość urządzeń się mnoży, a wraz z nimi – szansa na wystąpienie awarii. Wówczas pojawił się pomysł zwirtualizowania centrali oraz routera. I tutaj z pomocą przyszły urządzenia marki MikroTik.
Przygotowane rozwiązanie zakłada wstawienie do klienta jedynie zarządzalnego switcha L2, która pozwala na oddanie usługi na vlanie, ew. QinQ. W oddawanym vlanie zakładamy oddanie również usługę DHCP serwującą przydzieloną klientowi pulę adresową. Jeśli klient sobie życzy – oddajemy w jego ręce zarządzanie routerem, który jest zwirtualizowaną instancją OpenWRT uruchomioną jako usługa metaROUTER. Podobnie sprawa wygląda z centralą głosową – na potrzeby klienta tworzymy wirtualną centralę (opartą o Asterisk), która obsługuje posiadane przez klienta telefony VoIP oraz odpowiada za logikę działania PBX. Oczywiście takie rozwiązanie ma sens, gdy wspomniany przez nas MikroTik znajduje się u nas (u operatora) i jest routerem oraz serwerem PBX jednocześnie dla wielu klientów.
Poniższy artykuł zaprezentuje funkcjonalności:
– automatyczną transkrypcję głosu do tekstu (wraz z wysyłką transkrypcji na email)
– transkrypcję tekstu do głosu
– zabezpieczenie dostępu do IVR (hasło głosowe oraz hasło DTMF)
– prosty przykład pobrania danych z SQL i ich prezentacji głosowej
Urządzeniem, który stanowi “trzon” rozwiązania jest MikroTik RB1100AH MikroTik – RB1100AH – specyfikacja, który doskonale radzi sobie z powierzonymi zadaniami. W szczytowym momencie jest w stanie przerzucić 600-700Mbit bez strat pakietów, obciążenie procesora sięga 35% (na potrzeby testów – 5 zwirtualizowanych routerów OpenWRT oraz 5 central głosowych). Mimo iż RB1100AH jest leciwym urządzeniem bez problemu jest w stanie pracować jako stosunkowo wydajny router L3, na którym dodatkowo terminować będziemy naszych klientów z wirtualizowanymi usługami.
Obrazy OpenWRT dla zwirtualizowanych maszyn możecie uzyskać odnajdując je w sieci, albo samodzielnie zbudować. Rozległe opracowanie dotykające tej tematyki są łatwe do odnalezienia, więc nie zamierzam odkrywać Ameryki na nowo. Ścieżki są przetarte, więc możemy zaoszczędzić sporo czasu korzystając z gotowych rozwiązań. W moim przypadku korzystam z OpenWRT w wersji 14.07 (Barrier Breaker) jeśli chodzi o obraz będący routerem oraz 8.09 (Kamikaze) wraz z Asteriskiem w wersji 1.8.11.1. Pamiętajcie, aby po uruchomieniu systemów edytować /etc/opkg.conf i uzupełnić go o repozytorium, skąd czerpać będziecie pakiety. Aby Asterisk wspierał używaną przeze mnie w dialplanie funkcjonalność byłem zmuszony doinstalować kilkanaście paczek.
Nie będę zajmował się opisem szczegółowej konfiguracji OpenWRT, gdyż jest to temat po stokroć wyczerpany. Dodam tylko od siebie, abyście pamiętali, że wirtualne interfejsy (vif) tworzone na potrzeby instancji routera dla klienta należy prawidłowo przypisać do odpowiednich bridgy w MikroTiku. Nie jest to nic trudnego. W tym artykule skupimy się na centrali głosowej.
Zaczynamy od pobrania obrazu OpenWRT wraz z Asteriskiem.
OpenWRT 8.09 + Asterisk – PPC
Oto link do repozytorium z paczkami, które może być Wam przydatne.
Archive OpenWRT 8.09
Kopiujemy obraz do MikroTika i zaczynamy jego import (w tym przypadku przydzieliłem 64MB pamięci, dostosujcie ten parametr do swoich potrzeb).
import-image file-name=openwrt-metarouter-asterisk-ppc.tar.gz memory-size=64
Zmieńcie nazwę swojej maszyny dla lepszej czytelności (będzie przejrzyściej jak stworzycie ich osiem) i zajmijmy się konfiguracją wirtualnych interfejsów.
Poniższe polecenie utworzy interfejs eth0 i “dopnie” go do mostka “bridge-LAN”. W takim przypadku najczęściej tworzę statyczny wpis w serwerze DHCP dla utworzonego interfejsu i za każdym razem przydzielam ten sam adres IP.
[admin@MikroTik] /metarouter> interface add virtual-machine=asterisk type=dynamic dynamic-bridge=bridge-LAN
Tak wygląda plik /etc/config/network u mnie (DHCP na eth0):
root@meta-asterisk:~# cat /etc/config/network # Copyright (C) 2006 OpenWrt.org config interface loopback option ifname lo option proto static option ipaddr 127.0.0.1 option netmask 255.0.0.0 config interface lan option ifname eth0 option proto dhcp
Po pierwszym zalogowaniu się do maszyny zmieniamy hasło, wymieniamy klucze i konfigurujemy firewall wedle swoich potrzeb. Kolejnym krokiem jest czyszczenie plików konfiguracyjnych.
cd /etc/asterisk cat /dev/null > sip.conf cat /dev/null > voicemail.conf cat /dev/null > extensions.conf
Doinstalujcie paczkę ssmtp z repozytorium, aby zapewnić centrali łatwą wysyłkę e-mail. Poniżej przykład pliku konfiguracyjnego:
root@meta-asterisk:/etc/ssmtp# cat ssmtp.conf Hostname=DOMENA root=ADRES_ZRODLOWY mailhub=ADRES_SERWERA_POCZTOWEGO:465 rewriteDomain= UseTLS=YES UseSTARTTLS=NO AuthUser=LOGIN AuthPass=HASŁO FromLineOverride=YES
Zacznijmy od konfiguracji parametrów pracy centrali oraz zarejestrowania konta VoIP, które przydzieliliśmy klientowi. Poniżej przedstawiam Wam sprawdzoną przeze mnie i spełniającą moje potrzeby konfigurację (mówimy o sip.conf). Zweryfikujcie ją, zmodyfikujcie i wklejcie do pliku.
[general] allowsubscribe=yes disallow=all allow=alaw allowexternalinvites=no allowguest=no allowoverlap=yes autocreatepeer=no autodomain=no bindaddr=0.0.0.0 bindport=5060 canreinvite=no checkmwi=60 compactheaders=no defaultexpirey=60 dtmfmode=rfc2833 dumphistory=no ignoreregexpire=yes language=pl localnet=0.0.0.0/0.0.0.0 insecure=no maxexpiry=120 nat=force_rport,comedia notifyringing=yes pedantic=no progressinband=yes promiscredir=yes qualify=no realm=DOMENA recordhistory=no registerattempts=0 registertimeout=30 relaxdtmf=yes rtautoclear=no rtcachefriends=no rtsavesysname=no rtpholdtimeout=180 rtpkeepalive=180 rtptimeout=180 rtupdate=no sendrpid=no sipdebug=no srvlookup=no trustrpid=no useclientcode=no usereqphone=no rtignoreregexpire=yes useragent=MR-Asterisk videosupport=no callevents=no
Następnie – zarejestrujmy konta. Poniżej powyższego listingu w pliku sip.conf doklejamy:
;; Rejestrujemy konto 1 register => 123456789:silneHASLO-vOIP12%@HOST/123456789 [123456789] type=friend username=123456789 secret=silneHASLO-vOIP12% context=incoming disallow=all allow=alaw,ulaw qualify=yes host=HOST defaultip=HOST canreinvite=no insecure=port,invite call-limit=5
Logujemy się do CLI Asteriska, przeładowujemy klientów SIP i weryfikujemy poprawność rejestracji.
root@meta-asterisk:/etc/asterisk# asterisk -r Asterisk 1.8.11.1, Copyright (C) 1999 - 2012 Digium, Inc. and others. Created by Mark Spencer <markster@digium.com> Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details. This is free software, with components licensed under the GNU General Public License version 2 and other licenses; you are welcome to redistribute it under certain conditions. Type 'core show license' for details. ========================================================================= Connected to Asterisk 1.8.11.1 currently running on meta-asterisk (pid = 2146) meta-asterisk*CLI> sip reload meta-asterisk*CLI> sip show peers Name/username Host Dyn Forcerport ACL Port Status 123456789/123456789 IP_REJESTRATORA_VOIP N 5060 OK (3 ms) 1 sip peers [Monitored: 1 online, 0 offline Unmonitored: 0 online, 0 offline]
Utwórzmy następnie dwa konta SIP dla telefonów VoIP w firmie. Przydzielimy im numery 10 oraz 11. Analogiczne ustawienia wprowadzamy w telefonach VoIP, aby je zarejestrować na wirtualnej centrali.
[10] callerid=10 type=friend username=10 accountcode=10 secret=hasloWEWN10-tajn3! host=dynamic context=outgoing qualify=yes keepalive=yes ;nat=no nat=force_rport,comedia disallow=all allow=alaw limitonpeers=yes call-limit=3 [11] callerid=11 type=friend username=11 accountcode=11 secret=hasloWEWN11-tajn3! host=dynamic context=outgoing qualify=yes keepalive=yes ;nat=no nat=force_rport,comedia disallow=all allow=alaw limitonpeers=yes call-limit=3
Utwórzmy prosty dialplan i przetestujmy działanie centrali. Wykorzystajcie przeze mnie podany przykład pliku /etc/asterisk/extensions.conf i zmodyfikujcie go na własne potrzeby.
[general] static=yes writeprotect=yes [globals] CONSOLE=Console/dsp SOUNDPATH=/etc/asterisk/SOUNDS/ RECINPATH=/var/www/RECORDS RECOUTPATH=/var/www/RECORDS RECINPATH-IPB=/var/www/ipb/RECORDS RECOUTPATH-IPB=/var/www/ipb/RECORDS MONITOR_EXEC=/usr/bin/sox -m [incoming] exten => 123456789,1,NoOp("Przychodzace | Numer : ${CALLERID(num)}") ;;; ;;; PBX Firma ;;; exten => 123456789,n,Wait(1) exten => 123456789,n,NoOp("Rozmowa przychodzaca - numer: ${CALLERID(num)}") exten => 123456789,n,System(echo "To: ADRES_DO_POWIADOMIEN@DOMENA.COM" > /etc/ssmtp/mail-body && echo "Subject: Polaczenie przychodzące do firmy z numeru: ${CALLERID(num)}" >> /etc/ssmtp/mail-body && echo " " >> /etc/ssmtp/mail-body && echo " " >> /etc/ssmtp/mail-body && cat /etc/ssmtp/mail-body | sendmail -t) ;dzwonienie na numer wewnętrzny nr 10, a następnie 11 exten => 123456789,n,Dial(sip/10,25,tTr); exten => 123456789,n,Dial(sip/11,20,tTr); exten => 123456789,n,Hangup()
Następnie przeładujcie dialplan (będąc w CLI Asterisk), zmieńcie verbose na wysoki, a następnie wykonajcie połączenie z zewnątrz na zarejestrowany numer:
asterisk -r dialplan reload core set verbose 99
Zgodnie z dialplanem – w pierwszej kolejności otrzymacie maila z tematem: “Połączenie przychodzące do firmy z numeru: WASZ_NUMER_ŹRÓDŁOWY”, następnie w konsoli zobaczycie, że wykonywane jest połączenie na numer wewnętrzny nr 10. Po 25 sekundach zacznie dzwonić nr 11. Oto najprostszy i najłatwiejszy do zbudowania przykład centrali PBX wykorzystujący również wysyłkę maili. Pamiętajcie, że lista zmiennych w Asterisku jest bardzo bogata i za ich pomocą można tworzyć rozbudowane statystyki oraz cyklicznie podsyłać je mailem, bądź prezentować w postaci strony WWW. Kolejny krok to analiza głosu (voice2text oraz text2voice), gdzie zaprezentuję Wam przykładowe scenariusze i zastosowania.
Zacząć musimy od uzyskania dostępu do interesującego nas API Google. Logujemy się na nasze konto Google, przechodzimy do Console Developers Google, tworzymy projekt i włączamy API dla “Cloud Speech API”. Zapisujemy gdzieś na boku nasz klucz API. Wykorzystamy skrypt AGI autorstwa Lefterisa Zafirisa, o którym pisze on więcej tutaj: Speech recognition for Asterisk. Po spełnieniu zależności (czeka Was trochę szukania) przystępujemy do konfiguracji.
Edytujemy /etc/asterisk/asterisk.conf i umieszczamy tam linię wskazującą położenie skryptów AGI.
astagidir => /var/lib/asterisk/agi-bin/
Kopiujemy skrypty AGI (speech-recog.agi, googletts.agi) do wskazanej lokalizacji i zacznijmy od prostego przykładu – odczytanie prostego komunikatu, następnie nagranie własnego (jakieś krótkie zdanie), sprawdzenie jakości transkrypcji oraz odtworzenie nagrania.
exten => 123456789,1,Answer() exten => 123456789,n,Wait(1) ; test zamiany tekstu na głos exten => 123456789,n,agi(googletts.agi,"Witamy. Pierwszy test.",pl) exten => 123456789,n,Wait(1) exten => 123456789,n,agi(googletts.agi,"Powiedz zdanie po sygnale.",pl) exten => 123456789,n(record),agi(speech-recog.agi,pl_PL) exten => 123456789,n,Verbose(1,Skrypt zwrocil dane: ${confidence} , ${utterance}) ; sprawdź jakość porównania exten => 123456789,n(success),GotoIf($["${confidence}" > "0.8"]?playback:retry) ; odtwórz tekst exten => 123456789,n,NoOp(${confidence}) exten => 123456789,n(playback),agi(googletts.agi,"Skuteczność procentowa transkrypcji wynosi: ${confidence:2:2}",pl) exten => 123456789,n,Wait(1) exten => 123456789,n,agi(googletts.agi,"Nagrany komunikat brzmi",pl) exten => 123456789,n,agi(googletts.agi,"${utterance}",pl) exten => 123456789,n,goto(end) ; powtórzenie, jeśli "jakość" transkrypcji jest mniejsza niż 80% exten => 123456789,n(retry),agi(googletts.agi,"Nagraj ponownie komunikat",pl) exten => 123456789,n,goto(record) exten => 123456789,n(fail),agi(googletts.agi,"Nie otrzymano danych transkrypcji.",en) exten => 123456789,n(end),Hangup()
Dobrze, utworzyliśmy zatem prostą centralę z zarejestrowanym kontem “miejskim”, numerami wewnętrznymi oraz dołożyliśmy funkcjonalność zamiany nagranych komunikatów głosowych na tekst.
Teraz pokażę Wam przykład prostego NOCu zrealizowanego w oparciu o powyższe rozwiązanie. Najpierw konfiguracja:
exten => VOIP_NUMBER,1,Answer() exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playback),agi(googletts.agi,"Witamy w firmie Blogtech",pl) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"Prosimy odpowiadac na pytania zadawane przez system i zatwierdzac krzyzykiem.",pl) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbackfirma),agi(googletts.agi,"Prosze podac nazwe firmy na jaka zarejestrowana jest usluga.",pl) exten => VOIP_NUMBER,n(recordfirma),agi(speech-recog.agi,pl_PL) exten => VOIP_NUMBER,n,Verbose(1,Jakosc transkrypcji: ${confidence}, Nazwa firmy: ${utterance}) exten => VOIP_NUMBER,n,Set(firmazgloszenie=${utterance}) exten => VOIP_NUMBER,n,Set(confidence=0) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbackmiasto),agi(googletts.agi,"Prosze podac miejscowosc swiadczenia uslugi..",pl) exten => VOIP_NUMBER,n(recordmiasto),agi(speech-recog.agi,pl_PL) exten => VOIP_NUMBER,n,Verbose(1,Jakosc transkrypcji: ${confidence}, Miasto: ${utterance}) exten => VOIP_NUMBER,n,Set(firmamiasto=${utterance}) exten => VOIP_NUMBER,n(successmiasto),GotoIf($["${confidence}" > "0.6"]?playbackulica:retrymiasto) exten => VOIP_NUMBER,n(retrymiasto),agi(googletts.agi,"Prosze powtorzyc nazwe miejscowosci",pl) exten => VOIP_NUMBER,n,goto(recordmiasto) exten => VOIP_NUMBER,n,Set(confidence=0) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbackulica),agi(googletts.agi,"Prosze podac nazwe ulicy, numer oraz numer lokalu gdzie swiadczona jest usluga.",pl) exten => VOIP_NUMBER,n(recordulica),agi(speech-recog.agi,pl_PL) exten => VOIP_NUMBER,n,Verbose(1,Jakosc transkrypcji: ${confidence}, Ulica: ${utterance}) exten => VOIP_NUMBER,n,Set(firmaulica=${utterance}) exten => VOIP_NUMBER,n(successulica),GotoIf($["${confidence}" > "0.7"]?playbackzasilanie:retryulica) exten => VOIP_NUMBER,n(retryulica),agi(googletts.agi,"Prosze powtorzyc nazwe ulicy, numer oraz numer lokalu.",pl) exten => VOIP_NUMBER,n,Set(firmaulica=${utterance}) exten => VOIP_NUMBER,n,Set(confidence=0) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbackzasilanie),agi(googletts.agi,"Prosze odpowiedziec, tak lub nie, czy zweryfikowane zostalo zasilanie po stronie klienta w lokalizacji.",pl) exten => VOIP_NUMBER,n(recordzasilanie),agi(speech-recog.agi,pl_PL) exten => VOIP_NUMBER,n,Verbose(1,Jakosc transkrypcji: ${confidence}, Zasilanie: ${utterance}) exten => VOIP_NUMBER,n,Set(firmazasilanie=${utterance}) exten => VOIP_NUMBER,n(successzasilanie),GotoIf($["${confidence}" > "0.6"]?playbacknumer:retryzasilanie) exten => VOIP_NUMBER,n(retryzasilanie),agi(googletts.agi,"Prosze powtorzyc odpowiedz - tak lub nie, czy zasilanie zostalo zweryfikowane w lokalizacji.",pl) exten => VOIP_NUMBER,n,Set(confidence=0) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbacknumer),agi(googletts.agi,"Prosze za pomoca klawiatury podac numer kontaktowy do osoby odpowiedzialnej za realizacje zgloszenia.",pl) exten => VOIP_NUMBER,n,Read(digito,,9) exten => VOIP_NUMBER,n,Set(firmanumer=${digito}) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n(playbackprzyjete),agi(googletts.agi,"Dziekuje. Informacje zostaly przeanalizowane przez system i przekazane do realizacji. Prosze czekac na kontakt.",pl) exten => VOIP_NUMBER,n,System(echo "To: MAIL@DOMENA.COM.PL" > /tmp/noc-mail) exten => VOIP_NUMBER,n,NoOp(${firmazgloszenie}) exten => VOIP_NUMBER,n,NoOp(${firmamiasto}) exten => VOIP_NUMBER,n,NoOp(${firmaulica}) exten => VOIP_NUMBER,n,NoOp(${firmazasilanie}) exten => VOIP_NUMBER,n,NoOp(${firmanumer}) exten => VOIP_NUMBER,n,System(echo "Subject: PBX: NOC ZGLOSZENIE Firma: "${firmazgloszenie}" - "${CALLERID(NUM)}" - "${firmaulica}" - "${firmamiasto} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "" >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Polaczenie z ${CALLERID(NUM)} na ${EXTEN} w godzinach: ${STRFTIME(%C%m%d%y%H%M)}" >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "" >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Nazwa firmy: "${firmazgloszenie} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Miasto: "${firmamiasto} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Ulica: "${firmaulica} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Numer kontaktowy: "${firmanumer} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(echo "Weryfikacja zasilania u klienta: "${firmazasilanie} >> /tmp/noc-mail) exten => VOIP_NUMBER,n,System(sendmail -t -f MAIL@DOMENA.COM.PL < /tmp/noc-mail) exten => VOIP_NUMBER,n,Hangup()
Powyższy dialplan zakłada zautomatyzowanie przyjęcia zgłoszenia, przetworzenia nagrania głosowego na tekst i wysyłkę transkrypcji na mail (jako osobne zgłoszenie awarii). Jeśli uważacie, że jest to konieczne – możecie do maila załączyć głosowy zapis odpowiedzi klienta – będzie to pomocne, gdy trzeba będzie zweryfikować poprawność transkrypcji głosowej. Podczas testów określam “celność” tego rozwiązania na 80%. Nadmienię, że transkrypcja numeru kontaktowego zawsze przebiegała w 100% prawidłowo.
Załóżmy, że dostęp do naszego automatycznego IVR mają mieć tylko osoby uprawnione. Możemy to uzyskać na kilka sposobów – pierwszy to podanie hasła głosowego, drugi – kod dostępu (DTMF).
Poniżej konfiguracje uwzględniające oba rozwiązania.
Hasło głosowe:
exten => VOIP_NUMBER,1,Answer() exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"Witaj. Tutaj super tajny system. Podaj haslo dostepu i nacisnij kratke",pl) exten => VOIP_NUMBER,n(record),agi(speech-recog.agi,pl_PL) exten => VOIP_NUMBER,n,Verbose(1,Skrypt zwrocil dane: ${confidence} , ${utterance}) exten => VOIP_NUMBER,n(success),GotoIf($["${utterance}" = "tajna sentencja"]?granted) exten => VOIP_NUMBER,n,agi(googletts.agi,"Haslo nieprawidlowe. Odmowa dostepu.",pl) exten => VOIP_NUMBER,n,agi(googletts.agi,"Do widzenia",pl) exten => VOIP_NUMBER,n,Hangup() exten => VOIP_NUMBER,n(granted),agi(googletts.agi,"Podales prawidlowe haslo. Gratuluje.",pl) exten => VOIP_NUMBER,n,Hangup()
Hasło DTMF:
exten => VOIP_NUMBER,1,Answer() exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"Witaj. Podaj kod DTMF.",pl) exten => VOIP_NUMBER,n,WaitExten(5) exten => 1410,1,Answer() exten => 1410,n,agi(googletts.agi,"Haslo prawidlowe.",pl) exten => 1410,n,agi(googletts.agi,"Gratuluje.",pl) exten => 1410,n,Hangup() exten => VOIP_NUMBER,n,Hangup() exten => VOIP_NUMBER,n,agi(googletts.agi,"Haslo nieprawidlowe.",pl) exten => VOIP_NUMBER,n,Hangup()
Takie rozwiązanie jest proste, dodatkowo oprócz takiego zabezpieczenia proponuję określenie listy numerów, które na dany numer mogą się wdzwonić. Ograniczenie dostępu może mieć zastosowanie również w sytacji, gdy dane zgłoszeń przechowujemy w bazie danych. Wówczas IVR może nam wyciągać te dane z tabel i prezentować głosowo.
Konfiguracja pod MySQL:
exten => VOIP_NUMBER,1,Hangup() exten => VOIP_NUMBER,1,MYSQL(Connect connid localhost LOGIN DB_PASS DB_NAME) exten => VOIP_NUMBER,n,GotoIf($["${connid}" = ""]?error,1) exten => VOIP_NUMBER,n,MYSQL(Query resultid ${connid} SELECT transcription, sourcenumber FROM zgloszenia) exten => VOIP_NUMBER,n(fetchrow),MYSQL(Fetch foundRow ${resultid} transkrypcja sourcenumber) exten => VOIP_NUMBER,n,Set(numbercut=${SHELL(echo ${sourcenumber} | sed -e 's/\(.\)/\1 /g')}); exten => VOIP_NUMBER,n,GotoIf($["${foundRow}" = "1"]?done) exten => VOIP_NUMBER,n,Goto(fetchrow) exten => VOIP_NUMBER,n(done),MYSQL(Clear ${resultid}) exten => VOIP_NUMBER,n,NoOp(${transkrypcja},${sourcenumber}) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"Ostatnie nagrane zgloszenie: ",pl) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"${transkrypcja}",pl) exten => VOIP_NUMBER,n,Wait(1) exten => VOIP_NUMBER,n,agi(googletts.agi,"Zgloszenie z numeru",pl) exten => VOIP_NUMBER,n,agi(googletts.agi,"'${numbercut}'"\",pl) exten => VOIP_NUMBER,n,MYSQL(Disconnect ${connid}) exten => VOIP_NUMBER,n,Hangup()
W oparciu o zaprezentowane scenariusze można bez problemu zbudować funkcjonalną centralę głosową z ciekawymi rozwiązaniami technicznymi. Obraz asteriska na MR po skonfigurowanie może być sklonowany i migrowany bądź powielany na dla kolejnych klientów.
Nadmienię, że tak zwirtualizowana centrala pracuje niemalże 2 rok na Mikrotiku u mnie w domu. Żadnych przerw, awarii, problemów. Centralizacja rozwiązania pozwala na łatwe zarządzanie kopiami zapasowymi (w przypadku awarii RB), łatwą migrację usług i ich ewentualne odtworzenie.