mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 10:33:13 +00:00
Merge changes from timing branch
- Convert chan_iax2 to use the timing API - Convert usage of timing in the core to use the timing API instead of using DAHDI directly - Make a change to the timing API to add the set_rate() function - change the timing core to use a rwlock - merge a timing implementation, res_timing_dahdi Basic testing was successful using res_timing_dahdi git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@122523 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<use>dahdi</use>
|
||||
<use>crypto</use>
|
||||
***/
|
||||
|
||||
@@ -55,7 +54,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/stat.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "asterisk/dahdi.h"
|
||||
#include "asterisk/paths.h" /* need ast_config_AST_DATA_DIR for firmware */
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
@@ -89,6 +87,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/event.h"
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/timing.h"
|
||||
|
||||
#include "iax2.h"
|
||||
#include "iax2-parser.h"
|
||||
@@ -7253,32 +7252,17 @@ static inline int iax2_trunk_expired(struct iax2_trunk_peer *tpeer, struct timev
|
||||
|
||||
static int timing_read(int *id, int fd, short events, void *cbdata)
|
||||
{
|
||||
char buf[1024];
|
||||
int res, processed = 0, totalcalls = 0;
|
||||
struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
|
||||
#ifdef DAHDI_TIMERACK
|
||||
int x = 1;
|
||||
#endif
|
||||
struct timeval now = ast_tvnow();
|
||||
|
||||
if (iaxtrunkdebug)
|
||||
ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
|
||||
if (events & AST_IO_PRI) {
|
||||
#ifdef DAHDI_TIMERACK
|
||||
/* Great, this is a timing interface, just call the ioctl */
|
||||
if (ioctl(fd, DAHDI_TIMERACK, &x)) {
|
||||
ast_log(LOG_WARNING, "Unable to acknowledge DAHDI timer. IAX trunking will fail!\n");
|
||||
usleep(1);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* Read and ignore from the pseudo channel for timing */
|
||||
res = read(fd, buf, sizeof(buf));
|
||||
if (res < 1) {
|
||||
ast_log(LOG_WARNING, "Unable to read from timing fd\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (timingfd > -1) {
|
||||
ast_timer_ack(timingfd, 1);
|
||||
}
|
||||
|
||||
/* For each peer that supports trunking... */
|
||||
AST_LIST_LOCK(&tpeers);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&tpeers, tpeer, list) {
|
||||
@@ -10844,21 +10828,6 @@ static void prune_peers(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void set_timing(void)
|
||||
{
|
||||
#ifdef HAVE_DAHDI
|
||||
int bs = trunkfreq * 8;
|
||||
if (timingfd > -1) {
|
||||
if (
|
||||
#ifdef DAHDI_TIMERACK
|
||||
ioctl(timingfd, DAHDI_TIMERCONFIG, &bs) &&
|
||||
#endif
|
||||
ioctl(timingfd, DAHDI_SET_BLOCKSIZE, &bs))
|
||||
ast_log(LOG_WARNING, "Unable to set blocksize on timing source\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_config_destroy(void)
|
||||
{
|
||||
strcpy(accountcode, "");
|
||||
@@ -11265,7 +11234,6 @@ static int set_config(char *config_file, int reload)
|
||||
cat = ast_category_browse(cfg, cat);
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
set_timing();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -12050,6 +12018,10 @@ static int __unload_module(void)
|
||||
ao2_ref(users, -1);
|
||||
ao2_ref(iax_peercallno_pvts, -1);
|
||||
|
||||
if (timingfd > -1) {
|
||||
ast_timer_close(timingfd);
|
||||
}
|
||||
|
||||
con = ast_context_find(regcontext);
|
||||
if (con)
|
||||
ast_context_destroy(con, "IAX2");
|
||||
@@ -12121,16 +12093,6 @@ static int load_module(void)
|
||||
iax_set_error(iax_error_output);
|
||||
jb_setoutput(jb_error_output, jb_warning_output, NULL);
|
||||
|
||||
#ifdef HAVE_DAHDI
|
||||
#ifdef DAHDI_TIMERACK
|
||||
timingfd = open("/dev/dahdi/timer", O_RDWR);
|
||||
if (timingfd < 0)
|
||||
#endif
|
||||
timingfd = open("/dev/dahdi/pseudo", O_RDWR);
|
||||
if (timingfd < 0)
|
||||
ast_log(LOG_WARNING, "Unable to open IAX timing interface: %s\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
memset(iaxs, 0, sizeof(iaxs));
|
||||
|
||||
for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
|
||||
@@ -12178,6 +12140,11 @@ static int load_module(void)
|
||||
if(set_config(config, 0) == -1)
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
|
||||
timingfd = ast_timer_open();
|
||||
if (timingfd > -1) {
|
||||
ast_timer_set_rate(timingfd, trunkfreq);
|
||||
}
|
||||
|
||||
if (ast_channel_register(&iax2_tech)) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class %s\n", "IAX2");
|
||||
__unload_module();
|
||||
|
@@ -1423,9 +1423,17 @@ int ast_autoservice_start(struct ast_channel *chan);
|
||||
*/
|
||||
int ast_autoservice_stop(struct ast_channel *chan);
|
||||
|
||||
/* If built with dahdi optimizations, force a scheduled expiration on the
|
||||
timer fd, at which point we call the callback function / data */
|
||||
int ast_settimeout(struct ast_channel *c, int samples, int (*func)(const void *data), void *data);
|
||||
/*!
|
||||
* \brief Enable or disable timer ticks for a channel
|
||||
*
|
||||
* \arg rate number of timer ticks per second
|
||||
*
|
||||
* If timers are supported, force a scheduled expiration on the
|
||||
* timer fd, at which point we call the callback function / data
|
||||
*
|
||||
* Call this function with a rate of 0 to turn off the timer ticks
|
||||
*/
|
||||
int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data);
|
||||
|
||||
/*! \brief Transfer a channel (if supported). Returns -1 on error, 0 if not supported
|
||||
and 1 if supported and requested
|
||||
|
@@ -65,8 +65,9 @@ enum ast_timing_event {
|
||||
* public API calls.
|
||||
*/
|
||||
struct ast_timing_functions {
|
||||
int (*timer_open)(unsigned int rate);
|
||||
int (*timer_open)(void);
|
||||
void (*timer_close)(int handle);
|
||||
int (*timer_set_rate)(int handle, unsigned int rate);
|
||||
void (*timer_ack)(int handle, unsigned int quantity);
|
||||
int (*timer_enable_continuous)(int handle);
|
||||
int (*timer_disable_continuous)(int handle);
|
||||
@@ -97,12 +98,10 @@ void ast_uninstall_timing_functions(void *handle);
|
||||
/*!
|
||||
* \brief Open a timing fd
|
||||
*
|
||||
* \arg rate number of timer ticks per second
|
||||
*
|
||||
* \retval -1 error, with errno set
|
||||
* \retval >=0 success
|
||||
*/
|
||||
int ast_timer_open(unsigned int rate);
|
||||
int ast_timer_open(void);
|
||||
|
||||
/*!
|
||||
* \brief Close an opened timing handle
|
||||
@@ -113,6 +112,21 @@ int ast_timer_open(unsigned int rate);
|
||||
*/
|
||||
void ast_timer_close(int handle);
|
||||
|
||||
/*!
|
||||
* \brief Set the timing tick rate
|
||||
*
|
||||
* \arg handle timing fd returned from timer_open()
|
||||
* \arg rate ticks per second, 0 turns the ticks off if needed
|
||||
*
|
||||
* Use this function if you want the timing fd to show input at a certain
|
||||
* rate. The other alternative use of a timing fd, is using the continuous
|
||||
* mode.
|
||||
*
|
||||
* \retval -1 error, with errno set
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_timer_set_rate(int handle, unsigned int rate);
|
||||
|
||||
/*!
|
||||
* \brief Acknowledge a timer event
|
||||
*
|
||||
|
@@ -3299,35 +3299,7 @@ int main(int argc, char *argv[])
|
||||
printf("%s", term_quit());
|
||||
exit(1);
|
||||
}
|
||||
#ifdef HAVE_DAHDI
|
||||
{
|
||||
int fd;
|
||||
int x = 160;
|
||||
fd = open("/dev/dahdi/timer", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
|
||||
ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
|
||||
exit(1);
|
||||
}
|
||||
if ((x = ast_wait_for_input(fd, 300)) < 0) {
|
||||
ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer could not be polled during the DAHDI timer test.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!x) {
|
||||
const char dahdi_timer_error[] = {
|
||||
"Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection. You have options:"
|
||||
"\n\t1. You only have to compile DAHDI support into Asterisk if you need it. One option is to recompile without DAHDI support."
|
||||
"\n\t2. You only have to load DAHDI drivers if you want to take advantage of DAHDI services. One option is to unload DAHDI modules if you don't need them."
|
||||
"\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
|
||||
};
|
||||
ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
|
||||
usleep(100);
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
threadstorage_init();
|
||||
|
||||
astobj2_init();
|
||||
|
@@ -61,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/threadstorage.h"
|
||||
#include "asterisk/slinfactory.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/timing.h"
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
@@ -808,27 +809,19 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_DAHDI
|
||||
tmp->timingfd = open("/dev/dahdi/timer", O_RDWR);
|
||||
tmp->timingfd = ast_timer_open();
|
||||
if (tmp->timingfd > -1) {
|
||||
/* Check if timing interface supports new
|
||||
ping/pong scheme */
|
||||
flags = 1;
|
||||
if (!ioctl(tmp->timingfd, DAHDI_TIMERPONG, &flags))
|
||||
needqueue = 0;
|
||||
}
|
||||
#else
|
||||
tmp->timingfd = -1;
|
||||
#endif
|
||||
|
||||
if (needqueue) {
|
||||
if (pipe(tmp->alertpipe)) {
|
||||
ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
|
||||
alertpipe_failed:
|
||||
#ifdef HAVE_DAHDI
|
||||
if (tmp->timingfd > -1)
|
||||
close(tmp->timingfd);
|
||||
#endif
|
||||
if (tmp->timingfd > -1) {
|
||||
ast_timer_close(tmp->timingfd);
|
||||
}
|
||||
|
||||
sched_context_destroy(tmp->sched);
|
||||
ast_string_field_free_memory(tmp);
|
||||
ast_free(tmp);
|
||||
@@ -1007,10 +1000,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
|
||||
if (write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
|
||||
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
|
||||
chan->name, f->frametype, f->subclass, qlen, strerror(errno));
|
||||
#ifdef HAVE_DAHDI
|
||||
} else if (chan->timingfd > -1) {
|
||||
ioctl(chan->timingfd, DAHDI_TIMERPING, &blah);
|
||||
#endif
|
||||
ast_timer_enable_continuous(chan->timingfd);
|
||||
} else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
|
||||
pthread_kill(chan->blocker, SIGURG);
|
||||
}
|
||||
@@ -1343,7 +1334,7 @@ void ast_channel_free(struct ast_channel *chan)
|
||||
if ((fd = chan->alertpipe[1]) > -1)
|
||||
close(fd);
|
||||
if ((fd = chan->timingfd) > -1)
|
||||
close(fd);
|
||||
ast_timer_close(fd);
|
||||
#ifdef HAVE_EPOLL
|
||||
for (i = 0; i < AST_MAX_FDS; i++) {
|
||||
if (chan->epfd_data[i])
|
||||
@@ -1795,7 +1786,7 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen,
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
ast_settimeout(chan, 160, generator_force, chan);
|
||||
ast_settimeout(chan, 50, generator_force, chan);
|
||||
chan->generator = gen;
|
||||
}
|
||||
|
||||
@@ -2181,21 +2172,26 @@ int ast_waitfordigit(struct ast_channel *c, int ms)
|
||||
return ast_waitfordigit_full(c, ms, -1, -1);
|
||||
}
|
||||
|
||||
int ast_settimeout(struct ast_channel *c, int samples, int (*func)(const void *data), void *data)
|
||||
int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
|
||||
{
|
||||
int res = -1;
|
||||
#ifdef HAVE_DAHDI
|
||||
if (c->timingfd > -1) {
|
||||
if (!func) {
|
||||
samples = 0;
|
||||
data = 0;
|
||||
int res;
|
||||
|
||||
if (c->timingfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
ast_debug(1, "Scheduling timer at %d sample intervals\n", samples);
|
||||
res = ioctl(c->timingfd, DAHDI_TIMERCONFIG, &samples);
|
||||
|
||||
if (!func) {
|
||||
rate = 0;
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
ast_debug(1, "Scheduling timer at %u timer ticks per second\n", rate);
|
||||
|
||||
res = ast_timer_set_rate(c->timingfd, rate);
|
||||
|
||||
c->timingfunc = func;
|
||||
c->timingdata = data;
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2334,7 +2330,7 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram
|
||||
} else if (f->frametype == AST_FRAME_CNG) {
|
||||
if (chan->generator && !chan->timingfunc && (chan->timingfd > -1)) {
|
||||
ast_debug(1, "Generator got CNG, switching to timed mode\n");
|
||||
ast_settimeout(chan, 160, generator_force, chan);
|
||||
ast_settimeout(chan, 50, generator_force, chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
main/file.c
25
main/file.c
@@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/_private.h" /* declare ast_file_init() */
|
||||
#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
|
||||
@@ -659,21 +660,17 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
|
||||
}
|
||||
}
|
||||
if (whennext != s->lasttimeout) {
|
||||
#ifdef HAVE_DAHDI
|
||||
if (s->owner->timingfd > -1) {
|
||||
int zap_timer_samples = whennext;
|
||||
int rate;
|
||||
/* whennext is in samples, but DAHDI timers operate in 8 kHz samples. */
|
||||
if ((rate = ast_format_rate(s->fmt->format)) != 8000) {
|
||||
float factor;
|
||||
factor = ((float) rate) / ((float) 8000.0);
|
||||
zap_timer_samples = (int) ( ((float) zap_timer_samples) / factor );
|
||||
}
|
||||
ast_settimeout(s->owner, zap_timer_samples, ast_fsread_audio, s);
|
||||
} else
|
||||
#endif
|
||||
float samp_rate = (float) ast_format_rate(s->fmt->format);
|
||||
unsigned int rate;
|
||||
|
||||
rate = (unsigned int) roundf(samp_rate / ((float) whennext));
|
||||
|
||||
ast_settimeout(s->owner, rate, ast_fsread_audio, s);
|
||||
} else {
|
||||
s->owner->streamid = ast_sched_add(s->owner->sched,
|
||||
whennext / (ast_format_rate(s->fmt->format) / 1000), ast_fsread_audio, s);
|
||||
}
|
||||
s->lasttimeout = whennext;
|
||||
return FSREAD_SUCCESS_NOSCHED;
|
||||
}
|
||||
@@ -681,9 +678,7 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
|
||||
|
||||
return_failure:
|
||||
s->owner->streamid = -1;
|
||||
#ifdef HAVE_DAHDI
|
||||
ast_settimeout(s->owner, 0, NULL, NULL);
|
||||
#endif
|
||||
return FSREAD_FAILURE;
|
||||
}
|
||||
|
||||
@@ -792,9 +787,7 @@ int ast_closestream(struct ast_filestream *f)
|
||||
if (f->fmt->format & AST_FORMAT_AUDIO_MASK) {
|
||||
f->owner->stream = NULL;
|
||||
AST_SCHED_DEL(f->owner->sched, f->owner->streamid);
|
||||
#ifdef HAVE_DAHDI
|
||||
ast_settimeout(f->owner, 0, NULL, NULL);
|
||||
#endif
|
||||
} else {
|
||||
f->owner->vstream = NULL;
|
||||
AST_SCHED_DEL(f->owner->sched, f->owner->vstreamid);
|
||||
|
@@ -30,7 +30,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/timing.h"
|
||||
#include "asterisk/lock.h"
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(lock);
|
||||
AST_RWLOCK_DEFINE_STATIC(lock);
|
||||
|
||||
static struct ast_timing_functions timer_funcs;
|
||||
|
||||
@@ -38,6 +38,7 @@ void *ast_install_timing_functions(struct ast_timing_functions *funcs)
|
||||
{
|
||||
if (!funcs->timer_open ||
|
||||
!funcs->timer_close ||
|
||||
!funcs->timer_set_rate ||
|
||||
!funcs->timer_ack ||
|
||||
!funcs->timer_get_event ||
|
||||
!funcs->timer_enable_continuous ||
|
||||
@@ -45,94 +46,113 @@ void *ast_install_timing_functions(struct ast_timing_functions *funcs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_wrlock(&lock);
|
||||
|
||||
if (timer_funcs.timer_open) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
ast_log(LOG_NOTICE, "Multiple timing modules are loaded. You should only load one.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timer_funcs = *funcs;
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return &timer_funcs;
|
||||
}
|
||||
|
||||
void ast_uninstall_timing_functions(void *handle)
|
||||
{
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_wrlock(&lock);
|
||||
|
||||
if (handle != &timer_funcs) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&timer_funcs, 0, sizeof(timer_funcs));
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
}
|
||||
|
||||
int ast_timer_open(unsigned int rate)
|
||||
int ast_timer_open(void)
|
||||
{
|
||||
int timer;
|
||||
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_open) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
timer = timer_funcs.timer_open(rate);
|
||||
timer = timer_funcs.timer_open();
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
void ast_timer_close(int timer)
|
||||
{
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_close) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return;
|
||||
}
|
||||
|
||||
timer_funcs.timer_close(timer);
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
}
|
||||
|
||||
int ast_timer_set_rate(int handle, unsigned int rate)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_set_rate) {
|
||||
ast_rwlock_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = timer_funcs.timer_set_rate(handle, rate);
|
||||
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ast_timer_ack(int handle, unsigned int quantity)
|
||||
{
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_ack) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return;
|
||||
}
|
||||
|
||||
timer_funcs.timer_ack(handle, quantity);
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
}
|
||||
|
||||
int ast_timer_enable_continuous(int handle)
|
||||
{
|
||||
int result;
|
||||
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_enable_continuous) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = timer_funcs.timer_enable_continuous(handle);
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -141,16 +161,16 @@ int ast_timer_disable_continous(int handle)
|
||||
{
|
||||
int result;
|
||||
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_disable_continuous) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = timer_funcs.timer_disable_continuous(handle);
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -159,16 +179,16 @@ enum ast_timing_event ast_timer_get_event(int handle)
|
||||
{
|
||||
enum ast_timing_event result;
|
||||
|
||||
ast_mutex_lock(&lock);
|
||||
ast_rwlock_rdlock(&lock);
|
||||
|
||||
if (!timer_funcs.timer_get_event) {
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = timer_funcs.timer_get_event(handle);
|
||||
|
||||
ast_mutex_unlock(&lock);
|
||||
ast_rwlock_unlock(&lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
188
res/res_timing_dahdi.c
Normal file
188
res/res_timing_dahdi.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2008, Digium, Inc.
|
||||
*
|
||||
* Russell Bryant <russell@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \author Russell Bryant <russell@digium.com>
|
||||
*
|
||||
* \brief DAHDI timing interface
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>dahdi</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/timing.h"
|
||||
#include "asterisk/dahdi.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static void *timing_funcs_handle;
|
||||
|
||||
static int dahdi_timer_open(void);
|
||||
static void dahdi_timer_close(int handle);
|
||||
static int dahdi_timer_set_rate(int handle, unsigned int rate);
|
||||
static void dahdi_timer_ack(int handle, unsigned int quantity);
|
||||
static int dahdi_timer_enable_continuous(int handle);
|
||||
static int dahdi_timer_disable_continuous(int handle);
|
||||
static enum ast_timing_event dahdi_timer_get_event(int handle);
|
||||
|
||||
static struct ast_timing_functions dahdi_timing_functions = {
|
||||
.timer_open = dahdi_timer_open,
|
||||
.timer_close = dahdi_timer_close,
|
||||
.timer_set_rate = dahdi_timer_set_rate,
|
||||
.timer_ack = dahdi_timer_ack,
|
||||
.timer_enable_continuous = dahdi_timer_enable_continuous,
|
||||
.timer_disable_continuous = dahdi_timer_disable_continuous,
|
||||
.timer_get_event = dahdi_timer_get_event,
|
||||
};
|
||||
|
||||
static int dahdi_timer_open(void)
|
||||
{
|
||||
return open("/dev/dahdi/timer", O_RDWR);
|
||||
}
|
||||
|
||||
static void dahdi_timer_close(int handle)
|
||||
{
|
||||
close(handle);
|
||||
}
|
||||
|
||||
static int dahdi_timer_set_rate(int handle, unsigned int rate)
|
||||
{
|
||||
int samples;
|
||||
|
||||
/* DAHDI timers are configured using a number of samples,
|
||||
* based on an 8 kHz sample rate. */
|
||||
samples = (unsigned int) roundf((8000.0 / ((float) rate)));
|
||||
|
||||
if (ioctl(handle, DAHDI_TIMERCONFIG, &samples)) {
|
||||
ast_log(LOG_ERROR, "Failed to configure DAHDI timing fd for %u sample timer ticks\n",
|
||||
samples);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dahdi_timer_ack(int handle, unsigned int quantity)
|
||||
{
|
||||
ioctl(handle, DAHDI_TIMERACK, &quantity);
|
||||
}
|
||||
|
||||
static int dahdi_timer_enable_continuous(int handle)
|
||||
{
|
||||
int flags = 1;
|
||||
|
||||
return ioctl(handle, DAHDI_TIMERPING, &flags) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int dahdi_timer_disable_continuous(int handle)
|
||||
{
|
||||
int flags = -1;
|
||||
|
||||
return ioctl(handle, DAHDI_TIMERPONG, &flags) ? -1 : 0;
|
||||
}
|
||||
|
||||
static enum ast_timing_event dahdi_timer_get_event(int handle)
|
||||
{
|
||||
int res;
|
||||
int event;
|
||||
|
||||
res = ioctl(handle, DAHDI_GETEVENT, &event);
|
||||
|
||||
if (res) {
|
||||
event = DAHDI_EVENT_TIMER_EXPIRED;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case DAHDI_EVENT_TIMER_PING:
|
||||
return AST_TIMING_EVENT_CONTINUOUS;
|
||||
case DAHDI_EVENT_TIMER_EXPIRED:
|
||||
default:
|
||||
return AST_TIMING_EVENT_EXPIRED;
|
||||
}
|
||||
}
|
||||
|
||||
static int dahdi_test_timer(void)
|
||||
{
|
||||
int fd;
|
||||
int x = 160;
|
||||
|
||||
fd = open("/dev/dahdi/timer", O_RDWR);
|
||||
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
|
||||
ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((x = ast_wait_for_input(fd, 300)) < 0) {
|
||||
ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer could not be polled during the DAHDI timer test.\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!x) {
|
||||
const char dahdi_timer_error[] = {
|
||||
"Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection. You have options:"
|
||||
"\n\t1. You only have to compile DAHDI support into Asterisk if you need it. One option is to recompile without DAHDI support."
|
||||
"\n\t2. You only have to load DAHDI drivers if you want to take advantage of DAHDI services. One option is to unload DAHDI modules if you don't need them."
|
||||
"\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
|
||||
};
|
||||
ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
|
||||
usleep(100);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
if (dahdi_test_timer()) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
return (timing_funcs_handle = ast_install_timing_functions(&dahdi_timing_functions)) ?
|
||||
AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
ast_uninstall_timing_functions(timing_funcs_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI Timing Interface");
|
Reference in New Issue
Block a user