Version 0.1.12 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@465 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer
2002-06-21 01:40:13 +00:00
parent 9086941a86
commit 123613853b
14 changed files with 2703 additions and 273 deletions

449
channel.c
View File

@@ -18,7 +18,9 @@
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <asterisk/lock.h>
#include <unistd.h>
#include <math.h> /* For PI */
#include <asterisk/frame.h>
#include <asterisk/sched.h>
#include <asterisk/options.h>
@@ -28,6 +30,7 @@
#include <asterisk/file.h>
#include <asterisk/translate.h>
static int shutting_down = 0;
/* XXX Lock appropriately in more functions XXX */
@@ -62,7 +65,7 @@ struct ast_channel *channels = NULL;
/* Protect the channel list (highly unlikely that two things would change
it at the same time, but still! */
static pthread_mutex_t chlock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t chlock = AST_MUTEX_INITIALIZER;
int ast_check_hangup(struct ast_channel *chan)
{
@@ -79,6 +82,45 @@ time_t myt;
return 1;
}
void ast_begin_shutdown(int hangup)
{
struct ast_channel *c;
shutting_down = 1;
if (hangup) {
PTHREAD_MUTEX_LOCK(&chlock);
c = channels;
while(c) {
c->softhangup = 1;
c = c->next;
}
PTHREAD_MUTEX_UNLOCK(&chlock);
}
}
int ast_active_channels(void)
{
struct ast_channel *c;
int cnt = 0;
PTHREAD_MUTEX_LOCK(&chlock);
c = channels;
while(c) {
cnt++;
c = c->next;
}
PTHREAD_MUTEX_UNLOCK(&chlock);
return cnt;
}
void ast_cancel_shutdown(void)
{
shutting_down = 0;
}
int ast_shutting_down(void)
{
return shutting_down;
}
void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
{
time_t myt;
@@ -189,11 +231,15 @@ int ast_best_codec(int fmts)
return 0;
}
struct ast_channel *ast_channel_alloc(void)
struct ast_channel *ast_channel_alloc(int needqueue)
{
struct ast_channel *tmp;
struct ast_channel_pvt *pvt;
int x;
int flags;
/* If shutting down, don't allocate any new channels */
if (shutting_down)
return NULL;
PTHREAD_MUTEX_LOCK(&chlock);
tmp = malloc(sizeof(struct ast_channel));
memset(tmp, 0, sizeof(struct ast_channel));
@@ -203,24 +249,43 @@ struct ast_channel *ast_channel_alloc(void)
memset(pvt, 0, sizeof(struct ast_channel_pvt));
tmp->sched = sched_context_create();
if (tmp->sched) {
for (x=0;x<AST_MAX_FDS;x++)
for (x=0;x<AST_MAX_FDS - 1;x++)
tmp->fds[x] = -1;
strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
tmp->pvt = pvt;
tmp->state = AST_STATE_DOWN;
tmp->stack = -1;
tmp->streamid = -1;
tmp->appl = NULL;
tmp->data = NULL;
pthread_mutex_init(&tmp->lock, NULL);
strncpy(tmp->context, "default", sizeof(tmp->context)-1);
strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
tmp->priority=1;
tmp->amaflags = ast_default_amaflags;
strncpy(tmp->accountcode, ast_default_accountcode, sizeof(tmp->accountcode)-1);
tmp->next = channels;
channels= tmp;
if (needqueue &&
pipe(pvt->alertpipe)) {
ast_log(LOG_WARNING, "Alert pipe creation failed!\n");
free(pvt);
free(tmp);
tmp = NULL;
pvt = NULL;
} else {
/* Make sure we've got it done right if they don't */
if (needqueue) {
flags = fcntl(pvt->alertpipe[0], F_GETFL);
fcntl(pvt->alertpipe[0], F_SETFL, flags | O_NONBLOCK);
flags = fcntl(pvt->alertpipe[1], F_GETFL);
fcntl(pvt->alertpipe[1], F_SETFL, flags | O_NONBLOCK);
} else
pvt->alertpipe[0] = pvt->alertpipe[1] = -1;
/* Always watch the alertpipe */
tmp->fds[AST_MAX_FDS-1] = pvt->alertpipe[0];
strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
tmp->pvt = pvt;
tmp->state = AST_STATE_DOWN;
tmp->stack = -1;
tmp->streamid = -1;
tmp->appl = NULL;
tmp->data = NULL;
ast_pthread_mutex_init(&tmp->lock);
strncpy(tmp->context, "default", sizeof(tmp->context)-1);
strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
tmp->priority=1;
tmp->amaflags = ast_default_amaflags;
strncpy(tmp->accountcode, ast_default_accountcode, sizeof(tmp->accountcode)-1);
tmp->next = channels;
channels= tmp;
}
} else {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
free(tmp);
@@ -237,6 +302,56 @@ struct ast_channel *ast_channel_alloc(void)
return tmp;
}
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
{
struct ast_frame *f;
struct ast_frame *prev, *cur;
int blah = 1;
int qlen = 0;
f = ast_frdup(fin);
if (!f) {
ast_log(LOG_WARNING, "Unable to duplicate frame\n");
return -1;
}
if (lock)
ast_pthread_mutex_lock(&chan->lock);
prev = NULL;
cur = chan->pvt->readq;
while(cur) {
prev = cur;
cur = cur->next;
qlen++;
}
if (prev)
prev->next = f;
else
chan->pvt->readq = f;
if (chan->pvt->alertpipe[1] > -1) {
if (write(chan->pvt->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
ast_log(LOG_WARNING, "Unable to write to alert pipe, frametype/subclass %d/%d (qlen = %d): %s!\n",
f->frametype, f->subclass, qlen, strerror(errno));
}
if (qlen > 128) {
ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
}
if (lock)
ast_pthread_mutex_unlock(&chan->lock);
return 0;
}
int ast_queue_hangup(struct ast_channel *chan, int lock)
{
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
return ast_queue_frame(chan, &f, lock);
}
int ast_queue_control(struct ast_channel *chan, int control, int lock)
{
struct ast_frame f = { AST_FRAME_CONTROL, };
f.subclass = control;
return ast_queue_frame(chan, &f, lock);
}
int ast_channel_defer_dtmf(struct ast_channel *chan)
{
int pre = 0;
@@ -272,9 +387,28 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
}
int ast_safe_sleep(struct ast_channel *chan, int ms)
{
struct ast_frame *f;
while(ms > 0) {
ms = ast_waitfor(chan, ms);
if (ms <0)
return -1;
if (ms > 0) {
f = ast_read(chan);
if (!f)
return -1;
ast_frfree(f);
}
}
return 0;
}
void ast_channel_free(struct ast_channel *chan)
{
struct ast_channel *last=NULL, *cur;
int fd;
struct ast_frame *f, *fp;
PTHREAD_MUTEX_LOCK(&chlock);
cur = channels;
while(cur) {
@@ -306,6 +440,17 @@ void ast_channel_free(struct ast_channel *chan)
if (chan->ani)
free(chan->ani);
pthread_mutex_destroy(&chan->lock);
/* Close pipes if appropriate */
if ((fd = chan->pvt->alertpipe[0]) > -1)
close(fd);
if ((fd = chan->pvt->alertpipe[1]) > -1)
close(fd);
f = chan->pvt->readq;
while(f) {
fp = f;
f = f->next;
ast_frfree(fp);
}
free(chan->pvt);
free(chan);
PTHREAD_MUTEX_UNLOCK(&chlock);
@@ -359,6 +504,11 @@ int ast_hangup(struct ast_channel *chan)
ast_stopstream(chan);
if (chan->sched)
sched_context_destroy(chan->sched);
/* Clear any tone stuff remaining */
if (chan->generatordata)
chan->generator->release(chan, chan->generatordata);
chan->generatordata = NULL;
chan->generator = NULL;
if (chan->cdr) {
/* End the CDR if it hasn't already */
ast_cdr_end(chan->cdr);
@@ -434,6 +584,29 @@ int ast_answer(struct ast_channel *chan)
return 0;
}
void ast_deactivate_generator(struct ast_channel *chan)
{
if (chan->generatordata) {
chan->generator->release(chan, chan->generatordata);
chan->generatordata = NULL;
chan->writeinterrupt = 0;
}
}
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
{
if (chan->generatordata) {
chan->generator->release(chan, chan->generatordata);
chan->generatordata = NULL;
}
if ((chan->generatordata = gen->alloc(chan, params))) {
chan->generator = gen;
} else {
return -1;
}
return 0;
}
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
{
/* Wait for x amount of time on a file descriptor to have input. */
@@ -511,9 +684,10 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
tv.tv_usec = (*ms % 1000) * 1000;
FD_ZERO(&rfds);
FD_ZERO(&efds);
for (x=0;x<n;x++) {
for (y=0;y<AST_MAX_FDS;y++) {
if (c[x]->fds[y] > 0) {
if (c[x]->fds[y] > -1) {
FD_SET(c[x]->fds[y], &rfds);
FD_SET(c[x]->fds[y], &efds);
if (c[x]->fds[y] > max)
@@ -623,12 +797,13 @@ char ast_waitfordigit(struct ast_channel *c, int ms)
struct ast_frame *ast_read(struct ast_channel *chan)
{
struct ast_frame *f = NULL;
int blah;
static struct ast_frame null_frame =
{
AST_FRAME_NULL,
};
pthread_mutex_lock(&chan->lock);
ast_pthread_mutex_lock(&chan->lock);
if (chan->masq) {
if (ast_do_masquerade(chan)) {
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
@@ -644,7 +819,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
pthread_mutex_unlock(&chan->lock);
return NULL;
}
if (!chan->deferdtmf && strlen(chan->dtmfq)) {
/* We have DTMF that has been deferred. Return it now */
chan->dtmff.frametype = AST_FRAME_DTMF;
@@ -655,19 +830,35 @@ struct ast_frame *ast_read(struct ast_channel *chan)
return &chan->dtmff;
}
chan->blocker = pthread_self();
if (chan->exception) {
if (chan->pvt->exception)
f = chan->pvt->exception(chan);
/* Read and ignore anything on the alertpipe, but read only
one sizeof(blah) per frame that we send from it */
if (chan->pvt->alertpipe[0] > -1) {
read(chan->pvt->alertpipe[0], &blah, sizeof(blah));
}
/* Check for pending read queue */
if (chan->pvt->readq) {
f = chan->pvt->readq;
chan->pvt->readq = f->next;
/* Interpret hangup and return NULL */
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))
f = NULL;
} else {
chan->blocker = pthread_self();
if (chan->exception) {
if (chan->pvt->exception)
f = chan->pvt->exception(chan);
else
ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
/* Clear the exception flag */
chan->exception = 0;
} else
if (chan->pvt->read)
f = chan->pvt->read(chan);
else
ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
/* Clear the exception flag */
chan->exception = 0;
} else
if (chan->pvt->read)
f = chan->pvt->read(chan);
else
ast_log(LOG_WARNING, "No read routine on channel %s\n", chan);
ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
}
if (f && (f->frametype == AST_FRAME_VOICE)) {
if (chan->pvt->readtrans) {
f = ast_translate(chan->pvt->readtrans, f, 1);
@@ -675,6 +866,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
f = &null_frame;
}
}
/* Make sure we always return NULL in the future */
if (!f) {
chan->softhangup = 1;
@@ -689,10 +881,26 @@ struct ast_frame *ast_read(struct ast_channel *chan)
f = &null_frame;
} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
/* Answer the CDR */
chan->state = AST_STATE_UP;
ast_cdr_answer(chan->cdr);
}
pthread_mutex_unlock(&chan->lock);
/* Run any generator sitting on the line */
if (f && (f->frametype == AST_FRAME_VOICE) && chan->generatordata) {
/* Mask generator data temporarily */
void *tmp;
int res;
tmp = chan->generatordata;
chan->generatordata = NULL;
res = chan->generator->generate(chan, tmp, f->datalen);
chan->generatordata = tmp;
if (res) {
ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
ast_deactivate_generator(chan);
}
}
return f;
}
@@ -769,6 +977,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
if (chan->masqr)
return 0;
if (chan->generatordata) {
if (chan->writeinterrupt)
ast_deactivate_generator(chan);
else
return 0;
}
CHECK_BLOCKING(chan);
switch(fr->frametype) {
case AST_FRAME_CONTROL:
@@ -796,6 +1010,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
}
chan->blocking = 0;
/* Consider a write failure to force a soft hangup */
if (res < 0)
chan->softhangup = 1;
return res;
}
@@ -899,7 +1116,7 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
return anyway. */
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
pthread_mutex_lock(&chan->lock);
ast_pthread_mutex_lock(&chan->lock);
if (!chan->zombie && !ast_check_hangup(chan))
if (chan->pvt->call)
res = chan->pvt->call(chan, addr, timeout);
@@ -975,19 +1192,19 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
chanf = chan->nativeformats;
res = ast_translator_best_choice(&peerf, &chanf);
if (res < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan, chan->nativeformats, peer, peer->nativeformats);
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, chan->nativeformats, peer->name, peer->nativeformats);
return -1;
}
/* Set read format on channel */
res = ast_set_read_format(chan, peerf);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan, chanf);
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set write format on peer channel */
res = ast_set_write_format(peer, peerf);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer, peerf);
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, peerf);
return -1;
}
/* Now we go the other way */
@@ -995,19 +1212,19 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
chanf = chan->nativeformats;
res = ast_translator_best_choice(&chanf, &peerf);
if (res < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer, peer->nativeformats, chan, chan->nativeformats);
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, peer->nativeformats, chan->name, chan->nativeformats);
return -1;
}
/* Set writeformat on channel */
res = ast_set_write_format(chan, chanf);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan, chanf);
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set read format on peer channel */
res = ast_set_read_format(peer, chanf);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer, peerf);
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, peerf);
return -1;
}
return 0;
@@ -1057,7 +1274,7 @@ static int ast_do_masquerade(struct ast_channel *original)
free_translation(original);
/* We need the clone's lock, too */
pthread_mutex_lock(&clone->lock);
ast_pthread_mutex_lock(&clone->lock);
/* Unlink the masquerade */
original->masq = NULL;
@@ -1224,7 +1441,8 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
}
if ((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) {
if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) &&
!(c0->generator || c1->generator)) {
if (ast_channel_make_compatible(c0, c1)) {
ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
return -1;
@@ -1282,10 +1500,14 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
last = who;
#endif
tackygoto:
if (who == c0)
ast_write(c1, f);
else
ast_write(c0, f);
/* Don't copy packets if there is a generator on either one, since they're
not supposed to be listening anyway */
if (!c0->generator && !c1->generator) {
if (who == c0)
ast_write(c1, f);
else
ast_write(c0, f);
}
}
ast_frfree(f);
} else
@@ -1320,3 +1542,136 @@ int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int
return 0;
}
struct tonepair_def {
int freq1;
int freq2;
int duration;
int vol;
};
struct tonepair_state {
float freq1;
float freq2;
float vol;
int duration;
int pos;
int origrfmt;
int origwfmt;
struct ast_frame f;
unsigned char offset[AST_FRIENDLY_OFFSET];
short data[4000];
};
static void tonepair_release(struct ast_channel *chan, void *params)
{
struct tonepair_state *ts = params;
if (chan) {
ast_set_write_format(chan, ts->origwfmt);
ast_set_read_format(chan, ts->origrfmt);
}
free(ts);
}
static void * tonepair_alloc(struct ast_channel *chan, void *params)
{
struct tonepair_state *ts;
struct tonepair_def *td = params;
ts = malloc(sizeof(struct tonepair_state));
if (!ts)
return NULL;
memset(ts, 0, sizeof(struct tonepair_state));
ts->origrfmt = chan->readformat;
ts->origwfmt = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
tonepair_release(NULL, ts);
ts = NULL;
} else if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (read)\n", chan->name);
ast_set_write_format(chan, ts->origwfmt);
tonepair_release(NULL, ts);
ts = NULL;
} else {
ts->freq1 = td->freq1;
ts->freq2 = td->freq2;
ts->duration = td->duration;
ts->vol = td->vol;
}
/* Let interrupts interrupt :) */
chan->writeinterrupt = 1;
return ts;
}
static int tonepair_generator(struct ast_channel *chan, void *data, int len)
{
struct tonepair_state *ts = data;
int x;
if (len > sizeof(ts->data) / 2 - 1) {
ast_log(LOG_WARNING, "Can't generate that much data!\n");
return -1;
}
memset(&ts->f, 0, sizeof(ts->f));
for (x=0;x<len/2;x++) {
ts->data[x] = ts->vol * (
sin((ts->freq1 * 2.0 * M_PI / 8000.0) * (ts->pos + x)) +
sin((ts->freq2 * 2.0 * M_PI / 8000.0) * (ts->pos + x))
);
}
ts->f.frametype = AST_FRAME_VOICE;
ts->f.subclass = AST_FORMAT_SLINEAR;
ts->f.datalen = len;
ts->f.timelen = len/8;
ts->f.offset = AST_FRIENDLY_OFFSET;
ts->f.data = ts->data;
ast_write(chan, &ts->f);
ts->pos += x;
if (ts->duration > 0) {
if (ts->pos >= ts->duration * 8)
return -1;
}
return 0;
}
static struct ast_generator tonepair = {
alloc: tonepair_alloc,
release: tonepair_release,
generate: tonepair_generator,
};
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
{
struct tonepair_def d = { 0, };
d.freq1 = freq1;
d.freq2 = freq2;
d.duration = duration;
if (vol < 1)
d.vol = 8192;
else
d.vol = vol;
if (ast_activate_generator(chan, &tonepair, &d))
return -1;
return 0;
}
void ast_tonepair_stop(struct ast_channel *chan)
{
ast_deactivate_generator(chan);
}
int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
{
struct ast_frame *f;
int res;
if ((res = ast_tonepair_start(chan, freq1, freq2, duration, vol)))
return res;
/* Give us some wiggle room */
while(chan->generatordata && (ast_waitfor(chan, 100) >= 0)) {
f = ast_read(chan);
if (f)
ast_frfree(f);
else
return -1;
}
return 0;
}