Настройка обработки занятых номеров в 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}, отсутствие корректной проверки состояния устройства и неверная логика обработки вызова.
Содержание
- Основные проблемы в вашей конфигурации
- Правильная настройка DEVICE_STATE в Asterisk 18
- Альтернативные методы обработки занятых номеров
- Решение проблемы с отображением звонящего номера
- Проверка и отладка конфигурации
- Пример рабочей конфигурации
Основные проблемы в вашей конфигурации
Ваш код содержит несколько критических ошибок, которые объясняют наблюдаемое поведение:
-
Неправильное использование переменной ${DSTRING}
- Переменная ${DSTRING} обычно содержит строку набора (например, “SIP/201”), но в контексте макроса она может быть пустой или содержать некорректные данные
- Вместо ${DSTRING} следует использовать конкретный канал назначения, который передается в макрос
-
Отсутствие корректной проверки состояния устройства
- Проверка “{DEVICE_STATE({DSTRING})}” = “INUSE” может не срабатывать, если ${DSTRING} не определен или содержит неверный формат
- Необходимо явно указать тип канала (SIP, DAHDI и т.д.) в проверке состояния
-
Неверная логика обработки вызова
- Ваша конфигурация не прерывает вызов при обнаружении занятого состояния, а лишь устанавливает параметры
- После проверки состояния нужно явно остановить вызов, чтобы не происходило соединение
-
Проблема с отображением Caller ID
- На абонентском телефоне 201 отображается неверный звонящий номер (200 вместо 205), что указывает на проблему с передачей Caller ID в макросе
Правильная настройка DEVICE_STATE в Asterisk 18
Для корректной работы с DEVICE_STATE в Asterisk 18 необходимо использовать следующую структуру:
[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
Более надежный метод проверки доступности канала:
[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:
[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 с предварительной проверкой:
[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. Вот исправленная версия:
[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:
- Убедитесь, что Caller ID установлен до вызова макроса
- Используйте переменные ${CALLERID(num)} и ${CALLERID(name)} для контроля
- Проверяйте передачу Caller ID на каждом этапе вызова
Проверка и отладка конфигурации
Для диагностики проблем с DEVICE_STATE используйте следующие команды:
1. Проверка состояния устройства вручную
asterisk -rx "device state SIP/201"
asterisk -rx "database show DEVICE_STATE"
2. Активация отладки для DEVICE_STATE
Добавьте в logger.conf:
debug=device_state
3. Мониторинг вызовов в реальном времени
asterisk -rx "core set debug 5"
asterisk -rx "core show channels"
4. Проверка переменных в макросе
Добавьте отладочные команды в ваш макрос:
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:
[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())
Источники
- Официальная документация Asterisk 18 - DEVICE_STATE
- Asterisk Documentation - Dialplan Functions
- Asterisk Documentation - Macro
- Asterisk Documentation - ChanIsAvail
- Asterisk Wiki - Device State
Заключение
-
Основная проблема в вашей конфигурации заключается в неправильном использовании переменной ${DSTRING} и отсутствии корректной логики обработки занятого состояния.
-
Решение заключается в использовании аргументов макроса (${ARG1}) и явной проверки состояния с завершением вызова при обнаружении занятого номера.
-
Для правильной работы необходимо добавить отладочные команды для мониторинга переменных и состояния устройств в реальном времени.
-
Альтернативные методы включают использование ChanIsAvail, настройки в команде Dial или Call Files для более сложных сценариев.
-
Проблема с отображением Caller ID решается корректной передачей параметров Caller ID на всех этапах вызова и проверкой их значения в макросе.
Рекомендуется протестировать предложенную рабочую конфигурацию и добавить подробную отладку для выявления специфических особенностей вашей системы.