summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-09-14 12:37:56 -0500
committerGitHub <noreply@github.com>2016-09-14 12:37:56 -0500
commit7695d4e287234056252cc39cc2d3fa697a6fd0a6 (patch)
tree132baea27341d72547f32524d726f6a0b49b4bb9
parent873c1208e937d816cd3e57e5db53d6c51bbdd4cb (diff)
parentaf6aa1c03bad837c366dcb603b6d922a07c52814 (diff)
downloadjack1-7695d4e287234056252cc39cc2d3fa697a6fd0a6.tar.gz
Merge pull request #43 from devnexen/master
OpenBSD compilable :
-rw-r--r--configure.ac26
-rw-r--r--drivers/Makefile.am10
-rw-r--r--drivers/dummy/dummy_driver.c5
-rw-r--r--drivers/sndio/Makefile.am13
-rw-r--r--drivers/sndio/sndio_driver.c997
-rw-r--r--drivers/sndio/sndio_driver.h74
-rw-r--r--jackd/Makefile.am4
-rw-r--r--jackd/controlapi.c2
-rw-r--r--jackd/engine.c2
-rw-r--r--jackd/jackd.1.in41
-rw-r--r--jackd/jackd.c2
11 files changed, 1167 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac
index 85e32d8..02bd02c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,15 +165,18 @@ CFLAGS="$ORIGINAL_CFLAGS"
AC_MSG_CHECKING([platform dependencies])
HOST_DEFAULT_TMP_DIR=/dev/shm
+USE_MD5SUM=1
case "${host_os}" in
freebsd*)
# current FreeBSD header files conflict with the OSS driver's
# barrier code, this may be fixed in 5.3, stay tuned.
USE_BARRIER="no"
+ USE_MD5SUM=0
;;
openbsd*)
# pthread_barrier* not implemented
USE_BARRIER="no"
+ USE_MD5SUM=0
# need small realtime stack
JACK_THREAD_STACK_TOUCH=10000
;;
@@ -189,6 +192,9 @@ case "${host_os}" in
esac
AC_SUBST(OS_LDFLAGS)
+AC_SUBST(USE_MD5SUM)
+AC_DEFINE_UNQUOTED(USE_MD5SUM,"$USE_MD5SUM",[Using md5sum command line if available])
+AM_CONDITIONAL(USE_MD5SUM, $USE_MD5SUM)
#
# We need to establish suitable defaults for a 64-bit OS
@@ -228,7 +234,7 @@ if test "x$JACK_USE_MACH_THREADS" != "x"; then
fi
# headers
-AC_CHECK_HEADERS(string.h strings.h alloca.h db.h, [],
+AC_CHECK_HEADERS(string.h strings.h db.h, [],
AC_MSG_ERROR([*** a required header file is missing]))
AC_CHECK_HEADERS(getopt.h, [], [
@@ -797,7 +803,7 @@ AC_SUBST(NETJACK_CFLAGS)
# Check which backend drivers can be built. The last one successfully
# configured becomes the default JACK driver; so the order of
-# precedence is: alsa, sun, oss, coreaudio, portaudio, dummy.
+# precedence is: alsa, sun, oss, coreaudio, portaudio, sndio, dummy.
JACK_DEFAULT_DRIVER=\"dummy\"
@@ -857,6 +863,20 @@ then
fi
AM_CONDITIONAL(HAVE_SUN, $HAVE_SUN)
+AC_ARG_ENABLE(sndio, AC_HELP_STRING([--disable-sndio],[ignore sndio driver ]),
+ TRY_SNDIO=$enableval , TRY_SNDIO=yes )
+HAVE_SNDIO="false"
+if test "x$TRY_SNDIO" = "xyes"
+then
+ # check for sndio audio API
+ AC_CHECK_HEADER([sndio.h],
+ [HAVE_SNDIO="true"
+ JACK_DEFAULT_DRIVER=\"sndio\"])
+ SNDIO_LIBS="-lsndio"
+ AC_SUBST([SNDIO_LIBS])
+fi
+AM_CONDITIONAL(HAVE_SNDIO, $HAVE_SNDIO)
+
AC_ARG_ENABLE(freebob, AC_HELP_STRING([--disable-freebob],[ignore FreeBob driver ]),
TRY_FREEBOB=$enableval , TRY_FREEBOB=yes )
HAVE_FREEBOB="false"
@@ -989,6 +1009,7 @@ drivers/alsa_midi/Makefile
drivers/dummy/Makefile
drivers/oss/Makefile
drivers/sun/Makefile
+drivers/sndio/Makefile
drivers/portaudio/Makefile
drivers/coreaudio/Makefile
drivers/freebob/Makefile
@@ -1020,6 +1041,7 @@ echo \| Build with old FireWire \(FreeBob\) support............. : $HAVE_FREEBOB
echo \| Build with new FireWire \(FFADO\) support............... : $HAVE_FIREWIRE
echo \| Build with OSS support................................ : $HAVE_OSS
echo \| Build with Sun audio support.......................... : $HAVE_SUN
+echo \| Build with Sndio audio support........................ : $HAVE_SNDIO
echo \| Build with CoreAudio support.......................... : $HAVE_COREAUDIO
echo \| Build with PortAudio support.......................... : $HAVE_PA
echo \| Build with Celt support............................... : $HAVE_CELT
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
index b159b19..4554857 100644
--- a/drivers/Makefile.am
+++ b/drivers/Makefile.am
@@ -48,5 +48,11 @@ else
FIREWIRE_DIR =
endif
-SUBDIRS = $(ALSA_MIDI_DIR) $(ALSA_DIR) dummy $(OSS_DIR) $(SUN_DIR) $(PA_DIR) $(CA_DIR) $(FREEBOB_DIR) $(FIREWIRE_DIR) netjack
-DIST_SUBDIRS = alsa alsa_midi dummy oss sun portaudio coreaudio freebob firewire netjack
+if HAVE_SNDIO
+SNDIO_DIR = sndio
+else
+SNDIO_DIR =
+endif
+
+SUBDIRS = $(ALSA_MIDI_DIR) $(ALSA_DIR) dummy $(OSS_DIR) $(SUN_DIR) $(PA_DIR) $(CA_DIR) $(FREEBOB_DIR) $(FIREWIRE_DIR) ${SNDIO_DIR} netjack
+DIST_SUBDIRS = alsa alsa_midi dummy oss sun portaudio coreaudio freebob firewire netjack sndio
diff --git a/drivers/dummy/dummy_driver.c b/drivers/dummy/dummy_driver.c
index b8e1b9c..361ab9a 100644
--- a/drivers/dummy/dummy_driver.c
+++ b/drivers/dummy/dummy_driver.c
@@ -111,6 +111,7 @@ dummy_driver_wait (dummy_driver_t *driver, int extra_fd, int *status,
{
jack_nframes_t nframes = driver->period_size;
struct timespec now;
+ struct timespec ts;
*status = 0;
/* this driver doesn't work so well if we report a delay */
@@ -136,7 +137,9 @@ dummy_driver_wait (dummy_driver_t *driver, int extra_fd, int *status,
}
driver->next_wakeup = add_ts (driver->next_wakeup, driver->wait_time);
} else {
- if (clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, &driver->next_wakeup, NULL)) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = ts_to_nsec(driver->next_wakeup) - ts_to_nsec(now);
+ if (nanosleep (&ts, NULL)) {
jack_error ("error while sleeping");
*status = -1;
} else {
diff --git a/drivers/sndio/Makefile.am b/drivers/sndio/Makefile.am
new file mode 100644
index 0000000..1e22bef
--- /dev/null
+++ b/drivers/sndio/Makefile.am
@@ -0,0 +1,13 @@
+MAINTAINCLEANFILES = Makefile.in
+
+AM_CFLAGS = $(JACK_CFLAGS)
+
+plugindir = $(ADDON_DIR)
+
+plugin_LTLIBRARIES = jack_sndio.la
+
+jack_sndio_la_LDFLAGS = -module -avoid-version
+jack_sndio_la_LIBADD = $(SNDIO_LIBS)
+jack_sndio_la_SOURCES = sndio_driver.c sndio_driver.h
+
+noinst_HEADERS = sndio_driver.h
diff --git a/drivers/sndio/sndio_driver.c b/drivers/sndio/sndio_driver.c
new file mode 100644
index 0000000..49ab79f
--- /dev/null
+++ b/drivers/sndio/sndio_driver.c
@@ -0,0 +1,997 @@
+/*
+ * Copyright (c) 2009 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _THREAD_SAFE
+#define _THREAD_SAFE
+#endif
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <poll.h>
+#include <sndio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <jack/types.h>
+#include <internal.h>
+#include <engine.h>
+#include <jack/thread.h>
+#include <sysdeps/time.h>
+
+#include "sndio_driver.h"
+
+
+#define SNDIO_DRIVER_N_PARAMS 10
+const static jack_driver_param_desc_t sndio_params[SNDIO_DRIVER_N_PARAMS] = {
+ { "rate",
+ 'r',
+ JackDriverParamUInt,
+ { .ui = SNDIO_DRIVER_DEF_FS },
+ NULL,
+ "sample rate",
+ "sample rate"
+ },
+ { "period",
+ 'p',
+ JackDriverParamUInt,
+ { .ui = SNDIO_DRIVER_DEF_BLKSIZE },
+ NULL,
+ "period size",
+ "period size"
+ },
+ { "nperiods",
+ 'n',
+ JackDriverParamUInt,
+ { .ui = SNDIO_DRIVER_DEF_NPERIODS },
+ NULL,
+ "number of periods in buffer",
+ "number of periods in buffer"
+ },
+ { "wordlength",
+ 'w',
+ JackDriverParamInt,
+ { .i = SNDIO_DRIVER_DEF_BITS },
+ NULL,
+ "word length",
+ "word length"
+ },
+ { "inchannels",
+ 'i',
+ JackDriverParamUInt,
+ { .ui = SNDIO_DRIVER_DEF_INS },
+ NULL,
+ "capture channels",
+ "capture channels"
+ },
+ { "outchannels",
+ 'o',
+ JackDriverParamUInt,
+ { .ui = SNDIO_DRIVER_DEF_OUTS },
+ NULL,
+ "playback channels",
+ "playback channels"
+ },
+ { "device",
+ 'd',
+ JackDriverParamString,
+ { },
+ NULL,
+ "device",
+ "device"
+ },
+ { "ignorehwbuf",
+ 'b',
+ JackDriverParamBool,
+ { },
+ NULL,
+ "ignore hardware period size",
+ "ignore hardware period size"
+ },
+ { "input latency",
+ 'I',
+ JackDriverParamUInt,
+ { .ui = 0 },
+ NULL,
+ "system capture latency",
+ "system capture latency"
+ },
+ { "output latency",
+ 'O',
+ JackDriverParamUInt,
+ { .ui = 0 },
+ NULL,
+ "system playback latency",
+ "system playback latency"
+ }
+};
+
+
+/* internal functions */
+
+
+static void
+set_period_size (sndio_driver_t *driver, jack_nframes_t new_period_size)
+{
+ driver->period_size = new_period_size;
+
+ driver->period_usecs =
+ ((double)driver->period_size /
+ (double)driver->sample_rate) * 1e6;
+ driver->last_wait_ust = 0;
+ driver->poll_timeout = (int)(driver->period_usecs / 666);
+}
+
+
+static void
+sndio_driver_write_silence (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ size_t localsize, io_res, nbytes, offset;
+ void *localbuf;
+
+ localsize = nframes * driver->sample_bytes * driver->playback_channels;
+ localbuf = malloc(localsize);
+ if (localbuf == NULL)
+ {
+ jack_error("sndio_driver: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return;
+ }
+ memset(localbuf, 0, localsize);
+
+ offset = 0;
+ nbytes = localsize;
+ while (nbytes > 0)
+ {
+ io_res = sio_write(driver->hdl, localbuf + offset, nbytes);
+ if (io_res == 0)
+ {
+ jack_error("sndio_driver: sio_write() failed: "
+ "count=%d/%d: %s@%i", io_res, localsize,
+ __FILE__, __LINE__);
+ }
+ offset += io_res;
+ nbytes -= io_res;
+ }
+ free(localbuf);
+}
+
+
+static void
+sndio_driver_read_silence (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ size_t localsize, io_res, nbytes, offset;
+ void *localbuf;
+
+ localsize = nframes * driver->sample_bytes * driver->capture_channels;
+ localbuf = malloc(localsize);
+ if (localbuf == NULL)
+ {
+ jack_error("sndio_driver: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return;
+ }
+
+ offset = 0;
+ nbytes = localsize;
+ while (nbytes > 0) {
+ io_res = sio_read(driver->hdl, localbuf + offset, nbytes);
+ if (io_res == 0) {
+ jack_error("sndio_driver: sio_read() failed: "
+ "count=%d/%d: %s@%i", io_res, nbytes,
+ __FILE__, __LINE__);
+ break;
+ }
+ offset +=- io_res;
+ nbytes -= io_res;
+ }
+ free(localbuf);
+}
+
+
+static int
+sndio_driver_start (sndio_driver_t *driver)
+{
+ if (!sio_start(driver->hdl))
+ jack_error("sio_start failed: %s@%i",
+ __FILE__, __LINE__);
+
+ /* prime playback buffers */
+ if (driver->playback_channels > 0)
+ sndio_driver_write_silence(driver, driver->pprime);
+
+ return 0;
+}
+
+
+static int
+sndio_driver_set_parameters (sndio_driver_t *driver)
+{
+ struct sio_par par;
+ unsigned int period_size = 0;
+ unsigned int nperiods;
+ int mode = 0;
+
+ if (driver->capture_channels > 0)
+ mode |= SIO_REC;
+
+ if (driver->playback_channels > 0)
+ mode |= SIO_PLAY;
+
+ driver->hdl = sio_open(driver->dev, mode, 0);
+ if (driver->hdl == NULL)
+ {
+ jack_error("sndio_driver: failed to open device "
+ "%s: %s@%i", (driver->dev == NULL) ?
+ "default" : driver->dev, __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (driver->bits != 16 && driver->bits != 24 && driver->bits != 32)
+ {
+ jack_error("sndio_driver: invalid sample bits");
+ return -1;
+ }
+
+ sio_initpar(&par);
+ par.sig = 1;
+ par.bits = driver->bits;
+ par.pchan = driver->playback_channels;
+ par.rchan = driver->capture_channels;
+ par.rate = driver->sample_rate;
+ par.appbufsz = driver->period_size * driver->nperiods;
+ par.round = driver->period_size;
+ par.xrun = SIO_SYNC;
+
+ if (!sio_setpar(driver->hdl, &par))
+ {
+ jack_error("sndio_driver: failed to set parameters: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (!sio_getpar(driver->hdl, &par))
+ {
+ jack_error("sndio_driver: sio_getpar() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (par.sig != 1 || par.bits != driver->bits ||
+ par.pchan != driver->playback_channels ||
+ par.rchan != driver->capture_channels ||
+ par.rate != driver->sample_rate)
+ {
+ jack_error("sndio_driver: setting parameters failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ period_size = par.round;
+ nperiods = par.appbufsz / par.round;
+ driver->sample_bytes = par.bps;
+ driver->pprime = par.bufsz;
+
+ if (period_size != 0 && !driver->ignorehwbuf &&
+ (period_size != driver->period_size ||
+ nperiods != driver->nperiods))
+ {
+ printf("sndio_driver: buffer update: "
+ "period_size=%u, nperiods=%u\n", period_size, nperiods);
+
+ driver->nperiods = nperiods;
+ set_period_size(driver, period_size);
+
+ if (driver->engine)
+ driver->engine->set_buffer_size(driver->engine,
+ driver->period_size);
+ }
+
+ driver->capbufsize = 0;
+ driver->capbuf = NULL;
+ if (driver->capture_channels != 0)
+ {
+ driver->capbufsize = driver->period_size *
+ driver->capture_channels * driver->sample_bytes;
+ driver->capbuf = malloc(driver->capbufsize);
+ if (driver->capbuf == NULL)
+ {
+ jack_error("sndio_driver: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ memset(driver->capbuf, 0, driver->capbufsize);
+ }
+
+ driver->playbufsize = 0;
+ driver->playbuf = NULL;
+ if (driver->playback_channels > 0)
+ {
+ driver->playbufsize = driver->period_size *
+ driver->playback_channels * driver->sample_bytes;
+ driver->playbuf = malloc(driver->playbufsize);
+ if (driver->playbuf == NULL)
+ {
+ jack_error("sndio_driver: malloc() failed: %s@%i",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ memset(driver->playbuf, 0, driver->playbufsize);
+ }
+
+ printf("sndio_driver: capbuf %zd B, playbuf %zd B\n",
+ driver->capbufsize, driver->playbufsize);
+
+ return 0;
+}
+
+
+static int
+sndio_driver_stop (sndio_driver_t *driver)
+{
+ if (driver->hdl != NULL)
+ sio_stop(driver->hdl);
+
+ return 0;
+}
+
+
+static jack_nframes_t
+sndio_driver_wait (sndio_driver_t *driver, int *status, float *iodelay)
+{
+ struct pollfd pfd;
+ nfds_t snfds, nfds;
+ jack_time_t poll_ret;
+ int need_capture, need_playback;
+ int events, revents;
+
+ *status = 0;
+ *iodelay = 0;
+
+ need_capture = need_playback = 0;
+
+ if (driver->capture_channels > 0)
+ need_capture = 1;
+
+ if (driver->playback_channels > 0)
+ need_playback = 1;
+
+ if (jack_get_microseconds() > driver->poll_next)
+ {
+ /* late. don't count as wakeup delay. */
+ driver->poll_next = 0;
+ }
+
+ snfds = sio_nfds(driver->hdl);
+
+ while (need_capture || need_playback)
+ {
+ events = 0;
+ if (need_capture)
+ events |= POLLIN;
+
+ if (need_playback)
+ events |= POLLOUT;
+
+ if (snfds != sio_pollfd(driver->hdl, &pfd, events)) {
+ jack_error("sndio_driver: sio_pollfd failed: %s@%i",
+ __FILE__, __LINE__);
+ *status = -1;
+ return 0;
+ }
+ nfds = poll(&pfd, snfds, 1000);
+ if (nfds == -1)
+ {
+ jack_error("sndio_driver: poll() error: %s: %s@%i",
+ strerror(errno), __FILE__, __LINE__);
+ *status = -1;
+ return 0;
+ }
+ else if (nfds == 0)
+ {
+ jack_error("sndio_driver: poll() time out: %s@%i",
+ __FILE__, __LINE__);
+ *status = -1;
+ return 0;
+ }
+ revents = sio_revents(driver->hdl, &pfd);
+ if (revents & (POLLERR | POLLHUP | POLLNVAL))
+ {
+ jack_error("sndio_driver: poll() error: %s@%i",
+ __FILE__, __LINE__);
+ *status = -1;
+ return 0;
+ }
+
+ if (revents & POLLIN)
+ need_capture = 0;
+
+ if (revents & POLLOUT)
+ need_playback = 0;
+
+ if (sio_eof(driver->hdl))
+ {
+ jack_error("sndio_driver: sio_eof(): %s@%i",
+ __FILE__, __LINE__);
+ *status = -1;
+ return 0;
+ }
+ }
+ poll_ret = jack_get_microseconds();
+
+ if (driver->poll_next && poll_ret > driver->poll_next)
+ *iodelay = poll_ret - driver->poll_next;
+
+ driver->poll_next = poll_ret + driver->period_usecs;
+ driver->engine->transport_cycle_start(driver->engine, poll_ret);
+
+ driver->last_wait_ust = poll_ret;
+
+ return driver->period_size;
+}
+
+
+static inline int
+sndio_driver_run_cycle (sndio_driver_t *driver)
+{
+ jack_nframes_t nframes;
+ int wait_status;
+ float iodelay;
+
+ nframes = sndio_driver_wait(driver, &wait_status, &iodelay);
+
+ if (wait_status < 0)
+ return -1;
+
+ return driver->engine->run_cycle(driver->engine, nframes, iodelay);
+}
+
+
+static void
+copy_and_convert_in (jack_sample_t *dst, void *src,
+ size_t nframes, int channel, int chcount, int bits)
+{
+ int srcidx, 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:
+ 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] >= 0.0f) ?
+ (src[srcidx] * scale + 0.5f) :
+ (src[srcidx] * scale - 0.5f);
+ dstidx += chcount;
+ }
+ break;
+ case 24:
+ case 32:
+ scale = 0x7fffffff;
+ for (srcidx = 0; srcidx < nframes; srcidx++)
+ {
+ s32dst[dstidx] = (signed int)
+ (src[srcidx] >= 0.0f) ?
+ (src[srcidx] * scale + 0.5f) :
+ (src[srcidx] * scale - 0.5f);
+ dstidx += chcount;
+ }
+ break;
+ }
+}
+
+
+/* jack driver interface */
+
+static int
+sndio_driver_attach (sndio_driver_t *driver)
+{
+ int port_flags;
+ int channel;
+ char channel_name[64];
+ jack_port_t *port;
+ jack_latency_range_t range;
+
+ driver->engine->set_buffer_size(driver->engine, driver->period_size);
+ driver->engine->set_sample_rate(driver->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("sndio_driver: cannot register port for %s: "
+ "%s@%i", channel_name, __FILE__, __LINE__);
+ break;
+ }
+ range.min = range.max = driver->period_size +
+ driver->sys_cap_latency;
+ jack_port_set_latency_range(port, JackCaptureLatency, &range);
+ 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("sndio_driver: cannot register port for "
+ "%s: %s@%i", channel_name, __FILE__, __LINE__);
+ break;
+ }
+ range.min = range.max = driver->period_size +
+ driver->sys_play_latency;
+ jack_port_set_latency_range(port, JackPlaybackLatency, &range);
+ driver->playback_ports =
+ jack_slist_append(driver->playback_ports, port);
+ }
+
+ return jack_activate(driver->client);
+}
+
+
+static int
+sndio_driver_detach (sndio_driver_t *driver)
+{
+ JSList *node;
+
+ if (driver->engine == NULL)
+ return 0;
+
+ node = driver->capture_ports;
+ while (node != NULL)
+ {
+ jack_port_unregister(driver->client,
+ ((jack_port_t *) node->data));
+ node = jack_slist_next(node);
+ }
+ if (driver->capture_ports != NULL)
+ {
+ 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);
+ }
+ if (driver->playback_ports != NULL)
+ {
+ jack_slist_free(driver->playback_ports);
+ driver->playback_ports = NULL;
+ }
+
+ return 0;
+}
+
+
+static int
+sndio_driver_read (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ jack_nframes_t nbytes, offset;
+ int channel;
+ size_t io_res;
+ jack_sample_t *portbuf;
+ JSList *node;
+ jack_port_t *port;
+
+ if (driver->engine->freewheeling || driver->capture_channels == 0)
+ return 0;
+
+ if (nframes > driver->period_size)
+ {
+ jack_error("sndio_driver: 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->capbuf,
+ nframes, channel,
+ driver->capture_channels,
+ driver->bits);
+ }
+
+ node = jack_slist_next(node);
+ channel++;
+ }
+
+ io_res = offset = 0;
+ nbytes = nframes * driver->capture_channels * driver->sample_bytes;
+ while (nbytes > 0)
+ {
+ io_res = sio_read(driver->hdl, driver->capbuf + offset, nbytes);
+ if (io_res == 0)
+ {
+ jack_error("sndio_driver: sio_read() failed: %s@%i",
+ __FILE__, __LINE__);
+ break;
+ }
+ offset += io_res;
+ nbytes -= io_res;
+ }
+ return 0;
+}
+
+
+static int
+sndio_driver_write (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ jack_nframes_t nbytes;
+ int channel;
+ size_t io_res, offset;
+ jack_sample_t *portbuf;
+ JSList *node;
+ jack_port_t *port;
+
+ if (driver->engine->freewheeling || driver->playback_channels == 0)
+ return 0;
+
+ if (nframes > driver->period_size)
+ {
+ jack_error("sndio_driver: 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->playbuf, portbuf,
+ nframes, channel,
+ driver->playback_channels,
+ driver->bits);
+ }
+
+ node = jack_slist_next(node);
+ channel++;
+ }
+
+ io_res = offset = 0;
+ nbytes = nframes * driver->playback_channels * driver->sample_bytes;
+ while (nbytes > 0)
+ {
+ io_res = sio_write(driver->hdl, driver->playbuf + offset, nbytes);
+ if (io_res == 0)
+ {
+ jack_error("sndio_driver: sio_write() failed: %s@%i",
+ __FILE__, __LINE__);
+ break;
+ }
+ offset += io_res;
+ nbytes -= io_res;
+ }
+ memset(driver->playbuf, 0, driver->playbufsize);
+ return 0;
+}
+
+
+static int
+sndio_driver_null_cycle (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ if (nframes > driver->period_size)
+ {
+ jack_error("sndio_driver: null cycle failed: "
+ "nframes > period_size (%u/%u): %s@%i", nframes,
+ driver->period_size, __FILE__, __LINE__);
+ return -1;
+ }
+
+ printf("sndio_driver: running null cycle\n");
+
+ if (driver->playback_channels > 0)
+ sndio_driver_write_silence (driver, nframes);
+
+ if (driver->capture_channels > 0)
+ sndio_driver_read_silence (driver, nframes);
+
+ return 0;
+}
+
+
+static int
+sndio_driver_bufsize (sndio_driver_t *driver, jack_nframes_t nframes)
+{
+ return sndio_driver_set_parameters(driver);
+}
+
+
+static void
+sndio_driver_delete (sndio_driver_t *driver)
+{
+ if (driver->hdl != NULL)
+ {
+ sio_close(driver->hdl);
+ driver->hdl = NULL;
+ }
+
+ if (driver->capbuf != NULL)
+ {
+ free(driver->capbuf);
+ driver->capbuf = NULL;
+ }
+ if (driver->playbuf != NULL)
+ {
+ free(driver->playbuf);
+ driver->playbuf = NULL;
+ }
+
+ if (driver->dev != NULL)
+ {
+ free(driver->dev);
+ driver->dev = NULL;
+ }
+
+ jack_driver_nt_finish((jack_driver_nt_t *) driver);
+
+ if (driver != NULL)
+ {
+ free(driver);
+ driver = NULL;
+ }
+}
+
+
+void
+driver_finish (jack_driver_t *driver)
+{
+ sndio_driver_delete((sndio_driver_t *)driver);
+}
+
+
+static jack_driver_t *
+sndio_driver_new (char *dev, jack_client_t *client,
+ jack_nframes_t sample_rate, jack_nframes_t period_size,
+ jack_nframes_t nperiods, int bits,
+ int capture_channels, int playback_channels,
+ jack_nframes_t cap_latency, jack_nframes_t play_latency,
+ int ignorehwbuf)
+{
+ sndio_driver_t *driver;
+
+ driver = (sndio_driver_t *)calloc(1, sizeof(sndio_driver_t));
+ if (driver == NULL)
+ {
+ jack_error("sndio_driver: malloc() failed: %s: %s@%i",
+ strerror(errno), __FILE__, __LINE__);
+ return NULL;
+ }
+ driver->engine = NULL;
+ jack_driver_nt_init((jack_driver_nt_t *)driver);
+
+ driver->nt_attach = (JackDriverNTAttachFunction)sndio_driver_attach;
+ driver->nt_detach = (JackDriverNTDetachFunction)sndio_driver_detach;
+ driver->read = (JackDriverReadFunction)sndio_driver_read;
+ driver->write = (JackDriverWriteFunction)sndio_driver_write;
+ driver->null_cycle = (JackDriverNullCycleFunction)sndio_driver_null_cycle;
+ driver->nt_bufsize = (JackDriverNTBufSizeFunction)sndio_driver_bufsize;
+ driver->nt_start = (JackDriverNTStartFunction)sndio_driver_start;
+ driver->nt_stop = (JackDriverNTStopFunction)sndio_driver_stop;
+ driver->nt_run_cycle = (JackDriverNTRunCycleFunction)sndio_driver_run_cycle;
+
+ if (dev != NULL)
+ driver->dev = strdup(dev);
+ else
+ driver->dev = NULL;
+
+ driver->ignorehwbuf = ignorehwbuf;
+
+ driver->sample_rate = sample_rate;
+ driver->period_size = period_size;
+ driver->orig_period_size = period_size;
+ driver->nperiods = nperiods;
+ driver->bits = bits;
+ driver->capture_channels = capture_channels;
+ driver->playback_channels = playback_channels;
+ driver->sys_cap_latency = cap_latency;
+ driver->sys_play_latency = play_latency;
+
+ set_period_size(driver, period_size);
+
+ driver->hdl = NULL;
+ driver->capbuf = driver->playbuf = NULL;
+ driver->capture_ports = driver->playback_ports = NULL;
+
+ driver->poll_next = 0;
+
+ if (sndio_driver_set_parameters(driver) < 0)
+ {
+ free(driver);
+ return NULL;
+ }
+
+ driver->client = client;
+
+ return (jack_driver_t *)driver;
+}
+
+
+/* jack driver published interface */
+
+
+const char driver_client_name[] = "sndio";
+
+
+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)
+ {
+ jack_error("sndio_driver: calloc() failed: %s: %s@%i",
+ strerror(errno), __FILE__, __LINE__);
+ return NULL;
+ }
+ strlcpy(desc->name, driver_client_name, sizeof(desc->name));
+ desc->nparams = SNDIO_DRIVER_N_PARAMS;
+
+ params = calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
+ if (params == NULL)
+ {
+ jack_error("sndio_driver: calloc() failed: %s: %s@%i",
+ strerror(errno), __FILE__, __LINE__);
+ return NULL;
+ }
+ memcpy(params, sndio_params,
+ desc->nparams * sizeof(jack_driver_param_desc_t));
+ desc->params = params;
+
+ return desc;
+}
+
+
+jack_driver_t *
+driver_initialize (jack_client_t *client, JSList * params)
+{
+ int bits = SNDIO_DRIVER_DEF_BITS;
+ jack_nframes_t sample_rate = SNDIO_DRIVER_DEF_FS;
+ jack_nframes_t period_size = SNDIO_DRIVER_DEF_BLKSIZE;
+ jack_nframes_t cap_latency = 0;
+ jack_nframes_t play_latency = 0;
+ unsigned int nperiods = SNDIO_DRIVER_DEF_NPERIODS;
+ unsigned int capture_channels = SNDIO_DRIVER_DEF_INS;
+ unsigned int playback_channels = SNDIO_DRIVER_DEF_OUTS;
+ const JSList *pnode;
+ const jack_driver_param_t *param;
+ char *dev = NULL;
+ int ignorehwbuf = 0;
+
+ pnode = params;
+ while (pnode != NULL)
+ {
+ param = (const jack_driver_param_t *)pnode->data;
+
+ switch (param->character)
+ {
+ case 'r':
+ sample_rate = param->value.ui;
+ break;
+ case 'p':
+ period_size = param->value.ui;
+ break;
+ case 'n':
+ nperiods = param->value.ui;
+ break;
+ case 'w':
+ bits = param->value.i;
+ break;
+ case 'i':
+ capture_channels = param->value.ui;
+ break;
+ case 'o':
+ playback_channels = param->value.ui;
+ break;
+ case 'd':
+ dev = strdup(param->value.str);
+ break;
+ case 'b':
+ ignorehwbuf = 1;
+ break;
+ case 'I':
+ cap_latency = param->value.ui;
+ break;
+ case 'O':
+ play_latency = param->value.ui;
+ break;
+ }
+ pnode = jack_slist_next(pnode);
+ }
+
+ return sndio_driver_new(dev, client, sample_rate, period_size,
+ nperiods, bits, capture_channels, playback_channels,
+ cap_latency, play_latency, ignorehwbuf);
+}
diff --git a/drivers/sndio/sndio_driver.h b/drivers/sndio/sndio_driver.h
new file mode 100644
index 0000000..03df4f1
--- /dev/null
+++ b/drivers/sndio/sndio_driver.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __JACK_SNDIO_DRIVER_H__
+#define __JACK_SNDIO_DRIVER_H__
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <jack/types.h>
+#include <jack/jslist.h>
+#include <driver.h>
+#include <jack/jack.h>
+
+#define SNDIO_DRIVER_DEF_DEV "default"
+#define SNDIO_DRIVER_DEF_FS 44100
+#define SNDIO_DRIVER_DEF_BLKSIZE 1024
+#define SNDIO_DRIVER_DEF_NPERIODS 2
+#define SNDIO_DRIVER_DEF_BITS 16
+#define SNDIO_DRIVER_DEF_INS 2
+#define SNDIO_DRIVER_DEF_OUTS 2
+
+typedef jack_default_audio_sample_t jack_sample_t;
+
+typedef struct _sndio_driver
+{
+ JACK_DRIVER_NT_DECL
+
+ jack_nframes_t sample_rate;
+ jack_nframes_t period_size;
+ jack_nframes_t orig_period_size;
+ unsigned int nperiods;
+ int bits;
+ unsigned int capture_channels;
+ unsigned int playback_channels;
+ jack_nframes_t sys_cap_latency;
+ jack_nframes_t sys_play_latency;
+ int ignorehwbuf;
+
+ struct sio_hdl *hdl;
+ char *dev;
+
+ void *capbuf;
+ size_t capbufsize;
+ void *playbuf;
+ size_t playbufsize;
+ JSList *capture_ports;
+ JSList *playback_ports;
+
+ int sample_bytes;
+ size_t pprime;
+
+ int poll_timeout;
+ jack_time_t poll_next;
+
+ jack_client_t *client;
+
+} sndio_driver_t;
+
+#endif
diff --git a/jackd/Makefile.am b/jackd/Makefile.am
index eb03ca3..b284f9a 100644
--- a/jackd/Makefile.am
+++ b/jackd/Makefile.am
@@ -37,7 +37,11 @@ jack_md5.h: jackd
if STRIPPED_JACKD
strip -R .note -R .comment .libs/jackd
endif
+if USE_MD5SUM
echo "#define JACKD_MD5_SUM \"`md5sum .libs/jackd | awk '{print $$1}'`\"" > jack_md5.h
+else
+ echo "#define JACKD_MD5_SUM \"`md5 -q .libs/jackd | awk '{print $$1}'`\"" > jack_md5.h
+endif
jackstart_SOURCES = jackstart.c md5.c
jackstart_LDFLAGS = -lcap
diff --git a/jackd/controlapi.c b/jackd/controlapi.c
index 90edc28..a117e20 100644
--- a/jackd/controlapi.c
+++ b/jackd/controlapi.c
@@ -843,7 +843,7 @@ get_realtime_priority_constraint ()
return constraint_ptr;
#else
- return NULL
+ return NULL;
#endif
}
diff --git a/jackd/engine.c b/jackd/engine.c
index 365a29a..ad0a8d6 100644
--- a/jackd/engine.c
+++ b/jackd/engine.c
@@ -1435,7 +1435,7 @@ handle_external_client_request (jack_engine_t *engine, int fd)
if ((r = read (client->request_fd, &req, sizeof(req)))
< (ssize_t)sizeof(req)) {
if (r == 0) {
-#ifdef JACK_USE_MACH_THREADS
+#if defined(JACK_USE_MACH_THREADS) || defined(__OpenBSD__)
/* poll is implemented using
select (see the macosx/fakepoll
code). When the socket is closed
diff --git a/jackd/jackd.1.in b/jackd/jackd.1.in
index 1bc7c9c..6b86210 100644
--- a/jackd/jackd.1.in
+++ b/jackd/jackd.1.in
@@ -28,7 +28,7 @@ For the latest JACK information, please consult the web site,
.br
Select the audio interface backend. The current list of supported
backends is: \fBalsa\fR, \fBcoreaudio\fR, \fBdummy\fR, \fBfreebob\fR,
-\fBoss\fR \fBsun\fR and \fBportaudio\fR. They are not all available
+\fBoss\fR \fBsun\fR \fBportaudio\fR and \fB sndio. They are not all available
on all platforms. All \fIbackend\-parameters\fR are optional.
.TP
\fB\-h, \-\-help\fR
@@ -523,6 +523,43 @@ Driver name (default: none)
.TP
\fB\-z \-\-dither\fR
Dithering mode (default: none)
+.SS SNDIO BACKEND PARAMETERS
+.TP
+\fB\-r, \-\-rate \fIint\fR
+Specify the sample rate. The default is 44100.
+.TP
+\fB\-p, \-\-period \fIint\fR
+Specify the number of frames between JACK \fBprocess()\fR calls. This
+value must be a power of 2, and the default is 1024. If you need low
+latency, set \fB\-p\fR as low as you can go without seeing xruns. A larger
+period size yields higher latency, but makes xruns less likely. The JACK
+capture latency in seconds is \fB\-\-period\fR divided by \fB\-\-rate\fR.
+Note that this value is mostly advisory when aucat server is running
+and may be updated internally.
+.TP
+\fB\-n, \-\-nperiods \fIint\fR
+Specify the number of periods in the hardware buffer. The default is
+2. The period size (\fB\-p\fR) times \fB\-\-nperiods\fR times four
+(assuming 2 channels 16-bit samples) is the JACK buffer size in bytes.
+The JACK output latency in seconds is \fB\-\-nperiods\fR times
+\fB\-\-period\fR divided by \fB\-\-rate\fR.
+Note that this value is mostly advisory when aucat server is running
+and may be updated internally.
+.TP
+\fB\-w, \-\-wordlength \fIint\fR
+Specify the sample size in bits. The default is 16.
+.TP
+\fB\-i, \-\-inchannels \fIint\fR
+Specify how many channels to capture (default: 2)
+.TP
+\fB\-o, \-\-outchannels \fIint\fR
+Specify number of playback channels (default: 2)
+.TP
+\fB\-d, \-\-device \fIdevice_file\fR
+Specify device for capture and playback (default: NULL)
+.TP
+\fB\-b, \-\-ignorehwbuf \fIboolean\fR
+Specify, whether to ignore hardware period size (default: false)
.SH "EXAMPLES"
.PP
Print usage message for the parameters specific to each backend.
@@ -544,6 +581,8 @@ Print usage message for the parameters specific to each backend.
\fBjackd \-d sun \-\-help\fR
.br
\fBjackd \-d portaudio \-\-help\fR
+.br
+\fBjackd \-d sndio \-\-help\fR
.PP
Run the JACK daemon with realtime priority using the first ALSA
hardware card defined in \fB/etc/modules.conf\fR.
diff --git a/jackd/jackd.c b/jackd/jackd.c
index 90fb38f..b27dde2 100644
--- a/jackd/jackd.c
+++ b/jackd/jackd.c
@@ -537,7 +537,7 @@ static void usage (FILE *file)
#ifdef __APPLE__
" Available backends may include: coreaudio, dummy, net, portaudio.\n\n"
#else
- " Available backends may include: alsa, dummy, freebob, firewire, net, oss, sun, or portaudio.\n\n"
+ " Available backends may include: alsa, dummy, freebob, firewire, net, oss, sun, portaudio or sndio.\n\n"
#endif
" jackd -d backend --help\n"
" to display options for each backend\n\n");