diff --git a/channel.c b/channel.c index 87d527d37db7b4341b58257f37da931c8661166f..b7c4ff355ecee6bcd44ff6e601abc8909651b452 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 5c730f098cd74fc11d80ed23cbc41939e3420eda..e702e556305f376daee5594618362aa2dd731ffd 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);