[zaptel-commits] qwell: branch 1.4 r2433 - /branches/1.4/

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Tue Apr 24 11:32:49 MST 2007


Author: qwell
Date: Tue Apr 24 13:32:49 2007
New Revision: 2433

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2433
Log:
Merge in pre-echocan debugging for ztmonitor.

Added:
    branches/1.4/jpah.h
      - copied unchanged from r2432, team/group/echocan-debug/jpah.h
Modified:
    branches/1.4/zaptel-base.c
    branches/1.4/zaptel.h
    branches/1.4/zconfig.h
    branches/1.4/ztmonitor.c

Modified: branches/1.4/zaptel-base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/zaptel-base.c?view=diff&rev=2433&r1=2432&r2=2433
==============================================================================
--- branches/1.4/zaptel-base.c (original)
+++ branches/1.4/zaptel-base.c Tue Apr 24 13:32:49 2007
@@ -424,6 +424,8 @@
 #include "kb1ec.h"
 #elif defined(ECHO_CAN_MG2)
 #include "mg2ec.h"
+#elif defined(ECHO_CAN_JP1)
+#include "jpah.h"
 #else
 #include "mec3.h"
 #endif
@@ -982,6 +984,7 @@
 	void *rxgain = NULL;
 	struct echo_can_state *ec = NULL;
 	int oldconf;
+	short *readchunkpreec;
 #ifdef CONFIG_ZAPATA_PPP
 	struct ppp_channel *ppp;
 #endif
@@ -996,6 +999,8 @@
 #endif
 	ec = chan->ec;
 	chan->ec = NULL;
+	readchunkpreec = chan->readchunkpreec;
+	chan->readchunkpreec = NULL;
 	chan->curtone = NULL;
 	chan->curzone = NULL;
 	chan->cadencepos = 0;
@@ -1056,6 +1061,7 @@
 		kfree(rxgain);
 	if (ec)
 		echo_can_free(ec);
+	kfree(readchunkpreec);
 
 #ifdef CONFIG_ZAPATA_PPP
 	if (ppp) {
@@ -1713,6 +1719,9 @@
 				((chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR ||
 				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX ||
 				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH ||
+				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO ||
 				(chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_DIGITALMON)) {
 				/* Take them out of conference with us */
 				/* release conference resource if any */
@@ -3920,7 +3929,10 @@
 		if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL); 
 		if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR ||
 			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX ||
-			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH) {
+			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH ||
+			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+			(stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO) {
 			/* Monitor mode -- it's a channel */
 			if ((stack.conf.confno < 0) || (stack.conf.confno >= ZT_MAX_CHANNELS) || !chans[stack.conf.confno]) return(-EINVAL);
 		} else {
@@ -3973,6 +3985,16 @@
 			/* Get alias */
 			chans[i]->_confn = zt_get_conf_alias(stack.conf.confno);
 		}
+
+		if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+		    (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+		    (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO)
+			chans[stack.conf.confno]->readchunkpreec = kmalloc(sizeof(*chans[stack.conf.confno]->readchunkpreec) * ZT_CHUNKSIZE, GFP_KERNEL);
+		else {
+			kfree(chans[stack.conf.confno]->readchunkpreec);
+			chans[stack.conf.confno]->readchunkpreec = NULL;
+		}
+
 		spin_unlock_irqrestore(&chan->lock, flags);
 		spin_unlock_irqrestore(&bigzaplock, flagso);
 		if (copy_to_user((struct zt_confinfo *) data,&stack.conf,sizeof(stack.conf)))
@@ -4993,6 +5015,51 @@
 			for (x=0;x<ZT_CHUNKSIZE;x++)
 				txb[x] = ZT_LIN2X(getlin[x], ms);
 			break;
+		case ZT_CONF_MONITOR_RX_PREECHO:	/* Monitor a channel's rx mode */
+			  /* if a pseudo-channel, ignore */
+			if (ms->flags & ZT_FLAG_PSEUDO)
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			/* Add monitored channel */
+			ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+			     chans[ms->confna]->readchunkpreec : chans[ms->confna]->putlin);
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				txb[x] = ZT_LIN2X(getlin[x], ms);
+
+			break;
+		case ZT_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */
+			  /* if a pseudo-channel, ignore */
+			if (ms->flags & ZT_FLAG_PSEUDO)
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			/* Add monitored channel */
+			ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+			     chans[ms->confna]->putlin : chans[ms->confna]->readchunkpreec);
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				txb[x] = ZT_LIN2X(getlin[x], ms);
+
+			break;
+		case ZT_CONF_MONITORBOTH_PREECHO: /* monitor a channel's rx and tx mode */
+			  /* if a pseudo-channel, ignore */
+			if (ms->flags & ZT_FLAG_PSEUDO)
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			ACSS(getlin, chans[ms->confna]->putlin);
+			ACSS(getlin, chans[ms->confna]->readchunkpreec);
+
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				txb[x] = ZT_LIN2X(getlin[x], ms);
+
+			break;
 		case ZT_CONF_REALANDPSEUDO:
 			/* This strange mode takes the transmit buffer and
 				puts it on the conference, minus its last sample,
@@ -5681,7 +5748,16 @@
 	short rxlin, txlin;
 	int x;
 	unsigned long flags;
+
 	spin_lock_irqsave(&ss->lock, flags);
+
+	if (ss->readchunkpreec) {
+		/* Save a copy of the audio before the echo can has its way with it */
+		for (x = 0; x < ZT_CHUNKSIZE; x++)
+			/* We only ever really need to deal with signed linear - let's just convert it now */
+			ss->readchunkpreec[x] = ZT_XLAW(rxchunk[x], ss);
+	}
+
 	/* Perform echo cancellation on a chunk if necessary */
 	if (ss->ec) {
 #if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
@@ -5915,6 +5991,54 @@
 			/* Convert back */
 			for(x=0;x<ZT_CHUNKSIZE;x++)
 				rxb[x] = ZT_LIN2X(putlin[x], ms);
+			break;
+		case ZT_CONF_MONITOR_RX_PREECHO:		/* Monitor a channel's rx mode */
+			  /* if not a pseudo-channel, ignore */
+			if (!(ms->flags & ZT_FLAG_PSEUDO))
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			/* Add monitored channel */
+			ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+			     chans[ms->confna]->getlin : chans[ms->confna]->readchunkpreec);
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				rxb[x] = ZT_LIN2X(putlin[x], ms);
+
+			break;
+		case ZT_CONF_MONITOR_TX_PREECHO:	/* Monitor a channel's tx mode */
+			  /* if not a pseudo-channel, ignore */
+			if (!(ms->flags & ZT_FLAG_PSEUDO))
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			/* Add monitored channel */
+			ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+			     chans[ms->confna]->readchunkpreec : chans[ms->confna]->getlin);
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				rxb[x] = ZT_LIN2X(putlin[x], ms);
+
+			break;
+		case ZT_CONF_MONITORBOTH_PREECHO:	/* Monitor a channel's tx and rx mode */
+			  /* if not a pseudo-channel, ignore */
+			if (!(ms->flags & ZT_FLAG_PSEUDO))
+				break;
+
+			if (!chans[ms->confna]->readchunkpreec)
+				break;
+
+			/* Note: Technically, saturation should be done at 
+			   the end of the whole addition, but for performance
+			   reasons, we don't do that.  Besides, it only matters
+			   when you're so loud you're clipping anyway */
+			ACSS(putlin, chans[ms->confna]->getlin);
+			ACSS(putlin, chans[ms->confna]->readchunkpreec);
+			for (x = 0; x < ZT_CHUNKSIZE; x++)
+				rxb[x] = ZT_LIN2X(putlin[x], ms);
+
 			break;
 		case ZT_CONF_REALANDPSEUDO:
 			  /* do normal conf mode processing */

Modified: branches/1.4/zaptel.h
URL: http://svn.digium.com/view/zaptel/branches/1.4/zaptel.h?view=diff&rev=2433&r1=2432&r2=2433
==============================================================================
--- branches/1.4/zaptel.h (original)
+++ branches/1.4/zaptel.h Tue Apr 24 13:32:49 2007
@@ -970,6 +970,9 @@
 #define	ZT_CONF_CONFANNMON 7		/* conference announce/monitor mode */
 #define	ZT_CONF_REALANDPSEUDO 8	/* real and pseudo port both on conf */
 #define ZT_CONF_DIGITALMON 9	/* Do not decode or interpret */
+#define	ZT_CONF_MONITOR_RX_PREECHO 10	/* monitor mode (rx of other chan) - before echo can is done */
+#define	ZT_CONF_MONITOR_TX_PREECHO 11	/* monitor mode (tx of other chan) - before echo can is done */
+#define	ZT_CONF_MONITORBOTH_PREECHO 12	/* monitor mode (rx & tx of other chan) - before echo can is done */
 #define	ZT_CONF_FLAG_MASK 0xff00	/* mask for flags */
 #define	ZT_CONF_LISTENER 0x100		/* is a listener on the conference */
 #define	ZT_CONF_TALKER 0x200		/* is a talker on the conference */
@@ -1129,6 +1132,7 @@
 	u_char swritechunk[ZT_MAX_CHUNKSIZE];	/* Buffer to be written */
 	u_char *readchunk;						/* Actual place to read from */
 	u_char sreadchunk[ZT_MAX_CHUNKSIZE];	/* Preallocated static area */
+	short *readchunkpreec;
 
 	/* Pointer to tx and rx gain tables */
 	u_char *rxgain;

Modified: branches/1.4/zconfig.h
URL: http://svn.digium.com/view/zaptel/branches/1.4/zconfig.h?view=diff&rev=2433&r1=2432&r2=2433
==============================================================================
--- branches/1.4/zconfig.h (original)
+++ branches/1.4/zconfig.h Tue Apr 24 13:32:49 2007
@@ -64,6 +64,13 @@
 /* #define ECHO_CAN_KB1 */
 /* This is the new latest and greatest */
 #define ECHO_CAN_MG2
+
+/*
+ * This is only technically an "echo canceller"...
+ * It purposely drops 2 out of 3 samples and sounds horrible.
+ * You really only want this for testing "echo cancelled" audio.
+ */
+/* #define ECHO_CAN_JP1 */
 
 /*
  * Uncomment for aggressive residual echo suppression under 

Modified: branches/1.4/ztmonitor.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/ztmonitor.c?view=diff&rev=2433&r1=2432&r2=2433
==============================================================================
--- branches/1.4/ztmonitor.c (original)
+++ branches/1.4/ztmonitor.c Tue Apr 24 13:32:49 2007
@@ -51,11 +51,11 @@
 
 #define FRAG_SIZE 8
 
-/* Put the ofh (output file handle) outside
+/* Put the ofh (output file handles) outside
  * the main loop in case we ever add a signal
- * hanlder.
+ * handler.
  */
-static FILE*  ofh = 0;
+static FILE*  ofh[4] = {0, 0, 0, 0};
 
 static int stereo = 0;
 static int verbose = 0;
@@ -255,62 +255,148 @@
 
 int main(int argc, char *argv[])
 {
-	int afd = -1, pfd, pfd2 = -1;
+	int afd = -1;
+	int pfd[4] = {-1, -1, -1, -1};
 	short buf[8192];
 	short buf2[16384];
 	char  output_file[255];
 	int res, res2;
 	int visual = 0;
-	int x,i;
+	int multichannel = 0;
+	int ossoutput = 0;
+	int preecho = 0;
+	int savefile = 0;
+	int x, i;
 	struct zt_confinfo zc;
 
 	if ((argc < 2) || (atoi(argv[1]) < 1)) {
-		fprintf(stderr, "Usage: ztmonitor <channel num> [-v[v]] [-f FILE]\n");
+		fprintf(stderr, "Usage: ztmonitor <channel num> [-v[v]] [-m] [-o] [-p] [-f FILE | -r FILE1 -t FILE2] [-F FILE | -R FILE1 -T FILE2]\n");
+		fprintf(stderr, "Options:\n");
+		fprintf(stderr, "        -v: Visual mode.  Implies -m.\n");
+		fprintf(stderr, "        -vv: Visual/Verbose mode.  Implies -m.\n");
+		fprintf(stderr, "        -m: Separate rx/tx streams.\n");
+		fprintf(stderr, "        -o: Output audio via OSS.  Note: Only 'normal' combined rx/tx streams are output via OSS.\n");
+		fprintf(stderr, "        -p: Get a pre-echocanceled stream.\n");
+		fprintf(stderr, "        -f FILE: Save combined rx/tx stream to FILE.  Cannot be used with -m.\n");
+		fprintf(stderr, "        -r FILE: Save rx stream to FILE.  Implies -m.\n");
+		fprintf(stderr, "        -t FILE: Save tx stream to FILE.  Implies -m.\n");
+		fprintf(stderr, "        -F FILE: Save combined pre-echocanceled rx/tx stream to FILE.  Cannot be used with -m.  Implies -p.\n");
+		fprintf(stderr, "        -R FILE: Save pre-echocanceled rx stream to FILE.  Implies -m and -p.\n");
+		fprintf(stderr, "        -T FILE: Save pre-echocanceled tx stream to FILE.  Implies -m and -p.\n");
+		fprintf(stderr, "Examples:\n");
+		fprintf(stderr, "Save a stream to a file\n");
+		fprintf(stderr, "        ztmonitor 1 -f stream.raw\n");
+		fprintf(stderr, "Visualize an rx/tx stream and save them to separate files.\n");
+		fprintf(stderr, "        ztmonitor 1 -v -r streamrx.raw -t streamtx.raw\n");
+		fprintf(stderr, "Play a combined rx/tx stream via OSS and save it to a file\n");
+		fprintf(stderr, "        ztmonitor 1 -o -f stream.raw\n");
+		fprintf(stderr, "Play a combined rx/tx stream via OSS and save them to separate files\n");
+		fprintf(stderr, "        ztmonitor 1 -m -o -r streamrx.raw -t streamtx.raw\n");
+		fprintf(stderr, "Save a combined normal rx/tx stream and a combined 'preecho' rx/tx stream to files\n");
+		fprintf(stderr, "        ztmonitor 1 -m -p -f stream.raw -F streampreecho.raw\n");
+		fprintf(stderr, "Save a normal rx/tx stream and a 'preecho' rx/tx stream to separate files\n");
+		fprintf(stderr, "        ztmonitor 1 -m -p -r streamrx.raw -t streamtx.raw -R streampreechorx.raw -T streampreechotx.raw\n");
 		exit(1);
 	}
 	for (i = 2; i < argc; ++i) {
 		if (!strcmp(argv[i], "-v")) {
-				if (visual)
-					verbose = 1;
+			if (visual)
+				verbose = 1;
 		        visual = 1;
+			multichannel = 1;
 		} else if (!strcmp(argv[i], "-vv")) {
 			visual = 1;
 			verbose = 1;
-       	} else if (!strcmp(argv[i], "-f") && (i+1) < argc) {
-			++i; /*we care about hte file name */
+			multichannel = 1;
+		} else if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "-r") || !strcmp(argv[i], "-t")
+				|| !strcmp(argv[i], "-F") || !strcmp(argv[i], "-R") || !strcmp(argv[i], "-T"))
+				&& (i+1) < argc) {
+			/* Set which file descriptor to use */
+			if (!strcmp(argv[i], "-f")) {
+				savefile = 1;
+				x = 0;
+			} else if (!strcmp(argv[i], "-r")) {
+				savefile = 1;
+				multichannel = 1;
+				x = 0;
+			} else if (!strcmp(argv[i], "-t")) {
+				savefile = 1;
+				multichannel = 1;
+				x = 1;
+			} else if (!strcmp(argv[i], "-F")) {
+				savefile = 1;
+				preecho = 1;
+				x = 2;
+			} else if (!strcmp(argv[i], "-R")) {
+				savefile = 1;
+				multichannel = 1;
+				preecho = 1;
+				x = 2;
+			} else if (!strcmp(argv[i], "-T")) {
+				savefile = 1;
+				multichannel = 1;
+				preecho = 1;
+				x = 3;
+			} else
+				x = 0;
+
+			++i; /* we care about the file name */
 			if (strlen(argv[i]) < 255 ) {
 				strcpy(output_file, argv[i]);
 				fprintf(stderr, "Output to %s\n", output_file);
-				if ((ofh = fopen(output_file, "w"))<0) {
+				if ((ofh[x] = fopen(output_file, "w"))<0) {
 					fprintf(stderr, "Could not open %s for writing: %s\n", output_file, strerror(errno));
-					exit(0);
+					exit(1);
 				}
-				fprintf(stderr, "Run e.g., 'sox -r 8000 -s -w -c 1 file.raw file.wav' to convert.\n");
+				fprintf(stderr, "Run e.g., 'sox -r 8000 -s -w -c 1 %s file.wav' to convert.\n", output_file);
 			} else {
 				fprintf(stderr, "File Name %s too long\n",argv[i+1]);
 			}
-		}
-	}
-	if (!visual) {
-		/* Open audio */
-		if ((afd = audio_open()) < 0) {
-			printf("Cannot open audio ...\n");
-			if (!ofh) exit(0);
-		}
-	}
+		} else if (!strcmp(argv[i], "-m")) {
+			multichannel = 1;
+		} else if (!strcmp(argv[i], "-o")) {
+			ossoutput = 1;
+		} else if (!strcmp(argv[i], "-p")) {
+			preecho = 1;
+		}
+	}
+
+	if (ossoutput) {
+		if (multichannel) {
+			printf("Multi-channel audio is enabled.  OSS output will be disabled.\n");
+			ossoutput = 0;
+		} else {
+			/* Open audio */
+			if ((afd = audio_open()) < 0) {
+				printf("Cannot open audio ...\n");
+				ossoutput = 0;
+			}
+		}
+	}
+	if (!ossoutput && !multichannel && !savefile) {
+		fprintf(stderr, "Nothing to do with the stream(s) ...\n");
+		exit(1);
+	}
+
 	/* Open Pseudo device */
-	if ((pfd = pseudo_open()) < 0)
+	if ((pfd[0] = pseudo_open()) < 0)
 		exit(1);
-	if (visual && ((pfd2 = pseudo_open()) < 0))
+	if (multichannel && ((pfd[1] = pseudo_open()) < 0))
 		exit(1);
+	if (preecho) {
+		if ((pfd[2] = pseudo_open()) < 0)
+			exit(1);
+		if (multichannel && ((pfd[3] = pseudo_open()) < 0))
+			exit(1);
+	}
 	/* Conference them */
-	memset(&zc, 0, sizeof(zc));
-	zc.chan = 0;
-	zc.confno = atoi(argv[1]);
-	if (visual) {
+	if (multichannel) {
+		memset(&zc, 0, sizeof(zc));
+		zc.chan = 0;
+		zc.confno = atoi(argv[1]);
 		/* Two pseudo's, one for tx, one for rx */
 		zc.confmode = ZT_CONF_MONITORTX;
-		if (ioctl(pfd, ZT_SETCONF, &zc) < 0) {
+		if (ioctl(pfd[0], ZT_SETCONF, &zc) < 0) {
 			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
 			exit(1);
 		}
@@ -318,15 +404,47 @@
 		zc.chan = 0;
 		zc.confno = atoi(argv[1]);
 		zc.confmode = ZT_CONF_MONITOR;
-		if (ioctl(pfd2, ZT_SETCONF, &zc) < 0) {
+		if (ioctl(pfd[1], ZT_SETCONF, &zc) < 0) {
 			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
 			exit(1);
 		}
+		if (preecho) {
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = atoi(argv[1]);
+			/* Two pseudo's, one for tx, one for rx */
+			zc.confmode = ZT_CONF_MONITOR_TX_PREECHO;
+			if (ioctl(pfd[2], ZT_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = atoi(argv[1]);
+			zc.confmode = ZT_CONF_MONITOR_RX_PREECHO;
+			if (ioctl(pfd[3], ZT_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
+		}
 	} else {
+		memset(&zc, 0, sizeof(zc));
+		zc.chan = 0;
+		zc.confno = atoi(argv[1]);
 		zc.confmode = ZT_CONF_MONITORBOTH;
-		if (ioctl(pfd, ZT_SETCONF, &zc) < 0) {
+		if (ioctl(pfd[0], ZT_SETCONF, &zc) < 0) {
 			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
 			exit(1);
+		}
+		if (preecho) {
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = atoi(argv[1]);
+			zc.confmode = ZT_CONF_MONITORBOTH_PREECHO;
+			if (ioctl(pfd[2], ZT_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
 		}
 	}
 	if (visual) {
@@ -338,31 +456,63 @@
 	}
 	/* Now, copy from pseudo to audio */
 	for (;;) {
-		res = read(pfd, buf, sizeof(buf));
-		if (res < 1) 
+		res = read(pfd[0], buf, sizeof(buf));
+		if (res < 1)
 			break;
-		if (visual) {
-			res2 = read(pfd2, buf2, res);
-			if (res2 < 1) 
+		if (ofh[0])
+			fwrite(buf, 1, res, ofh[0]);
+
+		if (multichannel) {
+			res2 = read(pfd[1], buf2, res);
+			if (res2 < 1)
 				break;
-			if (res == res2)
-				visualize((short *)buf, (short *)buf2, res/2);
-			else
-				printf("Huh?  res = %d, res2 = %d?\n", res, res2);
-			
-		} else {
-			if (ofh)	        
-				fwrite(buf, 1, res, ofh);
-		 	if (afd) {
-				if (stereo) {
-					for (x=0;x<res;x++)
-						buf2[x<<1] = buf2[(x<<1) + 1] = buf[x];
-					write(afd, buf2, res << 1);
-				} else
-					write(afd, buf, res);
-			}
-		}
-	}
-	if (ofh) fclose(ofh); /*Never Reached */
+			if (ofh[1])
+				fwrite(buf2, 1, res2, ofh[1]);
+
+			if (visual) {
+				if (res == res2)
+					visualize((short *)buf, (short *)buf2, res/2);
+				else
+					printf("Huh?  res = %d, res2 = %d?\n", res, res2);
+			}
+		}
+
+		if (preecho) {
+			res = read(pfd[2], buf, sizeof(buf));
+			if (res < 1)
+				break;
+			if (ofh[2])
+				fwrite(buf, 1, res, ofh[2]);
+
+			if (multichannel) {
+				res2 = read(pfd[3], buf2, res);
+				if (res2 < 1)
+					break;
+				if (ofh[3])
+					fwrite(buf2, 1, res, ofh[3]);
+
+				/* XXX How are we going to visualize the preecho set of streams?
+				if (visual) {
+					if (res == res2)
+						visualize((short *)buf, (short *)buf2, res/2);
+					else
+						printf("Huh?  res = %d, res2 = %d?\n", res, res2);
+				} */
+			}
+		}
+
+		if (ossoutput && afd) {
+			if (stereo) {
+				for (x=0;x<res;x++)
+					buf2[x<<1] = buf2[(x<<1) + 1] = buf[x];
+				write(afd, buf2, res << 1);
+			} else
+				write(afd, buf, res);
+		}
+	}
+	if (ofh[0]) fclose(ofh[0]);
+	if (ofh[1]) fclose(ofh[1]);
+	if (ofh[2]) fclose(ofh[2]);
+	if (ofh[3]) fclose(ofh[3]);
 	exit(0);
 }



More information about the zaptel-commits mailing list