Tamkovich.com: Телеком/VoIP блог
Телеком, ИТ и все все все
Время и Asterisk
Декабрь 21st, 2008 by sergee

Мат. Часть
Наличие синхронизирующего сигнала – является ключевым требованием для реализации такого функционала как: микширование нескольких звуковых потоков, IAX2 уплотнение (trunking), подавление тишины, качественное проигрывание файлов и т.д. До недавнего времени Asterisk использовал модули DAHDI (Zaptel) для доступа к высокоточному таймеру. Данный метод замечательно подходил для пользователей, использующих оборудование Digium. Для тех, у кого телефонных плат не было, предлагался модуль ztdummy. Однако данный модуль вызывал много нареканий. Изначально, ztdummy разрабатывался только для Linux, и имел проблемы с работоспособностью на других unix-like платформах. Начиная с версии 1.6.1 Asterisk переходит на использование нового API времени. Теперь источник точного времени для Asterisk зависит от того, какой модуль вы загрузили. На сегодня доступно три модуля: res_timing_dahdi, res_timing_pthread и res_timing_timerfd.
res_timing_timerfd
Начиная с версии 2.6.22 в ядре доступно новое API для тайминга – timerfd(). Ключевой идеей данного API является ассоциация таймеров с файловыми дескрипторами. Да да! Теперь с таймерами можно работать как с обычными файлами. Вызов
int timerfd_create(int clockid);
создает таймер и возвращает файловый дескриптор ассоциированный с ним. Настроить созданный таймер можно с помощью вызова:
int timerfd_settime(int fd, int flags, const struct itimerspec *timer, struct itimerspec *previous);
Где fd – файловый дескриптор, возвращенный вызовом int timerfd_create(int clockid), timer – указатель на структуру с новыми настройками таймера, а previous – указатель на структуру, где будут сохранены текущие настройки таймера. Теперь, если вызвать read() на дескрипторе, ассоциированном с таймером, вызов заблокируется до срабатывания таймера, иначе, read() вернет целочисленное 64 битное значение, содержащие количество срабатываний таймера.
Месяц назад, 19 ноября, в транк был добавлен новый модуль res_timing_timerfd. Данный модуль реализует доступ к высокоточному источнику времени с помощью нового API ядра. Еще предстоит всестороннее тестирование и обкатка данного модуля, однако уже сейчас он выглядит весьма многообещающе.
res_timing_pthread
Вместе с новыми API времени, в Asterisk был добавлен модуль res_timing_pthread. Принцип работы этого модуля заключается в создании отдельного потока (thread) в фоновом режиме. Далее, с помощью вызовов ast_cond_wait() и ast_cond_timedwait() (которые являются аналогами вызовов pthread_cond_wait() и pthread_cond_timedwait()) при каждом тике таймера в файловый дескритер пайпа записывается байт 0×2A. Данный модуль очень интенсивно использует процессор. Уже были жалобы о невозможности использования данного модуля в устройствах со слабыми (портативными) процессорами. Так же пока не ясно, как изменится точность таймера, предоставляемого данным модулем, при загрузке системы близкой к максимальной. Не стоит использовать данный модуль на production системах, это, скорее, демонстрация возможностей нового API времени.
res_timing_dahdi
Данный модуль является реализацией стандартного, на сегодняшний день, таймера – модулей DAHDI (Zaptel). Исходный код модуля res_timing_dahdi является самым маленьким, т.к. его единственной задачей является трансляция вызовов между API времени Asterisk и модулями DAHDI (Zaptel), с помощью ioctl(). По совместительству, данный таймер является самым «взрослым» и обкатанным решением для Asterisk.
API времени в Asterisk
Новое API времени представляет собой набор программных вызовов, для управления источником времени. Все вызовы описаны в файле заголовке include/asterisk/timing.h. Перечислим их с краткими комментариями:
-
ast_install_timing_functions()– Инициирует колбеки для функций времени. Используется при загрузке модуля, предоставляющего источник времени, для того, что бы сообщить Asterisk адреса функций в модуле. -
ast_uninstall_timing_functions()– Удаляет установленные ранее колбеки. Используется при выгрузке модуля для предотвращения сегфолта. -
ast_timer_open()– Открывает файловый дескриптор таймера для Asterisk. -
ast_timer_close()– Закрывает ранее открытый файловый дескриптор таймера. -
ast_timer_set_rate()– Устанавливает частоту тиков для таймера. -
ast_timer_ack()– Подтверждает срабатывание таймера. Используется только в том случае, если состояние таймера –AST_TIMING_EVENT_EXPIRED. -
ast_timer_enable_continuous()– Перевести таймер в непрерывный режим. Основное отличие непрерывного режима, состоит в том, что вызовpoll()на файловом дескрипторе таймера – не блокируется. -
ast_timer_disable_continuous()– Выключает непрерывный режим таймера. -
ast_timer_get_event()– Возвращает событие, которое вызвало срабатывание таймера. -
ast_timer_get_max_rate()– Возвращает максимальную поддерживаемую частоту тиков для данного таймера.
Использованная литература
- LWN: The new timerfd() API
- Asterisk 1.6, Now with a New Timing API
- A New Timing API for Asterisk, Silencing Digium Critics
- include/asterisk/timing.h
- pthread_cond_wait() и pthread_cond_timedwait()
