hints(Дополнено)

Первоначально идея была написать о hint, все так и было, но потом Остапа понесло…
1. SIP NOTIFY
2. hints
3. DEVICE_STATE
4. EXTENSION_STATE
5. BLF на примере DND
Hint позволяет узнать состояние устройства еще до того как мы что то пытаемся с ним сделать:)
Кому интересно милости прошу

SIP SUBSCRIBE/NOTIFY механизм — Что это и как это работает:)
Протокол SIP позволяет любому SIP клиент мониторить состояние другого, детальнее читаем тут RFC 3265.
Работает это приблизительно так:
Если устройство А хочет знать о состоянии устройства Б, посылает SUBSCRIBE запрос или прямо устройству Б или серверу который в курсе состояния устройства Б. Если SUBSCRIBE запрос был успешен, то после о каждом изменении состояния устройства Б, устройство А узнает об этом с помощью SIP NOTIFY! так работает Busy Lamp Field(BLF). Термин любезно позаимствован со старых телефонных станций, когда с помощью лампочки можно было посмотреть занятость линии.
NOTIFY сообщение отсылается при первой регистрации телефона, и в дальнейшем отсылаются при изменении в номере сообщений или в статусе хранимых сообщений.

Asterisk всегда в курсе состояния многих вещей: телефонов, очередей, голосовой почты. поэтому астериск должен бы принимать SUBSCRIBE запросы и сообщать о изменениях в устройствах которые мониторятся. Однако, SIP протоколы и стандарты не могут описать все возможные названия устройств или статусы — но протоколы предоставляют общий фреймворк для информирования о событиях без определения точного события или имени устройства. Для максимальной гибкости, Астериск позволяет задать имена устройств в диалплане(extensions.conf). Для этого и используются Hintы. Hints это простое,настраиваемое, сопоставление между произвольной именной меткой и определенным телефоном или приложением, о каком знает Астериск.

Когда Астериск получает SIP SUBSCRIBE запрос он проверяет хинты в диалплане, какие должны совпадать с именем устройств которые мониторятся. Хинты сообщают Астериску, какому устройству они соответствуют. Хинты связывают номера с физическими или виртуальными(конференции, парковки) устройствами
Примеры:

exten => 1234,hint,SIP/phoneA&SIP/phoneB&SIP/phoneC
exten => 1234,1,Dial(SIP/phoneA&SIP/phoneB&SIP/phoneC)

exten => 5555,hint,DAHDI/1
exten => 5555,1,Dial(DAHDI/1)

exten => 31337,hint,MeetMe:31337
exten => 31337,1,MeetMe(31337,dM)

Проверить состояние через CLI:

CLI>core show hints

Также можно добавить наблюдателя(watcher) тот кто подписан на обновления(см начало статьи)

В версии 1.6 появилась специальная функция DEVICE_STATE() — Получение или установка состояния устройства.
Синтаксис:
DEVICE_STATE(device)

Описание:
Функция DEVICE_STATE может использоваться для получения состояния устройства с любого из тех, которые могут предоставлять эту информацию.
Также функция может использоваться для установки некоторых особенных состояний устройства из плана набора. В этом случае для указания имени состояния должен использоваться префикс «Custom:».
!!! Если у Вас SIP постоянно отвечает NOT_INUSE, то нужно добавить в [general] раздел sip.conf
callcounter=yes

Вы можете подписаться на отслеживание изменения этого «особенного» состояния устройства, используя hint приоритет в плане набора:
exten => 1234,hint,Custom:lamp1

Возможные значения для обоих случаев применения данной функции следующие:
UNKNOWN
NOT_INUSE
INUSE
BUSY
INVALID
UNAVAILABLE
RINGING
RINGINUSE
ONHOLD

Пример получение статуса устройства:
NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})
NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})

Пример установки статуса устройства:
Set(DEVICE_STATE(Custom:lamp1)=BUSY)
Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)

[use_ctx]
include => parkedcalls-tenant
exten => 999,1,NoOp(Show parked call hint state)
exten => 999,n,NoOp(DEVICE_STATE(park:[email protected]_ctx)=${DEVICE_STATE(park:[email protected]_ctx)})
exten => 999,n,NoOp(DEVICE_STATE(park:[email protected])=${DEVICE_STATE(park:[email protected])})
exten => 999,n,NoOp(EXTENSION_STATE([email protected]_ctx)=${EXTENSION_STATE([email protected]_ctx)})
exten => 999,n,NoOp(EXTENSION_STATE([email protected])=${EXTENSION_STATE([email protected])})

Также есть функция EXTENSION_STATE(), работает подобно DEVICE_STATE, но для экстеншенов

exten => 7013,1,Answer()
same => n,Verbose(3,The state of [email protected] is ${EXTENSION_STATE([email protected])})
same => n,Hangup()

Возможные значения:
• UNKNOWN
• NOT_INUSE
• INUSE
• BUSY
• UNAVAILABLE
• RINGING
• RINGINUSE
• HOLDINUSE
• ONHOLD

BLF (МИГАЮЩА ЛАМПАЧГА)
Для нормальной работы нам понадобятся такие опции:
callcounter=yes если не указать, SIP устройство всегда будет NOT_INUSE
busylevel=N задает к-во звонков, при котором считается, что телефон занят. Можно указывать индивидуально для каждого профиля в файле sip.conf.
call-limit устаревшая функция использовалась как callcounter и для установки ограничения к-ва звонков, теперь нужно использовать функции GROUP() и GROUP_COUNT().
allowsubscribe=no и система не будет отслеживать подписки на BLF от этого абонента.
subscribecontext=context устанавливает особый контекст на подписки.
notifyringing=yes Отсылать или нет уведомление о том что устройство звонит, по умолчанию да. Используется dialog-info. Опция устанавливается в разделе [general] в sip.conf.
notifyhold=yes Позволяет chan_sip устанавливать состояние SIP устройств в ONHOLD, по умолчанию да. Опция устанавливается в разделе [general] в sip.conf.
notifycid=yes вкл возможность передачи инфо о CID c dialog-info+xml сообщениями (snom телефоны). По умолчанию No. Эта функция будет корректно работать только при входящем звонке использующим то же контекст и номер, которые используются как hint для вызываемого номера. не будет работать если используется subscribecontext!=context также огр для пользователя, если экстеншен звонит(несколько входящих) только один будет использоваться как источник CID. Укажите ‘ignore-context’ для игнора вызываемого контекста при просмотре канала звонящего. отображение CID может быть полезным когда агент решает перехватывать вызов или нет.

Пример реализации DND(«do not disturb»)

; Создаем хинт, чтобы телефон мог использовать BLF для сигнализации состояния DND
;
exten => DND_7015,hint,Custom:DND_7015
;
; Создаем номер, который привяжем к определенной кнопке на телефоне, которая и будет переключать состояние DND. 
;
exten => DND_7015,1,Answer()
same => n,GotoIf($["${DEVICE_STATE(Custom:DND_7015)}"="BUSY"]?turn_off:turn_on)
same => n(turn_off),Set(DEVICE_STATE(Custom:DND_7015)=NOT_INUSE)
same => n,Hangup()
same => n(turn_on),Set(DEVICE_STATE(Custom:DND_7015)=BUSY)
same => n,Hangup()
;
; Пример использования состояния DND.
;
exten => 7015,1,GotoIf($["${DEVICE_STATE(Custom:DND_7015)}"="BUSY"]?busy:available)
same => n(available),Verbose(3,DND is currently off for 7015.)
same => n,Dial(SIP/exampledevice)
same => n,Hangup()
same => n(busy),Verbose(3,DND is on for 7015.)
same => n,Playback(vm-theperson)
same => n,Playback(digits/7&digits/0&digits/1&digits/5)
same => n,Playback(vm-isunavail)
same => n,Playback(vm-goodbye)
same => n,Hangup()

Еще есть прикольное применение, подсмотрел у сименсовских АТСок, Перехват вызова.
Есть у нас парочка телефонов разнесенных по зданию. И вот решил коллега зайти к Вам в гости, по служебным вопросам), НО мы хотим сделать возможным перехват вызова,с его трубу, как будто он ответил со своего места.
В руки ко мне попал аппарат китайских мастеров телефонного дела Grandstream GXP-2000
1. В вебморде аппарата на закладке BASIC SETTINGS находим поле Multi Purpose Key 1 Выставляем Key Mode: BLF, выбираем аккаунт(у этого телефона 4 линии) Name пишем произвольное, а вот UserID точно такое как номер и привязанный к нему hint(например 7107)
2. Создаем перехватывалку))
или отдельным контекстом или..

exten => _**71XX,1,Pickup(${EXTEN:2})
exten => _**71XX,2,Hangup

3. Создаем хинты устройств. Если разбить хинты по разным контекстам, то мы разделим группы пользователей для перехвата, для примера добавил 2 группы.

exten => 7107,hint,SIP/7107
[BLF_Group_1]
exten => 501,hint,SIP/501
exten => 502,hint,SIP/502
exten => 503,hint,SIP/503
[BLF_Group_2]
exten => 504,hint,SIP/504
exten => 505,hint,SIP/505
exten => 506,hint,SIP/506
exten => 507,hint,SIP/507

4. в Sip.conf добавляем контекст подписчика)

[504]
type=friend
username=504
secret=mypassword
context=localcontext
host=dynamic
nat=yes
canreinvite=no
mailbox=504
subscribecontext=BLF_Group_2

Теперь пояснения по индикации
Горит зеленая лампочка — линия свободна, нажав на нее мы наберем данного абонента.
Мигает красная лампочка — кто-то звонит, нажав на нее, мы перехватываем звонок GXP-2000 отправит SIP INVITE на номер “**7107” Астериску.
Горит красная лампочка — кто-то говорит по линии(вх или исх звонок)

Связка Шеф-Секретарь с помощью BLF.
Дано:
Секретарь(359)
Шеф(350)
По умолчанию все звонки приходят на секретаря, и она уже может соединить с шефом.
У каждого на телефоне есть кнопка(цеплял на 4ю линию) при нажатии которой можно изменить состояние связки.
Если секретарь уходит, или шеф хочет лично принимать звонки, это можно сделать нажатием кнопки.
В диалплане создаем вот такую штуку:
Кто хочет может приаккуратить диалплан милости прошу)

exten => DND350,hint,Custom:DND350
exten => DND350,1,Answer()
same => n,GotoIf($["${DEVICE_STATE(Custom:DND350)}"="BUSY"]?turn_off:turn_on)
same => n(turn_off),Set(DEVICE_STATE(Custom:DND350)=NOT_INUSE)
same => n,Hangup()
same => n(turn_on),Set(DEVICE_STATE(Custom:DND350)=BUSY)
same => n,Hangup()

exten => 350,1,NoOp(Start)
same => n, GotoIf($[${CALLERID(num)}=359]?busy:normal)
same => n(normal), GotoIf($["${DEVICE_STATE(Custom:DND350)}"="BUSY"]?busy:available)
same => n(available),Verbose(3,DND is currently off for 350.)
same => n,Dial(SIP/359)
same => n,Hangup()
same => n(busy),Verbose(3,DND is on for 350.)
same => n,Dial(SIP/${EXTEN})
same => n,Hangup()

В качестве конечных устройств Шефа и секретаря я использую Cisco SPA504G
Как прошить обновить и пр, есть у меня в бложеге )

В телефоне настраиваем кнопку, или скриптами, или как в данном случае через вебморду.
Заходим в настройки телефона, Admin->Advanced->Voice->Phone

Выбираем линию, например 4…выставляем:

Extension: Disabled
Share Call Appearance: private
Extended Function: fnc=blf+sd;[email protected]$PROXY;[email protected]$PROXY
Short Name: Какое пожелаете)

Естественно, это нужно проделать на двух телефонах)

Комментарии: