summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqwell <qwell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-24 18:54:06 +0000
committerqwell <qwell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-24 18:54:06 +0000
commita461c286fb7d9aae69594f2d89b4f0a853ef57e2 (patch)
treeb95b8b903b93ebbc18eb805c8907038546eec2fc
parentdada4a9ae08e61724182a524fd4bb25b6188181d (diff)
merge (manually) ztmonitor pre-echocan debugging
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2436 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--jpah.h104
-rw-r--r--zaptel.c126
-rw-r--r--zaptel.h4
-rw-r--r--zconfig.h7
-rw-r--r--ztmonitor.c246
5 files changed, 438 insertions, 49 deletions
diff --git a/jpah.h b/jpah.h
new file mode 100644
index 0000000..f72c5fa
--- /dev/null
+++ b/jpah.h
@@ -0,0 +1,104 @@
+/*
+ * ECHO_CAN_JP1
+ *
+ * by Jason Parker
+ *
+ * Based upon mg2ec.h - sort of.
+ * This "echo can" will completely hose your audio.
+ * Don't use it unless you're absolutely sure you know what you're doing.
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ */
+
+#ifndef _JP_ECHO_H
+#define _JP_ECHO_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+/* Echo canceller definition */
+struct echo_can_state {
+ /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+ int id;
+
+ /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+ int i_d;
+};
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Audio Hoser: JP1\n");
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ strncpy(buf, "JP1", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+static inline void init_cc(struct echo_can_state *ec)
+{
+ void *ptr = ec;
+ unsigned long tmp;
+ /* Double-word align past end of state */
+ ptr += sizeof(struct echo_can_state);
+ tmp = (unsigned long)ptr;
+ tmp += 3;
+ tmp &= ~3L;
+ ptr = (void *)tmp;
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ FREE(ec);
+}
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
+{
+ static int blah = 0;
+
+ if (blah < 2) {
+ blah++;
+ return 0;
+ } else {
+ blah = (blah + 1) % 3;
+ return isig;
+ }
+}
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+ struct echo_can_state *ec;
+ ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) + 4); /* align */
+ if (ec) {
+ memset(ec, 0, sizeof(struct echo_can_state) + 4); /* align */
+ init_cc(ec);
+ }
+ return ec;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ return 0;
+}
+#endif
diff --git a/zaptel.c b/zaptel.c
index d47bcb0..63d31de 100644
--- a/zaptel.c
+++ b/zaptel.c
@@ -115,6 +115,8 @@
#elif defined(ECHO_CAN_MG2)
#define ZAPTEL_ECHO_CANCELLER "MG2"
#include "mg2ec.h"
+#elif defined(ECHO_CAN_JP1)
+#include "jpah.h"
#else
#define ZAPTEL_ECHO_CANCELLER "MARK3"
#include "mec3.h"
@@ -991,6 +993,7 @@ static void close_channel(struct zt_chan *chan)
void *rxgain = NULL;
struct echo_can_state *ec = NULL;
int oldconf;
+ short *readchunkpreec;
#ifdef CONFIG_ZAPATA_PPP
struct ppp_channel *ppp;
#endif
@@ -1005,6 +1008,8 @@ static void close_channel(struct zt_chan *chan)
#endif
ec = chan->ec;
chan->ec = NULL;
+ readchunkpreec = chan->readchunkpreec;
+ chan->readchunkpreec = NULL;
chan->curtone = NULL;
chan->curzone = NULL;
chan->cadencepos = 0;
@@ -1065,6 +1070,7 @@ static void close_channel(struct zt_chan *chan)
kfree(rxgain);
if (ec)
echo_can_free(ec);
+ kfree(readchunkpreec);
#ifdef CONFIG_ZAPATA_PPP
if (ppp) {
@@ -1722,6 +1728,9 @@ static void zt_chan_unreg(struct zt_chan *chan)
((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 */
@@ -3927,7 +3936,10 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
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 {
@@ -3980,6 +3992,16 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
/* 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)))
@@ -5000,6 +5022,51 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
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,
@@ -5688,7 +5755,16 @@ static inline void __zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, con
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)
@@ -5912,6 +5988,54 @@ static inline void __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char
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 */
if (ms->confmode & ZT_CONF_TALKER) {
diff --git a/zaptel.h b/zaptel.h
index 0f862e9..1d64092 100644
--- a/zaptel.h
+++ b/zaptel.h
@@ -975,6 +975,9 @@ struct zt_tone_def { /* Structure for zone programming */
#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 */
@@ -1120,6 +1123,7 @@ struct zt_chan {
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;
diff --git a/zconfig.h b/zconfig.h
index cbfec91..d40d5e0 100644
--- a/zconfig.h
+++ b/zconfig.h
@@ -66,6 +66,13 @@
#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
* MARK2, KB1, and MG2 echo canceler
*/
diff --git a/ztmonitor.c b/ztmonitor.c
index 43333e3..26b6ccb 100644
--- a/ztmonitor.c
+++ b/ztmonitor.c
@@ -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 @@ void visualize(short *tx, short *rx, int cnt)
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]);
}
+ } 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 (!visual) {
- /* Open audio */
- if ((afd = audio_open()) < 0) {
- printf("Cannot open audio ...\n");
- if (!ofh) exit(0);
+
+ 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,16 +404,48 @@ int main(int argc, char *argv[])
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) {
printf("\nVisual Audio Levels.\n");
@@ -338,31 +456,63 @@ int main(int argc, char *argv[])
}
/* 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[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) fclose(ofh); /*Never Reached */
+ 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);
}