- PVSM.RU - https://www.pvsm.ru -
В преддверии выходных не чем себя занять, так как по регламенту не позволены грандиозные настройки? На старом, заброшенном сервере запылился asterisk? Абоненту нечем тестировать телефонную линию? Для тех, кому не с кем поговорить и для тех, кто потерялся во времени.
В этой публикации мы будем делать акцент на падежи порядковых числительных, так как произносимый текст должен быть связан и не резать слух. Попытаемся добиться следующего произношения:
Текущее время пятнадцать часов, двадцать одна минута, двадцать секунд. Сегодня среда, пятнадцатое октября.
или
Текущее время один час, тридцать пять минут, десять секунд. Сегодня четверг, шестнадцатое октября.
Для простоты и прозрачности внедрения мы не будем пользоваться AGI и попросим железную леди сообщать нам дату и время, по большому счету, поработав лишь с dialplan`ом и say.conf`ом. И если ваш asterisk до сих пор не говорит по-русски — не беда, этому мы его научим. Кому стало интересно, добро пожаловать под хабракат.
Думаю, не стоит даже упоминать, что ваш сервер должен знать точное время, опираясь, например, на NTP.
#yum -y install ntp
Вариант №1. Добавляем сервера по вкусу [1], в зависимости от региона, в котором находится asterisk. Чем быстрее отклик от сервера времени, тем точнее оно выставится, при прочих равных. Я выберу российский пул.
#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
Проверяем, что демон слушает нужные порты:
#netstat -putln | grep ntpd
Если есть желание раздавать время своим серверам, не забудьте проверить файервол, порт UDP/123. Правило должно встать до завершающего REJECT`а. Не забудьте сохранить.
#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
Вариант №2. Для разовой корректировки подойдет утилита ntpdate, входящая в тот же пакет ntp. Такой вариант годен, если раздача времени с сервера не планируется.
#ntpdate ru.pool.ntp.org 9 Oct 17:08:41 ntpdate[32744]: adjust time server 85.21.78.8 offset -0.183259 sec
Можно добавить в cron:
#echo -e "n47 */1 * * * root /usr/sbin/ntpdate pool.ntp.org > /dev/nulln" >> /etc/crontab
Далее предположим, что asterisk установлен, но если это не так, то есть [2] много [3]материалов [4] на эту тему. Так же будем считать, что первоначальная настройка хотя бы одного SIP-телефона или софтфона уже произведена.
sounds/xx sounds/xx/digits sounds/xx/letters sounds/xx/phonetic
Создадим каталог, если его нет
#mkdir /var/lib/asterisk/sounds/ru/
Загружаем русские звуки:
#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
Распаковываем:
#unzip asterisk-sounds-additional-master.zip #unzip asterisk-sounds-master.zip
Копируем на свое место:
#cp -R ./asterisk-sounds-additional-master/* /var/lib/asterisk/sounds/ru/ #cp -R ./asterisk-sounds-master/* /var/lib/asterisk/sounds/ru/
Посмотреть, какие фразы записаны можно в следующих файлах:
#less ./asterisk-sounds-additional-master/additional-sounds-ru.txt #less ./asterisk-sounds-master/core-sounds-ru.txt
Укажем asterisk`у, использовать русский язык для SIP, добавив language=ru в [general]:
#cat /etc/asterisk/sip.conf [general] language=ru
Применяем настройки:
#asterisk -rx "sip reload"
[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]
Применяем настройки:
#asterisk -rx "module reload app_playback.so"
Контекст [ru-base] в say.conf имеет завершающий (!)
восклицательный знак в скобках означает, что это шаблон, который мы в дальнейшем включаем в [ru]
Попробуем разобрать одно правило. Первое, на что стоит обратить внимание, это символы X Z N. Они интерпретируются asterisk`ом как специальные и если эти литеры фигурируют в названии правила чтения, их следует взять в квадратные скобки, например mo[n]th.
_mo[n]th:XX => digits/mon-$[${SAY} - 1]
Синтаксис достаточно прост и правило совпадает, если входные данные XX — две любые цифры. Проигрываем файл digits/mon-(XX-1), где (XX-1) это арифметическая операция. При X=02 (да, «переваривает» даже такие цифры, что нам очень поможет), 02-1=1, digits/mon-1: «Февраля».
Отдельно стоит упомянуть секунды. Во-первых, в записанных фразах есть только единственная запись: «секунд». Это значит, что на вход этой функции должны приходить округленные данные, например 0, 10, 20, и так далее. А во-вторых, по мнению автора, это облегчит восприятие полученной информации.
[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()
Применяем настройки:
#asterisk -rx "dialplan reload"
same => n,Set(FreezeEPOCH=$[${EPOCH} + 15])
В контексте [informer_100]
стоит объяснить строчку, где мы в переменной FreezeEPOCH
добавляем 15 секунд к unixtime. Сделано это для компенсации времени, потраченного на проигрывание файлов, предшествующих секундам.
Далее мы формируем необходимый нам формат даты в переменной TimeNow
. Она содержит данные в виде: 201410160043.34-4-289
. При чтении мы выдергиваем из «массива» необходимые числа. Они всегда на своих местах и извлечение не составит труда. Более подробно о форматах можно посмотреть в #man strftime
.
${AnyVariable:x:y}
, где x — начальное положение, а y — количество цифр, которое должно быть возвращено. Пусть задана строка:201410160043.34-4-289
Используя конструкцию ${AnyVariable:x:y}
, можно извлечь следующие данные:
${AnyVariable:0:4}
— будет возвращена строка 2014. Пропустить ноль символов слева и взять четыре символа.
${AnyVariable:4:8}
— будет возвращена строка 10160043.
${AnyVariable:-3:3}
— строка будет начинаться с третьего символа, считая с конца и включает три символа, что даст 289.
${AnyVariable:2}
— если количество цифр, которое должно быть возвращено, не задано, будет возвращена вся оставшаяся строка, получим 1410160043.34-4-289.
Исходя из say.conf, секунды у нас должны округляться. Из двухзначного формата секунд мы выбираем первую цифру и добавляем к ней ноль: ${TimeNow:13:1}0
Возможно, кто-то из читателей захочет самостоятельно сформировать правила, например, для прочтения рублей. Объема готовых примеров должно быть достаточно, чтобы справиться с этой задачей. А для проверки произношения можно воспользоваться нижеприведенным dialplan`ом.
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()
Прослушать готовый результат в живую можно по телефону:
Автор: xBrowser
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ip-telefoniya/71902
Ссылки в тексте:
[1] по вкусу: http://support.ntp.org/bin/view/Servers/NTPPoolServers
[2] есть: https://wiki.asterisk.org/wiki/display/AST/Installing+Asterisk
[3] много: http://habrahabr.ru/post/171163/
[4] материалов: http://voxlink.ru/knowledge-base/asterisk-installation/
[5] Источник: http://habrahabr.ru/post/240649/
Нажмите здесь для печати.