Как настроить «Службу точного времени» с использованием Asterisk 16
Мне для моей телефонии нужно разобрать, как заставить или научить Asterisk 16
проговаривать звонок на номер, где цель узнать, как раньше, а может и сейчас есть у тех кто использует городской телефон при звонке на номер 1000
с целью узнать точное время. Помню, я когда был маленький то частенько на дисковом телефоне набирал номер 1000
чтобы услышать: «Точное время 10 часов 10 минут 10 секунд». А разобрав текущую задачу я смогу адаптировать ее и для голосового уведомления баланса на своем номере «Мегафон
» и «Теле2
».
В роли сервера где развернут сервис телефонии у меня выступает Ubuntu 18.04 Server amd64.
Первым делом нужно проверить, а если не сделано ранее настроить чтобы в системе было точное синхронизированное время и правильный часовой пояс. Хотя все это делает мой скрипт который я при разворачивании сервисов на Ubuntu
выкачиваю со своего хранилища Mercurial
, затем запускаю. В итоге получаю полностью настроенную систему.
Настройки АТС:
ekzorchik@srv-asterisk:~$ sudo cp /etc/asterisk/sip.conf /etc/asterisk/sip.conf.backup ekzorchik@srv-asterisk:~$ sudo rm /etc/asterisk/sip.conf ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/sip.conf [general] externaddr=172.33.33.2:5060 language=ru ;Локализация звуков allowguest=no ;Разрешить/Запретить гостевые подключения srvlookup=yes ;Принимать SIP-вызовы на основании доменных имен limitopnpeers=yes ;Разрешить/Запретить лимит на кол-во одновременных разговоров allowoverlap=no ;Разрешить/Запретить набор по одной цифре useragent=Asterisk ekzorchik ;Значение поля useragent в SIP заголовке [authentication] [default-sip](!) host=dynamic type=friend nat=no ;Политика работы через nat deny=0.0.0.0/0.0.0.0 ;Сети из которых запрещено подключение permit=0.0.0.0/0.0.0.0 ;Сети из которых разрешено подключение qualify=yes ;Периодическая проверка доступности клиента canreinvity=no ;Разрешить/Запретить потоки peer-to-peer в обход сервера insecure=port,invite ;port (не требовать совпадение порта), invite (не требовать аутентификации) call-limit=2 ;Лимит входящих вызовов dtmfmode=auto ;Какую спецификацию использовать при передачи DTMF сигналов context=phones ;Контекст обработки вызовов disallow=all ;Запретить использование все кодеков, ниже разрешаем нужные allow=alaw allow=ulaw [2002](default-sip) callerid="Number 2002" <2002> username=2002 secret=pbx2002 [2003](default-sip) callerid="Number 2003" <2003> username=2003 secret=pbx2003 ekzorchik@srv-asterisk:~$ sudo asterisk -rx "sip reload" ekzorchik@srv-asterisk:~$ sudo cp /etc/asterisk/extensions.conf /etc/asterisk/extensions.conf.backup ekzorchik@srv-asterisk:~$ sudo rm /etc/asterisk/extensions.conf ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf [general] [globals] [default] [handup-sip] exten = > _X!,1,HangUp() include => handup-sip [local] exten = _2XXX,1,Dial(SIP/${EXTEN}) [phones] include = local
Шаг №1: Текущее время и дата:
ekzorchik@srv-asterisk:~$ date Wed Nov 27 20:14:10 MSK 2019
Шаг №2: Т.к. я в конфигурационном файле sip.conf
предопределил параметр language=ru
, то мне нужно чтобы сервис asterisk
использовал аудиофайлы русского языка в дополнении к тем которые я отмечал при установке Asterisk
ekzorchik@srv-asterisk:~$ sudo apt-get install -y asterisk-core-sounds-ru
Но можно и в диалплане использовать вот так
ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf [general] [globals] [default] [handup-sip] exten = > _X!,1,HangUp() include => handup-sip [russ] exten => 2005,1,Answer() exten => 2005,n,Set(CHANNEL(language)=ru) exten => 2005,n,SayDigits(${CALLERID(num)}) exten => 2005,n,Wait(0.5) exten => 2005,n,Hangup() [local] exten = _2XXX,1,Dial(SIP/${EXTEN}) [phones] include = local include = russ ekzorchik@srv-asterisk:~$ sudo asterisk -rx "dialplan reload" Dialplan reloaded.
Так почему-то при звонке на номер 2005
с номера 2003
я в лог получил:
== Using SIP RTP CoS mark 5 [Nov 28 21:09:50] WARNING[792][C-00000002]: chan_sip.c:6331 create_addr: Purely numeric hostname (2005), and not a peer--rejecting! [Nov 28 21:09:50] WARNING[792][C-00000002]: app_dial.c:2578 dial_exec_full: Unable to create channel of type 'SIP' (cause 20 - Subscriber absent) == Everyone is busy/congested at this time (1:0/0/1)
ага я просто забыл указать в sip.conf
данный номер, а то получается что я набираю несуществующий номер.
[2005](default-sip) callerid="Number 2005" <2005> username=2005 secret=pbx2005 ekzorchik@srv-asterisk:~$ sudo systemctl restart asterisk && sudo systemctl status asterisk | grep head -n5
Теперь при звонке на номер 2005
— я получаю проговаривание текущего номера с которого совершаю звонок, т.е. 2003
. Работает. Двигаюсь дальше.
Так, как я оформляю данную заметку то аудио файлы я уже все откуда-то либо выкачал и они у меня лежат на моем OwnCloud 10.
https://own.ekzorchik.ru:38444/index.php/s/Ze6j48W4wpy96jP
https://172.35.35.6/index.php/s/Ze6j48W4wpy96jP
скачиваю sounds_ru.tar.gz
, распаковываю и копирую содержимое в путь который предопределен у astvarlibdir
(конфигурационного файла asterisk.conf
) по умолчанию устанавливается путь: /var/lib/asterisk
. Аудио файлы лежат в sounds
поддиректории. В Asterisk
(е) один и тот же audio
файл может быть сохранен с разными расширениями которые определяют формат файла.
ekzorchik@srv-asterisk:~$ sudo apt-get install curl tree -y ekzorchik@srv-asterisk:~$ curl -k -u "login:pass" https://172.35.35.6/index.php/s/Ze6j48W4wpy96jP/download -o sounds_ru.tar.gz Но через WAN-адрес можно скачать без логина и пароля. ekzorchik@srv-asterisk:~$ ls -lh sounds_ru.tar.gz -rw-rw-r-- 1 ekzorchik ekzorchik 158M Nov 28 21:42 sounds_ru.tar.gz ekzorchik@srv-asterisk:~$ tar zxf sounds_ru.tar.gz tar: Removing leading `/' from member names ekzorchik@srv-asterisk:~$ ekzorchik@srv-asterisk:~$ sudo cp var/lib/asterisk/sounds/ru/digits/* /var/lib/asterisk/sounds/ru/digits/ ekzorchik@srv-asterisk:~$ sudo chown -R asterisk:asterisk /var/lib/asterisk/sounds/ru/digits/
Отобразить количество каталогов — этот каталог содержит звуковые файлы которые я буду использовать с учетом скопированного выше:
ekzorchik@srv-asterisk:~$ tree -L 1 /var/lib/asterisk/sounds/ru/digits | grep directories 0 directories, 450 files
Шаг №3: Сервис точного времени буду базировать на использовании файла say.conf
ekzorchik@srv-asterisk:~$ sudo mv /etc/asterisk/say.conf /etc/asterisk/say.conf.backup ekzorchik@srv-asterisk:~ $ sudo nano /etc/asterisk/say.conf [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]
После не забываем сохранить внесенные изменения.
Применяем настройки:
ekzorchik@srv-asterisk:~$ sudo asterisk -rx "module reload app_playback.so" Module 'app_playback.so' reloaded successfully.
Контекст [ru-base] в say.conf имеет завершающий (!) восклицательный знак в скобках означает, что это шаблон, аналогия когда в sip.conf описываем дефолтные
настройки для аккаунтов.
Попробуем разобрать одно правило. Первое, на что стоит обратить внимание, это символы 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, и так далее.
ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf [general] [globals] [default] [handup-sip] exten => _X!,1,HangUp() include => handup-sip [info] exten = 1000,1,Answer() same = n,Goto(informer_1000,s,1) [informer_1000] 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() [russ] exten => 2005,1,Answer() exten => 2005,n,Set(CHANNEL(language)=ru) exten => 2005,n,SayDigits(${CALLERID(num)}) exten => 2005,n,Wait(0.5) exten => 2005,n,Hangup() [local] exten = _2XXX,1,Dial(SIP/${EXTEN}) [phones] include = local include = russ include = info
Применяем настройки:
ekzorchik@srv-asterisk:~$ sudo asterisk -rx "dialplan reload" Dialplan reloaded. ekzorchik@srv-asterisk:~$ sudo systemctl restart asterisk && sudo systemctl status asterisk | head -n5
Проверяю, набираю на телефоне номер 1000
, а тем временем в открытой консоли:
ekzorchik@srv-asterisk:~$ sudo asterisk -rvvv
и ошибок нет. Была произнесена фраза: В момент звукового сигнала точное
время будет 22 часа 10 минут 30 секунд Сегодня 28 ноября
Задача: Нужно доработать как изменить формуляр чтобы еще и произносило год с этому: 21 час 55 минут 40 секунд. Сегодня Среда 27 ноября
ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf same => n,Playback(year:${TimeNow:0:4},say); год
но не произносит, а лишь пишет ниже (лог)
-- Executing [s@informer_1000:10] Playback("SIP/2003-0000000b", "month:11,say") in new stack -- <SIP/2003-0000000b> Playing 'digits/mon-10.alaw' (language 'ru') -- Executing [s@informer_1000:11] Playback("SIP/2003-0000000b", "year:2019,say") in new stack
Добился чтобы произносился год — пока будет просто цифрами:
ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf [general] [globals] [default] [handup-sip] exten = > _X!,1,HangUp() include => handup-sip [local] exten = _2XXX,1,Dial(SIP/${EXTEN}) [info] exten = 1000,1,Answer() same = n,Goto(informer_1000,s,1) [informer_1000] 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(num:${TimeNow:0:2},say); год same => n,Playback(num:${TimeNow:2:2},say); год same => n,Playback(silence/1&beep) ; тишина 1 секунда + короткий гудок same => n,Hangup() [phones] include = local include = info
После не забываем сохранить внесенные изменения:
%Y%m%d%H%M.%S-%w-%j
%Y -> год
%m -> месяц (01..12)
%d -> день в месяца (01,02 и т.д)
%H -> часы (00..23)
%M -> минуты (00..59)
%S -> секунды (00..60)
%w -> дать недели (0..6, где 0 это воскресенье)
%j -> день в годы (001..366)
same => n,Set(FreezeEPOCH=$[${EPOCH} + 15])
FreezeEPOCH → переменная
В контексте [informer_100] я использую переменную FreezeEPOCH к оторой добавляю 15 секунд к unixtime. Это нужно дабы компенсировать время потраченной на проигрывание файла с учетом выполнения. Далее формируется формат даты в переменной TimeNow. Она содержит данные в виде: 2019(%Y).10(%m).16(%d).00(%H).43(%M).34(%S)-4(%w)-289(%j)
. При чтении мы выдергиваем из «массива» необходимые числа. Они всегда на своих местах и извлечение не составит труда.
Полный синтаксис переменной ${AnyVariable:x:y}, где x — начальное положение, а y — количество цифр, которое должно быть возвращено. Пусть задана строка:
201410160043.34-4-289
Используя конструкцию ${AnyVariable:x:y}, можно извлечь следующие данные:
${AnyVariable:0:4}
0 — пропустить ноль символов слева
4 — взять слева четыре символа
${AnyVariable:0:4} — будет возвращена строка 2014. Пропустить ноль символов слева и взять четыре символа.
${AnyVariable:4:8} — будет возвращена строка 10160043. Пропустить 4 символа слева и взять восемь символов.
${AnyVariable:-3:3} — строка будет начинаться с третьего символа, считая с конца и включает три символа, что даст 289.
${AnyVariable:2} — если количество цифр, которое должно быть возвращено, не задано, будет возвращена вся оставшаяся строка, получим 1410160043.34-4-289.
Исходя из say.conf, секунды у нас должны округляться. Из двухзначного формата секунд мы выбираем первую цифру и добавляем к ней ноль: ${TimeNow:13:1}0
ekzorchik@srv-asterisk:~$ sudo asterisk -rx "dialplan reload" Dialplan reloaded. ekzorchik@srv-asterisk:~$ sudo asterisk -rx "core reload" && sudo asterisk -rvvvv
в логах идет проигрывание *.alaw
файлов по умолчанию, если файла нет то любой другой с таким же именованием.
silence/1.alaw
at-tone-time-exactly.alaw
digits/20.alaw
digits/2.alaw
digits/hours-a.slin
digits/minutes-i.slin
digits/today.alaw
digits/day-4.alaw
digits/h-8n.slin
silence/1.alaw
beep.alaw
Произносит все: 22 час 55 минут 40 секунд. Сегодня Среда 27 ноября 2019
кроме
слова год
. А звукового файла «год
» в аудиофайлах asterisk
кажись нет. Нужно
наверное самим записать звуковой файл «год».
Для этого на своем рабочем месте — Ubuntu 18.04 Desktop amd64 ноутбук Lenovo E555
устанавливаю приложение Audacity:
ekzorchik@navy:~$ sudo apt-get install -y audacity
Т.к. Asterisk
воспроизводит аудио файлы в формате mono, то после того как запустили
аудиоредактор:
Дорожки - Создать новую - Моно дорожку
Нажимаю на кнопку с красным кружком и произношу в микрофон "год"
Затем нажимаю на иконку квадрата дабы остановить запись.
Теперь необходимо поменять частоту звучания с 44100 Гц в 8000 Гц. Выбираем: Правка — Параметры:
Выбираем частоту дискретизации по умолчанию — 8000 Гц.
Теперь экспортирую данный файл. Делается это так: Файл — Export - Экспортировать как WAV
ekzorchik@navy:~$ file Downloads/year.wav Downloads/year.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 8000 Hz
Теперь копирую данный аудио файл в дефолтный каталог аудио файлов Asterisk
и добавляю строчку в extensions.conf
на предмет его воспроизведения в плане обработки:
ekzorchik@srv-asterisk:~$ sudo scp ekzorchik@172.33.33.16:/home/ekzorchik/Downloads/year.wav /var/lib/asterisk/sounds/ru/digits/year.wav ekzorchik@172.33.33.16's password: year.wav 100% 24KB 6.2MB/s 00:00 ekzorchik@srv-asterisk:~$ ekzorchik@srv-asterisk:~$ sudo chown asterisk:asterisk /var/lib/asterisk/sounds/ru/digits/year.wav ekzorchik@srv-asterisk:~$ sudo nano /etc/asterisk/extensions.conf [informer_1000] 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(num:${TimeNow:0:2},say) ; год same => n,Playback(num:${TimeNow:2:2},say) ; год same => n,Playback(digits/year) ; год same => n,Playback(silence/1&beep) ; тишина 1 секунда + короткий гудок same => n,Hangup() ekzorchik@srv-asterisk:~$ sudo asterisk -rx "dialplan reload" Dialplan reloaded. ekzorchik@srv-asterisk:~$
Пусть и грубо но все же по хендмайду.
Работает. Пусть данная заметка будет моей первой отправной точкой к последующим задача которые я буду решать для своего «Умного дома
» который я строю на базе Zabbix Server 4.4 on Ubuntu 18.04 Server amd64
. Все выше опробовано и работает у меня. На этом я прощаюсь, с уважением автор блога Олло Александр
aka ekzorchik.