From 7157261be4bc6700118cb8a405302a61a8d91c8b Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sat, 10 Mar 2001 19:12:11 +0000
Subject: [PATCH] Version 0.1.7 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@236 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_intercom.c            |  73 ++++++++--------
 apps/app_mp3.c                 | 149 +++++++++++++++++----------------
 apps/app_voicemail.c           |   7 +-
 channels/chan_modem.c          |  11 ++-
 channels/chan_phone.c          |  36 ++++++--
 channels/chan_vofr.c           |   7 +-
 cli.c                          |  12 +--
 file.c                         |  77 +++++------------
 include/asterisk/channel.h     |  58 ++++++++++---
 include/asterisk/channel_pvt.h |  12 +++
 include/asterisk/translate.h   |  29 +++----
 11 files changed, 268 insertions(+), 203 deletions(-)

diff --git a/apps/app_intercom.c b/apps/app_intercom.c
index 97b427ba15..a50b533a2d 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 a7e53cff21..7b49dc1727 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");
+
+	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;
-				} else if (res == trans->fd) {
-					f = ast_read(trans);
-					if (!f) {
-						ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
+				}
+				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;
 					}
-					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");
-					res = -1;
-					break;
+					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 0106d6168f..45a6229f1a 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 fc45194d35..247149c262 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 f46083a587..b7f82ea047 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 6ea76c0d2f..cfd669eb0e 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 fb8d0731e2..aa41b0e7a7 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 89ba69836d..0ab0676e8c 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 b3ef376538..3f7d5e7449 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 8657d4d58d..7fc464ebbe 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 a2bcfff19b..640c5794df 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)
-- 
GitLab