Version 0.1.8 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Mark Spencer 24 years ago
parent 677e22cd2c
commit 48c30eaca2

@ -24,6 +24,8 @@
#include <asterisk/callerid.h>
#include <asterisk/logger.h>
#include <asterisk/fskmodem.h>
#include "sas.h"
#include "cas.h"
struct callerid_state {
@ -96,6 +98,33 @@ void callerid_get(struct callerid_state *cid, char **name, char **number, int *f
*number = cid->number;
}
int ast_callerid_gen_cas(unsigned char *outbuf, int len)
{
int pos = 0;
int cnt;
int saslen=2400;
if (len < saslen)
return -1;
while(saslen) {
cnt = saslen;
if (cnt > sizeof(sas))
cnt = sizeof(sas);
memcpy(outbuf + pos, sas, cnt);
pos += cnt;
len -= cnt;
saslen -= cnt;
}
while(len) {
cnt = len;
if (cnt > sizeof(cas))
cnt = sizeof(cas);
memcpy(outbuf + pos, cas, cnt);
pos += cnt;
len -= cnt;
}
return 0;
}
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
{
int mylen = len;
@ -363,7 +392,7 @@ static inline float callerid_getcarrier(float *cr, float *ci, int bit)
PUT_CLID_BAUD(1); /* Stop bit */ \
} while(0);
int callerid_generate(unsigned char *buf, char *number, char *name, int flags)
int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting)
{
int bytes=0;
int x, sum;
@ -373,11 +402,14 @@ int callerid_generate(unsigned char *buf, char *number, char *name, int flags)
float scont = 0.0;
char msg[256];
callerid_genmsg(msg, sizeof(msg), number, name, flags);
for (x=0;x<4000;x++)
PUT_BYTE(0x7f);
/* Transmit 30 0x55's (looks like a square wave */
for (x=0;x<30;x++)
PUT_CLID(0x55);
if (!callwaiting) {
/* Wait a half a second */
for (x=0;x<4000;x++)
PUT_BYTE(0x7f);
/* Transmit 30 0x55's (looks like a square wave) for channel seizure */
for (x=0;x<30;x++)
PUT_CLID(0x55);
}
/* Send 150ms of callerid marks */
for (x=0;x<150;x++)
PUT_CLID_MARKMS;
@ -412,6 +444,8 @@ void ast_shrink_phone_number(char *n)
int ast_isphonenumber(char *n)
{
int x;
if (!n)
return 0;
for (x=0;n[x];x++)
if (!strchr("0123456789", n[x]))
return 0;
@ -422,6 +456,7 @@ int ast_callerid_parse(char *instr, char **name, char **location)
{
char *ns, *ne;
char *ls, *le;
char tmp[256];
/* Try for "name" <location> format or
name <location> format */
if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
@ -446,29 +481,46 @@ int ast_callerid_parse(char *instr, char **name, char **location)
return 0;
}
} else {
/* Assume it's just a location */
*name = NULL;
*location = instr;
strncpy(tmp, instr, sizeof(tmp));
ast_shrink_phone_number(tmp);
if (!ast_isphonenumber(tmp)) {
/* Assume it's just a location */
*name = NULL;
*location = instr;
} else {
/* Assume it's just a name */
*name = instr;
*location = NULL;
}
return 0;
}
return -1;
}
int ast_callerid_generate(unsigned char *buf, char *callerid)
static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting)
{
char tmp[256];
char *n, *l;
if (!callerid)
return callerid_generate(buf, NULL, NULL, 0);
return callerid_generate(buf, NULL, NULL, 0, callwaiting);
strncpy(tmp, callerid, sizeof(tmp));
if (ast_callerid_parse(tmp, &n, &l)) {
ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
return callerid_generate(buf, NULL, NULL, 0);
return callerid_generate(buf, NULL, NULL, 0, callwaiting);
}
ast_shrink_phone_number(l);
if (!n && (!ast_isphonenumber(l)))
return callerid_generate(buf, NULL, NULL, 0);
if (!ast_isphonenumber(l))
return callerid_generate(buf, NULL, n, 0);
return callerid_generate(buf, l, n, 0);
if (l)
ast_shrink_phone_number(l);
if (!ast_isphonenumber(l))
return callerid_generate(buf, NULL, n, 0, callwaiting);
return callerid_generate(buf, l, n, 0, callwaiting);
}
int ast_callerid_generate(unsigned char *buf, char *callerid)
{
return __ast_callerid_generate(buf, callerid, 0);
}
int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid)
{
return __ast_callerid_generate(buf, callerid, 1);
}

@ -28,6 +28,7 @@
#include <asterisk/translate.h>
/* XXX Lock appropriately in more functions XXX */
#ifdef DEBUG_MUTEX
/* Convenient mutex debugging functions */
@ -36,16 +37,16 @@
static int __PTHREAD_MUTEX_LOCK(char *f, pthread_mutex_t *a) {
ast_log(LOG_DEBUG, "Locking %p (%s)\n", a, f);
return pthread_mutex_lock(a);
return ast_pthread_mutex_lock(a);
}
static int __PTHREAD_MUTEX_UNLOCK(char *f, pthread_mutex_t *a) {
ast_log(LOG_DEBUG, "Unlocking %p (%s)\n", a, f);
return pthread_mutex_unlock(a);
return ast_pthread_mutex_unlock(a);
}
#else
#define PTHREAD_MUTEX_LOCK(a) pthread_mutex_lock(a)
#define PTHREAD_MUTEX_UNLOCK(a) pthread_mutex_unlock(a)
#define PTHREAD_MUTEX_LOCK(a) ast_pthread_mutex_lock(a)
#define PTHREAD_MUTEX_UNLOCK(a) ast_pthread_mutex_unlock(a)
#endif
struct chanlist {
@ -103,10 +104,35 @@ int ast_channel_register(char *type, char *description, int capabilities,
return 0;
}
char *ast_state2str(int state)
{
switch(state) {
case AST_STATE_DOWN:
return "Down";
case AST_STATE_RESERVED:
return "Rsrvd";
case AST_STATE_OFFHOOK:
return "OffHook";
case AST_STATE_DIALING:
return "Dialing";
case AST_STATE_RING:
return "Ring";
case AST_STATE_RINGING:
return "Ringing";
case AST_STATE_UP:
return "Up";
case AST_STATE_BUSY:
return "Busy";
default:
return "Unknown";
}
}
struct ast_channel *ast_channel_alloc(void)
{
struct ast_channel *tmp;
struct ast_channel_pvt *pvt;
int x;
PTHREAD_MUTEX_LOCK(&chlock);
tmp = malloc(sizeof(struct ast_channel));
memset(tmp, 0, sizeof(struct ast_channel));
@ -116,7 +142,8 @@ struct ast_channel *ast_channel_alloc(void)
memset(pvt, 0, sizeof(struct ast_channel_pvt));
tmp->sched = sched_context_create();
if (tmp->sched) {
tmp->fd = -1;
for (x=0;x<AST_MAX_FDS;x++)
tmp->fds[x] = -1;
strncpy(tmp->name, "**Unknown**", sizeof(tmp->name));
tmp->pvt = pvt;
tmp->state = AST_STATE_DOWN;
@ -206,16 +233,10 @@ void ast_channel_free(struct ast_channel *chan)
int ast_softhangup(struct ast_channel *chan)
{
int res = 0;
if (chan->stream)
ast_stopstream(chan);
if (option_debug)
ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
if (chan->pvt->hangup)
res = chan->pvt->hangup(chan);
if (chan->pvt->pvt)
ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
if (chan->pbx)
ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
/* Inform channel driver that we need to be hung up, if it cares */
chan->softhangup = 1;
/* Interrupt any select call or such */
if (chan->blocking)
pthread_kill(chan->blocker, SIGURG);
@ -225,6 +246,16 @@ int ast_softhangup(struct ast_channel *chan)
int ast_hangup(struct ast_channel *chan)
{
int res = 0;
/* Don't actually hang up a channel that will masquerade as someone else, or
if someone is going to masquerade as us */
if (chan->masq)
return 0;
/* If this channel is one which will be masqueraded into something,
mark it as a zombie already, so we know to free it later */
if (chan->masqr) {
chan->zombie=1;
return 0;
}
if (chan->stream)
ast_stopstream(chan);
if (chan->sched)
@ -235,10 +266,15 @@ int ast_hangup(struct ast_channel *chan)
pthread_self(), chan->name, chan->blocker, chan->blockproc);
CRASH;
}
if (option_debug)
ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
if (chan->pvt->hangup)
res = chan->pvt->hangup(chan);
if (!chan->zombie) {
if (option_debug)
ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
if (chan->pvt->hangup)
res = chan->pvt->hangup(chan);
} else
if (option_debug)
ast_log(LOG_DEBUG, "Hanging up zombie '%s'\n", chan->name);
ast_channel_free(chan);
return res;
}
@ -271,10 +307,18 @@ void ast_channel_unregister(char *type)
int ast_answer(struct ast_channel *chan)
{
/* Answer the line, if possible */
if (chan->state == AST_STATE_RING) {
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup)
return -1;
switch(chan->state) {
case AST_STATE_RING:
case AST_STATE_RINGING:
if (chan->pvt->answer)
return chan->pvt->answer(chan);
chan->state = AST_STATE_UP;
break;
case AST_STATE_UP:
break;
}
return 0;
}
@ -293,84 +337,125 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
FD_ZERO(&rfds);
FD_ZERO(&efds);
for (x=0;x<n;x++) {
FD_SET(fds[x], &rfds);
FD_SET(fds[x], &efds);
if (fds[x] > max)
max = fds[x];
if (fds[x] > -1) {
FD_SET(fds[x], &rfds);
FD_SET(fds[x], &efds);
if (fds[x] > max)
max = fds[x];
}
}
if (*ms >= 0)
res = select(max + 1, &rfds, NULL, &efds, &tv);
else
res = select(max + 1, &rfds, NULL, &efds, NULL);
if (res < 0) {
/* Simulate a timeout if we were interrupted */
if (errno != EINTR)
*ms = -1;
else
*ms = 0;
return -1;
}
for (x=0;x<n;x++) {
if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
if ((fds[x] > -1) && (FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
if (exception)
*exception = FD_ISSET(fds[x], &efds);
winner = fds[x];
}
}
*ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (res < 0)
*ms = -10;
return winner;
}
static int ast_do_masquerade(struct ast_channel *original);
struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
{
/* Wait for x amount of time on a file descriptor to have input. */
struct timeval tv;
fd_set rfds, efds;
int res;
int x, max=-1;
int x, y, max=-1;
struct ast_channel *winner = NULL;
/* Perform any pending masquerades */
for (x=0;x<n;x++) {
if (c[x]->masq) {
if (ast_do_masquerade(c[x])) {
ast_log(LOG_WARNING, "Masquerade failed\n");
*ms = -1;
return NULL;
}
}
}
tv.tv_sec = *ms / 1000;
tv.tv_usec = (*ms % 1000) * 1000;
FD_ZERO(&rfds);
FD_ZERO(&efds);
for (x=0;x<n;x++) {
FD_SET(c[x]->fd, &rfds);
FD_SET(c[x]->fd, &efds);
for (y=0;y<AST_MAX_FDS;y++) {
if (c[x]->fds[y] > 0) {
FD_SET(c[x]->fds[y], &rfds);
FD_SET(c[x]->fds[y], &efds);
if (c[x]->fds[y] > max)
max = c[x]->fds[y];
}
}
CHECK_BLOCKING(c[x]);
if (c[x]->fd > max)
max = c[x]->fd;
}
if (*ms >= 0)
res = select(max + 1, &rfds, NULL, &efds, &tv);
else
res = select(max + 1, &rfds, NULL, &efds, NULL);
if (res < 0) {
for (x=0;x<n;x++)
c[x]->blocking = 0;
/* Simulate a timeout if we were interrupted */
if (errno != EINTR)
*ms = -1;
else
*ms = 0;
return NULL;
}
for (x=0;x<n;x++) {
c[x]->blocking = 0;
if ((FD_ISSET(c[x]->fd, &rfds) || FD_ISSET(c[x]->fd, &efds)) && !winner) {
/* Set exception flag if appropriate */
if (FD_ISSET(c[x]->fd, &efds))
c[x]->exception = 1;
winner = c[x];
for (y=0;y<AST_MAX_FDS;y++) {
if (c[x]->fds[y] > -1) {
if ((FD_ISSET(c[x]->fds[y], &rfds) || FD_ISSET(c[x]->fds[y], &efds)) && !winner) {
/* Set exception flag if appropriate */
if (FD_ISSET(c[x]->fds[y], &efds))
c[x]->exception = 1;
c[x]->fdno = y;
winner = c[x];
}
}
}
}
*ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (res < 0)
*ms = -10;
return winner;
}
int ast_waitfor(struct ast_channel *c, int ms)
{
if (ast_waitfor_n(&c, 1, &ms)) {
if (ms < 0)
return -ms;
return ms;
}
/* Error if ms < 0 */
if (ms < 0)
struct ast_channel *chan;
chan = ast_waitfor_n(&c, 1, &ms);
if (ms < 0)
return -1;
return 0;
return ms;
}
char ast_waitfordigit(struct ast_channel *c, int ms)
{
struct ast_frame *f;
char result = 0;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || c->softhangup)
return -1;
/* Wait for a digit, no more than ms milliseconds total. */
while(ms && !result) {
ms = ast_waitfor(c, ms);
@ -397,6 +482,24 @@ struct ast_frame *ast_read(struct ast_channel *chan)
{
AST_FRAME_NULL,
};
pthread_mutex_lock(&chan->lock);
if (chan->masq) {
if (ast_do_masquerade(chan)) {
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
f = NULL;
} else
f = &null_frame;
pthread_mutex_unlock(&chan->lock);
return f;
}
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup) {
pthread_mutex_unlock(&chan->lock);
return NULL;
}
chan->blocker = pthread_self();
if (chan->exception) {
if (chan->pvt->exception)
@ -417,12 +520,35 @@ 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;
pthread_mutex_unlock(&chan->lock);
return f;
}
int ast_indicate(struct ast_channel *chan, int condition)
{
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup)
return -1;
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;
}
int ast_sendtext(struct ast_channel *chan, char *text)
{
int res = 0;
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup)
return -1;
CHECK_BLOCKING(chan);
if (chan->pvt->send_text)
res = chan->pvt->send_text(chan, text);
@ -434,6 +560,18 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
struct ast_frame *f;
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup)
return -1;
/* Handle any pending masquerades */
if (chan->masq) {
if (ast_do_masquerade(chan)) {
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
return -1;
}
}
if (chan->masqr)
return 0;
CHECK_BLOCKING(chan);
switch(fr->frametype) {
case AST_FRAME_CONTROL:
@ -453,6 +591,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
f = fr;
if (f)
res = chan->pvt->write(chan, f);
else
res = 0;
}
}
chan->blocking = 0;
@ -483,7 +623,8 @@ int ast_set_write_format(struct ast_channel *chan, int fmts)
ast_translator_free_path(chan->pvt->writetrans);
/* Build a translation path from the user write format to the raw writing format */
chan->pvt->writetrans = ast_translator_build_path(chan->pvt->rawwriteformat, chan->writeformat);
ast_log(LOG_DEBUG, "Set channel %s to format %d\n", chan->name, chan->writeformat);
if (option_debug)
ast_log(LOG_DEBUG, "Set channel %s to format %d\n", chan->name, chan->writeformat);
return 0;
}
@ -555,8 +696,12 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
If the remote end does not answer within the timeout, then do NOT hang up, but
return anyway. */
int res = -1;
if (chan->pvt->call)
res = chan->pvt->call(chan, addr, timeout);
/* Stop if we're a zombie or need a soft hangup */
pthread_mutex_lock(&chan->lock);
if (!chan->zombie && !chan->softhangup)
if (chan->pvt->call)
res = chan->pvt->call(chan, addr, timeout);
pthread_mutex_unlock(&chan->lock);
return res;
}
@ -565,6 +710,9 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
int pos=0;
int to = ftimeout;
char d;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || c->softhangup)
return -1;
if (!len)
return -1;
do {
@ -638,7 +786,134 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
return 0;
}
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
{
ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
clone->name, original->name);
if (original->masq) {
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
original->masq->name, original->name);
return -1;
}
if (clone->masqr) {
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
clone->name, clone->masqr->name);
return -1;
}
original->masq = clone;
clone->masqr = original;
return 0;
}
static int ast_do_masquerade(struct ast_channel *original)
{
int x;
int res=0;
char *tmp;
struct ast_channel_pvt *p;
struct ast_channel *clone = original->masq;
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->state, original->name, original->state);
/* 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
channel's backend. I'm not sure we're going to keep this function, because
while the features are nice, the cost is very high in terms of pure nastiness. XXX */
/* We need the clone's lock, too */
pthread_mutex_lock(&clone->lock);
/* Unlink the masquerade */
original->masq = NULL;
clone->masqr = NULL;
/* Copy the name from the clone channel */
strncpy(original->name, clone->name, sizeof(original->name));
/* Mangle the name of the clone channel */
strncat(clone->name, "<MASQ>", sizeof(clone->name));
/* Swap the guts */
p = original->pvt;
original->pvt = clone->pvt;
clone->pvt = p;
/* Start by disconnecting the original's physical side */
if (clone->pvt->hangup)
res = clone->pvt->hangup(clone);
if (res) {
ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n");
pthread_mutex_unlock(&clone->lock);
return -1;
}
/* Mangle the name of the clone channel */
snprintf(clone->name, sizeof(clone->name), "%s<ZOMBIE>", original->name);
/* Keep the same language. */
/* Update the type. */
original->type = clone->type;
/* Copy the FD's */
for (x=0;x<AST_MAX_FDS;x++)
original->fds[x] = clone->fds[x];
/* Bridge remains the same */
/* CDR fields remain the same */
/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
/* Application and data remain the same */
/* Clone exception becomes real one, as with fdno */
original->exception = clone->exception;
original->fdno = clone->fdno;
/* Schedule context remains the same */
/* Stream stuff stays the same */
/* Keep the original state. The fixup code will need to work with it most likely */
/* dnid and callerid change to become the new, HOWEVER, we also link the original's
fields back into the defunct 'clone' so that they will be freed when
ast_frfree is eventually called */
tmp = original->dnid;
original->dnid = clone->dnid;
clone->dnid = tmp;
tmp = original->callerid;
original->callerid = clone->callerid;
clone->callerid = tmp;
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
/* Now, at this point, the "clone" channel is totally F'd up. We mark it as
a zombie so nothing tries to touch it. If it's already been marked as a
zombie, then free it now (since it already is considered invalid). */
if (clone->zombie) {
pthread_mutex_unlock(&clone->lock);
ast_channel_free(clone);
} else {
clone->zombie=1;
pthread_mutex_unlock(&clone->lock);
}
/* Set the write format */
ast_set_write_format(original, original->writeformat);
/* Set the read format */
ast_set_read_format(original, original->readformat);
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
if (original->pvt->fixup) {
res = original->pvt->fixup(clone, original);
if (res) {
ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n",
original->type, original->name);
return -1;
}
} else
ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)! Bad things may happen.\n",
original->type, original->name);
/* Signal any blocker */
if (original->blocking)
pthread_kill(original->blocker, SIGURG);
return 0;
}
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
@ -648,11 +923,33 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
int to = -1;
struct ast_frame *f;
struct ast_channel *who;
int res;
/* Stop if we're a zombie or need a soft hangup */
if (c0->zombie || c0->softhangup || c1->zombie || c1->softhangup)
return -1;
if (c0->bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
c0->name, c0->bridge->name);
return -1;
}
if (c1->bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
c1->name, c1->bridge->name);
return -1;
}
/* Keep track of bridge */
c0->bridge = c1;
c1->bridge = c0;
if (c0->pvt->bridge &&
(c0->pvt->bridge == c1->pvt->bridge)) {
/* Looks like they share a bridge code */
if (!c0->pvt->bridge(c0, c1, flags, fo, rc))
if (!c0->pvt->bridge(c0, c1, flags, fo, rc)) {
c0->bridge = NULL;
c1->bridge = NULL;
return 0;
}
ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
/* If they return non-zero then continue on normally */
}
@ -664,36 +961,47 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
for (/* ever */;;) {
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_WARNING, "Nobody there??\n");
ast_log(LOG_WARNING, "Nobody there??\n");
continue;
}
f = ast_read(who);
if (!f) {
*fo = NULL;
*rc = who;
return 0;
res = 0;
break;
}
if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
*fo = f;
*rc = who;
return 0;
res = 0;
break;
}
if ((f->frametype == AST_FRAME_VOICE) ||
(f->frametype == AST_FRAME_TEXT) ||
(f->frametype == AST_FRAME_VIDEO) ||
(f->frametype == AST_FRAME_IMAGE) ||
(f->frametype == AST_FRAME_DTMF)) {
if ((f->frametype == AST_FRAME_DTMF) && (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
if ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
*rc = c0;
*fo = f;
/* Take out of conference mode */
return 0;
if ((f->frametype == AST_FRAME_DTMF) &&
(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
if ((who == c0)) {
if ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
*rc = c0;
*fo = f;
/* Take out of conference mode */
res = 0;
break;
} else
goto tackygoto;
} else
if ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
*rc = c1;
*fo = f;
return 0;
if ((who == c1)) {
if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
*rc = c1;
*fo = f;
res = 0;
break;
} else
goto tackygoto;
}
} else {
#if 0
@ -702,6 +1010,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
last = who;
#endif
tackygoto:
if (who == c0)
ast_write(c1, f);
else
@ -715,5 +1024,27 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
cs[0] = cs[1];
cs[1] = cs[2];
}
c0->bridge = NULL;
c1->bridge = NULL;
return res;
}
int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block)
{
int res;
if (chan->pvt->setoption) {
res = chan->pvt->setoption(chan, option, data, datalen);
if (res < 0)
return res;
} else {
errno = ENOSYS;
return -1;
}
if (block) {
/* XXX Implement blocking -- just wait for our option frame reply, discarding
intermediate packets. XXX */
ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
return -1;
}
return 0;
}

@ -25,6 +25,60 @@ extern "C" {
#include <pthread.h>
#ifdef DEBUG_THREADS
#define TRIES 500
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
struct mutex_info {
pthread_mutex_t *mutex;
char *file;
int lineno;
char *func;
struct mutex_info *next;
};
static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, pthread_mutex_t *t) {
int res;
int tries = TRIES;
do {
res = pthread_mutex_trylock(t);
/* If we can't run, yield */
if (res) {
sched_yield();
usleep(1);
}
} while(res && tries--);
if (res) {
fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
filename, lineno, func, strerror(res));
res = pthread_mutex_lock(t);
fprintf(stderr, "%s line %d (%s): Got it eventually...\n",
filename, lineno, func);
}
return res;
}
#define ast_pthread_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, pthread_mutex_t *t) {
int res;
res = pthread_mutex_unlock(t);
if (res)
fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n",
filename, lineno, func, strerror(res));
return res;
}
#define ast_pthread_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
#else
#define ast_pthread_mutex_lock pthread_mutex_lock
#define ast_pthread_mutex_unlock pthread_mutex_unlock
#endif
#define AST_CHANNEL_NAME 80
#define AST_CHANNEL_MAX_STACK 32
@ -33,14 +87,24 @@ extern "C" {
/* Max length an extension can be (unique) is this number */
#define AST_MAX_EXTENSION 80
#define AST_MAX_FDS 4
struct ast_channel {
char name[AST_CHANNEL_NAME]; /* ASCII Description of channel name */
char language[MAX_LANGUAGE]; /* Language requested */
char *type; /* Type of channel */
int fd; /* File descriptor for channel -- all must have
a file descriptor! */
int fds[AST_MAX_FDS]; /* File descriptor for channel -- Drivers will poll
on these file descriptors, so at least one must be
non -1. */
struct ast_channel *bridge; /* Who are we bridged to, if we're bridged */
struct ast_channel *masq; /* Channel that will masquerade as us */
struct ast_channel *masqr; /* Who we are masquerading as */
int cdrflags; /* Call Detail Record Flags */
int blocking; /* Whether or not we're blocking */
int softhangup; /* Whether or not we have been hung up */
int zombie; /* Non-zero if this is a zombie channel */
pthread_t blocker; /* If anyone is blocking, this is them */
pthread_mutex_t lock; /* Lock, can be used to lock a channel for some operations */
char *blockproc; /* Procedure causing blocking */
@ -49,6 +113,7 @@ struct ast_channel {
char *data; /* Data passed to current application */
int exception; /* Has an exception been detected */
int fdno; /* Which fd had an event detected on */
struct sched_context *sched; /* Schedule context */
int streamid; /* For streaming playback, the schedule ID */
@ -79,6 +144,11 @@ struct ast_channel {
};
#define AST_CDR_TRANSFER (1 << 0)
#define AST_CDR_FORWARD (1 << 1)
#define AST_CDR_CALLWAIT (1 << 2)
#define AST_CDR_CONFERENCE (1 << 3)
/* Bits 0-15 of state are reserved for the state (up/down) of the line */
#define AST_STATE_DOWN 0 /* Channel is down and available */
@ -123,6 +193,9 @@ int ast_answer(struct ast_channel *chan);
the number of seconds the connect took otherwise. */
int ast_call(struct ast_channel *chan, char *addr, int timeout);
/* Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel */
int ast_indicate(struct ast_channel *chan, int condition);
/* Misc stuff */
/* Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
@ -180,6 +253,28 @@ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
*rf (remember, it could be NULL) and which channel (0 or 1) in rc */
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
/* This is a very strange and freaky function used primarily for transfer. Suppose that
"original" and "clone" are two channels in random situations. This function takes
the guts out of "clone" and puts them into the "original" channel, then alerts the
channel driver of the change, asking it to fixup any private information (like the
p->owner pointer) that is affected by the change. The physical layer of the original
channel is hung up. */
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
/* Give a name to a state */
char *ast_state2str(int state);
/* Options: Some low-level drivers may implement "options" allowing fine tuning of the
low level channel. See frame.h for options. Note that many channel drivers may support
none or a subset of those features, and you should not count on this if you want your
asterisk application to be portable. They're mainly useful for tweaking performance */
/* Set an option on a channel (see frame.h), optionally blocking awaiting the reply */
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
/* Query the value of an option, optionally blocking until a reply is received */
struct ast_frame *ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
#ifdef DO_CRASH
#define CRASH do { *((int *)0) = 0; } while(0)
#else

@ -23,7 +23,7 @@ extern "C" {
struct ast_channel_pvt {
/* Private data used by channel backend */
void *pvt;
void *pvt;
/* Write translation path */
struct ast_trans_pvt *writetrans;
/* Read translation path */
@ -51,6 +51,14 @@ struct ast_channel_pvt {
struct ast_frame * (*exception)(struct ast_channel *chan);
/* Bridge two channels of the same type together */
int (*bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
/* Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */
int (*indicate)(struct ast_channel *c, int condition);
/* Fix up a channel: If a channel is consumed, this is called. Basically update any ->owner links */
int (*fixup)(struct ast_channel *oldchan, struct ast_channel *newchan);
/* Set a given option */
int (*setoption)(struct ast_channel *chan, int option, void *data, int datalen);
/* Query a given option */
int (*queryoption)(struct ast_channel *chan, int option, void *data, int *datalen);
};
/* Create a channel structure */

Loading…
Cancel
Save