mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
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:
449
channel.c
449
channel.c
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user