четверг, 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

21 комментарий:

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

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

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

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

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

      Удалить
    2. Доброго времени суток! Так все же в elastix как сделать чтоб заработало это?

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

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

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

    ОтветитьУдалить
  5. [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 и оттуда уже рулите.

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

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

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

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

    ОтветитьУдалить
  8. А можно ли сделать так чтобы вторая линия прилетала разговаривающему сразу, а не после окончания "говорилки"? Т.е. номер А - разговаривает, номер Б его вызывает, номеру А высвечивается уведомление только после того как полностью закончится "abonent_zanyat".

    ОтветитьУдалить
    Ответы
    1. Я просто фаилики с мелодией ожидания отредактировал, и в начале муз. дорожки вставил звук автоответчика. Фаилы тут /var/lib/asterisk/moh
      Конфиг такой
      [from-internal-custom]
      include => macro-dialout-one-predial-hook

      [macro-dialout-one-predial-hook]
      exten => s,1,Noop(HINT STATUS - ${EXTENSION_STATE(${DEXTEN})})
      ;exten => s,n,ExecIf($["${EXTENSION_STATE(${DEXTEN})}" = "INUSE"]?Playback(/var/lib/asterisk/sounds/ru/tt-allbusy))
      exten => s,n,ExecIf($["${EXTENSION_STATE(${DEXTEN})}" = "INUSE"]?Set(D_OPTIONS=Ttm))
      ;exten => s,n,ExecIf($["${EXTENSION_STATE(${DEXTEN})}" = "RINGINUSE"]?Playback(/var/lib/asterisk/sounds/ru/tt-allbusy))
      exten => s,n,ExecIf($["${EXTENSION_STATE(${DEXTEN})}" = "RINGINUSE"]?Set(D_OPTIONS=Ttm))

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

      Удалить
    3. Вы случаем не сталкивалась с тем, что при обновлении версии код переставал работать?

      Удалить
    4. Нет. Я просто давно уже не занимался астером. Там где настраивалась эта штука, астер так и не обновлялся, так как было много кастомного, написанного еще до меня, и вот оно тоже ломалось.

      Удалить
  9. О боги, спасибо тебе. Это работает. Единственное - если запись upload-ить через freepbx, нужно в экстеншен_кастом указывать custom/record

    И заставить Freepbx сделать Apply (красная кнопка сверху).

    ОтветитьУдалить
  10. Исключение номера сделал так:
    & $["${CALLERID(name)}" != "1010"] , но вот как исключить несколько номеров...

    ОтветитьУдалить
    Ответы
    1. Нихера исключение номера не работает. Как минимум не callerid надо проверять, а EXTEN

      Удалить