aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xchannel.c235
-rwxr-xr-xformats/format_mp3.c26
2 files changed, 220 insertions, 41 deletions
diff --git a/channel.c b/channel.c
index 87d527d37..b7c4ff355 100755
--- a/channel.c
+++ b/channel.c
@@ -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);
diff --git a/formats/format_mp3.c b/formats/format_mp3.c
index 5c730f098..e702e5563 100755
--- a/formats/format_mp3.c
+++ b/formats/format_mp3.c
@@ -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);