Записываем фразу “В настоящий момент абонент разговаривает, подождите на линии или перезвоните позже” в wav формате и загружаем на сервер. Перекодируем в формат, понятный для астериск:
1 |
sox abonent_zanyat.wav -r 8000 -c 1 -s abonent_zanyat1.wav resample -ql |
Кладем новый файл в директорию /var/lib/asterisk/sounds. После этого открываем диалплан и редактируем контекст внутренних звонков. Рассмотрю самый простой случай, когда изначально было вот так:
1 |
exten => _XXX,1,Dial(SIP/${EXTEN}) |
Редактируем и приводим к такому виду:
1 2 3 4 5 6 7 8 |
exten => _XXX,1,Noop(HINT STATUS - ${EXTENSION_STATE(${EXTEN})}) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "INUSE"]?Playback(abonent_zanyat1)) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "INUSE"]?Dial(SIP/${EXTEN},120,Ttm)) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "RINGINUSE"]?Playback(abonent_zanyat1)) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "RINGINUSE"]?Dial(SIP/${EXTEN},120,Ttm)) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "BUSY"]?Playback(abonent_zanyat1)) exten => _XXX,n,ExecIf($["${EXTENSION_STATE(${EXTEN})}" = "BUSY"]?Dial(SIP/${EXTEN},120,Ttm)) exten => _XXX,n,Dial(SIP/${EXTEN},30,Tt) |
Разберем, что здесь происходит:
1 2 3 4 |
Noop(HINT STATUS — ${EXTENSION_STATE(${EXTEN})}) — чисто отладочная информация, которую потом можно убрать. Просто выводим статус экстеншена в лог. Эта информация помогла мне решить одну проблему, о которой расскажу позже. ExecIf($[«${EXTENSION_STATE(${EXTEN})}» = «INUSE»]?Playback(abonent_zanyat1)) — если статут экстеншена INUSE, проговариваем записанную фразу. ExecIf($[«${EXTENSION_STATE(${EXTEN})}» = «INUSE»]?Dial(SIP/${EXTEN},120,Ttm)) — после проговоренной фразы звонящий будет 120 секунд ожидать ответ и слушать музыку. Далее идет обработка других статусов — RINGINUSE, BUSY. Ниже приведу описание всех возможных статусов. Dial(SIP/${EXTEN},30,Tt) — если он так и не ответил, набираем ему еще раз, слышим уже обычные гудки в течении 30 секунд. |
Насчет пункта 4 есть сомнения. Я просто не знаю, что лучше делать после того, как человек 2 минуты провисел на линии и ему не ответили. Можно направить звонок на секретаря, можно сразу сбросить. Можно еще раз ему проговорить, что абонент занять и опять повесить на ожидание и так по кругу. Я оставил стандартное правило, как было изначально. Мне почему-то кажется, что не так много людей будут висеть 2 минуты на трубке.
В общем, это не принципиально, сами придумайте, как поступать в конкретном случае. Теперь про EXTENSION_STATE. Функция может принимать следующие значения:
1 2 3 4 5 6 7 8 9 10 |
UNKNOWN NOT_INUSE INUSE BUSY INVALID UNAVAILABLE RINGING RINGINUSE HOLDINUSE ONHOLD |
Я не знаю точного описания всех значений, не нашел, но по названиям примерно понятно. Подобрал опытным путем те, что меня интересуют. Если пользователь разговаривает, значение BUSY, если он сам набирает кому-то, то INUSE, если ему идет звонок, но он еще не ответил, то RINGINUSE. Остальные значения в рамках указанной задачи меня не интересуют. Можете добавить сами обработку других ситуаций. Я раньше использовал для этого функцию DIALSTATUS, примерно так:
1 2 3 4 5 |
exten => _XXX,n,Goto(num-${DIALSTATUS},1) exten => num-NOANSWER,1,Wait(2) exten => num-NOANSWER,n,Playback(noanswer) exten => num-CHANUNAVAIL,1,Wait(2) exten => num-CHANUNAVAIL,n,Playback(vm-isunavail) |
Изначально я собирался решать вопрос с уведомлением о занятости пира через dialstatus, но эта функция не подходит. Опытным путем узнал, что если первая линия занята, новый звонок идет на вторую, статус линии не будет busy. Эта функция не подходит.
И еще одно важное замечание. Во время тестирования, пока я не добавил явно в свойства пира call-limit=2, я не мог определить статус пира через EXTENSION_STATE. Не помню, какое значение получал при звонке, но оно точно было не BUSY во время разговора по первой линии. После того, как явно указал call-limit, все заработало как надо.
Во время настройки на разных версиях Asterisk замечал, что иногда не работает функция EXTENSION_STATE. Возвращает значение UNKNOWN. В этом случае использовал другую функцию — DEVICE_STATE. Все остальные настройки те же. Не вдавался в подробности, почему это так. Сходу не мог понять, в чем причина.