четверг, 8 января 2015 г.

Уведовление занятости абонента при включенном Call Waiting в Asterisk.

     Наверное многие знают о существовании опции Call Waiting в Asterisk.  Функция конечно хорошая, но не без недостатка. Если абонент, кому звонят, понимает, что на второй линии другой абонент, на которого он в случае чего может переключиться, то звонящий же не узнает, разговаривает сейчас  абонент на другом конце или просто не отвечает на звонок. И, казалось бы, хорошая опция  этим недостатком может убить  все плюсы. По крайней мере в нашем офисе сотрудники часто были недовольны друг другом, думая что  на их звонки не отвечают.

     В конце концов  мне это надоело и решил искать решение. Нашел его достаточно быстро. Оказалось что я не один, кому не очень понравилась работа это функции. Решение нашел тут.

     Если  коротко, то в extensions_custom.conf надо добавить
  [from-internal-custom]  
 include => macro-dialout-one-predial-hook  
 [macro-dialout-one-predial-hook]   
  exten => s,1,Noop(DEVICE STATE - ${DEVICE_STATE(${DSTRING})})   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Playback(abonent_zanyat))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Set(D_OPTIONS=Ttm))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Playback(abonent_zanyat))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Set(D_OPTIONS=Ttm))   
где abonent_zanyat название проигрываемого файла. Кстати саму начитку заказывать  у сторонних фирм не хотелось (уж больно много просят за пару слов), так что на помощь пришли онлайн синтезаторы речи. В частности этот. Текст был следующий: "В настоящий момент абонент разговаривает. Вы можете дождаться ответа или перезвонить позже." Сохранить файл можно с помощью инструментов разработки  браузера. При выборе голоса Milena получилось очень даже натурально. Был даже удивлен что не сразу и заметно, что это речь синтезатора (особенно если это услышать в трубке телефона).

     В итоге теперь если мы звоним абоненту, который уже разговаривает, то услышим нашу запись, после чего  звонок попадет на удержание. Дальше уже либо дожидаемся ответа, либо кладем трубку.

     Сотрудники теперь довольны =)

UPD. Если у вас версия freepbx не самая свежая (например freepbx 2.11) то в файле ..admin/modules/core/functions.inc.php находим строку
 $ext->add($mcontext,$exten,'godial', new ext_dial('${DSTRING}', '${ARG1},${D_OPTIONS}'));  
и меняем на
 $ext->add($mcontext,$exten,'godial', new ext_execif('$["${QAGENT}"=""]', 'Macro', 'CHECK_DEVICE_STATE,')); 
 $ext->add($mcontext,$exten,'', new ext_dial('${DSTRING}', '${ARG1},${D_OPTIONS}'));  

В extensions_custom.conf в свою очередь контекс именуем не macro-dialout-one-predial-hook, а macro-CHECK_DEVICE_STATE

13 комментариев:

  1. Еще бы путь написал куда этот файлик положить, было бы вообще шикарно!

    ОтветитьУдалить
    Ответы
    1. Ну если не знать где лежит extensions_custom.conf то наверное не стоит и трогать вообще =)
      /etc/asterisk

      Удалить
  2. Буду очень признателен, если кто-то подскажет, почему это решение может не работать в Elastix =)

    ОтветитьУдалить
    Ответы
    1. в Elastix, насколько я помню, ядром является FreePBX версии 2, возможно в столь старой версии не было этого хука.

      Автору спасибо за решение. Год назад перелопатил интернет и не нашел решения, а тут наткнулся случайно на вашу статью. Все работает супер.

      Удалить
  3. Для 13 версии нужно
    ${DEVICE_STATE(${DSTRING})}
    заменить на
    ${EXTENSION_STATE(${DEXTEN})}

    ОтветитьУдалить
  4. Большое спасибо, всё работает. Но, встала необходимость на некоторых экстеншенах не выполнять данный макро (инклюд), как это можно реализовать? Подскажите пожалуйста.

    ОтветитьУдалить
    Ответы
    1. Ну первое что в голову приходит, это изменить строки exten чтоб проверялся CallerID. Вписать туда шаблон типа _10ХХ и по идее слышать уведомление будут только четырехзначные номера, начинающиеся с 10. Но сам подобное не проверял, поэтому сказать не могу.

      Удалить
  5. В том то и дело, что необходимо пяток номеров исключить для которых шаблон не сделать, а все кроме... через / не понятно как перечислять эти кроме, после слеша вроде только один номер можно задать

    ОтветитьУдалить
  6. [macro-CHECK_DEVICE_STATE]
    exten => _[2-3]XX,1,Noop(DEVICE STATE - ${DEVICE_STATE(${DSTRING})})
    exten => _[2-3]XX,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Playback(abonent_zanyat))
    exten => _[2-3]XX,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Set(D_OPTIONS=Ttm))
    exten => _[2-3]XX,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Playback(abonent_zanyat))
    exten => _[2-3]XX,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Set(D_OPTIONS=Ttm))

    Так вообще перестаёт работать данный макро

    ОтветитьУдалить
    Ответы
    1. Тогда другой вариант можно попробовать. Регистрируйте в Custom Context контекст macro и оттуда уже рулите.

      Удалить
  7. C Custom Context не получится. По умолчанию пользователям разрешены все, а контекстов 5. Соответственно создав ещё 1, он применится ко всем. Ув. a7lanov вы случайно не подскажете как вот это реализовать: анализировать содержимое ${DSTRING} и на его основе принимать решение о том двигаться ли по macro далее или выйти из него. Либо ДО вызова macro установить СВОЮ переменную и проверять её.

    ОтветитьУдалить
    Ответы
    1. К сожалению Астериск изучал и ковырял давно. Как видно из публикации 2 года назад . После этого было смена работы (в принципе в том же году), где Астериском заниматься больше не приходилось, и уже подзабыл что и где. Поэтому подсказать тут не смогу.

      К слову в посте есть ссылка на первоисточник (форум), можно там спросить. Контекст сам не писал, взял оттуда.

      Удалить
  8. Всё равно спс за отклик на зов о помощи.

    ОтветитьУдалить