aboutsummaryrefslogtreecommitdiff
path: root/audio/rat/files/patch-aa
diff options
context:
space:
mode:
Diffstat (limited to 'audio/rat/files/patch-aa')
-rw-r--r--audio/rat/files/patch-aa954
1 files changed, 945 insertions, 9 deletions
diff --git a/audio/rat/files/patch-aa b/audio/rat/files/patch-aa
index 72673143c99e..703674783904 100644
--- a/audio/rat/files/patch-aa
+++ b/audio/rat/files/patch-aa
@@ -1,11 +1,947 @@
---- rat/sdr2.plugin.in.orig Wed May 12 07:36:14 1999
-+++ rat/sdr2.plugin.in Sun Aug 22 10:47:05 1999
-@@ -12,7 +12,7 @@
+diff -uPr rat/MODS /home/oh/src/rat-newpcm/rat/MODS
+--- rat/MODS Fri Sep 8 21:02:40 2000
++++ /home/oh/src/rat-newpcm/rat/MODS Sat Sep 16 20:33:47 2000
+@@ -1,7 +1,7 @@
+ MODIFICATIONS FILE
+ ------------------
- media: audio
- proto: RTP/AVP
--tool: rat-__VERSION__
-+tool: rat
- protoname: RTP
- cryptflag: -K
+-$Id: MODS,v 1.225 2000/09/08 19:58:13 ucaccsp Exp $
++$Id: MODS,v 1.226 2000/09/16 17:43:21 ucacoxh Exp $
+ Copyright (C) 1995-2000 University College London
+ All rights reserved.
+@@ -1429,18 +1429,23 @@
+ - Fix labelling of transcoder input/output ports
+ * Released 8 September 2000
+
+-
+-
+-
++v4.2.9p1 - Added auddev_newpcm.[ch] with newpcm style mixer control. Includes
++ support for loopback and preservation of mixer settings so mixer is
++ returned to original state upon exit. [oh]
++
++ Note: both driver interfaces (luigi, newpcm) are pulled in
++ by configure and this is possible whilst luigi pcm and
++ newpcm maintain the same function call interface. This may
++ break in future. Both are necessary because mixer operation
++ is not consistent between the two interfaces.
+
+ TODO -- They're features not bugs dammit!
+ ----
+
+ - Assorted audio driver problems:
+- - FreeBSD driver bug on SoundBlaster 16 has small write buffers
++ - Luigi pcm driver bug on SoundBlaster 16 has small write buffers
+ and stops working full duplex mode after a time. Hard to fix because
+ of cushion.
+- - Loopback support is broken on FreeBSD newpcm driver.
+ - Broken auddev_pca with adding of audio interface conversion code.
+ FreeBSD 3.1 pca audio does not seem to work anymore.
+ - SunVideoPlus interface code does not work properly. The driver Sun
+diff -uPr rat/acconfig.h /home/oh/src/rat-newpcm/rat/acconfig.h
+--- rat/acconfig.h Fri Sep 8 21:02:44 2000
++++ /home/oh/src/rat-newpcm/rat/acconfig.h Sat Sep 16 20:33:49 2000
+@@ -1,7 +1,7 @@
+ /*
+ * Define this if your C library doesn't have usleep.
+ *
+- * $Id: acconfig.h,v 1.10 2000/02/06 22:04:23 ucacoxh Exp $
++ * $Id: acconfig.h,v 1.11 2000/09/16 17:43:22 ucacoxh Exp $
+ */
+ #undef NEED_USLEEP
+ #undef NEED_SNPRINTF
+@@ -42,12 +42,15 @@
+ #undef HAVE_SGI_AUDIO
+ #undef HAVE_PCA_AUDIO
+ #undef HAVE_LUIGI_AUDIO
++#undef HAVE_NEWPCM_AUDIO
+ #undef HAVE_OSS_AUDIO
+ #undef HAVE_HP_AUDIO
+ #undef HAVE_NETBSD_AUDIO
+ #undef HAVE_OSPREY_AUDIO
+ #undef HAVE_MACHINE_PCAUDIOIO_H
+ #undef HAVE_ALSA_AUDIO
++
++#undef HAVE_IPv6
+
+ /* GSM related */
+ #undef SASR
+diff -uPr rat/auddev.c /home/oh/src/rat-newpcm/rat/auddev.c
+--- rat/auddev.c Fri Sep 8 21:02:44 2000
++++ /home/oh/src/rat-newpcm/rat/auddev.c Sat Sep 16 20:33:52 2000
+@@ -9,7 +9,7 @@
+
+ #ifndef HIDE_SOURCE_STRINGS
+ static const char cvsid[] =
+- "$Id: auddev.c,v 1.58 2000/05/08 10:11:40 ucaccsp Exp $";
++ "$Id: auddev.c,v 1.59 2000/09/16 17:43:22 ucacoxh Exp $";
+ #endif /* HIDE_SOURCE_STRINGS */
+
+ #include "config_unix.h"
+@@ -22,6 +22,7 @@
+ #include "auddev.h"
+ #include "auddev_null.h"
+ #include "auddev_luigi.h"
++#include "auddev_newpcm.h"
+ #include "auddev_osprey.h"
+ #include "auddev_oss.h"
+ #include "auddev_alsa.h"
+@@ -298,6 +299,38 @@
+ luigi_audio_supports
+ },
+ #endif /* HAVE_LUIGI_AUDIO */
++#ifdef HAVE_NEWPCM_AUDIO
++ {
++ newpcm_audio_query_devices,
++ NULL,
++ newpcm_get_device_count,
++ newpcm_get_device_name,
++ newpcm_audio_open,
++ newpcm_audio_close,
++ newpcm_audio_drain,
++ newpcm_audio_duplex,
++ newpcm_audio_read,
++ newpcm_audio_write,
++ newpcm_audio_non_block,
++ newpcm_audio_block,
++ newpcm_audio_set_igain,
++ newpcm_audio_get_igain,
++ newpcm_audio_set_ogain,
++ newpcm_audio_get_ogain,
++ newpcm_audio_loopback,
++ newpcm_audio_oport_set,
++ newpcm_audio_oport_get,
++ newpcm_audio_oport_details,
++ newpcm_audio_oport_count,
++ newpcm_audio_iport_set,
++ newpcm_audio_iport_get,
++ newpcm_audio_iport_details,
++ newpcm_audio_iport_count,
++ newpcm_audio_is_ready,
++ newpcm_audio_wait_for,
++ newpcm_audio_supports
++ },
++#endif /* HAVE_NEWPCM_AUDIO */
+ #ifdef HAVE_PCA_AUDIO
+ {
+ pca_audio_init,
+diff -uPr rat/auddev_luigi.c /home/oh/src/rat-newpcm/rat/auddev_luigi.c
+--- rat/auddev_luigi.c Fri Sep 8 21:02:46 2000
++++ /home/oh/src/rat-newpcm/rat/auddev_luigi.c Sat Sep 16 20:33:54 2000
+@@ -1,15 +1,13 @@
+ /*
+ * FILE: auddev_luigi.c - Sound interface for Luigi Rizzo's FreeBSD driver
+ *
+- * Modified to support newpcm (July 2000).
+- *
+ * Copyright (c) 1996-2000 University College London
+ * All rights reserved.
+ */
+
+ #ifndef HIDE_SOURCE_STRINGS
+ static const char cvsid[] =
+- "$Id: auddev_luigi.c,v 1.51 2000/07/23 10:33:29 ucacoxh Exp $";
++ "$Id: auddev_luigi.c,v 1.52 2000/09/16 17:43:23 ucacoxh Exp $";
+ #endif /* HIDE_SOURCE_STRINGS */
+
+ #include "config_unix.h"
+@@ -51,24 +49,6 @@
+ static audio_format *input_format, *output_format, *tmp_format;
+ static snd_capabilities soundcaps[LUIGI_MAX_AUDIO_DEVICES];
+
+-/* There are some differences between the FreeBSD 4x newpcm driver
+- * and Luigi's pcm driver:
+- *
+- * 1) Mixer loopback writes are handled differently (not supported
+- * on newpcm yet - new mixer infrastructure looks to be WIP)
+- *
+- * 2) newpcm does not set AFMT_FULLDUPLEX when device caps are queried.
+- * Luigi's driver does. Luigi's driver also opens half-duplex devices
+- * when open() use O_RDWR. So with Luigi's driver we have to check
+- * AFMT_FULLDUPLEX, with newpcm we assume if device opens O_RDWR it
+- * is full duplex.
+- *
+- * The variable is_newpcm indicates applications understanding of which
+- * driver it is talking to.
+- */
+-
+-static int is_newpcm;
+-
+ int
+ luigi_audio_open(audio_desc_t ad, audio_format *ifmt, audio_format *ofmt)
+ {
+@@ -100,16 +80,12 @@
+ LUIGI_AUDIO_IOCTL(audio_fd,SNDCTL_DSP_RESET,0);
+
+ /* Check card is full duplex - need for Luigi driver only */
+- if (is_newpcm == FALSE &&
+- (soundcaps[ad].formats & AFMT_FULLDUPLEX) == 0) {
++ if ((soundcaps[ad].formats & AFMT_FULLDUPLEX) == 0) {
+ fprintf(stderr, "Sorry driver does support full duplex for this soundcard\n");
+ luigi_audio_close(ad);
+ return FALSE;
+ }
+
+- /* From newpcm source code it looks like AFMT_WEIRD is handled
+- * by driver interface, but Luigi's driver needs this.
+- */
+ if (soundcaps[ad].formats & AFMT_WEIRD) {
+ /* this is a sb16/32/64...
+ * you can change either ifmt or ofmt to U8
+@@ -556,16 +532,14 @@
+ ndev++;
+ } else if (strstr(buf, "newpcm")) {
+ /* This is a clunky check for the
+- * newpcm driver.
++ * newpcm driver. Don't use luigi in this case
+ */
+- is_newpcm = TRUE;
++ ndev = 0;
++ break;
+ }
+ }
+ fclose(f);
+ }
+-
+- debug_msg("Audio driver is %s\n",
+- (is_newpcm) ? "newpcm" : "luigi");
+
+ return (ndev);
+ }
+diff -uPr rat/auddev_newpcm.c /home/oh/src/rat-newpcm/rat/auddev_newpcm.c
+--- rat/auddev_newpcm.c Thu Jan 1 01:00:00 1970
++++ /home/oh/src/rat-newpcm/rat/auddev_newpcm.c Sat Sep 16 20:33:54 2000
+@@ -0,0 +1,622 @@
++/*
++ * FILE: auddev_newpcm.c - Sound interface for newpcm FreeBSD driver.
++ *
++ * Modified to support newpcm (July 2000).
++ *
++ * Copyright (c) 1996-2000 University College London
++ * All rights reserved.
++ */
++
++#ifndef HIDE_SOURCE_STRINGS
++static const char cvsid[] =
++ "$Id: auddev_newpcm.c,v 1.1 2000/09/16 17:43:23 ucacoxh Exp $";
++#endif /* HIDE_SOURCE_STRINGS */
++
++#include "config_unix.h"
++#include "config_win32.h"
++#include "audio_types.h"
++#include "audio_fmt.h"
++#include "auddev_newpcm.h"
++#include "memory.h"
++#include "debug.h"
++
++#include <machine/soundcard.h>
++
++static char *port_names[] = SOUND_DEVICE_LABELS;
++static int iport, oport, loop;
++static snd_chan_param pa;
++static struct snd_size sz;
++static int audio_fd = -1;
++
++#define RAT_TO_DEVICE(x) ((x) * 100 / MAX_AMP)
++#define DEVICE_TO_RAT(x) ((x) * MAX_AMP / 100)
++
++#define NEWPCM_AUDIO_IOCTL(fd, cmd, val) if (ioctl((fd), (cmd), (val)) < 0) { \
++ debug_msg("Failed %s - line %d\n",#cmd, __LINE__); \
++ newpcm_error = __LINE__; \
++ }
++
++#define NEWPCM_MAX_AUDIO_NAME_LEN 32
++#define NEWPCM_MAX_AUDIO_DEVICES 3
++
++static int dev_ids[NEWPCM_MAX_AUDIO_DEVICES];
++static char names[NEWPCM_MAX_AUDIO_DEVICES][NEWPCM_MAX_AUDIO_NAME_LEN];
++static int ndev = 0;
++static int newpcm_error;
++static audio_format *input_format, *output_format, *tmp_format;
++static snd_capabilities soundcaps[NEWPCM_MAX_AUDIO_DEVICES];
++
++static void newpcm_mixer_save(int fd);
++static void newpcm_mixer_restore(int fd);
++static void newpcm_mixer_init(int fd);
++static void newpcm_audio_loopback_config(int gain);
++
++int
++newpcm_audio_open(audio_desc_t ad, audio_format *ifmt, audio_format *ofmt)
++{
++ int32_t fragment;
++ char thedev[64];
++
++ assert(ad >= 0 && ad < ndev);
++ sprintf(thedev, "/dev/audio%d", dev_ids[ad]);
++
++ debug_msg("Opening %s\n", thedev);
++
++ audio_fd = open(thedev, O_RDWR);
++ if (audio_fd >= 0) {
++ /* Ignore any earlier errors */
++ newpcm_error = 0;
++
++ newpcm_mixer_save(audio_fd);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, AIOGCAP, &soundcaps[ad]);
++ debug_msg("soundcaps[%d].rate_min = %d\n", ad, soundcaps[ad].rate_min);
++ debug_msg("soundcaps[%d].rate_max = %d\n", ad, soundcaps[ad].rate_max);
++ debug_msg("soundcaps[%d].formats = 0x%08lx\n", ad, soundcaps[ad].formats);
++ debug_msg("soundcaps[%d].bufsize = %d\n", ad, soundcaps[ad].bufsize);
++ debug_msg("soundcaps[%d].mixers = 0x%08lx\n", ad, soundcaps[ad].mixers);
++ debug_msg("soundcaps[%d].inputs = 0x%08lx\n", ad, soundcaps[ad].inputs);
++ debug_msg("soundcaps[%d].left = 0x%04lx\n", ad, soundcaps[ad].left);
++ debug_msg("soundcaps[%d].right = 0x%04lx\n", ad, soundcaps[ad].right);
++
++ /* Setup input and output format settings */
++ assert(ofmt->channels == ifmt->channels);
++ memset(&pa, 0, sizeof(pa));
++ if (ifmt->channels == 2) {
++ if (!soundcaps[ad].formats & AFMT_STEREO) {
++ fprintf(stderr,"Driver does not support stereo for this soundcard\n");
++ newpcm_audio_close(ad);
++ return FALSE;
++ }
++ pa.rec_format = AFMT_STEREO;
++ pa.play_format = AFMT_STEREO;
++ }
++
++ switch(ifmt->encoding) {
++ case DEV_PCMU: pa.rec_format |= AFMT_MU_LAW; break;
++ case DEV_PCMA: pa.rec_format |= AFMT_A_LAW; break;
++ case DEV_S8: pa.rec_format |= AFMT_S8; break;
++ case DEV_S16: pa.rec_format |= AFMT_S16_LE; break;
++ case DEV_U8: pa.rec_format |= AFMT_U8; break;
++ }
++
++ switch(ofmt->encoding) {
++ case DEV_PCMU: pa.play_format |= AFMT_MU_LAW; break;
++ case DEV_PCMA: pa.play_format |= AFMT_A_LAW; break;
++ case DEV_S8: pa.play_format |= AFMT_S8; break;
++ case DEV_S16: pa.play_format |= AFMT_S16_LE; break;
++ case DEV_U8: pa.play_format |= AFMT_U8; break;
++ }
++ pa.play_rate = ofmt->sample_rate;
++ pa.rec_rate = ifmt->sample_rate;
++ NEWPCM_AUDIO_IOCTL(audio_fd, AIOSFMT, &pa);
++
++ sz.play_size = ofmt->bytes_per_block;
++ sz.rec_size = ifmt->bytes_per_block;
++ NEWPCM_AUDIO_IOCTL(audio_fd, AIOSSIZE, &sz);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, AIOGSIZE, &sz);
++ debug_msg("rec size %d, play size %d bytes\n",
++ sz.rec_size, sz.play_size);
++
++ /* Fragment : 8msb = #frags, 16lsbs = log2 fragsize */
++ fragment = 0x08000007;
++ NEWPCM_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragment);
++
++ if (newpcm_error != 0) {
++ /* Failed somewhere in initialization - reset error and exit*/
++ newpcm_audio_close(ad);
++ newpcm_error = 0;
++ return FALSE;
++ }
++
++ /* Store format in case we have to re-open device because
++ * of driver bug. Careful with freeing format as input format
++ * could be static input_format if device reset during write.
++ */
++ tmp_format = audio_format_dup(ifmt);
++ if (input_format != NULL) {
++ audio_format_free(&input_format);
++ }
++ input_format = tmp_format;
++
++ tmp_format = audio_format_dup(ofmt);
++ if (output_format != NULL) {
++ audio_format_free(&output_format);
++ }
++ output_format = tmp_format;
++
++ newpcm_mixer_init(audio_fd);
++ /* Turn off loopback from input to output... not fatal so
++ * after error check.
++ */
++ newpcm_audio_loopback(ad, 0);
++
++ read(audio_fd, thedev, 64);
++ return TRUE;
++ } else {
++ fprintf(stderr,
++ "Could not open device: %s (half-duplex?)\n",
++ names[ad]);
++ perror("newpcm_audio_open");
++ newpcm_audio_close(ad);
++ return FALSE;
++ }
++}
++
++/* Close the audio device */
++void
++newpcm_audio_close(audio_desc_t ad)
++{
++ UNUSED(ad);
++
++ if (audio_fd < 0) {
++ debug_msg("Device already closed!\n");
++ return;
++ }
++ if (input_format != NULL) {
++ audio_format_free(&input_format);
++ }
++ if (output_format != NULL) {
++ audio_format_free(&output_format);
++ }
++ newpcm_mixer_restore(audio_fd);
++ newpcm_audio_drain(audio_fd);
++ close(audio_fd);
++ audio_fd = -1;
++}
++
++/* Flush input buffer */
++void
++newpcm_audio_drain(audio_desc_t ad)
++{
++ u_char buf[4];
++ int pre, post;
++
++ assert(audio_fd > 0);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, FIONREAD, &pre);
++ NEWPCM_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_RESET, 0);
++ NEWPCM_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_SYNC, 0);
++ NEWPCM_AUDIO_IOCTL(audio_fd, FIONREAD, &post);
++ debug_msg("audio drain: %d -> %d\n", pre, post);
++ read(audio_fd, buf, sizeof(buf));
++
++ UNUSED(ad);
++}
++
++int
++newpcm_audio_duplex(audio_desc_t ad)
++{
++ /* We only ever open device full duplex! */
++ UNUSED(ad);
++ return TRUE;
++}
++
++int
++newpcm_audio_read(audio_desc_t ad, u_char *buf, int read_bytes)
++{
++ int done, this_read;
++ int len;
++ /* Figure out how many bytes we can read before blocking... */
++
++ UNUSED(ad); assert(audio_fd > 0);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, FIONREAD, &len);
++
++ len = min(len, read_bytes);
++
++ /* Read the data... */
++ done = 0;
++ while(done < len) {
++ this_read = read(audio_fd, (void*)buf, len - done);
++ done += this_read;
++ buf += this_read;
++ }
++ return done;
++}
++
++int
++newpcm_audio_write(audio_desc_t ad, u_char *buf, int write_bytes)
++{
++ int done;
++
++ UNUSED(ad); assert(audio_fd > 0);
++
++ done = write(audio_fd, (void*)buf, write_bytes);
++ if (done != write_bytes && errno != EINTR) {
++ /* Only ever seen this with soundblaster cards.
++ * Driver occasionally packs in reading. Seems to be
++ * no way to reset cleanly whilst running, even
++ * closing device, waiting a few 100ms and re-opening
++ * seems to fail.
++ */
++ perror("Error writing device.");
++ fprintf(stderr, "Please email this message to rat-trap@cs.ucl.ac.uk with output of:\n\t uname -a\n\t cat /dev/sndstat\n");
++ return (write_bytes - done);
++ }
++
++ return write_bytes;
++}
++
++/* Set ops on audio device to be non-blocking */
++void
++newpcm_audio_non_block(audio_desc_t ad)
++{
++ int frag = 1;
++
++ UNUSED(ad); assert(audio_fd != -1);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
++}
++
++/* Set ops on audio device to be blocking */
++void
++newpcm_audio_block(audio_desc_t ad)
++{
++ int frag = 0;
++
++ UNUSED(ad); assert(audio_fd > 0);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
++}
++
++
++static int recmask, playmask;
++
++static void
++newpcm_mixer_init(int fd)
++{
++ int devmask;
++
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_READ_RECMASK, &recmask);
++
++ if (recmask & SOUND_MASK_MIC) {
++ iport = SOUND_MASK_MIC;
++ } else {
++ iport = 1;
++ while ((iport & recmask) == 0) {
++ iport <<= 1;
++ }
++ }
++
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
++ playmask = devmask & ~recmask & ~SOUND_MASK_RECLEV;
++ debug_msg("devmask 0x%08x recmask 0x%08x playmask 0x%08x\n",
++ devmask,
++ recmask,
++ playmask);
++}
++
++static int
++newpcm_count_ports(int mask)
++{
++ int n = 0, m = mask;
++
++ while (m > 0) {
++ n += (m & 0x01);
++ m >>= 1;
++ }
++
++ return n;
++}
++
++static int
++newpcm_get_nth_port_mask(int mask, int n)
++{
++ static int lgmask;
++
++ lgmask = -1;
++ do {
++ lgmask ++;
++ if ((1 << lgmask) & mask) {
++ n--;
++ }
++ } while (n >= 0);
++
++ assert((1 << lgmask) & mask);
++ return lgmask;
++}
++
++/* Gain and volume values are in the range 0 - MAX_AMP */
++void
++newpcm_audio_set_ogain(audio_desc_t ad, int vol)
++{
++ int volume, lgport, op;
++
++ UNUSED(ad); assert(audio_fd > 0);
++
++ volume = vol << 8 | vol;
++
++ lgport = -1;
++ op = oport;
++ while (op > 0) {
++ op >>= 1;
++ lgport ++;
++ }
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, MIXER_WRITE(lgport), &volume);
++}
++
++int
++newpcm_audio_get_ogain(audio_desc_t ad)
++{
++ int volume, lgport, op;
++
++ UNUSED(ad); assert(audio_fd > 0);
++
++ lgport = -1;
++ op = oport;
++ while (op > 0) {
++ op >>= 1;
++ lgport ++;
++ }
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, MIXER_READ(lgport), &volume);
++
++ return DEVICE_TO_RAT(volume & 0xff); /* Extract left channel volume */
++}
++
++void
++newpcm_audio_oport_set(audio_desc_t ad, audio_port_t port)
++{
++ UNUSED(ad);
++ oport = port;
++ return;
++}
++
++audio_port_t
++newpcm_audio_oport_get(audio_desc_t ad)
++{
++ UNUSED(ad);
++ return oport;
++}
++
++int
++newpcm_audio_oport_count(audio_desc_t ad)
++{
++ UNUSED(ad);
++ return newpcm_count_ports(playmask);
++}
++
++const audio_port_details_t*
++newpcm_audio_oport_details(audio_desc_t ad, int idx)
++{
++ static audio_port_details_t ap;
++ int lgmask;
++
++ UNUSED(ad);
++
++ lgmask = newpcm_get_nth_port_mask(playmask, idx);
++ ap.port = 1 << lgmask;
++ sprintf(ap.name, "%s", port_names[lgmask]);
++
++ return &ap;
++}
++
++void
++newpcm_audio_set_igain(audio_desc_t ad, int gain)
++{
++ int volume = RAT_TO_DEVICE(gain) << 8 | RAT_TO_DEVICE(gain);
++
++ UNUSED(ad); assert(audio_fd > 0);
++ newpcm_audio_loopback_config(gain);
++ NEWPCM_AUDIO_IOCTL(audio_fd, SOUND_MIXER_WRITE_RECLEV, &volume);
++}
++
++int
++newpcm_audio_get_igain(audio_desc_t ad)
++{
++ int volume;
++
++ UNUSED(ad); assert(audio_fd > 0);
++ NEWPCM_AUDIO_IOCTL(audio_fd, SOUND_MIXER_READ_RECLEV, &volume);
++ return (DEVICE_TO_RAT(volume & 0xff));
++}
++
++void
++newpcm_audio_iport_set(audio_desc_t ad, audio_port_t port)
++{
++ /* Check port is in record mask */
++ int gain;
++
++ debug_msg("port 0x%08x recmask 0x%08x\n", port, recmask);
++
++ assert((port & recmask) != 0);
++
++ if (ioctl(audio_fd, SOUND_MIXER_WRITE_RECSRC, &port) < 0) {
++ perror("Unable to write record mask\n");
++ return;
++ }
++ iport = port;
++ gain = newpcm_audio_get_igain(ad);
++ newpcm_audio_loopback_config(gain);
++ UNUSED(ad);
++}
++
++audio_port_t
++newpcm_audio_iport_get(audio_desc_t ad)
++{
++ UNUSED(ad); assert(audio_fd > 0);
++ return iport;
++}
++
++int
++newpcm_audio_iport_count(audio_desc_t ad)
++{
++ UNUSED(ad);
++ return newpcm_count_ports(recmask);
++}
++
++const audio_port_details_t *
++newpcm_audio_iport_details(audio_desc_t ad, int idx)
++{
++ static audio_port_details_t ap;
++ int lgmask;
++
++ UNUSED(ad);
++
++ lgmask = newpcm_get_nth_port_mask(recmask, idx);
++ ap.port = 1 << lgmask;
++ sprintf(ap.name, "%s", port_names[lgmask]);
++
++ return &ap;
++}
++
++void
++newpcm_audio_loopback(audio_desc_t ad, int gain)
++{
++ UNUSED(ad); assert(audio_fd > 0);
++ loop = gain;
++}
++
++static void
++newpcm_audio_loopback_config(int gain)
++{
++ int lgport, vol;
++
++ /* Find current input port id */
++ lgport = newpcm_get_nth_port_mask(iport, 0);
++
++ if (loop) {
++ vol = RAT_TO_DEVICE(gain) << 8 | RAT_TO_DEVICE(gain);
++ } else {
++ vol = 0;
++ }
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, MIXER_WRITE(lgport), &vol);
++}
++
++void
++newpcm_audio_wait_for(audio_desc_t ad, int delay_ms)
++{
++ if (!newpcm_audio_is_ready(ad)) {
++ usleep((unsigned int)delay_ms * 1000);
++ }
++}
++
++int
++newpcm_audio_is_ready(audio_desc_t ad)
++{
++ int avail;
++
++ UNUSED(ad);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, FIONREAD, &avail);
++
++ return (avail >= sz.rec_size);
++}
++
++int
++newpcm_audio_supports(audio_desc_t ad, audio_format *fmt)
++{
++ snd_capabilities s;
++
++ UNUSED(ad);
++
++ NEWPCM_AUDIO_IOCTL(audio_fd, AIOGCAP, &s);
++ if (!newpcm_error) {
++ if ((unsigned)fmt->sample_rate < s.rate_min || (unsigned)fmt->sample_rate > s.rate_max) return FALSE;
++ if (fmt->channels == 1) return TRUE; /* Always supports mono */
++ assert(fmt->channels == 2);
++ if (s.formats & AFMT_STEREO) return TRUE;
++ }
++ return FALSE;
++}
++
++int
++newpcm_audio_query_devices()
++{
++ FILE *f;
++ char buf[128], *p;
++ int n, newpcm = FALSE;
++
++ f = fopen("/dev/sndstat", "r");
++ if (f) {
++ while (!feof(f) && ndev < NEWPCM_MAX_AUDIO_DEVICES) {
++ p = fgets(buf, 128, f);
++ n = sscanf(buf, "pcm%d: <%[A-z0-9 ]>", dev_ids + ndev, names[ndev]);
++ if (p && n == 2) {
++ debug_msg("dev (%d) name (%s)\n", dev_ids[ndev], names[ndev]);
++ ndev++;
++ } else if (strstr(buf, "newpcm")) {
++ newpcm = TRUE;
++ }
++ }
++ fclose(f);
++ }
++
++ if (newpcm == FALSE) {
++ ndev = 0; /* Should be using Luigi's interface */
++ }
++
++ return (ndev);
++}
++
++int
++newpcm_get_device_count()
++{
++ return ndev;
++}
++
++char *
++newpcm_get_device_name(audio_desc_t idx)
++{
++ if (idx >=0 && idx < ndev) {
++ return names[idx];
++ }
++ return NULL;
++}
++
++/* Functions to save and restore recording source and mixer levels */
++
++static int saved_rec_mask, saved_gain_values[SOUND_MIXER_NRDEVICES];
++
++static void
++newpcm_mixer_save(int fd)
++{
++ int devmask, i;
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_READ_RECSRC, &saved_rec_mask);
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
++ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
++ if ((1 << i) & devmask) {
++ NEWPCM_AUDIO_IOCTL(fd, MIXER_READ(i), &saved_gain_values[i]);
++ } else {
++ saved_gain_values[i] = 0;
++ }
++ }
++}
++
++static void
++newpcm_mixer_restore(int fd)
++{
++ int devmask, i;
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_WRITE_RECSRC, &saved_rec_mask);
++
++ NEWPCM_AUDIO_IOCTL(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
++ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
++ if ((1 << i) & devmask) {
++ NEWPCM_AUDIO_IOCTL(fd, MIXER_WRITE(i), &saved_gain_values[i]);
++ }
++ }
++}
+diff -uPr rat/auddev_newpcm.h /home/oh/src/rat-newpcm/rat/auddev_newpcm.h
+--- rat/auddev_newpcm.h Thu Jan 1 01:00:00 1970
++++ /home/oh/src/rat-newpcm/rat/auddev_newpcm.h Sat Sep 16 20:33:54 2000
+@@ -0,0 +1,52 @@
++/*
++ * FILE: auddev_newpcm.h
++ * PROGRAM: RAT
++ * AUTHOR: Orion Hodson
++ *
++ * Copyright (c) 1998-2000 University College London
++ * All rights reserved.
++ *
++ * $Id: auddev_newpcm.h,v 1.1 2000/09/16 17:43:24 ucacoxh Exp $
++ */
++
++#ifndef _AUDDEV_NEWPCM_H_
++#define _AUDDEV_NEWPCM_H_
++
++int newpcm_audio_open (audio_desc_t ad, audio_format* ifmt, audio_format *ofmt);
++void newpcm_audio_close (audio_desc_t ad);
++void newpcm_audio_drain (audio_desc_t ad);
++int newpcm_audio_duplex (audio_desc_t ad);
++
++void newpcm_audio_set_igain (audio_desc_t ad, int gain);
++int newpcm_audio_get_igain (audio_desc_t ad);
++void newpcm_audio_set_ogain (audio_desc_t ad, int vol);
++int newpcm_audio_get_ogain (audio_desc_t ad);
++void newpcm_audio_loopback (audio_desc_t ad, int gain);
++
++int newpcm_audio_read (audio_desc_t ad, u_char *buf, int buf_len);
++int newpcm_audio_write (audio_desc_t ad, u_char *buf, int buf_len);
++void newpcm_audio_non_block (audio_desc_t ad);
++void newpcm_audio_block (audio_desc_t ad);
++
++void newpcm_audio_oport_set (audio_desc_t ad, audio_port_t port);
++audio_port_t newpcm_audio_oport_get (audio_desc_t ad);
++int newpcm_audio_oport_count (audio_desc_t ad);
++const audio_port_details_t*
++ newpcm_audio_oport_details (audio_desc_t ad, int idx);
++
++void newpcm_audio_iport_set (audio_desc_t ad, audio_port_t port);
++audio_port_t newpcm_audio_iport_get (audio_desc_t ad);
++int newpcm_audio_iport_count (audio_desc_t ad);
++const audio_port_details_t*
++ newpcm_audio_iport_details (audio_desc_t ad, int idx);
++
++int newpcm_audio_is_ready (audio_desc_t ad);
++void newpcm_audio_wait_for (audio_desc_t ad, int delay_ms);
++int newpcm_audio_supports (audio_desc_t ad, audio_format *f);
++
++/* Functions to get names of devices */
++int newpcm_audio_query_devices (void);
++int newpcm_get_device_count (void);
++char *newpcm_get_device_name (audio_desc_t ad);
++
++#endif /* _AUDDEV_NEWPCM_H_ */
+diff -uPr rat/config.h.in /home/oh/src/rat-newpcm/rat/config.h.in
+--- rat/config.h.in Fri Sep 8 21:03:01 2000
++++ /home/oh/src/rat-newpcm/rat/config.h.in Sat Sep 16 20:34:04 2000
+@@ -27,7 +27,7 @@
+ /*
+ * Define this if your C library doesn't have usleep.
+ *
+- * $Id: config.h.in,v 1.18 2000/03/03 15:05:32 ucaccsp Exp $
++ * $Id: config.h.in,v 1.19 2000/09/16 17:43:24 ucacoxh Exp $
+ */
+ #undef NEED_USLEEP
+ #undef NEED_SNPRINTF
+@@ -68,12 +68,15 @@
+ #undef HAVE_SGI_AUDIO
+ #undef HAVE_PCA_AUDIO
+ #undef HAVE_LUIGI_AUDIO
++#undef HAVE_NEWPCM_AUDIO
+ #undef HAVE_OSS_AUDIO
+ #undef HAVE_HP_AUDIO
+ #undef HAVE_NETBSD_AUDIO
+ #undef HAVE_OSPREY_AUDIO
+ #undef HAVE_MACHINE_PCAUDIOIO_H
+ #undef HAVE_ALSA_AUDIO
++
++#undef HAVE_IPv6
+
+ /* GSM related */
+ #undef SASR
+diff -uPr rat/configure.in /home/oh/src/rat-newpcm/rat/configure.in
+--- rat/configure.in Fri Sep 8 21:03:02 2000
++++ /home/oh/src/rat-newpcm/rat/configure.in Sat Sep 16 20:34:08 2000
+@@ -1,5 +1,5 @@
+ dnl UCL RAT configure script.
+-dnl $Header: /cs/research/mice/starship/src/local/CVS_repository/rat/configure.in,v 1.38 2000/03/23 10:00:53 ucacoxh Exp $
++dnl $Header: /cs/research/mice/starship/src/local/CVS_repository/rat/configure.in,v 1.39 2000/09/16 17:43:25 ucacoxh Exp $
+ dnl
+ dnl Process this file with GNU autoconf to generate a configure script.
+
+@@ -195,9 +195,12 @@
+ AU_OBJ="$AU_OBJ auddev_pca.o"
+ AC_DEFINE(HAVE_PCA_AUDIO)
+ fi
+- # Luigi's driver
+- AU_OBJ="$AU_OBJ auddev_luigi.o"
+- AC_DEFINE(HAVE_LUIGI_AUDIO)
++ # Note luigi and newpcm have compatible soundcard.h files but
++ # mixer behaves differently under both systems. During runtime
++ # only one of these modules will be used.
++ AU_OBJ="$AU_OBJ auddev_luigi.o auddev_newpcm.o"
++ AC_DEFINE(HAVE_LUIGI_AUDIO)
++ AC_DEFINE(HAVE_NEWPCM_AUDIO)
+ ;;
+ *netbsd*)
+ AU_OBJ="$AUDIOBJ auddev_netbsd.o"