From 5d5dc82555cc3cf1f1bdcedf7616fb967c4cf2b3 Mon Sep 17 00:00:00 2001 From: joq Date: Fri, 12 Mar 2004 05:00:12 +0000 Subject: [PATCH] [0.95.5] add OSS driver git-svn-id: svn+ssh://jackaudio.org/trunk/jack@656 0c269be4-1314-0410-8aa9-9f06e86f4224 --- AUTHORS | 11 +- configure.in | 140 +++-- drivers/Makefile.am | 17 +- drivers/oss/.cvsignore | 6 + drivers/oss/oss_driver.c | 1171 ++++++++++++++++++++++++++++++++++++++ drivers/oss/oss_driver.h | 90 +++ 6 files changed, 1368 insertions(+), 67 deletions(-) create mode 100644 drivers/oss/.cvsignore create mode 100644 drivers/oss/oss_driver.c create mode 100644 drivers/oss/oss_driver.h diff --git a/AUTHORS b/AUTHORS index e16f279..de54d26 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,14 +11,15 @@ Many other members of LAD contributed ideas to JACK, particularly Richard Guenther. Paul Davis was the principal author of the JACK API and of the -implementation contained here. Andy Wingo and Kai Vehmanen provided -many small patches and documentation. Fernando Pablo Lopez-Lezcano -contributed the capabilities-based code. Jeremy Hall, Steve Harris, +implementation contained here. Andy Wingo and Kai Vehmanen provided +many small patches and documentation. Fernando Pablo Lopez-Lezcano +contributed the capabilities-based code. Jeremy Hall, Steve Harris, and Martin Boer contributed sample clients and utilities. Jack O'Quin contributed new transport interfaces, implemented the buffer size callback, and added much documentation. Taybin Rutkin helps with -patch management and releases. Melanie Thielker contributed +patch management and releases. Melanie Thielker contributed significantly to JACK's interaction with aspects of both POSIX and -System V APIs. +System V APIs. Stephane Letz ported JACK to Mac OS X. Jussi Laako +wrote the OSS driver interface. Many others have contributed patches and/or test results. diff --git a/configure.in b/configure.in index ca17348..1a25284 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ dnl changes are made dnl --- JACK_MAJOR_VERSION=0 JACK_MINOR_VERSION=95 -JACK_MICRO_VERSION=4 +JACK_MICRO_VERSION=5 dnl --- dnl HOWTO: updating the jack protocal version @@ -114,9 +114,10 @@ else fi -JACK_CORE_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -Wall" - +JACK_CORE_CFLAGS="$CFLAGS -I\$(top_srcdir) -I\$(top_builddir) -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -Wall" JACK_CFLAGS="$JACK_CORE_CFLAGS -g" +JACK_OPT_CFLAGS="$JACK_CORE_CFLAGS -march=pentium2 -mcpu=pentium4 -O3 -ffast-math -funroll-loops -fprefetch-loop-arrays" + dnl dnl figure out how best to optimize dnl @@ -128,14 +129,14 @@ if test "$target_cpu" = "powerpc"; then AC_DEFINE(HAVE_ALTIVEC_LINUX, 1, "Is there Altivec Support ?") if test "$gcc_major_version" = "3"; then dnl -mcpu=7450 does not reliably work with gcc 3.* - JACK_OPT_FLAGS="-D_REENTRANT -O2 -mcpu=7400 -maltivec -mabi=altivec" + JACK_OPT_CFLAGS="-D_REENTRANT -O2 -mcpu=7400 -maltivec -mabi=altivec" else - JACK_OPT_FLAGS="-D_REENTRANT -O3 -mcpu=7400" + JACK_OPT_CFLAGS="-D_REENTRANT -O3 -mcpu=7400" fi else - JACK_OPT_FLAGS="-D_REENTRANT -O3 -mcpu=750 -mmultiple" + JACK_OPT_CFLAGS="-D_REENTRANT -O3 -mcpu=750 -mmultiple" fi - JACK_OPT_FLAGS="$OPTIM_FLAGS -mhard-float -mpowerpc-gfxopt" + JACK_OPT_CFLAGS="$OPTIM_FLAGS -mhard-float -mpowerpc-gfxopt" elif echo $target_cpu | grep "i*86" >/dev/null; then cat /proc/cpuinfo | grep mmx >/dev/null if test $? = 0; then @@ -151,14 +152,14 @@ elif echo $target_cpu | grep "i*86" >/dev/null; then fi AC_DEFINE(x86, 1, "Nope its intel") if test "$target_cpu" = "i586"; then - JACK_OPT_FLAGS="-DREENTRANT -O3 -march=i586 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" + JACK_OPT_CFLAGS="-DREENTRANT -O3 -march=i586 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" elif test "$target_cpu" = "i686"; then - JACK_OPT_FLAGS="-D_REENTRANT -O3 -march=i686 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" + JACK_OPT_CFLAGS="-D_REENTRANT -O3 -march=i686 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" if test "$gcc_major_version" = "3"; then - JACK_OPT_FLAGS="$OPTIM_FLAGS $mmx $sse $dreidnow" + JACK_OPT_CFLAGS="$OPTIM_FLAGS $mmx $sse $dreidnow" fi else - JACK_OPT_FLAGS="-D_REENTRANT -O3 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" + JACK_OPT_CFLAGS="-D_REENTRANT -O3 -fomit-frame-pointer -ffast-math -funroll-loops -fmove-all-movables" fi fi @@ -254,7 +255,7 @@ AC_ARG_ENABLE(stripped-jackd, ) AC_ARG_ENABLE(timestamps, - [ --enable-timestamps allow clients to use the JACK timestamp API ], + [ --enable-timestamps allow clients to use the JACK timestamp API ], [ if test "x$enable_debug" != "xno" ; then AC_DEFINE(WITH_TIMESTAMPS,,[Enable JACK timestamp API]) fi @@ -292,43 +293,67 @@ fi AC_SUBST(DEFAULT_TMP_DIR) AC_DEFINE_UNQUOTED(DEFAULT_TMP_DIR,"$DEFAULT_TMP_DIR",[Default tmp directory]) +# check for barrier functions in the pthreads library +AC_ARG_WITH(barrier, + AC_HELP_STRING([--without-barrier], + [avoid using pthread barrier functions]), + [ USE_BARRIER=$withval ], + [ USE_BARRIER="yes" ] +) +if test "x$USE_BARRIER" = "xyes" +then + AC_CHECK_LIB([pthread], [pthread_barrier_init], + AC_DEFINE(USE_BARRIER, 1, [Use pthread barrier functions])) +fi + +# check which drivers can be built jack_have_driver="no" -# jack depends on alsa 0.9. some example apps depend on libsndfile. -AC_CHECK_LIB(asound,snd_pcm_drop, - [ - HAVE_ALSA="true" - ALSA_LIBS=-lasound - jack_have_driver="yes" - ], - [ - HAVE_ALSA="false" - AC_MSG_WARN([ALSA 0.9 support not found]) - ], - [-lm] -) -AC_SUBST(ALSA_LIBS) -AM_CONDITIONAL(ALSA, test x$HAVE_ALSA = xtrue) - +AC_ARG_ENABLE(alsa, [ --disable-alsa ignore ALSA driver ], + TRY_ALSA=$enableval , TRY_ALSA=yes ) +HAVE_ALSA="false" +if test "x$TRY_ALSA" = "xyes" +then + # check for ALSA >= 0.9 + AC_CHECK_LIB(asound,snd_pcm_drop, + [HAVE_ALSA="true" + ALSA_LIBS=-lasound + jack_have_driver="yes" + ], [], [-lm] + ) + AC_SUBST(ALSA_LIBS) +fi +AM_CONDITIONAL(HAVE_ALSA, $HAVE_ALSA) AC_ARG_ENABLE(portaudio, [ --disable-portaudio ignore PortAudio driver ], TRY_PORTAUDIO=$enableval , TRY_PORTAUDIO=yes ) - - HAVE_PA="false" if test "x$TRY_PORTAUDIO" = "xyes" then # check for portaudio V18 AC_CHECK_LIB(portaudio, Pa_Initialize, - [HAVE_PA="true" - PA_LIBS=-lportaudio - jack_have_driver="yes" - ], [], [-lm -lpthread] - ) + [ AC_CHECK_HEADERS(portaudio.h PortAudio.h, + [ HAVE_PA="true" + PA_LIBS=-lportaudio + jack_have_driver="yes" + ]) + ], [], [-lm -lpthread]) AC_SUBST(PA_LIBS) fi -AM_CONDITIONAL(PORTAUDIO, test x$HAVE_PA = xtrue) +AM_CONDITIONAL(HAVE_PA, $HAVE_PA) + +AC_ARG_ENABLE(oss, [ --disable-oss ignore OSS driver ], + TRY_OSS=$enableval , TRY_OSS=yes ) +HAVE_OSS="false" +if test "x$TRY_OSS" = "xyes" +then + # check for Open Sound System + AC_CHECK_HEADER([sys/soundcard.h], + [HAVE_OSS="true" + jack_have_driver="yes"]) +fi +AM_CONDITIONAL(HAVE_OSS, $HAVE_OSS) jack_enable_iec61883="no" AC_ARG_ENABLE(iec61883, @@ -346,30 +371,28 @@ AC_ARG_ENABLE(iec61883, ]) if test x$jack_enable_iec61883 != xno; then - AC_CHECK_LIB(raw1394, raw1394_iso_xmit_init, - [ - AC_CHECK_HEADER(libraw1394/raw1394.h, - [ - HAVE_RAW1394="true" - RAW1394_LIBS=-lraw1394 - jack_have_driver="yes"; - ], - HAVE_RAW1394="false" - ) - ], - ) + AC_CHECK_LIB(raw1394, raw1394_iso_xmit_init, + [ AC_CHECK_HEADER(libraw1394/raw1394.h, + [ HAVE_RAW1394="true" + RAW1394_LIBS=-lraw1394 + jack_have_driver="yes" + AC_MSG_WARN([IEC61883 driver is experimental]) + ], + HAVE_RAW1394="false") + ]) else HAVE_RAW1394="false" fi AC_SUBST(RAW1394_LIBS) AM_CONDITIONAL(IEC61883, test x$HAVE_RAW1394 = xtrue) +AM_CONDITIONAL(HAVE_RAW1394, $HAVE_RAW1394) if test x$jack_have_driver = xno; then AC_ERROR([No drivers can be built]) fi - +# some example-clients need libsndfile HAVE_SNDFILE=false PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0,[HAVE_SNDFILE=true], [true]) if test x$HAVE_SNDFILE = xfalse; then @@ -399,11 +422,18 @@ AM_CONDITIONAL(HAVE_READLINE, $HAVE_READLINE) AM_CONDITIONAL(HAVE_DOXYGEN, $HAVE_DOXYGEN) AM_CONDITIONAL(USE_CAPABILITIES, $USE_CAPABILITIES) AM_CONDITIONAL(STRIPPED_JACKD, $STRIPPED_JACKD) -AM_CONDITIONAL(HAVE_ALSA, $HAVE_ALSA) -AM_CONDITIONAL(HAVE_PA, $HAVE_PA) AC_OUTPUT( Makefile +doc/Makefile +doc/reference.doxygen +drivers/Makefile +drivers/alsa/Makefile +drivers/dummy/Makefile +drivers/iec61883/Makefile +drivers/oss/Makefile +drivers/portaudio/Makefile +example-clients/Makefile jack.pc jack.spec jack/Makefile @@ -411,12 +441,4 @@ jack/version.h jackd/Makefile jackd/jackd.1 libjack/Makefile -drivers/Makefile -drivers/alsa/Makefile -drivers/dummy/Makefile -drivers/portaudio/Makefile -drivers/iec61883/Makefile -example-clients/Makefile -doc/Makefile -doc/reference.doxygen ) 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 + + 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_BARRIER +#include +#endif + +#include +#include +#include +#include + +#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 \tsample rate"); + puts("-b \tperiod size"); + puts("-w \tword length"); + puts("-c \tcapture channels"); + puts("-p \tplayback channels"); + puts("-i \tcapture device"); + puts("-o \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 + + 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 +#ifdef USE_BARRIER +#include +#endif + +#include +#include +#include +#include + + +#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 +