Voice auto-informer for date and time, in a pleasant female voice, Russian language, based on asterisk? Easy
- From the sandbox
- Tutorial
In anticipation of the weekend, there is nothing to occupy yourself with, because according to the regulations grandiose settings are not allowed? On an old, abandoned server, asterisk got dusty? Does the subscriber have nothing to test the telephone line? For those who have no one to talk to and for those who are lost in time .
In this publication, we will focus on cases of ordinal numbers, since the spoken text should be connected and not cut the ear. Let's try to achieve the following pronunciation:
or
For simplicity and transparency of implementation, we will not use AGI and ask the iron lady to tell us the date and time, by and large, after working only with dialplan and say.conf. And if your asterisk still does not speak Russian - it does not matter, we will teach it to that. To whom it became interesting, welcome under habrakat.
I think it’s not even worth mentioning that your server should know the exact time, relying, for example, on NTP.
Further, suppose that asterisk is installed, but if it is not, then there is a lot of material on this topic. We also assume that the initial configuration of at least one SIP-phone or softphone has already been made.
We tell asterisk to use the Russian language for SIP by adding language = ru to [general]:
Apply settings:
The context [ru-base] in say.conf has a trailing
Let's try to parse one rule. The first thing you should pay attention to is the characters of XZ N. They are interpreted by asterisk as special and if these characters appear in the name of the reading rule, they should be taken in square brackets, for example mo [n] th.
The syntax is quite simple and the rule is the same if the input XX is any two digits. Play the file digits / mon- (XX-1), where (XX-1) is an arithmetic operation. At X = 02 (yes, it’s “digesting” even such numbers that it will help us a lot), 02-1 = 1, digits / mon-1: “February”.
Separately, it is worth mentioning the seconds. Firstly, in the recorded phrases there is only one record: “seconds”. This means that rounded data should come to the input of this function, for example 0, 10, 20, and so on. And secondly, according to the author, this will facilitate the perception of the information received.
In the context,
Next, we form the date format we need in a variable
Based on say.conf, the seconds should be rounded off. From the two-digit seconds format, we select the first digit and add a zero to it:
Perhaps some of the readers will want to formulate rules on their own, for example, to read rubles. The volume of ready-made examples should be enough to cope with this task. And to check the pronunciation, you can use the dialplan below.
Bonus : you can listen to the finished result live by phone:
In this publication, we will focus on cases of ordinal numbers, since the spoken text should be connected and not cut the ear. Let's try to achieve the following pronunciation:
Current time fifteen hour s twenty odes to minutes and twenty seconds. Today is Wednesday, the fifteenth th October I .
or
All times are GMT od Ying hour , thirty-five minutes, ten seconds. Today is Thursday, October 16th.
For simplicity and transparency of implementation, we will not use AGI and ask the iron lady to tell us the date and time, by and large, after working only with dialplan and say.conf. And if your asterisk still does not speak Russian - it does not matter, we will teach it to that. To whom it became interesting, welcome under habrakat.
What time is it now?
I think it’s not even worth mentioning that your server should know the exact time, relying, for example, on NTP.
In a nutshell about setting up NTP
Time on servers has the property of being out of sync, if not failed. The ntp package is required anyway. For myself, I chose the first option with ntpd, as my other servers let the time inside the network.
Option number 1 . We add the server to taste , depending on the region in which asterisk is located. The faster the response from the time server, the more accurately it will be set, ceteris paribus. I will choose the Russian pool.
Check that the daemon is listening on the correct ports:
If you want to distribute time to your servers, do not forget to check the firewall, UDP / 123 port. The rule must stand before the final REJECT. Do not forget to save.
Option number 2 . For a one-time adjustment, the ntpdate utility included in the same ntp package is suitable. This option is suitable if the distribution of time from the server is not planned.
You can add to cron:
#yum -y install ntp
Option number 1 . We add the server to taste , depending on the region in which asterisk is located. The faster the response from the time server, the more accurately it will be set, ceteris paribus. I will choose the Russian pool.
#grep "^ server" /etc/ntp.conf server 0.ru.pool.ntp.org server 1.ru.pool.ntp.org server 2.ru.pool.ntp.org server 3.ru.pool.ntp.org #chkconfig ntpd on #service ntpd start
Check that the daemon is listening on the correct ports:
#netstat -putln | grep ntpd
If you want to distribute time to your servers, do not forget to check the firewall, UDP / 123 port. The rule must stand before the final REJECT. Do not forget to save.
#iptables -nL --line-numbers #iptables -I INPUT 4 -s 10.0.0.0/255.0.0.0 -p udp --dport 123 -j ACCEPT #service iptables save
Option number 2 . For a one-time adjustment, the ntpdate utility included in the same ntp package is suitable. This option is suitable if the distribution of time from the server is not planned.
#ntpdate ru.pool.ntp.org 9 Oct 17:08:41 ntpdate [32744]: adjust time server 85.21.78.8 offset -0.183259 sec
You can add to cron:
#echo -e "\ n47 * / 1 * * * root / usr / sbin / ntpdate pool.ntp.org> / dev / null \ n" >> / etc / crontab
We will teach the lady Russian
Further, suppose that asterisk is installed, but if it is not, then there is a lot of material on this topic. We also assume that the initial configuration of at least one SIP-phone or softphone has already been made.
Package of Russian sounds
For Asterisk 1.4, if you add languageprefix = yes to asterisk.conf, the sound directory structure will be the same as in newer versions by default.
Standard directory: / var / lib / asterisk / in which subfolders that depend on two "xx" letters of the ISO country code (ru, nl, fr, de, it, pt, es ...)
Create a directory if it is not
Loading Russian sounds:
Unpack:
Copy to your place:
See which phrases are recorded in the following files:
Standard directory: / var / lib / asterisk / in which subfolders that depend on two "xx" letters of the ISO country code (ru, nl, fr, de, it, pt, es ...)
sounds / xx sounds / xx / digits sounds / xx / letters sounds / xx / phonetic
Create a directory if it is not
#mkdir / var / lib / asterisk / sounds / ru /
Loading Russian sounds:
#wget -O asterisk-sounds-additional-master.zip https://github.com/pbxware/asterisk-sounds-additional/archive/master.zip #wget -O asterisk-sounds-master.zip https://github.com/pbxware/asterisk-sounds/archive/master.zip
Unpack:
#unzip asterisk-sounds-additional-master.zip #unzip asterisk-sounds-master.zip
Copy to your place:
#cp -R ./asterisk-sounds-additional-master/* / var / lib / asterisk / sounds / ru / #cp -R ./asterisk-sounds-master/* / var / lib / asterisk / sounds / ru /
See which phrases are recorded in the following files:
#less ./asterisk-sounds-additional-master/additional-sounds-ru.txt #less ./asterisk-sounds-master/core-sounds-ru.txt
sip.conf
We tell asterisk to use the Russian language for SIP by adding language = ru to [general]:
#cat /etc/asterisk/sip.conf [general] language = ru
Apply settings:
#asterisk -rx "sip reload"
say.conf
#cat /etc/asterisk/say.conf
Apply settings:
[ru-base](!)
_[n]um:0X => num:${SAY:1}
_[n]um:X => digits/${SAY}
_[n]um:[1-2]f => digits/${SAY:0:1}f
_[n]um:[3-9]f => digits/${SAY:0:1}
; Tens
_[n]um:1X => digits/${SAY:0:2}
_[n]um:1Xf => digits/${SAY:0:2}
_[n]um:[2-9]0 => digits/${SAY:0:2}
_[n]um:[2-9]0f => digits/${SAY:0:2}
_[n]um:[2-9][1-2] => digits/${SAY:0:1}0, num:${SAY:1}
_[n]um:[2-9][1-2]f => digits/${SAY:0:1}0, num:${SAY:1}
_[n]um:[2-9][3-9] => digits/${SAY:0:1}0, num:${SAY:1}
_[n]um:[2-9][3-9]f => digits/${SAY:0:1}0, num:${SAY:1}
; Hundreds
_[n]um:0XX => num:${SAY:1}
_[n]um:0XXf => num:${SAY:1}
_[n]um:[1-9]00 => digits/${SAY:0:1}00
_[n]um:[1-9]00f => digits/${SAY:0:1}00
_[n]um:XXX => num:${SAY:0:1}00, num:${SAY:1}
_[n]um:XXXf => num:${SAY:0:1}00, num:${SAY:1}
; enumeration
_e[n]um:X => digits/h-${SAY}
_e[n]um:X[n] => digits/h-${SAY}
_e[n]um:0X => enum:${SAY:1}
_e[n]um:0X[n] => enum:${SAY:1}
_e[n]um:1X => digits/h-${SAY}
_e[n]um:1X[n] => digits/h-${SAY}
_e[n]um:[2-9]0 => digits/h-${SAY}
_e[n]um:[2-9]0[n] => digits/h-${SAY}
_e[n]um:[2-9][1-9] => num:${SAY:0:1}0, digits/h-${SAY:1}
_e[n]um:[2-9][1-9][n] => num:${SAY:0:1}0, digits/h-${SAY:1}
_e[n]um:[1-9]00 => digits/h-${SAY}
_e[n]um:[1-9]00[n] => digits/h-${SAY}
_e[n]um:[1-9]XX => num:${SAY:0:1}00, enum:${SAY:1}
_e[n]um:[1-9]XX[n] => num:${SAY:0:1}00, enum:${SAY:1}
[ru](ru-base)
_chas:0 => num:${SAY}, digits/hours
_chas:1 => digits/${SAY}, digits/hour
_chas:[2-4] => num:${SAY}, digits/hours-a
_chas:[5-9] => num:${SAY}, digits/hours
_chas:0X => chas:${SAY:1}
_chas:1X => num:${SAY}, digits/hours
_chas:20 => num:${SAY}, digits/hours
_chas:2[1-4] => num:${SAY:0:1}0, chas:${SAY:1}
_mi[n]uta:0 => num:${SAY}, digits/minutes
_mi[n]uta:1 => digits/1f, digits/minute
_mi[n]uta:2 => digits/2f, digits/minutes-i
_mi[n]uta:[3-4] => num:${SAY}, digits/minutes-i
_mi[n]uta:[5-9] => num:${SAY}, digits/minutes
_mi[n]uta:0X => minuta:${SAY:1}
_mi[n]uta:1X => num:${SAY}, digits/minutes
_mi[n]uta:[2-5]0 => num:${SAY}, digits/minutes
_mi[n]uta:[2-5][1-9] => num:${SAY:0:1}0, minuta:${SAY:1}
_seku[n]da:0 => num:${SAY}, seconds
_seku[n]da:[5-9] => num:${SAY}, seconds
_seku[n]da:0X => sekunda:${SAY:1}
_seku[n]da:1X => num:${SAY}, seconds
_seku[n]da:[2-5]0 => num:${SAY}, seconds
_dayofweek:[0-6] => digits/day-${SAY}
_dayofmo[n]th:X => enum:${SAY}n
_dayofmo[n]th:XX => enum:${SAY}n
_mo[n]th:X => digits/mon-$[${SAY} - 1]
_mo[n]th:XX => digits/mon-$[${SAY} - 1]
Apply settings:
#asterisk -rx "module reload app_playback.so"
The context [ru-base] in say.conf has a trailing
(!)
exclamation point in brackets means that this is a pattern that we will include in the future. [ru]
Let's try to parse one rule. The first thing you should pay attention to is the characters of XZ N. They are interpreted by asterisk as special and if these characters appear in the name of the reading rule, they should be taken in square brackets, for example mo [n] th.
_mo[n]th:XX => digits/mon-$[${SAY} - 1]
The syntax is quite simple and the rule is the same if the input XX is any two digits. Play the file digits / mon- (XX-1), where (XX-1) is an arithmetic operation. At X = 02 (yes, it’s “digesting” even such numbers that it will help us a lot), 02-1 = 1, digits / mon-1: “February”.
Separately, it is worth mentioning the seconds. Firstly, in the recorded phrases there is only one record: “seconds”. This means that rounded data should come to the input of this function, for example 0, 10, 20, and so on. And secondly, according to the author, this will facilitate the perception of the information received.
extensions.conf
#cat /etc/asterisk/extensions.conf
Apply settings:
[my_regular_context] ; Там где живет ваш SIP абонент/телефон.
exten => 100,1,Goto(informer_100,s,1)
[informer_100]
exten => s,1,Set(FreezeEPOCH=$[${EPOCH} + 15]) ; Добавляем 15 секунд к unixtime.
same => n,Set(TimeNow=${STRFTIME(${FreezeEPOCH},,%Y%m%d%H%M.%S-%w-%j)})
same => n,Playback(silence/1&at-tone-time-exactly) ;Тишина 1 секунда + Текущее время
same => n,Playback(chas:${TimeNow:8:2},say) ; десять + часов
same => n,Playback(minuta:${TimeNow:10:2},say) ; сорок + одна + минута
same => n,Playback(sekunda:${TimeNow:13:1}0,say) ; двадцать + секунд
same => n,Playback(silence/1&digits/today) ; тишина 1 секунда + сегодня
same => n,Playback(dayofweek:${TimeNow:16:1},say) ; четверг
same => n,Playback(dayofmonth:${TimeNow:6:2},say) ; шестнадцатое
same => n,Playback(month:${TimeNow:4:2},say) ; октября
same => n,Playback(silence/1&beep) ; тишина 1 секунда + короткий гудок
same => n,Hangup()
Apply settings:
#asterisk -rx "dialplan reload"
same => n,Set(FreezeEPOCH=$[${EPOCH} + 15])
In the context,
[informer_100]
it’s worth explaining the line where we FreezeEPOCH
add 15 seconds to unixtime in a variable . This is done to compensate for the time spent playing files before seconds. Next, we form the date format we need in a variable
TimeNow
. It contains data in the form 201410160043.34-4-289
. When reading, we pull out the necessary numbers from the "array". They are always in their places and extraction is not difficult. For more information on formats, see #man strftime
.About working with asterisk variables can be found under the spoiler
The full syntax of the variable
Using the construction
${AnyVariable:x:y}
, where x is the starting position and y is the number of digits to be returned. Let the string be given: 201410160043.34-4-289
Using the construction
${AnyVariable:x:y}
, we can extract the following data: ${AnyVariable:0:4}
- string 2014 will be returned. Skip the zero characters on the left and take four characters. ${AnyVariable:4:8}
- the line 10160043 will be returned. ${AnyVariable:-3:3}
- the line will begin with the third character, counting from the end and include three characters, which will give 289. ${AnyVariable:2}
- if the number of digits to be returned is not specified, the entire remaining line will be returned, we get 1410160043.34-4- 289.Based on say.conf, the seconds should be rounded off. From the two-digit seconds format, we select the first digit and add a zero to it:
${TimeNow:13:1}0
Perhaps some of the readers will want to formulate rules on their own, for example, to read rubles. The volume of ready-made examples should be enough to cope with this task. And to check the pronunciation, you can use the dialplan below.
dialplan to iterate over digits / serial numbers / anything
exten => 101,1,Set(Number=0) ; от нуля
same=>n(start),playback(enum:0${Number}n,say) ; читать enum с предшествующим нулем
same=>n,Set(Number=$[ ${Number} + 1 ]) ; шаг в единицу
same=>n,GotoIf($[${Number} <= 9 ]?start) ; до девяти
same=>n,Hangup()
Bonus : you can listen to the finished result live by phone: