Zwirtualizowana centrala głosowa na MikroTiku (Asterisk + rozpoznawanie mowy + metaROUTER)

Od 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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *