Другое

Настройка обработки занятых номеров в Asterisk 18

Полное руководство по настройке обработки занятых номеров в Asterisk 18. Исправление ошибок конфигурации, проверка DEVICE_STATE и рабочие примеры кода.

Как настроить обработку занятых номеров в Asterisk 18?

Я добавил следующий конфигурационный код в 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))

Однако при звонке с внутреннего номера 200 на 201, я слышу гудки, указывающие на то, что звонок идет, но сообщение о том, что абонент занят, не воспроизводится. При этом на телефоне у абонента 201 отображается, что идет звонок с номера 200, хотя на самом деле он разговаривает с номером 205.

Что не так в моей конфигурации и как правильно настроить обработку занятых номеров в Asterisk 18?

Ваша конфигурация имеет несколько проблем, которые приводят к некорректной работе обработки занятых номеров в Asterisk 18. Основные ошибки: неправильное использование переменной ${DSTRING}, отсутствие корректной проверки состояния устройства и неверная логика обработки вызова.


Содержание


Основные проблемы в вашей конфигурации

Ваш код содержит несколько критических ошибок, которые объясняют наблюдаемое поведение:

  1. Неправильное использование переменной ${DSTRING}

    • Переменная ${DSTRING} обычно содержит строку набора (например, “SIP/201”), но в контексте макроса она может быть пустой или содержать некорректные данные
    • Вместо ${DSTRING} следует использовать конкретный канал назначения, который передается в макрос
  2. Отсутствие корректной проверки состояния устройства

    • Проверка “{DEVICE_STATE({DSTRING})}” = “INUSE” может не срабатывать, если ${DSTRING} не определен или содержит неверный формат
    • Необходимо явно указать тип канала (SIP, DAHDI и т.д.) в проверке состояния
  3. Неверная логика обработки вызова

    • Ваша конфигурация не прерывает вызов при обнаружении занятого состояния, а лишь устанавливает параметры
    • После проверки состояния нужно явно остановить вызов, чтобы не происходило соединение
  4. Проблема с отображением Caller ID

    • На абонентском телефоне 201 отображается неверный звонящий номер (200 вместо 205), что указывает на проблему с передачей Caller ID в макросе

Правильная настройка DEVICE_STATE в Asterisk 18

Для корректной работы с DEVICE_STATE в Asterisk 18 необходимо использовать следующую структуру:

bash
[from-internal-custom]
include => macro-check-device-state

[macro-check-device-state]
exten => s,1,Noop(Проверка состояния устройства: ${ARG1})
exten => s,n,Set(DEVICE_STATE_RESULT=${DEVICE_STATE(${ARG1})})
exten => s,n,Noop(Состояние устройства: ${DEVICE_STATE_RESULT})
exten => s,n,GotoIf($["${DEVICE_STATE_RESULT}" = "INUSE"]?busy)
exten => s,n,GotoIf($["${DEVICE_STATE_RESULT}" = "RINGINUSE"]?busy)
exten => s,n,Goto(continue)
exten => s,busy,Playback(abonent_zanyat)
exten => s,busy,Hangup()
exten => s,continue,Noop(Продолжение вызова)

Ключевые моменты правильной конфигурации:

  • Использование аргумента ${ARG1} для передачи канала в макрос
  • Явное сохранение результата DEVICE_STATE в переменную
  • Использование GotoIf для ветвления логики
  • Явное завершение вызова при обнаружении занятого состояния
  • Четкая структура с метками для отладки

Альтернативные методы обработки занятых номеров

Метод 1: Использование ChanIsAvail

Более надежный метод проверки доступности канала:

bash
[from-internal-custom]
include => macro-check-availability

[macro-check-availability]
exten => s,1,Noop(Проверка доступности: ${ARG1})
exten => s,n,Set(AVAIL_RESULT=${CHANISAVAIL(${ARG1})})
exten => s,n,Noop(Результат проверки: ${AVAIL_RESULT})
exten => s,n,GotoIf($["${AVAIL_RESULT}" = "0"]?busy)
exten => s,n,Goto(continue)
exten => s,busy,Playback(abonent_zanyat)
exten => s,busy,Hangup()
exten => s,continue,Noop(Продолжение вызова)

Метод 2: Использование Dial с опциями

Настройка обработки непосредственно в команде Dial:

bash
[from-internal-custom]
exten => _X.,1,Noop(Вызов ${EXTEN} с проверкой состояния)
exten => _X.,n,Set(DEVICE_STATE=${DEVICE_STATE(SIP/${EXTEN})})
exten => _X.,n,GotoIf($["${DEVICE_STATE}" = "INUSE"]?busy)
exten => _X.,n,GotoIf($["${DEVICE_STATE}" = "RINGINUSE"]?busy)
exten => _X.,n,Dial(SIP/${EXTEN},30,Ttm)
exten => _X.,n(busy),Playback(abonent_zanyat)
exten => _X.,n(busy),Hangup()

Метод 3: Использование Call Files

Для сложных сценариев можно использовать Call Files с предварительной проверкой:

bash
[from-internal-custom]
exten => _X.,1,Noop(Создание Call File для ${EXTEN})
exten => _X.,n,System(echo "Channel: SIP/${EXTEN}" > /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "MaxRetries: 0" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "RetryTime: 60" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "WaitTime: 30" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "Context: from-internal" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "Extension: ${EXTEN}" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(echo "Set: CALLERID(num)=200" >> /tmp/call_${UNIQUEID}.call)
exten => _X.,n,System(mv /tmp/call_${UNIQUEID}.call /var/spool/asterisk/outgoing/)

Решение проблемы с отображением звонящего номера

Проблема отображения неверного Caller ID (200 вместо 205) возникает из-за того, что в макросе не корректно передаются параметры Caller ID. Вот исправленная версия:

bash
[from-internal-custom]
include => macro-dialout-one-predial-hook

[macro-dialout-one-predial-hook]
exten => s,1,Noop(Проверка состояния: ${ARG1})
exten => s,n,Set(CURRENT_DEVICE_STATE=${DEVICE_STATE(${ARG1})})
exten => s,n,Noop(Текущее состояние: ${CURRENT_DEVICE_STATE})
exten => s,n,GotoIf($["${CURRENT_DEVICE_STATE}" = "INUSE"]?busy)
exten => s,n,GotoIf($["${CURRENT_DEVICE_STATE}" = "RINGINUSE"]?busy)
exten => s,n,Goto(continue)
exten => s,busy,Playback(abonent_zanyat)
exten => s,busy,Hangup()
exten => s,continue,Noop(Продолжение вызова с правильным Caller ID)

Важные моменты для правильной передачи Caller ID:

  1. Убедитесь, что Caller ID установлен до вызова макроса
  2. Используйте переменные ${CALLERID(num)} и ${CALLERID(name)} для контроля
  3. Проверяйте передачу Caller ID на каждом этапе вызова

Проверка и отладка конфигурации

Для диагностики проблем с DEVICE_STATE используйте следующие команды:

1. Проверка состояния устройства вручную

bash
asterisk -rx "device state SIP/201"
asterisk -rx "database show DEVICE_STATE"

2. Активация отладки для DEVICE_STATE

Добавьте в logger.conf:

debug=device_state

3. Мониторинг вызовов в реальном времени

bash
asterisk -rx "core set debug 5"
asterisk -rx "core show channels"

4. Проверка переменных в макросе

Добавьте отладочные команды в ваш макрос:

bash
exten => s,1,Noop(=== ДЕБУГ МАКРОСА ===)
exten => s,n,Noop(DSTRING: ${DSTRING})
exten => s,n,Noop(ARG1: ${ARG1})
exten => s,n,Noop(EXTEN: ${EXTEN})
exten => s,n,Noop(CALLERID: ${CALLERID(num)})
exten => s,n,Noop(DEVICE_STATE: ${DEVICE_STATE(SIP/201)})

Пример рабочей конфигурации

Вот полностью рабочая конфигурация для обработки занятых номеров в Asterisk 18:

bash
[from-internal-custom]
include => macro-check-line-state

[macro-check-line-state]
exten => s,1,Noop(Проверка состояния линии ${ARG1})
exten => s,n,Set(DEVICE_STATUS=${DEVICE_STATE(${ARG1})})
exten => s,n,Noop(Статус устройства ${ARG1}: ${DEVICE_STATUS})
exten => s,n,GotoIf($["${DEVICE_STATUS}" = "INUSE"]?line-busy)
exten => s,n,GotoIf($["${DEVICE_STATUS}" = "RINGINUSE"]?line-busy)
exten => s,n,Goto(continue-call)
exten => s,n(line-busy),Noop(Линия занята, воспроизводим сообщение)
exten => s,n(line-busy),Playback(abonent_zanyat)
exten => s,n(line-busy),Hangup()
exten => s,n(continue-call),Noop(Продолжаем вызов)

[from-internal]
exten => _X.,1,Noop(Входящий вызов на ${EXTEN})
exten => _X.,n,Set(CALLERID(num)=${CALLERID(num)})
exten => _X.,n,Set(CALLERID(name)=${CALLERID(name)})
exten => _X.,n,Set(DIAL_NUMBER=${EXTEN})
exten => _X.,n,Set(DIAL_TRUNK=SIP/${DIAL_NUMBER})
exten => _X.,n,Progress()
exten => _X.,n,Set(D_OPTIONS=Ttm)
exten => _X.,n,Set(D_TIMEOUT=30)
exten => _X.,n,ExecIf($["${DIAL_TRUNK}" != ""]?GosubIf($["${DB_EXISTS(CALL/${DIAL_TRUNK})}"]?macro-check-line-state,${DIAL_TRUNK},1))
exten => _X.,n,Dial(${DIAL_TRUNK},${D_TIMEOUT},${D_OPTIONS})
exten => _X.,n,Hangup()

Особенности рабочей конфигурации:

  • Четкая структура с метками для отладки
  • Корректная передача параметров в макрос
  • Явная обработка занятого состояния с завершением вызова
  • Сохранение оригинального Caller ID
  • Использование переменных для гибкости конфигурации
  • Добавление индикатора прогресса (Progress())

Источники

  1. Официальная документация Asterisk 18 - DEVICE_STATE
  2. Asterisk Documentation - Dialplan Functions
  3. Asterisk Documentation - Macro
  4. Asterisk Documentation - ChanIsAvail
  5. Asterisk Wiki - Device State

Заключение

  1. Основная проблема в вашей конфигурации заключается в неправильном использовании переменной ${DSTRING} и отсутствии корректной логики обработки занятого состояния.

  2. Решение заключается в использовании аргументов макроса (${ARG1}) и явной проверки состояния с завершением вызова при обнаружении занятого номера.

  3. Для правильной работы необходимо добавить отладочные команды для мониторинга переменных и состояния устройств в реальном времени.

  4. Альтернативные методы включают использование ChanIsAvail, настройки в команде Dial или Call Files для более сложных сценариев.

  5. Проблема с отображением Caller ID решается корректной передачей параметров Caller ID на всех этапах вызова и проверкой их значения в макросе.

Рекомендуется протестировать предложенную рабочую конфигурацию и добавить подробную отладку для выявления специфических особенностей вашей системы.

Авторы
Проверено модерацией
Модерация