а можешь мне скинуть?) Я просто не знаю, в каком формате регион (строка) будет приходить
Как-то так. Раньше не приходилось это делать, поэтому алгоритм, возможно, не самый оптимальный. Но это уже полгода стабильно работает.
а можешь мне скинуть?) Я просто не знаю, в каком формате регион (строка) будет приходить
· 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-метки и установка таймера работают штатно.
В общем, проблема оказалась в настройках менеджера. Когда добавляю в секцию [general] происходят вот такие проблемы и в cdr пишется фигня какая-то, как я указал выше и сыпется ошибка
ERROR[734261]: cdr.c:3481 ast_cdr_getvar: Unable to find CDR for channel
[general]
channelvars=CDR(linkedid),CDR(src),CDR(dst),FullFname,CallMeDISPOSITION,CallMeDURATION,CALLFILENAME,DIALSTATUS,ANSWEREDTIME
Интересно почему!? Кто-нибудь может объяснить?
Проблема, с которой вы столкнулись, — известное ограничение Asterisk. Ошибка возникает из-за того, что директива channelvars пытается получить доступ к переменным CDR до того, как сам механизм CDR будет готов предоставить эти данные.
Давайте разберем это на уровне механики Asterisk.
? Почему возникает ошибка
1. Разное время жизни: Директива channelvars в manager.conf заставляет AMI генерировать события с указанными переменными на протяжении всего жизненного цикла канала (события вроде Newchannel). В то же время, механизм CDR создается немного позже и привязан к конкретному каналу. Запрашивая CDR(src) на старте канала, вы обращаетесь к сущности, которая еще не существует.
2. Синтаксический конфликт: Ожидая простые канальные переменные, channelvars пытается обработать выражение CDR(src) как обычную переменную. Сложный синтаксис с круглыми скобками может нарушить парсинг AMI-протокола, особенно при работе с именами каналов, содержащими специальные символы.
3. Высокая нагрузка: Как упоминалось в списке рассылки, в версиях Asterisk 12+ эта опция стала очень затратной с точки зрения производительности. Прямой доступ к CDR-полям на каждое событие создает значительную нагрузку на систему.
✅ Как правильно передавать CDR-поля в AMI
Вот три надежных способа решить эту задачу без ошибок и падения производительности.
1. Использовать Set(CDR(userfield)) (Рекомендуемый):
В диалплане перед вызовом Dial явно скопируйте нужные данные в специальное поле CDR(userfield), а в manager.conf укажите только его.
· Диалплан: exten => _X.,1,Set(CDR(userfield)=${CDR(src)} ${CDR(dst)})
· manager.conf: channelvars = userfield
· Результат: CDR создается тогда, когда нужно, поле userfield предназначено для хранения дополнительной информации, а его использование в channelvars абсолютно безопасно.
2. Использовать кастомные канальные переменные:
Запишите нужные данные в обычные канальные переменные, которые гарантированно будут существовать с момента создания канала.
· Диалплан: exten => _X.,1,Set(MY_SRC=${CDR(src)})
· manager.conf: channelvars = MY_SRC
· Результат: Канальные переменные доступны всегда, поэтому ошибка Unable to find CDR не возникнет.
3. Читать CDR постфактум через БД/файлы:
Если вам не нужны CDR-данные в реальном времени в AMI, самый надежный способ — просто настроить запись CDR в базу данных (MySQL/PostgreSQL) или CSV-файл и получать информацию оттуда после завершения вызова.
Надеюсь, это объяснение помогло прояснить ситуацию. Если останутся вопросы, мы рядом, чтобы помочь.
Проблема, с которой вы столкнулись, — известное ограничение Asterisk. Ошибка возникает из-за того, что директива channelvars пытается получить доступ к переменным CDR до того, как сам механизм CDR будет готов предоставить эти данные.
Давайте разберем это на уровне механики Asterisk.
? Почему возникает ошибка
1. Разное время жизни: Директива channelvars в manager.conf заставляет AMI генерировать события с указанными переменными на протяжении всего жизненного цикла канала (события вроде Newchannel). В то же время, механизм CDR создается немного позже и привязан к конкретному каналу. Запрашивая CDR(src) на старте канала, вы обращаетесь к сущности, которая еще не существует.
2. Синтаксический конфликт: Ожидая простые канальные переменные, channelvars пытается обработать выражение CDR(src) как обычную переменную. Сложный синтаксис с круглыми скобками может нарушить парсинг AMI-протокола, особенно при работе с именами каналов, содержащими специальные символы.
3. Высокая нагрузка: Как упоминалось в списке рассылки, в версиях Asterisk 12+ эта опция стала очень затратной с точки зрения производительности. Прямой доступ к CDR-полям на каждое событие создает значительную нагрузку на систему.
✅ Как правильно передавать CDR-поля в AMI
Вот три надежных способа решить эту задачу без ошибок и падения производительности.
1. Использовать Set(CDR(userfield)) (Рекомендуемый):
В диалплане перед вызовом Dial явно скопируйте нужные данные в специальное поле CDR(userfield), а в manager.conf укажите только его.
· Диалплан: exten => _X.,1,Set(CDR(userfield)=${CDR(src)} ${CDR(dst)})
· manager.conf: channelvars = userfield
· Результат: CDR создается тогда, когда нужно, поле userfield предназначено для хранения дополнительной информации, а его использование в channelvars абсолютно безопасно.
2. Использовать кастомные канальные переменные:
Запишите нужные данные в обычные канальные переменные, которые гарантированно будут существовать с момента создания канала.
· Диалплан: exten => _X.,1,Set(MY_SRC=${CDR(src)})
· manager.conf: channelvars = MY_SRC
· Результат: Канальные переменные доступны всегда, поэтому ошибка Unable to find CDR не возникнет.
3. Читать CDR постфактум через БД/файлы:
Если вам не нужны CDR-данные в реальном времени в AMI, самый надежный способ — просто настроить запись CDR в базу данных (MySQL/PostgreSQL) или CSV-файл и получать информацию оттуда после завершения вызова.
Надеюсь, это объяснение помогло прояснить ситуацию. Если останутся вопросы, мы рядом, чтобы помочь.
Давайте избегать ГПТ
Давайте. Вы можете без нейросети объяснить? Собственно, меня в первую очередь интересует почему в базу данных в поле dst писался мусор, хотя переменная CDR(dst) была правильная. И эта ошибка проявляется именно тогда, когда указан параметр cannelvars в general в manager.conf.