Возврат звонка после безусловного перевода в Asterisk

Возврат звонка после безусловного перевода в Asterisk

Доброго времени суток, уважаемые читатели! Сегодня разберем основные типы трансфера звонка.
В телефонии существует множество видов перевода (трансфера) вызовов, из которых основных всего два: Attended Transfer/Consultative Transfer и Blind Transfer. Давайте рассмотрим каждый из представленных.

Attended transfer (Consultative transfer)

Перевод звонка, при котором секретарь или оператор, получив информацию от абонента А, ставит звонок на удержание, а затем соединяется с абонентом Б (абонент, с которым хочет соединиться абонент А), уведомляет о входящем вызове и лишь после разрешения третьей стороны, соединяет абонентов А и Б. После этого, оператор кладет трубку и больше никак не влияет на переведенный вызов. Таким образом, оператор остается уверенным в том, что звонящий соединен с нужным абонентом. В случае, если абонент Б занят или не отвечает, оператор снова соединяется с абонентом А и сообщает ему о невозможности соединиться с абонентом Б.

Blind transfer (Unattended)

В случае “слепого” перевода всё сложнее: оператор переводит абонента А на абонента Б, и сразу после перевода отключается от разговора. При этом абонент А остается предоставлен судьбе: если абонент Б ему отвечает, то всё хорошо. Если же нет (например, абонент Б занят или не отвечает), то у абонента А в трубке раздаются короткие гудки, после чего ему остается только повесить трубку и попытаться еще раз дозвониться до оператора. Согласитесь, ситуация крайне нежелательная, клиентам приходится заново набирать номер, общаться с оператором, объяснять, что разговора не состоялось и т.д. Теряется время, лояльность клиентов и интерес.Что же делать?
Функции передачи, предоставляемые ядром Asterisk, настраиваются в файлах .conf и доступны по кодами функций.
Технологии драйвера канала, такие как chan_sip и chan_pjsip, имеют встроенную возможность для различных типов трансфера. Эта встроенная функциональность переноса не зависит от функциональности передачи ядра. Функциональность передачи кода основной функции не зависит от канала.

Настройка функции трансфера

Существует три основных требования к использованию функциональных возможностей трансфера.
  • Должен быть включен тип передачи и назначен символьной строкой DTMF в функциях .conf или на канал.
  • Канал должен разрешить попытку передачи. Это можно настроить с помощью приложения, вызывающего канал, например Dial или Queue.
  • На задействованные каналы необходимо ответить и установить мост.

Включение Attended и Blind transfer

В функции features.conf вы должны настроить параметры blindxfer или atxfer в разделе Featuremap. Параметры настраиваются с помощью символьной строки DTMF, которую вы хотите использовать для доступа к этой функции.
[featuremap]
blindxfer = #1
atxfer = *2
Теперь, когда у вас включена функция, вам нужно настроить диалплан таким образом, чтобы конкретный канал мог использовать эту функцию.
В качестве примера, если вы хотите разрешить переводы через приложение Dial, вы можете использовать два варианта: «t» или «T».
  • t – разрешить вызываемой стороне передавать вызывающую сторону, отправив последовательность DTMF, определенную в feature.conf. Этот параметр не выполняет принудительное выполнение политики при переводах, инициированных другими методами;
  • T – разрешить вызывающей стороне передавать вызываемую сторону, отправив последовательность DTMF, определенную в features.conf. Этот параметр не выполняет принудительное выполнение политики при переводах, инициированных другими методами.
Установка этих параметров для Dial в extensions.conf будет выглядеть примерно так:
exten = 100,1,Dial(PJSIP/MAX,30,T)
Аргументы «t» и «T» работают для приложений Queue и Dial

Коды функций для управления attended трансфера

Существует несколько дополнительных кодов функций, связанных с “посещаемыми” переводами. Эти функции позволяют варьировать поведение посещаемой передачи по команде. Все они настроены в разделе [general] файла features.conf

Отмена участия в передаче

atxferabort – прерывает переносимую передачу. В противном случае нет возможности прервать перенесенный перевод.

Завершение участия в передаче

atxfercomplete – завершает посещаемый перевод и завершает вызов без необходимости вешать трубку.

Завершение участия в передаче в качестве трехстороннего моста

atxferthreeway – завершает посещаемый трансфер и соединяет абонентов.

Обмен между получателями

atxferswap – позволяет переключатся между соединяющими сторонами до завершения вызова. Это позволяет вам разговаривать с любой из сторон по одному за раз, прежде чем совершить трансфер.
Пример конфигурации
[general]
atxferabort = *3
atxfercomplete = *4
atxferthreeway = *5
atxferswap = *6

Настройка возврата вызова после attended трансфера

По умолчанию Asterisk перезвонит инициатору передачи, если он повесит трубку до того, как будут получены ответы и истечет время ожидания ответа. Существует несколько вариантов настройки этого поведения.

Нет тайм-аута ответа

atxfernoanswertimeout – позволяет определить время ожидания для attended трансфера. Это количество времени (в секундах), когда Asterisk попытается дозвонится, прежде чем завершить вызов.

Поведение сброшенного вызова

atxferdropcall – позволяет изменять поведение сброшенного вызова по умолчанию. По умолчанию «нет», что приводит к тому, что Asterisk обращается к инициатору передачи, когда он вешает трубку раньше времени, а также время передачи. Если установлено «да», то целевой канал передачи будет немедленно передан на передаваемый канал, как только инициатор зависает.

Время повторного набора

atxferloopdelay – устанавливает количество секунд ожидания между повторами обратного вызова. Этот параметр применим только тогда, когда atxferdropcall = no (или не определено).

Количество попыток для обратных вызовов

atxfercallbackretries – устанавливает количество попыток, когда Asterisk будет отправлять неудачный трансфер обратно инициатору. По умолчанию используется значение 2.
Пример конфигурации:
[general]
atxfernoanswertimeout = 15 
atxferdropcall = no 
atxferloopdelay = 10 
atxfercallbackretries = 2
Параметры поведения
Эти параметры настраиваются в разделе [general] файла features.conf
Общие варианты трансфера
; transferdigittimeout = 3; Количество секунд ожидания между цифрами при передаче вызова
; (по умолчанию - 3 секунды)
Варианты Attended трансфера
; xfersound = beep; указать, что передача участия завершена
; xferfailsound = beeperr; указать неудачную передачу
; transferdialattempts = 3; Количество попыток, по которому переводчик может набрать номер до
; возвращаясь к первоначальному вызову.
; transferretrysound = "beep"; Звук для воспроизведения, когда переводчик не набирает действительное расширение.
; transferinvalidsound = "beeperr"; Звук для воспроизведения, когда переводчик не набирает действительное расширение и не выполняет повторные попытки.

Примеры

С использованием Dial()

Для всех номеров в диалплане после команды Dial выполняется проверка результатов звонка, и если переменная DIALSTATUS не равна ANSWER (т.е. абонент занят, недоступен, не ответил и т.п.), то выполняется следующая команда Dial, соединяющая абонента, например, с секретарем. В случае неответа секретаря (что тоже возможно) выполняется третья команда Dial и так далее.
; Файл extensions.conf:
[local-phones]
exten => _XXX,1,Answer()
exten => _XXX,n(begin),Dial(SIP/${EXTEN},240,tTg)
; g - после окончания вызова, независимо от результата, продолжить выполнение сценария
; если DIALSTATUS = Answer (ответ на вызов), то завершаем вызов:
exten => _XXX,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?end:) 
exten => _XXX,n,Dial(SIP/100,240,tTg)
; 100 - номер секретаря
exten => _XXX,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?end:) 
exten => _XXX,n,Dial(SIP/101,240,tTg)
; 101 - номер второго секретаря
exten => _XXX,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?end:) 
exten => _XXX,n,Dial(SIP/102,240,tTg)
; 102 - номер третьего секретаря
; если никуда не дозвонились - завершаем вызов (или можем сделать goto на begin и продолжать по кругу до бесконечности)
exten => _XXX,n(end),Hangup()

С использованием Attended transfer вместо Blind transfer

Можно переделать attended transfer (сопровождаемый вызов), чтобы в случае неответа абонента вызов возвращался к тому, кто сделал перевод. Для этого в файле features.conf есть опции:
;atxfernoanswertimeout = 15
;atxferdropcall = no
;atxferloopdelay = 10
;atxfercallbackretries = 2
Рассмотрим ситуацию: абонент А звонит абоненту Б и пообщавшись с ним, просит перевести его на абонента С. Если абонент Б (делая attended transfer) дожидается ответа абонента С, возможно общается с ним, и отключается – то абоненты А и С связываются между собой и общаются. Это стандартный сопровождаемый перевод.
Если же абонент Б делает attended transfer на абонента С и сразу (не дожидаясь ответа) кладет трубку, то получается примерно та же ситуация, что и в случае blind transfer. Однако, всё хорошо только в случае, если абонент С снял трубку (или абонент А не дождавшись ответа, положил трубку сам).
atxferdropcall = yes – после неответа абонента С (или если этот абонент занят / сбросил вызов) происходит разрыв соединения, и абоненту А надо снова совершать вызов.
atxferdrpcall = no – теоретически, после неответа (или занятости/сброса вызова) абонента С, вызов абонента А должен вернуться обратно.

С использованием TRANSFER_CONTEXT

Это, вероятно, самый интересный вариант с возвратом вызова после “слепого” перевода. Зачастую необходимость перевести вызов на другого абонента возникает не только у секретаря. Представьте себе фирму (к примеру, тот же call-центр), в которой осуществляются консалтинговые услуги. При этом множество “секретарей” переводят вызовы на специалистов, специалисты могут переводить вызовы друг на друга, и зачастую нет времени (и желания) перевести вызов, а затем дожидаться на него ответа – а хочется перенаправить вызов на нужного сотрудника, чтобы в случае, если человека нет на месте (или он занят) вызов вернулся обратно автоматически. Таким образом, вызов должен возвращаться не “кому-нибудь”, а именно тому человеку, который его перевел.
В этом случае для всех переводимых вызовов настраивается отдельный контекст, в котором они будут обрабатываться (задав значение переменной TRANSFER_CONTEXT). При этом контролируется, был ли ответ на этот переведенный вызов, и при необходимости (используя переменную BLINDTRANSFER) можно вернуть вызов тому абоненту, который осуществлял перевод вызова:
[globals]
TRANSFER_CONTEXT=blind_transfer_mikhed_ringback

[local_phones]
exten => _XXX,1,Answer()
exten => _XXX,n,Dial(SIP/${EXTEN},45,tT)
exten => _XXX,n,Hangup()

[blind_transfer_mikhed_ringback]
exten => _X.,1,NoOp("Blindtransfer: " ${BLINDTRANSFER})
exten => _X.,n,Set(ExtLength=${LEN(${EXTEN})}).
; ${BLINDTRANSFER} - это не оригинальный номер, а оригинальный канал, например: SIP/1111-433242424242
exten => _X.,n,Set(OrigNumber=${BLINDTRANSFER:4:${ExtLength}})
; делаем основной вызов:
exten => _X.,n,Dial(SIP/${EXTEN},45,tTg)
; если он удался, то завершаем вызов, если нет - возвращаемся к тому, кто переводил вызов:
exten => _X.,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?hangup:callback)
exten => _X.,n(callback),Dial(local/${OrigNumber}@local_phones,45,tT)
; Обратите внимание: здесь делается только одна попытка вернуть вызов.
; Однако на самом деле к моменту возврата вызова сотрудник может быть уже занят.
; Так что имеет смысл делать несколько попыток, или перенаправлять вызовы куда-либо еще.
exten => _X.,n(hangup),Hangup().
Обратите внимание: в данном примере возможны переводы звонков только на SIP-абонентов. В общем же случае Вы можете захотеть переводить звонки на группы номеров, либо на номера с обработкой (в extensions.conf) до или после вызова.
Внимание: в описанном выше способе возврата звонка с помощью transfer_context обнаружен небольшой баг, ну или особенность реализации: номер того, кто переводит звонок и номер, куда переводят звонок, должны совпадать по длине. Если (например) у Вас в организации 4-значные номера и Вы переводите звонок на мобильный, то в случае, когда человек не дозвонился, звонок не вернется обратно (будет неправильный номер в OrigNumber). А если (вдруг) у Вас в организации используется много номеров и они могут различаться по длине (например: в одной и той же организации номера 11…19 и 300..399), то описанный выше вариант (с transfer_context) Вам однозначно придется переделывать.
Обратите внимание! С точки зрения безопасности Asterisk, в контексте перевода вызовов использован неправильный шаблон. Если вы хотите запретить внешнему абоненту (входящий вызов из СсОП) осуществлять трансфер вызова, необходимо в функции Dial убрать опцию “T”. Более подробно для чего это нужно вы можете ознакомится в разделе “Безопасность”.

Любое использование материалов сайта возможно только с разрешения автора и с обязательным указанием источника.