[linux-audio-dev] [PATCH] oss support for jack

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] [PATCH] oss support for jack
From: Jussi Laako (jussi.laako_AT_pp.inet.fi)
Date: Fri Nov 14 2003 - 22:47:27 EET


Hi,

I've written preliminary OSS driver for JACK. Patch for jack 0.80
attached.

This is by no means final, this is something pre-alpha, but seems to
work at least with alsaplayer. It's likely to contains errors in jack
driver implementation. All comments/patches/anything is welcome..

If you are compiling with OSS Lite, please comment out the non-S16
formats.

RedHat RPMs and patch available at http://www.sonarnerd.net/linux/ ,
SuSE 9 packages coming.

-- 
Jussi Laako <jussi.laako_AT_pp.inet.fi>

--- jack-audio-connection-kit-0.80.0/configure.in 2003-08-29 01:21:07.000000000 +0300 +++ jackit/configure.in 2003-11-14 00:43:54.000000000 +0200 @@ -112,8 +112,8 @@ JACK_CORE_CFLAGS="-I\$(top_srcdir) -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -Wall $SHM_FLAGS" -JACK_CFLAGS="$JACK_CORE_CFLAGS -g" -JACK_OPT_CFLAGS="$JACK_CORE_CFLAGS -O3 -fomit-frame-pointer -ffast-math -fstrength-reduce -funroll-loops -fmove-all-movables" +JACK_CFLAGS="$JACK_CORE_CFLAGS -g $CFLAGS" +JACK_OPT_CFLAGS="$JACK_CORE_CFLAGS -march=pentium2 -mcpu=pentium4 -O3 -ffast-math -funroll-loops -fprefetch-loop-arrays" AC_ARG_ENABLE(optimize, [ --enable-optimize ask the compiler for its best optimizations], @@ -295,6 +295,7 @@ drivers/Makefile drivers/alsa/Makefile drivers/dummy/Makefile +drivers/oss/Makefile example-clients/Makefile doc/Makefile doc/reference.doxygen --- jack-audio-connection-kit-0.80.0/drivers/Makefile.am 2003-08-29 02:41:21.000000000 +0300 +++ jackit/drivers/Makefile.am 2003-11-14 00:43:54.000000000 +0200 @@ -6,6 +6,6 @@ ALSA_DIR = endif -SUBDIRS = dummy $(ALSA_DIR) +SUBDIRS = dummy $(ALSA_DIR) oss -DIST_SUBDIRS = dummy alsa +DIST_SUBDIRS = dummy alsa oss --- jack-audio-connection-kit-0.80.0/drivers/oss/oss_driver.h 1970-01-01 02:00:00.000000000 +0200 +++ jackit/drivers/oss/oss_driver.h 2003-11-14 20:40:04.000000000 +0200 @@ -0,0 +1,76 @@ +/* + + OSS driver for Jack + Copyright (C) 2003 Jussi Laako <jussi_AT_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 <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 +#define OSS_DRIVER_MAX_PORTS 16 + + +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; + + size_t indevbufsize; + size_t outdevbufsize; + size_t portbufsize; + void *indevbuf; + void *outdevbuf; + jack_sample_t *inportbufs[OSS_DRIVER_MAX_PORTS]; + jack_sample_t *outportbufs[OSS_DRIVER_MAX_PORTS]; + + JSList *capture_ports; + JSList *playback_ports; + + jack_engine_t *engine; + jack_client_t *client; +} oss_driver_t; + + +#endif + --- jack-audio-connection-kit-0.80.0/drivers/oss/oss_driver.c 1970-01-01 02:00:00.000000000 +0200 +++ jackit/drivers/oss/oss_driver.c 2003-11-14 22:13:40.000000000 +0200 @@ -0,0 +1,694 @@ +/* + + OSS driver for Jack + Copyright (C) 2003 Jussi Laako <jussi_AT_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 <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 <jack/types.h> +#include <jack/internal.h> +#include <jack/engine.h> +#include <jack/time.h> + +#include "oss_driver.h" + +// #undef DEBUG_WAKEUP + + +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; + 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 / 0x7fffff00; + 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; + } +} + + +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; + 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 = 0x7fffff00; + 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; + } +} + + +static void set_fragment (int fd, int fragsize, int fragcount) +{ + int fragsize_2p; + int fragments; + + 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 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 channel; + size_t samplesize; + size_t fragsize; + const char *indev = driver->indev; + const char *outdev = driver->outdev; + + switch (driver->bits) + { + case 0: + samplesize = sizeof(unsigned int); + break; + case 24: + case 32: + samplesize = sizeof(int); + break; + case 16: + default: + samplesize = sizeof(short); + break; + } + if (strcmp(indev, outdev) != 0) + { + infd = open(indev, O_RDONLY); + outfd = open(outdev, O_WRONLY); + if (infd < 0) + { + jack_error( + "OSS: failed to open input device %s: %s@%i", + indev, __FILE__, __LINE__); + } + if (outfd < 0) + { + jack_error( + "OSS: failed to open output device %s: %s@%i", + outdev, __FILE__, __LINE__); + } + fragsize = driver->period_size * driver->capture_channels * + samplesize; + //set_fragment(infd, fragsize, 0xffff / fragsize); + set_fragment(infd, fragsize, 2); + fragsize = driver->period_size * driver->playback_channels * + samplesize; + //set_fragment(outfd, fragsize, 0xffff / fragsize); + set_fragment(outfd, fragsize, 2); + } + else + { + infd = outfd = open(indev, O_RDWR); + if (infd < 0) + { + jack_error( + "OSS: failed to open device %s: %s@%i", + indev, __FILE__, __LINE__); + } + fragsize = driver->period_size * driver->capture_channels * + samplesize; + //set_fragment(infd, fragsize, 0xffff / fragsize); + set_fragment(infd, fragsize, 2); + if (ioctl(infd, SNDCTL_DSP_SETDUPLEX, 0) < 0) + { + jack_error( + "OSS: failed to enable full duplex for %s: %s@%i", + indev, __FILE__, __LINE__); + } + } + driver->infd = infd; + driver->outfd = outfd; + + 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)); + + if (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)); + } + + driver->indevbufsize = driver->period_size * + driver->capture_channels * samplesize; + driver->outdevbufsize = driver->period_size * + driver->playback_channels * samplesize; + driver->indevbuf = malloc(driver->indevbufsize); + driver->outdevbuf = malloc(driver->outdevbufsize); + if (driver->indevbuf == NULL || driver->outdevbuf == NULL) + { + jack_error("OSS: malloc() failed: %s@%i", __FILE__, __LINE__); + return -1; + + } + memset(driver->indevbuf, 0x00, driver->indevbufsize); + memset(driver->outdevbuf, 0x00, driver->outdevbufsize); + printf("oss_driver: indevbuf %u B, outdevbuf %u B\n", + driver->indevbufsize, driver->outdevbufsize); + + driver->portbufsize = driver->period_size * sizeof(jack_sample_t); + for (channel = 0; channel < driver->capture_channels; channel++) + { + driver->inportbufs[channel] = (jack_sample_t *) + malloc(driver->portbufsize); + if (driver->inportbufs[channel] == NULL) + { + jack_error("OSS: malloc() failed: %s@%i", + __FILE__, __LINE__); + return -1; + } + memset(driver->inportbufs[channel], 0x00, + driver->portbufsize); + } + for (channel = 0; channel < driver->playback_channels; channel++) + { + driver->outportbufs[channel] = (jack_sample_t *) + malloc(driver->portbufsize); + if (driver->outportbufs[channel] == NULL) + { + jack_error("OSS: malloc() failed: %s@%i", + __FILE__, __LINE__); + return -1; + } + memset(driver->outportbufs[channel], 0x00, + driver->portbufsize); + } + printf("oss_driver: %u period buffers of size %u B\n", + driver->capture_channels + driver->playback_channels, + driver->portbufsize); + + return 0; +} + + +static int oss_driver_stop (oss_driver_t *driver) +{ + unsigned int channel; + + if (driver->outfd >= 0 && driver->outfd != driver->infd) + { + close(driver->outfd); + driver->outfd = -1; + } + if (driver->infd >= 0) + { + close(driver->infd); + driver->infd = -1; + } + + for (channel = 0; channel < driver->capture_channels; channel++) + { + if (driver->inportbufs[channel] != NULL) + { + free(driver->inportbufs[channel]); + driver->inportbufs[channel] = NULL; + } + } + for (channel = 0; channel < driver->playback_channels; channel++) + { + if (driver->outportbufs[channel] != NULL) + { + free(driver->outportbufs[channel]); + driver->outportbufs[channel] = NULL; + } + } + 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; + } + + 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++; + } + + 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; + } + + 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++; + } + + return 0; +} + + +static int oss_driver_null_cycle (oss_driver_t *driver, jack_nframes_t nframes) +{ + return 0; +} + + +static jack_nframes_t oss_driver_wait (oss_driver_t *driver, int fd, + int *status, float *delayed_usecs) +{ + *status = 0; + *delayed_usecs = 0; + + if (write(driver->outfd, driver->outdevbuf, driver->outdevbufsize) < + (ssize_t) driver->outdevbufsize) + { + //jack_error("OSS: write() failed: %s@%i", __FILE__, __LINE__); + oss_driver_stop(driver); + *status = 1; + } + + if (read(driver->infd, driver->indevbuf, driver->indevbufsize) < + (ssize_t) driver->indevbufsize) + { + //jack_error("OSS: read() failed: %s@%i", __FILE__, __LINE__); + oss_driver_stop(driver); + *status = 1; + } + + driver->last_wait_ust = jack_get_microseconds(); + + return driver->period_size; +} + + +/* - */ + + +const char driver_client_name[] = "oss"; + + +void driver_finish (jack_driver_t *); + + +jack_driver_t * driver_initialize (jack_client_t *client, + int argc, char *argv[]) +{ + int opt; + 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; + + 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->wait = (JackDriverWaitFunction) oss_driver_wait; + + driver->indev = NULL; + driver->outdev = NULL; + opt = 1; + while (opt < (argc - 1)) + { + if (strcmp(argv[opt], "-s") == 0) + sample_rate = (jack_nframes_t) atol(argv[++opt]); + if (strcmp(argv[opt], "-b") == 0) + period_size = (jack_nframes_t) atol(argv[++opt]); + if (strcmp(argv[opt], "-w") == 0) + bits = atoi(argv[++opt]); + if (strcmp(argv[opt], "-c") == 0) + capture_channels = (unsigned int) atoi(argv[++opt]); + if (strcmp(argv[opt], "-p") == 0) + playback_channels = (unsigned int) atoi(argv[++opt]); + if (strcmp(argv[opt], "-i") == 0) + driver->indev = strdup(argv[++opt]); + if (strcmp(argv[opt], "-o") == 0) + driver->outdev = strdup(argv[++opt]); + if (strcmp(argv[opt], "-h") == 0) + { + 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"); + } + opt++; + } + + 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) + { + case 0: + driver->format = AFMT_SPDIF_RAW; + break; + case 24: + driver->format = AFMT_S24_NE; + break; + case 32: + driver->format = AFMT_S32_NE; + break; + case 16: + default: + driver->format = AFMT_S16_NE; + break; + } + + driver->indevbuf = driver->outdevbuf = NULL; + memset(driver->inportbufs, 0x00, sizeof(driver->inportbufs)); + memset(driver->outportbufs, 0x00, sizeof(driver->outportbufs)); + + 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); +} +


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Fri Nov 14 2003 - 22:48:51 EET