diff --git a/apps/app_intercom.c b/apps/app_intercom.c index 97b427ba1..a50b533a2 100755 --- a/apps/app_intercom.c +++ b/apps/app_intercom.c @@ -116,48 +116,48 @@ static int intercom_exec(struct ast_channel *chan, void *data) int res = 0; struct localuser *u; struct ast_frame *f; - struct ast_channel *trans; + int oreadformat; if (!data) { ast_log(LOG_WARNING, "Playback requires an argument (filename)\n"); return -1; } LOCAL_USER_ADD(u); - /* See if we need a translator */ - if (!(chan->format & AST_FORMAT_SLINEAR)) - trans = ast_translator_create(chan, AST_FORMAT_SLINEAR, AST_DIRECTION_IN); - else - trans = chan; - if (trans) { - /* Read packets from the channel */ - while(!res) { - res = ast_waitfor(trans, -1); - if (res > 0) { - res = 0; - f = ast_read(trans); - if (f) { - if (f->frametype == AST_FRAME_DTMF) { - ast_frfree(f); - break; - } else { - if (f->frametype == AST_FRAME_VOICE) { - if (f->subclass == AST_FORMAT_SLINEAR) { - res = write_audio(f->data, f->datalen); - if (res > 0) - res = 0; - } else - ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass); - } - } + /* Remember original read format */ + oreadformat = chan->readformat; + /* Set mode to signed linear */ + res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name); + return -1; + } + /* Read packets from the channel */ + while(!res) { + res = ast_waitfor(chan, -1); + if (res > 0) { + res = 0; + f = ast_read(chan); + if (f) { + if (f->frametype == AST_FRAME_DTMF) { ast_frfree(f); - } else - res = -1; - } + break; + } else { + if (f->frametype == AST_FRAME_VOICE) { + if (f->subclass == AST_FORMAT_SLINEAR) { + res = write_audio(f->data, f->datalen); + if (res > 0) + res = 0; + } else + ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass); + } + } + ast_frfree(f); + } else + res = -1; } - if (trans != chan) - ast_translator_destroy(trans); - } else - ast_log(LOG_WARNING, "Unable to build translator to signed linear format on '%s'\n", chan->name); + } LOCAL_USER_REMOVE(u); + if (!res) + ast_set_read_format(chan, oreadformat); return res; } @@ -187,3 +187,8 @@ int usecount(void) STANDARD_USECOUNT(res); return res; } + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/apps/app_mp3.c b/apps/app_mp3.c index a7e53cff2..7b49dc172 100755 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -59,12 +59,13 @@ static int mp3_exec(struct ast_channel *chan, void *data) { int res=0; struct localuser *u; - struct ast_channel *trans; int fds[2]; int rfds[2]; int ms = -1; int pid; int us; + int exception; + int owriteformat; struct timeval tv; struct timeval last; struct ast_frame *f; @@ -85,87 +86,90 @@ static int mp3_exec(struct ast_channel *chan, void *data) } LOCAL_USER_ADD(u); ast_stopstream(chan); - if (chan->format & AST_FORMAT_SLINEAR) - trans = chan; - else - trans = ast_translator_create(chan, AST_FORMAT_SLINEAR, AST_DIRECTION_OUT); - if (trans) { - res = mp3play((char *)data, fds[1]); - if (res >= 0) { - pid = res; - /* Order is important -- there's almost always going to be mp3... we want to prioritize the - user */ - rfds[0] = trans->fd; - rfds[1] = fds[0]; - for (;;) { - CHECK_BLOCKING(trans); - res = ast_waitfor_n_fd(rfds, 2, &ms); - trans->blocking = 0; - if (res < 1) { - ast_log(LOG_DEBUG, "Hangup detected\n"); - res = -1; - break; - } else if (res == trans->fd) { - f = ast_read(trans); - if (!f) { - ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); - res = -1; - break; - } - if (f->frametype == AST_FRAME_DTMF) { - ast_log(LOG_DEBUG, "User pressed a key\n"); - ast_frfree(f); - res = 0; - break; - } - ast_frfree(f); - } else if (res == fds[0]) { - gettimeofday(&tv, NULL); - if (last.tv_sec || last.tv_usec) { - /* We should wait at least a frame length */ - us = sizeof(myf.frdata) / 16 * 1000; - /* Subtract 1,000,000 us for each second late we've passed */ - us -= (tv.tv_sec - last.tv_sec) * 1000000; - /* And one for each us late we've passed */ - us -= (tv.tv_usec - last.tv_usec); - /* Sleep that long if needed */ - if (us > 0) - usleep(us); - } - last = tv; - res = read(fds[0], myf.frdata, sizeof(myf.frdata)); - if (res > 0) { - myf.f.frametype = AST_FRAME_VOICE; - myf.f.subclass = AST_FORMAT_SLINEAR; - myf.f.datalen = res; - myf.f.timelen = res / 16; - myf.f.mallocd = 0; - myf.f.offset = AST_FRIENDLY_OFFSET; - myf.f.src = __PRETTY_FUNCTION__; - myf.f.data = myf.frdata; - if (ast_write(trans, &myf.f) < 0) { - res = -1; - break; - } - } else { - ast_log(LOG_DEBUG, "No more mp3\n"); - res = 0; - } - } else { - ast_log(LOG_DEBUG, "HuhHHH?\n"); + + owriteformat = chan->writeformat; + res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); + return -1; + } + + res = mp3play((char *)data, fds[1]); + if (res >= 0) { + pid = res; + /* Order is important -- there's almost always going to be mp3... we want to prioritize the + user */ + rfds[0] = chan->fd; + rfds[1] = fds[0]; + for (;;) { + CHECK_BLOCKING(chan); + res = ast_waitfor_n_fd(rfds, 2, &ms, &exception); + chan->blocking = 0; + if (res < 1) { + ast_log(LOG_DEBUG, "Hangup detected\n"); + res = -1; + break; + } else if (res == chan->fd) { + if (exception) + chan->exception = 1; + f = ast_read(chan); + if (!f) { + ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } + if (f->frametype == AST_FRAME_DTMF) { + ast_log(LOG_DEBUG, "User pressed a key\n"); + ast_frfree(f); + res = 0; + break; + } + ast_frfree(f); + } else if (res == fds[0]) { + gettimeofday(&tv, NULL); + if (last.tv_sec || last.tv_usec) { + /* We should wait at least a frame length */ + us = sizeof(myf.frdata) / 16 * 1000; + /* Subtract 1,000,000 us for each second late we've passed */ + us -= (tv.tv_sec - last.tv_sec) * 1000000; + /* And one for each us late we've passed */ + us -= (tv.tv_usec - last.tv_usec); + /* Sleep that long if needed */ + if (us > 0) + usleep(us); + } + last = tv; + res = read(fds[0], myf.frdata, sizeof(myf.frdata)); + if (res > 0) { + myf.f.frametype = AST_FRAME_VOICE; + myf.f.subclass = AST_FORMAT_SLINEAR; + myf.f.datalen = res; + myf.f.timelen = res / 16; + myf.f.mallocd = 0; + myf.f.offset = AST_FRIENDLY_OFFSET; + myf.f.src = __PRETTY_FUNCTION__; + myf.f.data = myf.frdata; + if (ast_write(chan, &myf.f) < 0) { + res = -1; + break; + } + } else { + ast_log(LOG_DEBUG, "No more mp3\n"); + res = 0; + } + } else { + ast_log(LOG_DEBUG, "HuhHHH?\n"); + res = -1; + break; } - kill(pid, SIGTERM); } - if (trans != chan) - ast_translator_destroy(trans); - } else - ast_log(LOG_WARNING, "No translator channel available\n"); + kill(pid, SIGTERM); + } close(fds[0]); close(fds[1]); LOCAL_USER_REMOVE(u); + if (!res) + ast_set_write_format(chan, owriteformat); return res; } @@ -191,3 +195,8 @@ int usecount(void) STANDARD_USECOUNT(res); return res; } + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 0106d6168..45a6229f1 100755 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -418,7 +418,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) ast_verbose( VERBOSE_PREFIX_3 "User '%s' logged in on channel %s with %d messages\n", username, chan->name, maxmsg); if (!ast_streamfile(chan, "vm-instructions", chan->language)) { for(;;) { - if (chan->stream || (chan->trans && chan->trans->stream)) { + if (chan->stream) { d = ast_waitstream(chan, AST_DIGIT_ANY); ast_stopstream(chan); if (!d && (state == STATE_MESSAGE_PLAYING)) { @@ -616,3 +616,8 @@ int usecount(void) STANDARD_USECOUNT(res); return res; } + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/channels/chan_modem.c b/channels/chan_modem.c index fc45194d3..247149c26 100755 --- a/channels/chan_modem.c +++ b/channels/chan_modem.c @@ -227,7 +227,7 @@ int ast_modem_read_response(struct ast_modem_pvt *p, int timeout) timeout *= 1000; strncpy(p->response, "(No Response)", sizeof(p->response)); do { - res = ast_waitfor_n_fd(&p->fd, 1, &timeout); + res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL); if (res < 0) { return -1; } @@ -244,7 +244,7 @@ int ast_modem_expect(struct ast_modem_pvt *p, char *result, int timeout) timeout *= 1000; strncpy(p->response, "(No Response)", sizeof(p->response)); do { - res = ast_waitfor_n_fd(&p->fd, 1, &timeout); + res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL); if (res < 0) { return -1; } @@ -432,7 +432,7 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state) snprintf(tmp->name, sizeof(tmp->name), "Modem[%s]/%s", i->mc->name, i->dev + 5); tmp->type = type; tmp->fd = i->fd; - tmp->format = i->mc->formats; + tmp->nativeformats = i->mc->formats; tmp->state = state; if (state == AST_STATE_RING) tmp->rings = 1; @@ -855,3 +855,8 @@ char *description() return desc; } +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/channels/chan_phone.c b/channels/chan_phone.c index f46083a58..b7f82ea04 100755 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -207,7 +207,7 @@ static int phone_setup(struct ast_channel *ast) p = ast->pvt->pvt; ioctl(p->fd, PHONE_CPT_STOP); /* Nothing to answering really, just start recording */ - if (ast->format & AST_FORMAT_G723_1) { + if (ast->pvt->rawreadformat == AST_FORMAT_G723_1) { /* Prefer g723 */ ioctl(p->fd, PHONE_REC_STOP); if (p->lastinput != AST_FORMAT_G723_1) { @@ -217,7 +217,7 @@ static int phone_setup(struct ast_channel *ast) return -1; } } - } else if (ast->format & AST_FORMAT_SLINEAR) { + } else if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) { ioctl(p->fd, PHONE_REC_STOP); if (p->lastinput != AST_FORMAT_SLINEAR) { p->lastinput = AST_FORMAT_SLINEAR; @@ -227,7 +227,7 @@ static int phone_setup(struct ast_channel *ast) } } } else { - ast_log(LOG_WARNING, "Can't do format %d\n", ast->format); + ast_log(LOG_WARNING, "Can't do format %d\n", ast->pvt->rawreadformat); return -1; } if (ioctl(p->fd, PHONE_REC_START)) { @@ -268,7 +268,7 @@ static char phone_2digit(char c) return '?'; } -static struct ast_frame *phone_read(struct ast_channel *ast) +static struct ast_frame *phone_exception(struct ast_channel *ast) { int res; union telephony_exception phonee; @@ -286,7 +286,7 @@ static struct ast_frame *phone_read(struct ast_channel *ast) phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION); if (phonee.bits.dtmf_ready) { if (option_debug) - ast_log(LOG_DEBUG, "phone_read(): DTMF\n"); + ast_log(LOG_DEBUG, "phone_exception(): DTMF\n"); /* We've got a digit -- Just handle this nicely and easily */ digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII); @@ -324,6 +324,25 @@ static struct ast_frame *phone_read(struct ast_channel *ast) if (phonee.bits.pstn_wink) ast_verbose("Detected Wink\n"); #endif + /* Strange -- nothing there.. */ + p->fr.frametype = AST_FRAME_NULL; + p->fr.subclass = 0; + return &p->fr; +} + +static struct ast_frame *phone_read(struct ast_channel *ast) +{ + int res; + struct phone_pvt *p = ast->pvt->pvt; + + /* Some nice norms */ + p->fr.datalen = 0; + p->fr.timelen = 0; + p->fr.data = NULL; + p->fr.src = type; + p->fr.offset = 0; + p->fr.mallocd=0; + /* Try to read some data... */ CHECK_BLOCKING(ast); res = read(p->fd, p->buf, PHONE_MAX_BUF); @@ -517,7 +536,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte tmp->type = type; tmp->fd = i->fd; /* XXX Switching formats silently causes kernel panics XXX */ - tmp->format = prefformat; + tmp->nativeformats = prefformat; tmp->state = state; if (state == AST_STATE_RING) tmp->rings = 1; @@ -528,6 +547,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte tmp->pvt->answer = phone_answer; tmp->pvt->read = phone_read; tmp->pvt->write = phone_write; + tmp->pvt->exception = phone_exception; strncpy(tmp->context, context, sizeof(tmp->context)); if (strlen(i->ext)) strncpy(tmp->exten, i->ext, sizeof(tmp->exten)); @@ -1052,3 +1072,7 @@ char *description() return desc; } +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/channels/chan_vofr.c b/channels/chan_vofr.c index 6ea76c0d2..cfd669eb0 100755 --- a/channels/chan_vofr.c +++ b/channels/chan_vofr.c @@ -795,7 +795,7 @@ static struct ast_channel *vofr_new(struct vofr_pvt *i, int state) tmp->type = type; tmp->fd = i->s; /* Adtran VoFR supports only G723.1 format data. G711 (ulaw) would be nice too */ - tmp->format = AST_FORMAT_G723_1; + tmp->nativeformats = AST_FORMAT_G723_1; tmp->state = state; if (state == AST_STATE_RING) tmp->rings = 1; @@ -1241,6 +1241,11 @@ int usecount() return res; } +char *key() +{ + return ASTERISK_GPL_KEY; +} + char *description() { return desc; diff --git a/cli.c b/cli.c index fb8d0731e..aa41b0e7a 100755 --- a/cli.c +++ b/cli.c @@ -168,13 +168,13 @@ static int handle_showchan(int fd, int argc, char *argv[]) " -- General --\n" " Name: %s\n" " Type: %s\n" - " Translator: %s\n" - " Master: %s\n" " Caller ID: %s\n" " DNID Digits: %s\n" " State: %d\n" " Rings: %d\n" - " Format: %d\n" + " WriteFormat: %d\n" + " ReadFormat: %d\n" + " NativeFormat: %d\n" "File Descriptor: %d\n" " -- PBX --\n" " Context: %s\n" @@ -184,9 +184,9 @@ static int handle_showchan(int fd, int argc, char *argv[]) " Data: %s\n" " Stack: %d\n" " Blocking in: %s\n", - c->name, c->type, (c->trans ? c->trans->name : "(N/A)"), - (c->master ? c->master->name : "(N/A)"), (c->callerid ? c->callerid : "(N/A)"), - (c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->format, + c->name, c->type, + (c->callerid ? c->callerid : "(N/A)"), + (c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat, c->fd, c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), ( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"), c->stack, (c->blocking ? c->blockproc : "(Not Blocking)")); diff --git a/file.c b/file.c index 89ba69836..0ab0676e8 100755 --- a/file.c +++ b/file.c @@ -142,23 +142,17 @@ int ast_format_unregister(char *name) int ast_stopstream(struct ast_channel *tmp) { - if (tmp->trans) - tmp = tmp->trans; /* Stop a running stream if there is one */ if (!tmp->stream) return 0; tmp->stream->fmt->close(tmp->stream); - if (tmp->master) { - ast_translator_destroy(tmp); - } + if (ast_set_write_format(tmp, tmp->oldwriteformat)) + ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat); return 0; } int ast_closestream(struct ast_filestream *f) { - if (f->trans) { - ast_translator_free_path(f->trans); - } /* Stop a running stream if there is one */ f->fmt->close(f); return 0; @@ -166,7 +160,7 @@ int ast_closestream(struct ast_filestream *f) int ast_writestream(struct ast_filestream *fs, struct ast_frame *f) { - struct ast_frame_chain *fc, *f2; + struct ast_frame *trf; int res = -1; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Tried to write non-voice frame\n"); @@ -183,24 +177,16 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f) /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't the one we've setup a translator for, we do the "wrong thing" XXX */ if (!fs->trans) - fs->trans = ast_translator_build_path(f->subclass, fs->fmt->format); + fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass); if (!fs->trans) ast_log(LOG_WARNING, "Unable to translate to format %s, source format %d\n", fs->fmt->name, f->subclass); else { res = 0; - /* Build a chain of translated frames */ - fc = ast_translate(fs->trans, f); - f2 = fc; - while(f2) { - res = fs->fmt->write(fs, f2->fr); - if (res) { - ast_log(LOG_WARNING, "Translated frame write failed\n"); - break; - } - f2 = f2->next; - } - if (fc) - ast_frchain(fc); + /* Get the translated frame but don't consume the original in case they're using it on another stream */ + trf = ast_translate(fs->trans, f, 0); + res = fs->fmt->write(fs, trf); + if (res) + ast_log(LOG_WARNING, "Translated frame write failed\n"); } return res; } @@ -232,7 +218,7 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action struct ast_filestream *s; int res=0, ret = 0; char *ext=NULL, *exts, *fn, *nfn; - struct ast_channel *trans = (struct ast_channel *)filename2; + struct ast_channel *chan = (struct ast_channel *)filename2; /* Start with negative response */ if (action == ACTION_EXISTS) @@ -280,18 +266,18 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action ast_log(LOG_WARNING, "Out of memory\n"); break; case ACTION_OPEN: - if ((ret < 0) && ((trans->format & f->format) /* == trans->format */)) { + if ((ret < 0) && ((chan->writeformat & f->format))) { ret = open(fn, O_RDONLY); if (ret >= 0) { s = f->open(ret); if (s) { s->fmt = f; s->trans = NULL; - trans->stream = s; - if (f->apply(trans, s)) { + chan->stream = s; + if (f->apply(chan, s)) { f->close(s); - trans->stream = NULL; - ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", trans->name); + chan->stream = NULL; + ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", chan->name); close(ret); ret = 0; } @@ -372,10 +358,10 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang) */ int fd = -1; - struct ast_channel *trans; int fmts = -1; char filename2[256]; char lang2[MAX_LANGUAGE]; + int res; ast_stopstream(chan); if (preflang && strlen(preflang)) { snprintf(filename2, sizeof(filename2), "%s-%s", filename, preflang); @@ -394,24 +380,11 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang) ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename); return -1; } - if (fmts & chan->format) { - /* No translation necessary -- we have a file in a format our channel can - handle */ - trans = chan; - } else { - /* Find the best */ - fmts = ast_translator_best_choice(chan->format, fmts); - if (fmts < 1) { - ast_log(LOG_WARNING, "Unable to find a translator method\n"); - return -1; - } - trans = ast_translator_create(chan, fmts, AST_DIRECTION_OUT); - if (!trans) { - ast_log(LOG_WARNING, "Unable to create translator\n"); - return -1; - } - } - fd = ast_filehelper(filename2, (char *)trans, NULL, ACTION_OPEN); + chan->oldwriteformat = chan->writeformat; + /* Set the channel to a format we can work with */ + res = ast_set_write_format(chan, fmts); + + fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN); if (fd >= 0) { #if 1 if (option_verbose > 2) @@ -419,9 +392,7 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang) #endif return 0; } - ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->format, strerror(errno)); - if (chan != trans) - ast_translator_destroy(trans); + ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->nativeformats, strerror(errno)); return -1; } @@ -473,12 +444,10 @@ char ast_waitstream(struct ast_channel *c, char *breakon) { int res; struct ast_frame *fr; - if (c->trans) - c=c->trans; while(c->stream) { res = ast_sched_wait(c->sched); if (res < 0) { - /* Okay, stop :) */ + ast_closestream(c->stream); return 0; } res = ast_waitfor(c, res); diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index b3ef37653..3f7d5e744 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -36,27 +36,37 @@ extern "C" { 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 blocking; /* Whether or not we're blocking */ 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 */ + char *appl; /* Current application */ char *data; /* Data passed to current application */ - int blocking; /* Whether or not we're blocking */ + + int exception; /* Has an exception been detected */ struct sched_context *sched; /* Schedule context */ + int streamid; /* For streaming playback, the schedule ID */ struct ast_filestream *stream; /* Stream itself. */ - struct ast_channel *trans; /* Translator if present */ - struct ast_channel *master; /* Master channel, if this is a translator */ - int fd; /* File descriptor for channel -- all must have - a file descriptor! */ - char *type; /* Type of channel */ + int oldwriteformat; /* Original writer format */ + int state; /* State of line */ int rings; /* Number of rings so far */ int stack; /* Current level of application */ - int format; /* Kinds of data this channel can + + int nativeformats; /* Kinds of data this channel can natively handle */ + int readformat; /* Requested read format */ + int writeformat; /* Requested write format */ + char *dnid; /* Malloc'd Dialed Number Identifier */ char *callerid; /* Malloc'd Caller ID */ + char context[AST_MAX_EXTENSION]; /* Current extension context */ char exten[AST_MAX_EXTENSION]; /* Current extension number */ int priority; /* Current extension priority */ @@ -125,7 +135,7 @@ int ast_waitfor(struct ast_channel *chan, int ms); struct ast_channel *ast_waitfor_n(struct ast_channel **chan, int n, int *ms); /* This version works on fd's only. Be careful with it. */ -int ast_waitfor_n_fd(int *fds, int n, int *ms); +int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception); /* Read a frame. Returns a frame, or NULL on error. If it returns NULL, you best just stop reading frames and assume the channel has been @@ -135,6 +145,12 @@ struct ast_frame *ast_read(struct ast_channel *chan); /* Write a frame to a channel */ int ast_write(struct ast_channel *chan, struct ast_frame *frame); +/* Set read format for channelto whichever component of "format" is best. */ +int ast_set_read_format(struct ast_channel *chan, int format); + +/* Set write format for channel to whichever compoent of "format" is best. */ +int ast_set_write_format(struct ast_channel *chan, int format); + /* Write text to a display on a channel */ int ast_sendtext(struct ast_channel *chan, char *text); @@ -148,10 +164,32 @@ char ast_waitfordigit(struct ast_channel *c, int ms); digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout for the first digit */ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders); + +#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0) /* Report DTMF on channel 0 */ +#define AST_BRIDGE_DTMF_CHANNEL_1 (1 << 1) /* Report DTMF on channel 1 */ +#define AST_BRIDGE_REC_CHANNEL_0 (1 << 2) /* Return all voice frames on channel 0 */ +#define AST_BRIDGE_REC_CHANNEL_1 (1 << 3) /* Return all voice frames on channel 1 */ +#define AST_BRIDGE_IGNORE_SIGS (1 << 4) /* Ignore all signal frames except NULL */ + + +/* Set two channels to compatible formats -- call before ast_channel_bridge in general . Returns 0 on success + and -1 if it could not be done */ +int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1); + +/* Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in + *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); + +#ifdef DO_CRASH +#define CRASH do { *((int *)0) = 0; } while(0) +#else +#define CRASH do { } while(0) +#endif + #define CHECK_BLOCKING(c) { \ if ((c)->blocking) {\ - ast_log(LOG_WARNING, "Blocking '%s', already blocked by thread %ld in procedure %s\n", (c)->name, (c)->blocker, (c)->blockproc); \ - /* *((int *)0)=0; */ \ + ast_log(LOG_WARNING, "Thread %ld Blocking '%s', already blocked by thread %ld in procedure %s\n", pthread_self(), (c)->name, (c)->blocker, (c)->blockproc); \ + CRASH; \ } else { \ (c)->blocker = pthread_self(); \ (c)->blockproc = __PRETTY_FUNCTION__; \ diff --git a/include/asterisk/channel_pvt.h b/include/asterisk/channel_pvt.h index 8657d4d58..7fc464ebb 100755 --- a/include/asterisk/channel_pvt.h +++ b/include/asterisk/channel_pvt.h @@ -24,6 +24,14 @@ extern "C" { struct ast_channel_pvt { /* Private data used by channel backend */ void *pvt; + /* Write translation path */ + struct ast_trans_pvt *writetrans; + /* Read translation path */ + struct ast_trans_pvt *readtrans; + /* Raw read format */ + int rawreadformat; + /* Raw write format */ + int rawwriteformat; /* Send a literal DTMF digit */ int (*send_digit)(struct ast_channel *chan, char digit); /* Call a given phone number (address, etc), but don't @@ -39,6 +47,10 @@ struct ast_channel_pvt { int (*write)(struct ast_channel *chan, struct ast_frame *frame); /* Display or transmit text */ int (*send_text)(struct ast_channel *chan, char *text); + /* Handle an exception, reading a frame */ + 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); }; /* Create a channel structure */ diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index a2bcfff19..640c5794d 100755 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -29,7 +29,7 @@ struct ast_translator { char name[80]; int srcfmt; int dstfmt; - struct ast_translator_pvt *(*new)(); + struct ast_translator_pvt *(*new)(void); int (*framein)(struct ast_translator_pvt *pvt, struct ast_frame *in); struct ast_frame * (*frameout)(struct ast_translator_pvt *pvt); void (*destroy)(struct ast_translator_pvt *pvt); @@ -44,29 +44,22 @@ struct ast_translator { struct ast_trans_pvt; -/* Create a pseudo channel which translates from a real channel into our - desired format. When a translator is installed, you should not use the - sub channel until you have stopped the translator. For all other - actions, use the real channel. Generally, translators should be created - when needed and immediately destroyed when no longer needed. */ - -/* Directions */ -#define AST_DIRECTION_OUT 1 -#define AST_DIRECTION_IN 2 -#define AST_DIRECTION_BOTH 3 - -extern struct ast_channel *ast_translator_create(struct ast_channel *real, int format, int direction); -extern void ast_translator_destroy(struct ast_channel *tran); /* Register a Codec translator */ extern int ast_register_translator(struct ast_translator *t); /* Unregister same */ extern int ast_unregister_translator(struct ast_translator *t); /* Given a list of sources, and a designed destination format, which should - I choose? */ -extern int ast_translator_best_choice(int dst, int srcs); -extern struct ast_trans_pvt *ast_translator_build_path(int source, int dest); + I choose? Returns 0 on success, -1 if no path could be found. Modifies + dests and srcs in place */ +extern int ast_translator_best_choice(int *dsts, int *srcs); + +/* Build a path (possibly NULL) from source to dest */ +extern struct ast_trans_pvt *ast_translator_build_path(int dest, int source); extern void ast_translator_free_path(struct ast_trans_pvt *tr); -extern struct ast_frame_chain *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f); + +/* Apply an input frame into the translator and receive zero or one output frames. Consume + determines whether the original frame should be freed */ +extern struct ast_frame *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume); #if defined(__cplusplus) || defined(c_plusplus)