diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Makefile.am | 17 | ||||
-rw-r--r-- | drivers/oss/.cvsignore | 6 | ||||
-rw-r--r-- | drivers/oss/oss_driver.c | 1171 | ||||
-rw-r--r-- | drivers/oss/oss_driver.h | 90 |
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 + |