Version 0.3.0 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@604 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer
2003-02-05 21:18:09 +00:00
parent e403f86b4b
commit b413c00ad1
2 changed files with 220 additions and 41 deletions

235
channel.c
View File

@@ -18,9 +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/pbx.h>
#include <asterisk/frame.h>
#include <asterisk/sched.h>
#include <asterisk/options.h>
@@ -32,6 +32,7 @@
#include <asterisk/manager.h>
#include <asterisk/chanvars.h>
#include <asterisk/linkedlists.h>
#include <asterisk/indications.h>
static int shutting_down = 0;
@@ -132,7 +133,10 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
time_t myt;
time(&myt);
chan->whentohangup = myt + offset;
if (offset)
chan->whentohangup = myt + offset;
else
chan->whentohangup = 0;
return;
}
@@ -290,6 +294,8 @@ struct ast_channel *ast_channel_alloc(int needqueue)
tmp->streamid = -1;
tmp->appl = NULL;
tmp->data = NULL;
tmp->fin = 0;
tmp->fout = 0;
headp=&tmp->varshead;
ast_pthread_mutex_init(&tmp->lock);
AST_LIST_HEAD_INIT(headp);
@@ -326,6 +332,7 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
struct ast_frame *prev, *cur;
int blah = 1;
int qlen = 0;
/* Build us a copy and free the original one */
f = ast_frdup(fin);
if (!f) {
ast_log(LOG_WARNING, "Unable to duplicate frame\n");
@@ -340,6 +347,18 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
cur = cur->next;
qlen++;
}
if (qlen > 128) {
if (fin->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
CRASH;
} else {
ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
ast_frfree(fin);
if (lock)
ast_pthread_mutex_unlock(&chan->lock);
return 0;
}
}
if (prev)
prev->next = f;
else
@@ -349,9 +368,6 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
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));
}
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;
@@ -405,6 +421,27 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
}
int ast_safe_sleep_conditional( struct ast_channel *chan, int ms,
int (*cond)(void*), void *data )
{
struct ast_frame *f;
while(ms > 0) {
if( cond && ((*cond)(data) == 0 ) )
return 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;
}
int ast_safe_sleep(struct ast_channel *chan, int ms)
{
struct ast_frame *f;
@@ -462,6 +499,8 @@ void ast_channel_free(struct ast_channel *chan)
free(chan->callerid);
if (chan->ani)
free(chan->ani);
if (chan->rdnis)
free(chan->rdnis);
pthread_mutex_destroy(&chan->lock);
/* Close pipes if appropriate */
if ((fd = chan->pvt->alertpipe[0]) > -1)
@@ -488,6 +527,7 @@ void ast_channel_free(struct ast_channel *chan)
free(chan->pvt);
chan->pvt = NULL;
free(chan);
PTHREAD_MUTEX_UNLOCK(&chlock);
}
@@ -516,6 +556,8 @@ int ast_softhangup(struct ast_channel *chan, int cause)
return res;
}
static int ast_do_masquerade(struct ast_channel *original);
static void free_translation(struct ast_channel *clone)
{
if (clone->pvt->writetrans)
@@ -535,7 +577,12 @@ int ast_hangup(struct ast_channel *chan)
if someone is going to masquerade as us */
ast_pthread_mutex_lock(&chan->lock);
if (chan->masq) {
ast_log(LOG_WARNING, "We're getting hung up, but someone is trying to masq into us?!?\n");
if (ast_do_masquerade(chan))
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
}
if (chan->masq) {
ast_log(LOG_WARNING, "%s getting hung up, but someone is trying to masq into us?!?\n", chan->name);
ast_pthread_mutex_unlock(&chan->lock);
return 0;
}
@@ -629,6 +676,8 @@ int ast_answer(struct ast_channel *chan)
return res;
break;
case AST_STATE_UP:
if (chan->cdr)
ast_cdr_answer(chan->cdr);
break;
}
return 0;
@@ -704,8 +753,6 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
return winner;
}
static int ast_do_masquerade(struct ast_channel *original);
struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
int *exception, int *outfd, int *ms)
{
@@ -901,8 +948,10 @@ struct ast_frame *ast_read(struct ast_channel *chan)
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");
else {
ast_log(LOG_WARNING, "Exception flag set on '%s', but no exception handler\n", chan->name);
f = &null_frame;
}
/* Clear the exception flag */
chan->exception = 0;
} else
@@ -912,8 +961,14 @@ struct ast_frame *ast_read(struct ast_channel *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) {
if (!(f->subclass & chan->nativeformats)) {
/* This frame can't be from the current native formats -- drop it on the
floor */
ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s since our native format has changed\n", chan->name);
f = &null_frame;
} else if (chan->pvt->readtrans) {
f = ast_translate(chan->pvt->readtrans, f, 1);
if (!f)
f = &null_frame;
@@ -948,14 +1003,14 @@ struct ast_frame *ast_read(struct ast_channel *chan)
int res;
tmp = chan->generatordata;
chan->generatordata = NULL;
res = chan->generator->generate(chan, tmp, f->datalen);
res = chan->generator->generate(chan, tmp, f->datalen, f->samples);
chan->generatordata = tmp;
if (res) {
ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
ast_deactivate_generator(chan);
}
}
chan->fin++;
return f;
}
@@ -965,13 +1020,39 @@ int ast_indicate(struct ast_channel *chan, int condition)
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || ast_check_hangup(chan))
return -1;
if (chan->pvt->indicate) {
if (chan->pvt->indicate)
res = chan->pvt->indicate(chan, condition);
if (res)
ast_log(LOG_WARNING, "Driver for channel '%s' failed to indicate condition %d\n", chan->name, condition);
} else
ast_log(LOG_WARNING, "Driver for channel '%s' does not support indication\n", chan->name);
return res;
if (!chan->pvt->indicate || res) {
/*
* Device does not support (that) indication, lets fake
* it by doing our own tone generation. (PM2002)
*/
if (condition >= 0) {
const struct tone_zone_sound *ts = NULL;
switch (condition) {
case AST_CONTROL_RINGING:
ts = ast_get_indication_tone(chan->zone, "ring");
break;
case AST_CONTROL_BUSY:
ts = ast_get_indication_tone(chan->zone, "busy");
break;
case AST_CONTROL_CONGESTION:
ts = ast_get_indication_tone(chan->zone, "congestion");
break;
}
if (ts && ts->data[0]) {
ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
ast_playtones_start(chan,0,ts->data);
}
else {
/* not handled */
ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
return -1;
}
}
else ast_playtones_stop(chan);
}
return 0;
}
int ast_recvchar(struct ast_channel *chan, int timeout)
@@ -1016,6 +1097,51 @@ int ast_sendtext(struct ast_channel *chan, char *text)
return res;
}
static int do_senddigit(struct ast_channel *chan, char digit)
{
int res = -1;
if (chan->pvt->send_digit)
res = chan->pvt->send_digit(chan, digit);
if (!chan->pvt->send_digit || res) {
/*
* Device does not support DTMF tones, lets fake
* it by doing our own generation. (PM2002)
*/
static const char* dtmf_tones[] = {
"!941+1336/50,!0/50", /* 0 */
"!697+1209/50,!0/50", /* 1 */
"!697+1336/50,!0/50", /* 2 */
"!697+1477/50,!0/50", /* 3 */
"!770+1209/50,!0/50", /* 4 */
"!770+1336/50,!0/50", /* 5 */
"!770+1477/50,!0/50", /* 6 */
"!852+1209/50,!0/50", /* 7 */
"!852+1336/50,!0/50", /* 8 */
"!852+1477/50,!0/50", /* 9 */
"!697+1633/50,!0/50", /* A */
"!770+1633/50,!0/50", /* B */
"!852+1633/50,!0/50", /* C */
"!941+1633/50,!0/50", /* D */
"!941+1209/50,!0/50", /* * */
"!941+1477/50,!0/50" }; /* # */
if (digit >= '0' && digit <='9')
ast_playtones_start(chan,0,dtmf_tones[digit-'0']);
else if (digit >= 'A' && digit <= 'D')
ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10]);
else if (digit == '*')
ast_playtones_start(chan,0,dtmf_tones[14]);
else if (digit == '#')
ast_playtones_start(chan,0,dtmf_tones[15]);
else {
/* not handled */
ast_log(LOG_WARNING, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
return -1;
}
}
return 0;
}
int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
@@ -1045,8 +1171,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
break;
case AST_FRAME_DTMF:
if (chan->pvt->send_digit)
res = chan->pvt->send_digit(chan, fr->subclass);
res = do_senddigit(chan,fr->subclass);
break;
case AST_FRAME_TEXT:
if (chan->pvt->send_text)
@@ -1068,6 +1193,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
/* Consider a write failure to force a soft hangup */
if (res < 0)
chan->_softhangup |= AST_SOFTHANGUP_DEV;
else
chan->fout++;
return res;
}
@@ -1129,7 +1256,7 @@ int ast_set_read_format(struct ast_channel *chan, int fmts)
return 0;
}
struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate)
struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid)
{
int state = 0;
struct ast_channel *chan;
@@ -1138,6 +1265,8 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
chan = ast_request(type, format, data);
if (chan) {
if (callerid)
ast_set_callerid(chan, callerid, 1);
if (!ast_call(chan, data, 0)) {
while(timeout && (chan->_state != AST_STATE_UP)) {
res = ast_waitfor(chan, timeout);
@@ -1370,11 +1499,20 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
return 0;
}
void ast_change_name(struct ast_channel *chan, char *newname)
{
char tmp[256];
strncpy(tmp, chan->name, 256);
strncpy(chan->name, newname, sizeof(chan->name) - 1);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", tmp, chan->name);
}
static int ast_do_masquerade(struct ast_channel *original)
{
int x;
int res=0;
char *tmp;
void *tmpv;
struct ast_channel_pvt *p;
struct ast_channel *clone = original->masq;
int rformat = original->readformat;
@@ -1384,9 +1522,9 @@ static int ast_do_masquerade(struct ast_channel *original)
char masqn[100];
char zombn[100];
#if 0
#if 1
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->state, original->name, original->state);
clone->name, clone->_state, original->name, original->_state);
#endif
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
the clone channel into the original channel. Start by killing off the original
@@ -1456,6 +1594,10 @@ static int ast_do_masquerade(struct ast_channel *original)
/* Copy the FD's */
for (x=0;x<AST_MAX_FDS;x++)
original->fds[x] = clone->fds[x];
/* Move the variables */
tmpv = original->varshead.first;
original->varshead.first = clone->varshead.first;
clone->varshead.first = tmpv;
/* Presense of ADSI capable CPE follows clone */
original->adsicpe = clone->adsicpe;
/* Bridge remains the same */
@@ -1482,6 +1624,11 @@ static int ast_do_masquerade(struct ast_channel *original)
/* Our native formats are different now */
original->nativeformats = clone->nativeformats;
/* And of course, so does our current state. Note we need not
call ast_setstate since the event manager doesn't really consider
these separate */
original->_state = clone->_state;
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
@@ -1492,6 +1639,7 @@ static int ast_do_masquerade(struct ast_channel *original)
if (clone->zombie) {
pthread_mutex_unlock(&clone->lock);
ast_channel_free(clone);
manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
} else {
clone->zombie=1;
pthread_mutex_unlock(&clone->lock);
@@ -1519,19 +1667,26 @@ static int ast_do_masquerade(struct ast_channel *original)
/* Signal any blocker */
if (original->blocking)
pthread_kill(original->blocker, SIGURG);
ast_log(LOG_DEBUG, "Done Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->_state, original->name, original->_state);
return 0;
}
void ast_set_callerid(struct ast_channel *chan, char *callerid)
void ast_set_callerid(struct ast_channel *chan, char *callerid, int anitoo)
{
if (chan->callerid)
free(chan->callerid);
if (callerid)
if (anitoo && chan->ani)
free(chan->ani);
if (callerid) {
chan->callerid = strdup(callerid);
else
if (anitoo)
chan->ani = strdup(callerid);
} else {
chan->callerid = NULL;
if (anitoo)
chan->ani = NULL;
}
if (chan->cdr)
ast_cdr_setcid(chan->cdr, chan);
manager_event(EVENT_FLAG_CALL, "Newcallerid",
"Channel: %s\r\n"
"Callerid: %s\r\n",
@@ -1571,6 +1726,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
struct ast_channel *who = NULL;
int res;
int nativefailed=0;
/* Stop if we're a zombie or need a soft hangup */
if (c0->zombie || ast_check_hangup(c0) || c1->zombie || ast_check_hangup(c1))
return -1;
@@ -1639,7 +1795,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
}
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_WARNING, "Nobody there??\n");
ast_log(LOG_DEBUG, "Nobody there, continuing...\n");
continue;
}
f = ast_read(who);
@@ -1649,6 +1805,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
res = 0;
break;
}
if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
*fo = f;
*rc = who;
@@ -1748,7 +1905,6 @@ struct tonepair_state {
float vol;
int duration;
int pos;
int origrfmt;
int origwfmt;
struct ast_frame f;
unsigned char offset[AST_FRIENDLY_OFFSET];
@@ -1760,7 +1916,6 @@ 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);
}
@@ -1773,17 +1928,11 @@ static void * tonepair_alloc(struct ast_channel *chan, void *params)
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;
@@ -1795,10 +1944,16 @@ static void * tonepair_alloc(struct ast_channel *chan, void *params)
return ts;
}
static int tonepair_generator(struct ast_channel *chan, void *data, int len)
static int tonepair_generator(struct ast_channel *chan, void *data, int len, int samples)
{
struct tonepair_state *ts = data;
int x;
/* we need to prepare a frame with 16 * timelen samples as we're
* generating SLIN audio
*/
len = samples * 2;
if (len > sizeof(ts->data) / 2 - 1) {
ast_log(LOG_WARNING, "Can't generate that much data!\n");
return -1;
@@ -1813,7 +1968,7 @@ static int tonepair_generator(struct ast_channel *chan, void *data, int len)
ts->f.frametype = AST_FRAME_VOICE;
ts->f.subclass = AST_FORMAT_SLINEAR;
ts->f.datalen = len;
ts->f.timelen = len/8;
ts->f.samples = samples;
ts->f.offset = AST_FRIENDLY_OFFSET;
ts->f.data = ts->data;
ast_write(chan, &ts->f);

View File

@@ -192,7 +192,7 @@ static int ast_read_callback(void *data)
s->adj -= (ms - delay);
s->adj -= 2;
}
s->fr.timelen = delay;
s->fr.samples = delay * 8;
#if 0
ast_log(LOG_DEBUG, "delay is %d, adjusting by %d, as last was %d\n", delay, s->adj, ms);
#endif
@@ -218,6 +218,11 @@ static int mp3_apply(struct ast_channel *c, struct ast_filestream *s)
{
/* Select our owner for this stream, and get the ball rolling. */
s->owner = c;
return 0;
}
static int mp3_play(struct ast_filestream *s)
{
ast_read_callback(s);
return 0;
}
@@ -240,6 +245,21 @@ static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
return 0;
}
static int mp3_seek(struct ast_filestream *fs, long sample_offset, int whence)
{
return -1;
}
static int mp3_trunc(struct ast_filestream *fs)
{
return -1;
}
static long mp3_tell(struct ast_filestream *fs)
{
return -1;
}
static char *mp3_getcomment(struct ast_filestream *s)
{
return NULL;
@@ -251,7 +271,11 @@ int load_module()
mp3_open,
mp3_rewrite,
mp3_apply,
mp3_play,
mp3_write,
mp3_seek,
mp3_trunc,
mp3_tell,
mp3_read,
mp3_close,
mp3_getcomment);