Ниже — подробный разбор каждой строки приведённого лога Asterisk. Лог относится к моменту обработки входящего или исходящего вызова через канал PJSIP (современный драйвер SIP в Asterisk).
---
1. Настройка TOS и CoS для RTP-аудио
== Using SIP RTP Audio TOS bits 184 == Using SIP RTP Audio TOS bits 184 in TCLASS field. == Using SIP RTP Audio CoS mark 5 Эти строки не являются ошибками, а информируют о применении QoS-меток к RTP-пакетам (аудиотрафику) вызова.
Параметр Значение Что означает TOS bits 184 (десятичная) В IPv4 заголовке поле TOS (Type of Service) устанавливается в 184. В шестнадцатеричном виде это 0xB8. В терминах DSCP (Differentiated Services Code Point) это значение соответствует классу EF (Expedited Forwarding, 46) – высший приоритет для реального времени. TCLASS field те же 184 Для IPv6 вместо TOS используется поле Traffic Class. Значение переиспользуется. CoS mark 5 Класс обслуживания на уровне Ethernet (802.1p). Значение 5 (обычно «voice») означает, что кадры с аудио будут помещаться в высокоприоритетную очередь коммутаторов.
Откуда берутся эти значения? Обычно из конфигурации канала или профиля RTP, например в rtp.conf: tos=ef или tos=184, cos=5. Также могут наследоваться от настроек peer/endpoint в PJSIP.
Зачем нужно? Чтобы голосовые пакеты не задерживались в очередях маршрутизаторов/коммутаторов в условиях перегрузки сети.
---
2. Ошибки CDR
[2026-04-03 23:21:32] ERROR[734261]: cdr.c:3481 ast_cdr_getvar: Unable to find CDR for channel PJSIP/1019-00001a96 [2026-04-03 23:21:32] ERROR[734261]: cdr.c:3481 ast_cdr_getvar: Unable to find CDR for channel PJSIP/1019-00001a96 [2026-04-03 23:21:32] ERROR[734261]: cdr.c:3481 ast_cdr_getvar: Unable to find CDR for channel PJSIP/1019-00001a96 CDR (Call Detail Record) – запись деталей вызова: кто звонил, кому, время начала/окончания, статус и т.д. Функция ast_cdr_getvar пытается прочитать переменную, связанную с CDR канала. Если CDR для канала не существует или уже уничтожена, возникает эта ошибка.
Возможные причины:
· Вызов ещё не полностью установлен – CDR создаётся при начале вызова (обычно на этапе ANSWER или даже раньше). Если скрипт диалплана (или приложение) пытается обратиться к переменным CDR до того, как канал привязан к CDR, получим такую ошибку. · Использование устаревших или несуществующих переменных – например, попытка прочитать ${CDR(uniqueid)} или другую переменную, но модуль cdr не настроен, либо CDR отключена для этого канала (настройка cdr=no в endpoint). · Параллельные или нестандартные сценарии – при transfer, bridge, masquerade канал может временно остаться без собственной CDR. · Три повторения ошибки – скорее всего, скрипт диалплана трижды пытается получить разные переменные CDR (например, ${CDR(src)}, ${CDR(dst)}, ${CDR(duration)}) или один и тот же вызов повторяется из-за цикла.
Как исправить:
· Проверить диалплан: перед обращением к CDR убедиться, что вызов отвечен или хотя бы начат. Иногда помогает принудительно вызвать NoCDR() в начале диалплана (отключает CDR) или, наоборот, ForkCDR() для инициализации. · Убедиться, что в cdr.conf и в конфигурации PJSIP endpoint не запрещена запись CDR. · Если ошибка не влияет на прохождение вызова – можно проигнорировать. Если критична – стоит обновить логику диалплана.
---
3. Выполнение действия Set в диалплане
-- Executing [1920@from-internal:1] Set("PJSIP/1019-00001a96", "__RINGTIMER=15") in new stack Это информационное сообщение (уровень VERBOSE) о том, что Asterisk выполняет команду Set в контексте from-internal, расширение 1920, приоритет 1.
Что происходит:
· Канал: PJSIP/1019-00001a96 – внутренний номер 1019, подключённый через PJSIP, уникальный идентификатор канала. · Устанавливается переменная __RINGTIMER = 15. · Двойное подчёркивание (__) означает наследование: переменная будет скопирована в любой другой канал, который будет соединён с текущим (например, при Dial, Bridge). Обычно используется для передачи таймаутов между каналами.
· RINGTIMER – не встроенная переменная Asterisk, а пользовательская. По смыслу – таймер ринга (сколько секунд ждать ответа вызываемого абонента). Далее в диалплане эта переменная, вероятно, используется в Dial(): Dial(PJSIP/1920,${RINGTIMER}).
Итог: Вызов с номера 1019 пытается дозвониться на расширение 1920, но перед набором задаётся таймер ожидания ответа 15 секунд.
---
Связь всех событий в одном вызове
1. При установке RTP-сессии (ещё до ответа) Asterisk применяет QoS-метки. 2. Одновременно скрипт диалплана (вероятно, в начале обработки вызова) пытается прочитать переменные CDR, но CDR ещё нет – отсюда три ошибки. 3. Затем диалплан продолжает работу, устанавливает переменную __RINGTIMER=15 и, скорее всего, переходит к команде Dial.
Рекомендация: Перенесите чтение переменных CDR на более поздний этап (например, после Answer() или в контекст h). Или подавите ошибки, проверив существование CDR через функцию CDR_exists().
Если же ошибки CDR не мешают работе – их можно игнорировать. QoS-метки и установка таймера работают штатно.
· RINGTIMER – не встроенная переменная Asterisk, а пользовательская. По смыслу – таймер ринга (сколько секунд ждать ответа вызываемого абонента). Далее в диалплане эта переменная, вероятно, используется в Dial(): Dial(PJSIP/1920,${RINGTIMER}).
Итог: Вызов с номера 1019 пытается дозвониться на расширение 1920, но перед набором задаётся таймер ожидания ответа 15 секунд.
---
Связь всех событий в одном вызове
1. При установке RTP-сессии (ещё до ответа) Asterisk применяет QoS-метки. 2. Одновременно скрипт диалплана (вероятно, в начале обработки вызова) пытается прочитать переменные CDR, но CDR ещё нет – отсюда три ошибки. 3. Затем диалплан продолжает работу, устанавливает переменную __RINGTIMER=15 и, скорее всего, переходит к команде Dial.
Рекомендация: Перенесите чтение переменных CDR на более поздний этап (например, после Answer() или в контекст h). Или подавите ошибки, проверив существование CDR через функцию CDR_exists().
Если же ошибки CDR не мешают работе – их можно игнорировать. QoS-метки и установка таймера работают штатно.
Спасибо большое. В принципе, мне это не особо мешает. Просто изначально у меня проблема что все звонки в CDR в базе денных в поле cdr.dst пишет s. Нет там номера куда звонили. Думал может это как-то влияет. Причём в macro-hangupcall всё красиво, проверил ${CDR(dst)} = 1920.
Приветствую, можно получить часовой пояс номера телефона в сервисе num.voxlink.ru? Или делал кто-то маппинг по "region" (какой часовой пояс у региона)? Нужен только для номеров РФ
Приветствую, можно получить часовой пояс номера телефона в сервисе num.voxlink.ru? Или делал кто-то маппинг по "region" (какой часовой пояс у региона)? Нужен только для номеров РФ
Привет! Я делал подобное вручную - брал список регионов, смотрел часовой пояс, сделал mysql табличку, заполнил, пока работает.
; Определение часового пояса вызываемого абонента same => n,Set(tz-region=${SHELL(/var/lib/asterisk/scripts/clean_text.sh "${PSTN_REGION}")}) same => n,Set(ARRAY(tz_region,tz_iana,tz_utc)=${ODBC_GET-TZ-BY-REGION(${tz-region})}) same => n,Return()```
[GET-TZ-BY-REGION] escapecommas=yes dsn=asterisk readsql=SELECT * FROM data.region_timezone WHERE region LIKE '%${SQL_ESC(${ARG1})}%' ORDER BY region ASC LIMIT 1
# Настройка локали (чтобы [:alpha:] поддерживал кириллицу) #export LC_ALL=ru_RU.UTF-8
# Удаляем всё до и включая "и" с пробелами вокруг input=$(echo "$input" | sed -E 's/.*[[:space:]]и[[:space:]]//')
# Шаг 1: удалить "г." (в начале слов) input=$(echo "$input" | sed -E 's/\bг\. ?//g')
# Шаг 2: удалить слово "город" (в любом регистре) input=$(echo "$input" | sed -E 's/\b[Гг]ород\b//g')
# Шаг 3: удалить слова "край", "республика", "округ" input=$(echo "$input" | sed -E 's/\b[Кк]рай\b//g') input=$(echo "$input" | sed -E 's/\b[Рр]еспублика\b//g') input=$(echo "$input" | sed -E 's/\b[Оо]круг\b//g') input=$(echo "$input" | sed -E 's/\b[Оо]бласть\b//g') input=$(echo "$input" | sed -E 's/\b[Оо]бл\b//g')
# Шаг 4: удалить всё в круглых скобках input=$(echo "$input" | sed -E 's/\([^)]*\)//g')
# Шаг 5: удалить всё после тире, если оно окружено пробелами # (поддерживаются: -, – и —) input=$(echo "$input" | sed -E 's/ [\-–—] .*//g') input=$(echo "$input" | sed -E 's/ [\-] .*//g')
# Шаг 6: удалить все символы, кроме букв, пробелов и дефисов (внутри слов) cleaned=$(echo "$input" | sed 's/[^[:alpha:] -]//g')
# Шаг 7: удалить лишние пробелы cleaned=$(echo "$cleaned" | sed -E 's/ +/ /g' | sed -E 's/^ | $//g')