summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorjoq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224>2004-03-12 05:00:12 +0000
committerjoq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224>2004-03-12 05:00:12 +0000
commit5d5dc82555cc3cf1f1bdcedf7616fb967c4cf2b3 (patch)
tree8c80d8518de851683ff9449fa0c390b276204ecc /drivers
parent0d1577094c6ca2fcd525936346efd0bc1083ce51 (diff)
downloadjack1-5d5dc82555cc3cf1f1bdcedf7616fb967c4cf2b3.tar.gz
[0.95.5] add OSS driver
git-svn-id: svn+ssh://jackaudio.org/trunk/jack@656 0c269be4-1314-0410-8aa9-9f06e86f4224
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile.am17
-rw-r--r--drivers/oss/.cvsignore6
-rw-r--r--drivers/oss/oss_driver.c1171
-rw-r--r--drivers/oss/oss_driver.h90
4 files changed, 1281 insertions, 3 deletions
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
index 45bf058..1dd6797 100644
--- a/drivers/Makefile.am
+++ b/drivers/Makefile.am
@@ -6,12 +6,23 @@ else
ALSA_DIR =
endif
+if HAVE_RAW1394
+IEC61883_DIR = iec61883
+else
+IEC61883_DIR =
+endif
+
+if HAVE_OSS
+OSS_DIR = oss
+else
+OSS_DIR =
+endif
+
if HAVE_PA
PA_DIR = portaudio
else
PA_DIR =
endif
-SUBDIRS = dummy iec61883 $(ALSA_DIR) $(PA_DIR)
-
-DIST_SUBDIRS = dummy iec61883 alsa portaudio
+SUBDIRS = $(ALSA_DIR) dummy $(IEC61883_DIR) $(OSS_DIR) $(PA_DIR)
+DIST_SUBDIRS = alsa dummy iec61883 oss portaudio
diff --git a/drivers/oss/.cvsignore b/drivers/oss/.cvsignore
new file mode 100644
index 0000000..6e5ca7e
--- /dev/null
+++ b/drivers/oss/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
diff --git a/drivers/oss/oss_driver.c b/drivers/oss/oss_driver.c
new file mode 100644
index 0000000..492555a
--- /dev/null
+++ b/drivers/oss/oss_driver.c
@@ -0,0 +1,1171 @@
+/*
+
+ OSS driver for Jack
+ Copyright (C) 2003-2004 Jussi Laako <jussi@sonarnerd.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <float.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <pthread.h>
+
+#ifdef USE_BARRIER
+#include <semaphore.h>
+#endif
+
+#include <jack/types.h>
+#include <jack/internal.h>
+#include <jack/engine.h>
+#include <jack/time.h>
+
+#include "oss_driver.h"
+
+
+#define OSS_DRIVER_N_PARAMS 9
+const static jack_driver_param_desc_t oss_params[OSS_DRIVER_N_PARAMS] = {
+ { "samplerate",
+ 's',
+ JackDriverParamUInt,
+ { .ui = OSS_DRIVER_DEF_FS },
+ "sample rate",
+ "sample rate"
+ },
+ { "periodsize",
+ 'b',
+ JackDriverParamUInt,
+ { .ui = OSS_DRIVER_DEF_BLKSIZE },
+ "period size",
+ "period size"
+ },
+ { "wordlength",
+ 'w',
+ JackDriverParamInt,
+ { .i = OSS_DRIVER_DEF_BITS },
+ "word length",
+ "word length"
+ },
+ { "capturech",
+ 'c',
+ JackDriverParamUInt,
+ { .ui = OSS_DRIVER_DEF_INS },
+ "capture channels",
+ "capture channels"
+ },
+ { "playbackch",
+ 'p',
+ JackDriverParamUInt,
+ { .ui = OSS_DRIVER_DEF_OUTS },
+ "playback channels",
+ "playback channels"
+ },
+ { "inputdev",
+ 'i',
+ JackDriverParamString,
+ { .str = "" },
+ "input device",
+ "input device"
+ },
+ { "outputdev",
+ 'o',
+ JackDriverParamString,
+ { .str = "" },
+ "output device",
+ "output device"
+ },
+ { "ignorehwbuf",
+ 'd',
+ JackDriverParamBool,
+ { },
+ "ignore hardware period size",
+ "ignore hardware period size"
+ },
+ { "help",
+ 'h',
+ JackDriverParamBool,
+ { },
+ "help",
+ "help"
+ }
+};
+
+
+
+/* internal functions */
+
+
+static void copy_and_convert_in (jack_sample_t *dst, void *src,
+ size_t nframes, int channel, int chcount, int bits)
+{
+ int srcidx;
+ int dstidx;
+ signed short *s16src = (signed short *) src;
+ signed int *s32src = (signed int *) src;
+ double *f64src = (double *) src;
+ jack_sample_t scale;
+
+ srcidx = channel;
+ switch (bits)
+ {
+ case 16:
+ scale = 1.0f / 0x7fff;
+ for (dstidx = 0; dstidx < nframes; dstidx++)
+ {
+ dst[dstidx] = (jack_sample_t)
+ s16src[srcidx] * scale;
+ srcidx += chcount;
+ }
+ break;
+ case 24:
+ scale = 1.0f / 0x7fffff;
+ for (dstidx = 0; dstidx < nframes; dstidx++)
+ {
+ dst[dstidx] = (jack_sample_t)
+ s32src[srcidx] * scale;
+ srcidx += chcount;
+ }
+ break;
+ case 32:
+ scale = 1.0f / 0x7fffffff;
+ for (dstidx = 0; dstidx < nframes; dstidx++)
+ {
+ dst[dstidx] = (jack_sample_t)
+ s32src[srcidx] * scale;
+ srcidx += chcount;
+ }
+ break;
+ case 64:
+ for (dstidx = 0; dstidx < nframes; dstidx++)
+ {
+ dst[dstidx] = (jack_sample_t) f64src[srcidx];
+ srcidx += chcount;
+ }
+ break;
+ }
+}
+
+
+static void copy_and_convert_out (void *dst, jack_sample_t *src,
+ size_t nframes, int channel, int chcount, int bits)
+{
+ int srcidx;
+ int dstidx;
+ signed short *s16dst = (signed short *) dst;
+ signed int *s32dst = (signed int *) dst;
+ double *f64dst = (double *) dst;
+ jack_sample_t scale;
+
+ dstidx = channel;
+ switch (bits)
+ {
+ case 16:
+ scale = 0x7fff;
+ for (srcidx = 0; srcidx < nframes; srcidx++)
+ {
+ s16dst[dstidx] = (signed short)
+ (src[srcidx] * scale + 0.5f);
+ dstidx += chcount;
+ }
+ break;
+ case 24:
+ scale = 0x7fffff;
+ for (srcidx = 0; srcidx < nframes; srcidx++)
+ {
+ s32dst[dstidx] = (signed int)
+ (src[srcidx] * scale + 0.5f);
+ dstidx += chcount;
+ }
+ break;
+ case 32:
+ scale = 0x7fffffff;
+ for (srcidx = 0; srcidx < nframes; srcidx++)
+ {
+ s32dst[dstidx] = (signed int)
+ (src[srcidx] * scale + 0.5f);
+ dstidx += chcount;
+ }
+ break;
+ case 64:
+ for (srcidx = 0; srcidx < nframes; srcidx++)
+ {
+ f64dst[dstidx] = (double) src[srcidx];
+ dstidx += chcount;
+ }
+ break;
+ }
+}
+
+
+static void set_fragment (int fd, int fragsize)
+{
+ int fragcount;
+ int fragsize_2p;
+ int fragments;
+
+ fragcount = 2;
+ //fragcount = 3;
+ //fragcount = 0xffff / fragsize;
+ fragsize_2p = (int) (log(fragsize) / log(2.0) + 0.5);
+ fragments = ((fragcount << 16) | (fragsize_2p & 0xffff));
+ if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragments) < 0)
+ {
+ jack_error("OSS: failed to set fragment size: %s@%i",
+ __FILE__, __LINE__);
+ }
+}
+
+
+static int get_fragment (int fd)
+{
+ int fragsize;
+
+ if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &fragsize) < 0)
+ {
+ jack_error("OSS: failed to get fragment size: %s@%i",
+ __FILE__, __LINE__);
+ return 0;
+ }
+ return fragsize;
+}
+
+
+static void *io_thread (void *);
+
+
+/* jack driver interface */
+
+
+static int oss_driver_attach (oss_driver_t *driver, jack_engine_t *engine)
+{
+ int port_flags;
+ unsigned int channel;
+ char channel_name[64];
+ jack_port_t *port;
+
+ driver->engine = engine;
+
+ engine->set_buffer_size(engine, driver->period_size);
+ engine->set_sample_rate(engine, driver->sample_rate);
+
+ port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal;
+ for (channel = 0; channel < driver->capture_channels; channel++)
+ {
+ snprintf(channel_name, sizeof(channel_name),
+ "capture_%u", channel + 1);
+ port = jack_port_register(driver->client, channel_name,
+ JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
+ if (port == NULL)
+ {
+ jack_error("OSS: cannot register port for %s: %s@%i",
+ channel_name, __FILE__, __LINE__);
+ break;
+ }
+ driver->capture_ports =
+ jack_slist_append(driver->capture_ports, port);
+ }
+
+ port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal;
+ for (channel = 0; channel < driver->playback_channels; channel++)
+ {
+ snprintf(channel_name, sizeof(channel_name),
+ "playback_%u", channel + 1);
+ port = jack_port_register(driver->client, channel_name,
+ JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
+ if (port == NULL)
+ {
+ jack_error("OSS: cannot register port for %s: %s@%i",
+ channel_name, __FILE__, __LINE__);
+ break;
+ }
+ driver->playback_ports =
+ jack_slist_append(driver->playback_ports, port);
+ }
+
+ jack_activate(driver->client);
+
+ return 0;
+}
+
+
+static int oss_driver_detach (oss_driver_t *driver, jack_engine_t *engine)
+{
+ JSList *node;
+
+ if (driver->engine == NULL)
+ return -1;
+
+ node = driver->capture_ports;
+ while (node != NULL)
+ {
+ jack_port_unregister(driver->client,
+ ((jack_port_t *) node->data));
+ node = jack_slist_next(node);
+ }
+ jack_slist_free(driver->capture_ports);
+ driver->capture_ports = NULL;
+
+ node = driver->playback_ports;
+ while (node != NULL)
+ {
+ jack_port_unregister(driver->client,
+ ((jack_port_t *) node->data));
+ node = jack_slist_next(node);
+ }
+ jack_slist_free(driver->playback_ports);
+ driver->playback_ports = NULL;
+
+ driver->engine = NULL;
+
+ return 0;
+}
+
+
+static int oss_driver_start (oss_driver_t *driver)
+{
+ int format;
+ int channels;
+ int samplerate;
+ int infd = driver->infd;
+ int outfd = driver->outfd;
+ unsigned int period_size;
+ size_t samplesize;
+ size_t fragsize;
+ const char *indev = driver->indev;
+ const char *outdev = driver->outdev;
+
+ switch (driver->bits)
+ {
+ case 24:
+ case 32:
+ samplesize = sizeof(int);
+ break;
+ case 64:
+ samplesize = sizeof(double);
+ break;
+ case 16:
+ default:
+ samplesize = sizeof(short);
+ break;
+ }
+ if (strcmp(indev, outdev) != 0)
+ {
+ if (driver->capture_channels > 0)
+ {
+ infd = open(indev, O_RDONLY);
+ if (infd < 0)
+ {
+ jack_error(
+ "OSS: failed to open input device %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ }
+ fragsize = driver->period_size *
+ driver->capture_channels * samplesize;
+ set_fragment(infd, fragsize);
+ }
+ else infd = -1;
+
+ if (driver->playback_channels > 0)
+ {
+ outfd = open(outdev, O_WRONLY);
+ if (outfd < 0)
+ {
+ jack_error(
+ "OSS: failed to open output device %s: %s@%i",
+ outdev, __FILE__, __LINE__);
+ }
+ fragsize = driver->period_size *
+ driver->playback_channels * samplesize;
+ set_fragment(outfd, fragsize);
+ }
+ else outfd = -1;
+ }
+ else
+ {
+ if (driver->capture_channels != 0 &&
+ driver->playback_channels == 0)
+ {
+ infd = open(indev, O_RDWR);
+ outfd = -1;
+ if (infd < 0)
+ {
+ jack_error(
+ "OSS: failed to open device %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ return -1;
+ }
+ }
+ else if (driver->capture_channels == 0 &&
+ driver->playback_channels != 0)
+ {
+ infd = -1;
+ outfd = open(outdev, O_RDWR);
+ if (outfd < 0)
+ {
+ jack_error(
+ "OSS: failed to open device %s: %s@%i",
+ outdev, __FILE__, __LINE__);
+ return -1;
+ }
+ }
+ else
+ {
+ infd = outfd = open(indev, O_RDWR);
+ if (infd < 0)
+ {
+ jack_error(
+ "OSS: failed to open device %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ return -1;
+ }
+ }
+ if (infd >= 0 && outfd >= 0)
+ {
+ if (ioctl(infd, SNDCTL_DSP_SETDUPLEX, 0) < 0)
+ {
+ jack_error(
+ "OSS: failed to enable full duplex for %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ }
+ }
+ if (infd >= 0)
+ {
+ fragsize = driver->period_size *
+ driver->capture_channels * samplesize;
+ set_fragment(infd, fragsize);
+ }
+ if (outfd >= 0 && infd < 0)
+ {
+ fragsize = driver->period_size *
+ driver->playback_channels * samplesize;
+ set_fragment(outfd, fragsize);
+ }
+ }
+ driver->infd = infd;
+ driver->outfd = outfd;
+
+ if (infd >= 0)
+ {
+ format = driver->format;
+ if (ioctl(infd, SNDCTL_DSP_SETFMT, &format) < 0)
+ jack_error(
+ "OSS: failed to set format for %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ channels = driver->capture_channels;
+ if (ioctl(infd, SNDCTL_DSP_CHANNELS, &channels) < 0)
+ jack_error(
+ "OSS: failed to set channels for %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ samplerate = driver->sample_rate;
+ if (ioctl(infd, SNDCTL_DSP_SPEED, &samplerate) < 0)
+ jack_error(
+ "OSS: failed to set samplerate for %s: %s@%i",
+ indev, __FILE__, __LINE__);
+ printf("oss_driver: %s : 0x%x/%i/%i (%i)\n", indev,
+ format, channels, samplerate, get_fragment(infd));
+
+ period_size = get_fragment(infd) / samplesize / channels;
+ if (period_size != driver->period_size &&
+ !driver->ignorehwbuf)
+ {
+ printf("oss_driver: period size update: %u\n",
+ period_size);
+ driver->period_size = period_size;
+ driver->period_usecs =
+ ((double) driver->period_size /
+ (double) driver->sample_rate) * 1e6;
+ driver->engine->set_buffer_size(driver->engine,
+ driver->period_size);
+ }
+ }
+
+ if (outfd >= 0 && infd != outfd)
+ {
+ format = driver->format;
+ if (ioctl(outfd, SNDCTL_DSP_SETFMT, &format) < 0)
+ jack_error(
+ "OSS: failed to set format for %s: %s@%i",
+ outdev, __FILE__, __LINE__);
+ channels = driver->playback_channels;
+ if (ioctl(outfd, SNDCTL_DSP_CHANNELS, &channels) < 0)
+ jack_error(
+ "OSS: failed to set channels for %s: %s@%i",
+ outdev, __FILE__, __LINE__);
+ samplerate = driver->sample_rate;
+ if (ioctl(outfd, SNDCTL_DSP_SPEED, &samplerate) < 0)
+ jack_error(
+ "OSS: failed to set samplerate for %s: %s@%i",
+ outdev, __FILE__, __LINE__);
+ printf("oss_driver: %s : 0x%x/%i/%i (%i)\n", outdev,
+ format, channels, samplerate,
+ get_fragment(outfd));
+
+ period_size = get_fragment(outfd) / samplesize / channels;
+ if (period_size != driver->period_size &&
+ !driver->ignorehwbuf)
+ {
+ printf("oss_driver: period size update: %u\n",
+ period_size);
+ driver->period_size = period_size;
+ driver->period_usecs =
+ ((double) driver->period_size /
+ (double) driver->sample_rate) * 1e6;
+ driver->engine->set_buffer_size(driver->engine,
+ driver->period_size);
+ }
+ }
+
+ if (driver->capture_channels > 0)
+ {
+ driver->indevbufsize = driver->period_size *
+ driver->capture_channels * samplesize;
+ driver->indevbuf = malloc(driver->indevbufsize);
+ if (driver->indevbuf == NULL)
+ {
+ jack_error( "OSS: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ memset(driver->indevbuf, 0x00, driver->indevbufsize);
+ }
+ else
+ {
+ driver->indevbufsize = 0;
+ driver->indevbuf = NULL;
+ }
+
+ if (driver->playback_channels > 0)
+ {
+ driver->outdevbufsize = driver->period_size *
+ driver->playback_channels * samplesize;
+ driver->outdevbuf = malloc(driver->outdevbufsize);
+ if (driver->outdevbuf == NULL)
+ {
+ jack_error("OSS: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ memset(driver->outdevbuf, 0x00, driver->outdevbufsize);
+ }
+ else
+ {
+ driver->outdevbufsize = 0;
+ driver->outdevbuf = NULL;
+ }
+
+ printf("oss_driver: indevbuf %u B, outdevbuf %u B\n",
+ driver->indevbufsize, driver->outdevbufsize);
+
+ pthread_mutex_init(&driver->mutex_in, NULL);
+ pthread_mutex_init(&driver->mutex_out, NULL);
+# ifdef USE_BARRIER
+ pthread_barrier_init(&driver->barrier, NULL, 2);
+ sem_init(&driver->sem_start, 0, 0);
+# endif
+ driver->run = 1;
+ driver->threads = 0;
+ if (infd >= 0)
+ {
+ if (pthread_create(&driver->thread_in, NULL, io_thread,
+ driver) < 0)
+ {
+ jack_error("OSS: pthread_create() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ driver->threads |= 1;
+ }
+# ifdef USE_BARRIER
+ if (outfd >= 0)
+# else
+ if (outfd >= 0 && infd != outfd)
+# endif
+ {
+ if (pthread_create(&driver->thread_out, NULL, io_thread,
+ driver) < 0)
+ {
+ jack_error("OSS: pthread_create() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ driver->threads |= 2;
+ }
+
+# ifdef USE_BARRIER
+ sem_post(&driver->sem_start);
+ sem_post(&driver->sem_start);
+# endif
+
+ return 0;
+}
+
+
+static int oss_driver_stop (oss_driver_t *driver)
+{
+ void *retval;
+
+ driver->run = 0;
+ if (driver->threads & 1)
+ {
+ if (pthread_join(driver->thread_in, &retval) < 0)
+ {
+ jack_error("OSS: pthread_join() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ }
+ if (driver->threads & 2)
+ {
+ if (pthread_join(driver->thread_out, &retval) < 0)
+ {
+ jack_error("OSS: pthread_join() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ }
+# ifdef USE_BARRIER
+ sem_destroy(&driver->sem_start);
+ pthread_barrier_destroy(&driver->barrier);
+# endif
+ pthread_mutex_destroy(&driver->mutex_in);
+ pthread_mutex_destroy(&driver->mutex_out);
+
+ if (driver->outfd >= 0 && driver->outfd != driver->infd)
+ {
+ close(driver->outfd);
+ driver->outfd = -1;
+ }
+ if (driver->infd >= 0)
+ {
+ close(driver->infd);
+ driver->infd = -1;
+ }
+
+ if (driver->indevbuf != NULL)
+ {
+ free(driver->indevbuf);
+ driver->indevbuf = NULL;
+ }
+ if (driver->outdevbuf != NULL)
+ {
+ free(driver->outdevbuf);
+ driver->outdevbuf = NULL;
+ }
+
+ return 0;
+}
+
+
+static int oss_driver_read (oss_driver_t *driver, jack_nframes_t nframes)
+{
+ int channel;
+ jack_sample_t *portbuf;
+ JSList *node;
+ jack_port_t *port;
+
+ if (nframes != driver->period_size)
+ {
+ jack_error(
+ "OSS: read failed nframes != period_size (%u/%u): %s@%i",
+ nframes, driver->period_size, __FILE__, __LINE__);
+ return -1;
+ }
+
+ pthread_mutex_lock(&driver->mutex_in);
+
+ node = driver->capture_ports;
+ channel = 0;
+ while (node != NULL)
+ {
+ port = (jack_port_t *) node->data;
+
+ if (jack_port_connected(port))
+ {
+ portbuf = jack_port_get_buffer(port, nframes);
+ copy_and_convert_in(portbuf, driver->indevbuf,
+ nframes, channel,
+ driver->capture_channels,
+ driver->bits);
+ }
+
+ node = jack_slist_next(node);
+ channel++;
+ }
+
+ pthread_mutex_unlock(&driver->mutex_in);
+
+ return 0;
+}
+
+
+static int oss_driver_write (oss_driver_t *driver, jack_nframes_t nframes)
+{
+ int channel;
+ jack_sample_t *portbuf;
+ JSList *node;
+ jack_port_t *port;
+
+ if (nframes != driver->period_size)
+ {
+ jack_error(
+ "OSS: write failed nframes != period_size (%u/%u): %s@%i",
+ nframes, driver->period_size, __FILE__, __LINE__);
+ return -1;
+ }
+
+ pthread_mutex_lock(&driver->mutex_out);
+
+ node = driver->playback_ports;
+ channel = 0;
+ while (node != NULL)
+ {
+ port = (jack_port_t *) node->data;
+
+ if (jack_port_connected(port))
+ {
+ portbuf = jack_port_get_buffer(port, nframes);
+ copy_and_convert_out(driver->outdevbuf, portbuf,
+ nframes, channel,
+ driver->playback_channels,
+ driver->bits);
+ }
+
+ node = jack_slist_next(node);
+ channel++;
+ }
+
+ pthread_mutex_unlock(&driver->mutex_out);
+
+ return 0;
+}
+
+
+static int oss_driver_null_cycle (oss_driver_t *driver, jack_nframes_t nframes)
+{
+ pthread_mutex_lock(&driver->mutex_in);
+ memset(driver->indevbuf, 0x00, driver->indevbufsize);
+ pthread_mutex_unlock(&driver->mutex_in);
+
+ pthread_mutex_lock(&driver->mutex_out);
+ memset(driver->outdevbuf, 0x00, driver->outdevbufsize);
+ pthread_mutex_unlock(&driver->mutex_out);
+
+ return 0;
+}
+
+
+static int oss_driver_bufsize (oss_driver_t *driver, jack_nframes_t nframes)
+{
+ oss_driver_stop(driver);
+
+ driver->period_size = nframes;
+ driver->period_usecs =
+ ((double) driver->period_size /
+ (double) driver->sample_rate) * 1e6;
+ printf("oss_driver: period size update: %u\n", driver->period_size);
+
+ oss_driver_start(driver);
+
+ return 0;
+}
+
+
+/* internal driver thread */
+
+
+#ifdef USE_BARRIER
+static inline void synchronize (oss_driver_t *driver)
+{
+ if (driver->threads == 3)
+ {
+ if (pthread_barrier_wait(&driver->barrier) ==
+ PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ driver->last_wait_ust = jack_get_microseconds();
+ driver->engine->run_cycle(driver->engine,
+ driver->period_size, 0);
+ }
+ }
+ else
+ {
+ driver->last_wait_ust = jack_get_microseconds();
+ driver->engine->run_cycle(driver->engine,
+ driver->period_size, 0);
+ }
+}
+#endif
+
+
+static void *io_thread (void *param)
+{
+ int schedpol;
+ size_t localsize;
+ void *localbuf;
+ oss_driver_t *driver = (oss_driver_t *) param;
+ struct sched_param schedp;
+
+ if (pthread_getschedparam(pthread_self(), &schedpol, &schedp) == 0)
+ {
+ schedpol = SCHED_FIFO;
+ schedp.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
+ if (pthread_setschedparam(pthread_self(), schedpol,
+ &schedp) < 0)
+ {
+ puts("oss_driver: pthread_setschedparam() failed\n");
+ }
+ }
+ else
+ {
+ puts("oss_driver: pthread_getschedparam() failed\n");
+ }
+
+# ifdef USE_BARRIER
+ sem_wait(&driver->sem_start);
+
+ if (pthread_self() == driver->thread_in)
+ {
+ localsize = driver->indevbufsize;
+ localbuf = malloc(localsize);
+ if (localbuf == NULL)
+ {
+ jack_error("OSS: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+
+ while (driver->run)
+ {
+ if (read(driver->infd, localbuf, localsize) <
+ (ssize_t) localsize)
+ {
+ /*jack_error("OSS: read() failed: %s@%i",
+ __FILE__, __LINE__);*/
+ break;
+ }
+
+ pthread_mutex_lock(&driver->mutex_in);
+ memcpy(driver->indevbuf, localbuf, localsize);
+ pthread_mutex_unlock(&driver->mutex_in);
+
+ synchronize(driver);
+ }
+
+ free(localbuf);
+ }
+ else if (pthread_self() == driver->thread_out)
+ {
+ localsize = driver->outdevbufsize;
+ localbuf = malloc(localsize);
+ if (localbuf == NULL)
+ {
+ jack_error("OSS: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+
+ while (driver->run)
+ {
+ pthread_mutex_lock(&driver->mutex_out);
+ memcpy(localbuf, driver->outdevbuf, localsize);
+ pthread_mutex_unlock(&driver->mutex_out);
+
+ if (write(driver->outfd, localbuf, localsize) <
+ (ssize_t) localsize)
+ {
+ /*jack_error("OSS: write() failed: %s@%i",
+ __FILE__, __LINE__);*/
+ break;
+ }
+
+ synchronize(driver);
+ }
+
+ free(localbuf);
+ }
+# else
+ localsize = (driver->indevbufsize >= driver->outdevbufsize) ?
+ driver->indevbufsize : driver->outdevbufsize;
+ localbuf = malloc(localsize);
+ if (localbuf == NULL)
+ {
+ jack_error("OSS: malloc() failed: %s@%i", __FILE__, __LINE__);
+ return NULL;
+ }
+
+ while (driver->run)
+ {
+ if (driver->playback_channels > 0)
+ {
+ pthread_mutex_lock(&driver->mutex_out);
+ memcpy(localbuf, driver->outdevbuf,
+ driver->outdevbufsize);
+ pthread_mutex_unlock(&driver->mutex_out);
+
+ if (write(driver->outfd, localbuf,
+ driver->outdevbufsize) <
+ (ssize_t) driver->outdevbufsize)
+ {
+ jack_error("OSS: write() failed: %s@%i",
+ __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ if (driver->capture_channels > 0)
+ {
+ if (read(driver->infd, localbuf,
+ driver->indevbufsize) <
+ (ssize_t) driver->indevbufsize)
+ {
+ jack_error("OSS: read() failed: %s@%i",
+ __FILE__, __LINE__);
+ break;
+ }
+
+ pthread_mutex_lock(&driver->mutex_in);
+ memcpy(driver->indevbuf, localbuf,
+ driver->indevbufsize);
+ pthread_mutex_unlock(&driver->mutex_in);
+ }
+
+ driver->last_wait_ust = jack_get_microseconds();
+ driver->engine->run_cycle(driver->engine,
+ driver->period_size, 0);
+ }
+
+ free(localbuf);
+# endif
+
+ return NULL;
+}
+
+
+/* jack driver published interface */
+
+
+const char driver_client_name[] = "oss";
+
+
+void driver_finish (jack_driver_t *);
+
+
+jack_driver_desc_t * driver_get_descriptor ()
+{
+ jack_driver_desc_t *desc;
+ jack_driver_param_desc_t *params;
+
+ desc = (jack_driver_desc_t *) calloc(1, sizeof(jack_driver_desc_t));
+ if (desc == NULL)
+ {
+ printf("oss_driver: malloc() failed: %s@%i\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ strcpy(desc->name, driver_client_name);
+ desc->nparams = 8;
+
+ params = calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
+ memcpy(params, oss_params,
+ OSS_DRIVER_N_PARAMS * sizeof(jack_driver_param_desc_t));
+ desc->params = params;
+
+ return desc;
+}
+
+
+jack_driver_t * driver_initialize (jack_client_t *client,
+ JSList * params)
+{
+ int bits = OSS_DRIVER_DEF_BITS;
+ jack_nframes_t sample_rate = OSS_DRIVER_DEF_FS;
+ jack_nframes_t period_size = OSS_DRIVER_DEF_BLKSIZE;
+ unsigned int capture_channels = OSS_DRIVER_DEF_INS;
+ unsigned int playback_channels = OSS_DRIVER_DEF_OUTS;
+ const JSList *pnode;
+ const jack_driver_param_t *param;
+ oss_driver_t *driver;
+
+ driver = (oss_driver_t *) malloc(sizeof(oss_driver_t));
+ if (driver == NULL)
+ {
+ jack_error("OSS: malloc() failed: %s@%i", __FILE__, __LINE__);
+ return NULL;
+ }
+ jack_driver_init((jack_driver_t *) driver);
+
+ driver->attach = (JackDriverAttachFunction) oss_driver_attach;
+ driver->detach = (JackDriverDetachFunction) oss_driver_detach;
+ driver->start = (JackDriverStartFunction) oss_driver_start;
+ driver->stop = (JackDriverStopFunction) oss_driver_stop;
+ driver->read = (JackDriverReadFunction) oss_driver_read;
+ driver->write = (JackDriverWriteFunction) oss_driver_write;
+ driver->null_cycle = (JackDriverNullCycleFunction)
+ oss_driver_null_cycle;
+ driver->bufsize = (JackDriverBufSizeFunction) oss_driver_bufsize;
+
+ driver->indev = NULL;
+ driver->outdev = NULL;
+ driver->ignorehwbuf = 0;
+
+ pnode = params;
+ while (pnode != NULL)
+ {
+ param = (const jack_driver_param_t *) pnode->data;
+
+ switch (param->character)
+ {
+ case 's':
+ sample_rate = param->value.ui;
+ break;
+ case 'b':
+ period_size = param->value.ui;
+ break;
+ case 'w':
+ bits = param->value.i;
+ break;
+ case 'c':
+ capture_channels = param->value.ui;
+ break;
+ case 'p':
+ playback_channels = param->value.ui;
+ break;
+ case 'i':
+ driver->indev = strdup(param->value.str);
+ break;
+ case 'o':
+ driver->outdev = strdup(param->value.str);
+ break;
+ case 'd':
+ driver->ignorehwbuf = 1;
+ break;
+ case 'h':
+ puts("-s <fs>\tsample rate");
+ puts("-b <size>\tperiod size");
+ puts("-w <bits>\tword length");
+ puts("-c <chs>\tcapture channels");
+ puts("-p <chs>\tplayback channels");
+ puts("-i <dev>\tcapture device");
+ puts("-o <dev>\tplayback device");
+ puts("-h\tthis help");
+ break;
+ }
+ pnode = jack_slist_next(pnode);
+ }
+
+ driver->sample_rate = sample_rate;
+ driver->period_size = period_size;
+ driver->bits = bits;
+ driver->capture_channels = capture_channels;
+ driver->playback_channels = playback_channels;
+
+ driver->period_usecs =
+ ((double) period_size / (double) sample_rate) * 1e6;
+ driver->last_wait_ust = 0;
+
+ driver->finish = driver_finish;
+
+ if (driver->indev == NULL)
+ driver->indev = strdup("/dev/dsp");
+ if (driver->outdev == NULL)
+ driver->outdev = strdup(driver->indev);
+ driver->infd = -1;
+ driver->outfd = -1;
+ switch (driver->bits)
+ {
+# ifndef OSS_ENDIAN
+# ifdef __GNUC__
+# if (defined(__i386__) || defined(__alpha__) || defined(__arm__) || defined(__x86_64__))
+# define OSS_LITTLE_ENDIAN 1234
+# define OSS_ENDIAN OSS_LITTLE_ENDIAN
+# else
+# define OSS_BIG_ENDIAN 4321
+# define OSS_ENDIAN OSS_BIG_ENDIAN
+# endif
+# else /* __GNUC__ */
+# if (defined(_AIX) || defined(AIX) || defined(sparc) || defined(__hppa) || defined(PPC) || defined(__powerpc__) && !defined(i386) && !defined(__i386) && !defined(__i386__))
+# define OSS_BIG_ENDIAN 4321
+# define OSS_ENDIAN OSS_BIG_ENDIAN
+# else
+# define OSS_LITTLE_ENDIAN 1234
+# define OSS_ENDIAN OSS_LITTLE_ENDIAN
+# endif
+# endif /* __GNUC__ */
+# endif /* OSS_ENDIAN */
+# if (OSS_ENDIAN == 1234)
+ /* little-endian architectures */
+ case 24: /* little-endian LSB aligned 24-bits in 32-bits integer */
+ driver->format = 0x00008000;
+ break;
+ case 32: /* little-endian 32-bit integer */
+ driver->format = 0x00001000;
+ break;
+ case 64: /* native-endian 64-bit float */
+ driver->format = 0x00004000;
+ break;
+ case 16: /* little-endian 16-bit integer */
+ default:
+ driver->format = 0x00000010;
+ break;
+ /* big-endian architectures */
+# else
+ case 24: /* big-endian LSB aligned 24-bits in 32-bits integer */
+ break;
+ driver->format = 0x00010000;
+ case 32: /* big-endian 32-bit integer */
+ driver->format = 0x00002000;
+ break;
+ case 64: /* native-endian 64-bit float */
+ driver->format = 0x00004000;
+ break;
+ case 16: /* big-endian 16-bit integer */
+ default:
+ driver->format = 0x00000020;
+# endif
+ }
+
+ driver->indevbuf = driver->outdevbuf = NULL;
+
+ driver->capture_ports = NULL;
+ driver->playback_ports = NULL;
+
+ driver->engine = NULL;
+ driver->client = client;
+
+ return ((jack_driver_t *) driver);
+}
+
+
+void driver_finish (jack_driver_t *driver)
+{
+ free(((oss_driver_t *) driver)->indev);
+ free(((oss_driver_t *) driver)->outdev);
+ free(driver);
+}
+
diff --git a/drivers/oss/oss_driver.h b/drivers/oss/oss_driver.h
new file mode 100644
index 0000000..ad89ba8
--- /dev/null
+++ b/drivers/oss/oss_driver.h
@@ -0,0 +1,90 @@
+/*
+
+ OSS driver for Jack
+ Copyright (C) 2003-2004 Jussi Laako <jussi@sonarnerd.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+
+*/
+
+
+#ifndef __JACK_OSS_DRIVER_H__
+#define __JACK_OSS_DRIVER_H__
+
+#include <pthread.h>
+#ifdef USE_BARRIER
+#include <semaphore.h>
+#endif
+
+#include <jack/types.h>
+#include <jack/jslist.h>
+#include <jack/driver.h>
+#include <jack/jack.h>
+
+
+#define OSS_DRIVER_DEF_FS 44100
+#define OSS_DRIVER_DEF_BLKSIZE 1024
+#define OSS_DRIVER_DEF_BITS 16
+#define OSS_DRIVER_DEF_INS 2
+#define OSS_DRIVER_DEF_OUTS 2
+
+
+typedef jack_default_audio_sample_t jack_sample_t;
+
+typedef struct _oss_driver
+{
+ JACK_DRIVER_DECL
+
+ jack_nframes_t sample_rate;
+ jack_nframes_t period_size;
+ int bits;
+ unsigned int capture_channels;
+ unsigned int playback_channels;
+
+ char *indev;
+ char *outdev;
+ int infd;
+ int outfd;
+ int format;
+ int ignorehwbuf;
+
+ size_t indevbufsize;
+ size_t outdevbufsize;
+ size_t portbufsize;
+ void *indevbuf;
+ void *outdevbuf;
+
+ JSList *capture_ports;
+ JSList *playback_ports;
+
+ jack_engine_t *engine;
+ jack_client_t *client;
+
+ volatile int run;
+ volatile int threads;
+ pthread_t thread_in;
+ pthread_t thread_out;
+ pthread_mutex_t mutex_in;
+ pthread_mutex_t mutex_out;
+# ifdef USE_BARRIER
+ pthread_barrier_t barrier;
+ sem_t sem_start;
+# endif
+} oss_driver_t;
+
+
+#endif
+