В данной статье мы расскажем как использовать статусы абонентов (extensions), используя Asterisk 16. Как известно app_macro – DEPRECATED, а это означает, что функция Macro устарела и разработчики Asterisk рекомендуют использовать GoSub. Шагаем в ногу со временем. Ее использовать и будем.
Преамбула
Asterisk включает в себя набор функций, которые позволяют получать информацию о состоянии устройств, расширений и пользовательских устройств. Например канальные драйверы chan_sip и chan_pjsip могут предоставлять состояние устройств а также получать EXTENSION_STATE для получения уведомлений об изменении состояния. Еще один пример – это использование app_queue (системы очередей), которая учитывает состояние устройств и операторов (extensions) очереди и влияет на логику обработки звонка. Или интерфейс Asterisk Manager, который предоставляет действия для запроса состояния того или иного расширения или состояния устройств. Какие же компоненты Asterisk предоставляют информацию о состоянии своих ресурсов? Это зависит от версии Asterisk. Для Asterisk 16 LTS (мы используем только LTS) следующие компоненты позволяют собирать информацию о состоянии:
- PJSIP – Стек SIP PJSIP, res_pjsip.so, chan_pjsip.so.
- SIP – Уже устаревший драйвер SIP-канала, chan_sip.so.
- DAHDI – Популярный драйвер аппаратного интерфейса телефонии, chan_dahdi.so.
- IAX2 – Протокол Asterisk chan_iax2.so.
- ConfBridge – Приложение для конференций app_confbridge.so.
- MettMe – Устаревшее приложение для создания конференций app_meetme.so.
- Park – Ядро Asterisk в версиях до 11. res_parking.so в версиях 12 или выше.
- Calendar – res_calendar.so и связанные с ним модули календаря.
- Custom – Пользовательское состояние устройства, предоставляемое Asterisk.
Asterisk позволяет настроить несколько активных линий для одного extension (внутреннего номера). Данная настройка позволит абоненту ответить на второй звонок, поставив первый вызов на hold (удержание). Но данный функционал содержит явный недостаток – второй позвонивший абонент будет слышать контроль посылки вызова (КПВ) дозвона. В традиционной телефонии данная звуковая сигнализация сообщает о том, что никто не подходит к телефону. Но наш то абонент разговаривает!
Обратите внимание, что сигнализацией о состоянии устройства может быть как физическое устройство, так и просто ресурсом отдельной функции Asterisk. С точки зрения понимания состояния устройства для использования в Asterisk это не имеет большого значения.
Возможные состояния устройств DEVICE_STATE()
- UNKNOWN
- NOT_INUSE
- INUSE
- BUSY
- INVALID
- UNAVAILABLE
- RINGING
- RINGINUSE
- ONHOLD
В данной статье мы расскажем как с помощью DEVICE_STATE() можно обрабатывать вызовы и сообщать статусы абонентов.
Call-limit в Asterisk
В Asterisk есть параметр call-limit, который позволяет ограничить количество активных линий, но у данного параметра есть недостатки. Если вы установите значение call-limit=1 вы получите как минимум два ограничения: вы не сможете переводить звонки и в случае вызова второго абонента произойдет сброс звонка и абонент ничего не поймет, а Asterisk сообщит следующую ошибку:
ERROR chan_sip.c: Call to peer '100' rejected due to usage limit of 1
Наша рекомендация устанавливать значение call-limit=2 чтобы абоненты могли получать второй вызов и переводить звонки. Если ваши бизнес-процессы настроены иначе и вам необходимо больше активных линий, мы рекомендуем использовать Queues (очереди вызовов).
Доступность канала через ChanIsAvail
Если же у вас установлено значение call-limit=2 вам стоит подумать об оповещении звонящим, если абонент разговаривает. Реализовать это можно с помощью функции ChanIsAvail.
Подготовка
Для того, чтобы второй позвонивший слышал фразу о занятости, её необходимо подготовить и разместить в директории /var/lib/asterisk/sounds/ru. О том как подготовить такую фразу мы рассказывали ранее.
Настройка DEVICE_STATE()
Алгоритм обработки вызовов изображен на рисунке ниже.
Далее необходимо отредактировать файл маршрутизации, обычно это /etc/asterisk/extensions.conf:
Как было:
[from-pstn]
exten => _XXX,1,Dial(SIP/${EXTEN},90,trm)
Как стало:
[from-pstn]
exten => _XXX,1,Gosub(sub-devstate,${EXTEN},1)
exten => _XXX,n,Dial(SIP/${EXTEN},90,trm)
exten => _XXX,n,Hangup()
[sub-devstate]
exten => _X.,1,Log(NOTICE, "${EXTEN} has DEVICE STATE ${DEVICE_STATE(SIP/${EXTEN})}")
exten => _X.,n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN})}" = "BUSY"]?s-BUSY,1)
exten => _X.,n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN})}" = "INUSE"]?s-BUSY,1)
exten => _X.,n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN})}" = "INVALID"]?s-INVALID,1)
exten => _X.,n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN})}" = "UNAVAILABLE"]?s-UNAVAILABLE,1)
exten => _X.,n,Return()
exten => s-BUSY,1,NoOp(Абонент ${EXTEN} в данный момент разговаривает)
exten => s-BUSY,n,Playback(extension-is-busy)
exten => s-BUSY,n,Hangup(17)
exten => s-INVALID,1,NoOp(Абонент ${EXTEN} не существует)
exten => s-INVALID,n,Goto(no-number,${EXTEN},1)
exten => s-INVALID,n,Hangup(1)
exten => s-UNAVAILABLE,1,NoOp(Абонент ${EXTEN} не доступен)
exten => s-UNAVAILABLE,n,Playback(ss-noservice)
exten => s-UNAVAILABLE,n,Wait(2)
exten => s-UNAVAILABLE,n,Hangup(18)
[no-number]
exten => _X.,1,NoOp(Статус набора - ${DIALSTATUS})
exten => _X.,n,Goto(invalid-number,1)
exten => invalid-number,1,NoOp(Неверно набран номер)
exten => invalid-number,n,Set(CDR(userfield)=No Number)
exten => invalid-number,n,Playback(pbx-invalid)
exten => invalid-number,n,Wait(1)
exten => invalid-number,n,Hangup()
exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()
На этом все! Общайтесь правильно.
Источник: наша база знаний