Add support for OSS/FreeBSD. From Tobias Kortkamp <t@tobik.me>.

This commit is contained in:
Alexandre Ratchov 2016-11-03 08:04:47 +01:00
parent dd3f3ee5ee
commit 02c2d1521c
5 changed files with 677 additions and 1 deletions

23
configure vendored
View File

@ -34,6 +34,7 @@ prefix=/usr/local # where to install sndio
so="libsndio.so.\${MAJ}.\${MIN}" # shared libs to build
alsa=no # do we want alsa support ?
sun=no # do we want sun support ?
oss=no # do we want oss support ?
rmidi=no # do we want support for raw char dev ?
precision=16 # aucat/sndiod arithmetic precision
user=_sndio # non-privileged user for sndio daemon
@ -74,6 +75,14 @@ case `uname` in
defs='-DHAVE_ARC4RANDOM -DHAVE_ISSETUGID \\\
-DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRTONUM'
;;
DragonFly|FreeBSD)
user=_sndio
so="$so libsndio.so"
defs='-DHAVE_ARC4RANDOM -DHAVE_ISSETUGID \\\
-DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRTONUM'
oss=yes
mandir=${prefix}/man
;;
esac
# shell word separator (none)
@ -109,6 +118,12 @@ for i; do
--disable-alsa)
alsa=no
shift;;
--enable-oss)
oss=yes
shift;;
--disable-oss)
oss=no
shift;;
--enable-sun)
sun=yes
shift;;
@ -170,6 +185,13 @@ if [ $alsa = yes ]; then
ldadd="$ldadd -lasound"
fi
#
# if using OSS, add corresponding parameters
#
if [ $oss = yes ]; then
defs="$defs -DUSE_OSS"
fi
#
# if using Sun API, add corresponding parameters
#
@ -227,6 +249,7 @@ user..................... $user
libbsd................... $libbsd
precision................ $precision
alsa..................... $alsa
oss...................... $oss
sun...................... $sun
rmidi.................... $rmidi
xvolkeys................. $xvolkeys

View File

@ -111,7 +111,7 @@ clean:
#
OBJS = debug.o aucat.o \
mio.o mio_rmidi.o mio_alsa.o mio_aucat.o \
sio.o sio_alsa.o sio_aucat.o sio_sun.o \
sio.o sio_alsa.o sio_aucat.o sio_oss.o sio_sun.o \
siomix.o siomix_aucat.o siomix_sun.o \
issetugid.o strlcat.o strlcpy.o strtonum.o
@ -151,6 +151,8 @@ sio_alsa.o: sio_alsa.c debug.h sio_priv.h sndio.h \
../bsd-compat/bsd-compat.h
sio_aucat.o: sio_aucat.c aucat.h amsg.h debug.h sio_priv.h sndio.h \
../bsd-compat/bsd-compat.h
sio_oss.o: sio_oss.c debug.h sio_priv.h sndio.h \
../bsd-compat/bsd-compat.h
sio_sun.o: sio_sun.c debug.h sio_priv.h sndio.h \
../bsd-compat/bsd-compat.h
siomix.o: siomix.c debug.h siomix_priv.h

View File

@ -64,6 +64,8 @@ sio_open(const char *str, unsigned int mode, int nbio)
return hdl;
#if defined(USE_SUN)
return _sio_sun_open("rsnd/0", mode, nbio);
#elif defined(USE_OSS)
return _sio_oss_open("rsnd/0", mode, nbio);
#elif defined(USE_ALSA)
return _sio_alsa_open("rsnd/0", mode, nbio);
#else
@ -75,6 +77,8 @@ sio_open(const char *str, unsigned int mode, int nbio)
if (_sndio_parsetype(str, "rsnd"))
#if defined(USE_SUN)
return _sio_sun_open(str, mode, nbio);
#elif defined(USE_OSS)
return _sio_oss_open(str, mode, nbio);
#elif defined(USE_ALSA)
return _sio_alsa_open(str, mode, nbio);
#else

644
libsndio/sio_oss.c Normal file
View File

@ -0,0 +1,644 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
* Copyright (c) 2016 Tobias Kortkamp <t@tobik.me>
*
* 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.
*/
#ifdef USE_OSS
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "debug.h"
#include "sio_priv.h"
#include "bsd-compat.h"
#define DEVPATH_PREFIX "/dev/dsp"
#define DEVPATH_MAX (1 + \
sizeof(DEVPATH_PREFIX) - 1 + \
sizeof(int) * 3)
struct sio_oss_fmt {
int fmt;
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
};
static struct sio_oss_fmt formats[] = {
/* See http://manuals.opensound.com/developer/formats.html.
* AFMT_{S8,U16}_* are marked as obsolete so are missing here.
*/
/* le+msb not important */
{ AFMT_U8, 8, 1, 0, 0, 0 },
{ AFMT_U8, 8, 1, 0, 1, 0 },
{ AFMT_U8, 8, 1, 0, 0, 1 },
{ AFMT_U8, 8, 1, 0, 1, 1 },
/* msb not important */
{ AFMT_S16_BE, 16, 2, 1, 0, 0 },
{ AFMT_S16_BE, 16, 2, 1, 0, 1 },
{ AFMT_S16_LE, 16, 2, 1, 1, 0 },
{ AFMT_S16_LE, 16, 2, 1, 1, 1 },
{ AFMT_S24_BE, 24, 3, 1, 0, 0 },
{ AFMT_S24_BE, 24, 3, 1, 0, 1 },
{ AFMT_S24_LE, 24, 3, 1, 1, 0 },
{ AFMT_S24_LE, 24, 3, 1, 1, 1 },
{ AFMT_U24_BE, 24, 3, 0, 0, 0 },
{ AFMT_U24_BE, 24, 3, 0, 0, 1 },
{ AFMT_U24_LE, 24, 3, 0, 1, 0 },
{ AFMT_U24_LE, 24, 3, 0, 1, 1 },
{ AFMT_S32_BE, 32, 4, 1, 0, 1 },
{ AFMT_S32_LE, 32, 4, 1, 1, 1 },
{ AFMT_U32_BE, 32, 4, 0, 0, 1 },
{ AFMT_U32_LE, 32, 4, 0, 1, 1 },
};
struct sio_oss_hdl {
struct sio_hdl sio;
int fd;
unsigned int isamples;
unsigned int osamples;
int idelta, odelta;
int fmt;
unsigned int rate;
unsigned int chan;
unsigned int appbufsz;
unsigned int round;
};
static struct sio_hdl *sio_oss_fdopen(const char *, int, unsigned int, int);
static int sio_oss_getcap(struct sio_hdl *, struct sio_cap *);
static int sio_oss_getfd(const char *, unsigned int, int);
static int sio_oss_getpar(struct sio_hdl *, struct sio_par *);
static int sio_oss_nfds(struct sio_hdl *);
static int sio_oss_pollfd(struct sio_hdl *, struct pollfd *, int);
static int sio_oss_revents(struct sio_hdl *, struct pollfd *);
static int sio_oss_setpar(struct sio_hdl *, struct sio_par *);
static int sio_oss_start(struct sio_hdl *);
static int sio_oss_stop(struct sio_hdl *);
static int sio_oss_xrun(struct sio_oss_hdl *);
static size_t sio_oss_read(struct sio_hdl *, void *, size_t);
static size_t sio_oss_write(struct sio_hdl *, const void *, size_t);
static void sio_oss_close(struct sio_hdl *);
static struct sio_ops sio_oss_ops = {
sio_oss_close,
sio_oss_setpar,
sio_oss_getpar,
sio_oss_getcap,
sio_oss_write,
sio_oss_read,
sio_oss_start,
sio_oss_stop,
sio_oss_nfds,
sio_oss_pollfd,
sio_oss_revents,
NULL, /* setvol */
NULL, /* getvol */
};
/*
* guess device capabilities
*/
static int
sio_oss_getcap(struct sio_hdl *sh, struct sio_cap *cap)
{
/* From sound(4):
* The FreeBSD multichannel matrix processor supports up to 18
* interleaved channels, but the limit is currently set to 8
* channels (as commonly used for 7.1 surround sound).
*/
static unsigned int chans[] = {
1, 2, 4, 6, 8
};
static unsigned int rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
48000, 64000, 88200, 96000, 192000
};
static int afmts[] = {
AFMT_U8, AFMT_S16_LE, AFMT_S16_BE, AFMT_S24_LE, AFMT_U24_LE,
AFMT_S32_LE, AFMT_U32_LE
};
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
unsigned int nconf = 0;
unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
unsigned int i, j, k, conf;
int fmts;
if (ioctl(hdl->fd, SNDCTL_DSP_GETFMTS, &fmts) < 0) {
DPERROR("sio_oss_getcap: GETFMTS");
hdl->sio.eof = 1;
return 0;
}
/*
* get a subset of supported encodings
*/
for (j = 0, i = 0; i < sizeof(afmts) / sizeof(afmts[0]); i++) {
if (fmts & afmts[i]) {
for (k = 0; k < sizeof(formats) / sizeof(formats[0]); k++) {
if (formats[k].fmt == afmts[i]) {
cap->enc[j].sig = formats[k].sig;
cap->enc[j].bits = formats[k].bits;
cap->enc[j].bps = formats[k].bps;
cap->enc[j].le = formats[k].le;
cap->enc[j].msb = formats[k].msb;
enc_map |= 1 << j;
j++;
break;
}
}
}
}
/*
* fill channels
*/
if (hdl->sio.mode & SIO_PLAY) {
for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
cap->pchan[i] = chans[i];
pchan_map |= (1 << i);
}
}
if (hdl->sio.mode & SIO_REC) {
for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
cap->rchan[i] = chans[i];
rchan_map |= (1 << i);
}
}
/*
* fill rates
*/
for (j = 0; j < sizeof(formats) / sizeof(formats[0]); j++) {
rate_map = 0;
if ((enc_map & (1 << j)) == 0)
continue;
for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
cap->rate[i] = rates[i];
rate_map |= (1 << i);
}
for (conf = 0; conf < nconf; conf++) {
if (cap->confs[conf].rate == rate_map) {
cap->confs[conf].enc |= (1 << j);
break;
}
}
if (conf == nconf) {
if (nconf == SIO_NCONF)
break;
cap->confs[nconf].enc = (1 << j);
cap->confs[nconf].pchan = pchan_map;
cap->confs[nconf].rchan = rchan_map;
cap->confs[nconf].rate = rate_map;
nconf++;
}
}
cap->nconf = nconf;
return 1;
}
static int
sio_oss_getfd(const char *str, unsigned int mode, int nbio)
{
const char *p;
char path[DEVPATH_MAX];
unsigned int devnum;
int fd, flags;
p = _sndio_parsetype(str, "rsnd");
if (p == NULL) {
DPRINTF("sio_oss_getfd: %s: \"rsnd\" expected\n", str);
return -1;
}
switch (*p) {
case '/':
p++;
break;
default:
DPRINTF("sio_oss_getfd: %s: '/' expected\n", str);
return -1;
}
p = _sndio_parsenum(p, &devnum, 255);
if (p == NULL || *p != '\0') {
DPRINTF("sio_oss_getfd: %s: number expected after '/'\n", str);
return -1;
}
snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
if (mode == (SIO_PLAY | SIO_REC))
flags = O_RDWR;
else
flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY;
while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
if (errno == EINTR)
continue;
DPERROR(path);
return -1;
}
return fd;
}
static struct sio_hdl *
sio_oss_fdopen(const char *str, int fd, unsigned int mode, int nbio)
{
struct sio_oss_hdl *hdl;
hdl = malloc(sizeof(struct sio_oss_hdl));
if (hdl == NULL)
return NULL;
_sio_create(&hdl->sio, &sio_oss_ops, mode, nbio);
/* Set default device parameters */
hdl->fmt = AFMT_S16_LE;
hdl->rate = 48000;
hdl->chan = 2;
hdl->round = 960;
hdl->appbufsz = 8 * 960;
hdl->fd = fd;
return (struct sio_hdl *)hdl;
}
struct sio_hdl *
_sio_oss_open(const char *str, unsigned int mode, int nbio)
{
struct sio_oss_hdl *hdl;
int fd;
fd = sio_oss_getfd(str, mode, nbio);
if (fd < 0)
return NULL;
hdl = (struct sio_oss_hdl *)sio_oss_fdopen(str, fd, mode, nbio);
if (hdl != NULL)
return (struct sio_hdl*)hdl;
while (close(fd) < 0 && errno == EINTR)
; /* retry */
return NULL;
}
static void
sio_oss_close(struct sio_hdl *sh)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
while (close(hdl->fd) < 0 && errno == EINTR)
; /* retry */
free(hdl);
}
static int
sio_oss_start(struct sio_hdl *sh)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
hdl->isamples = 0;
hdl->osamples = 0;
hdl->idelta = 0;
hdl->odelta = 0;
/* Nothing else to do here. OSS starts playing/recording
* on first write/read.
*/
_sio_onmove_cb(&hdl->sio, 0);
return 1;
}
static int
sio_oss_stop(struct sio_hdl *sh)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl*)sh;
if (ioctl(hdl->fd, SNDCTL_DSP_SYNC, NULL) < 0) {
DPERROR("sio_oss_stop: SYNC");
hdl->sio.eof = 1;
return 0;
}
if (ioctl(hdl->fd, SNDCTL_DSP_HALT, NULL) < 0) {
DPERROR("sio_oss_stop: HALT");
hdl->sio.eof = 1;
return 0;
}
/* Reset device parameters. When we do not do this, resuming
* playback/recording will trigger poll with revents=POLLIN
* too often, which leads to sndiod using 100 % CPU.
*/
return sio_oss_setpar(sh, &hdl->sio.par);
}
static int
sio_oss_setpar(struct sio_hdl *sh, struct sio_par *par)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
unsigned int i;
int policy;
hdl->fmt = AFMT_S16_LE;
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
if (formats[i].bits == par->bits
&& formats[i].le == par->le
&& formats[i].sig == par->sig
&& formats[i].msb == par->msb) {
hdl->fmt = formats[i].fmt;
break;
}
}
if (par->rate != ~0U)
hdl->rate = par->rate;
if (hdl->rate < 8000)
hdl->rate = 8000;
if (hdl->rate > 192000)
hdl->rate = 192000;
if (hdl->sio.mode & SIO_PLAY)
hdl->chan = par->pchan;
else if (hdl->sio.mode & SIO_REC)
hdl->chan = par->rchan;
if (par->round != ~0U && par->appbufsz != ~0U) {
hdl->round = par->round;
hdl->appbufsz = par->appbufsz;
} else if (par->round != ~0U) {
hdl->round = par->round;
hdl->appbufsz = 2 * par->round;
} else if (par->appbufsz != ~0U) {
hdl->round = par->appbufsz / 2;
hdl->appbufsz = par->appbufsz;
}
/* Set timing policy to 5 which is OSS' default. The
* user-settable hw.snd.latency sysctl influences the default
* policy.
*/
policy = 5;
if (ioctl(hdl->fd, SNDCTL_DSP_POLICY, &policy) < 0) {
DPERROR("sio_oss_setpar: POLICY");
hdl->sio.eof = 1;
return 0;
}
if (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &hdl->fmt) < 0) {
DPERROR("sio_oss_setpar: SETFMT");
hdl->sio.eof = 1;
return 0;
}
if (ioctl(hdl->fd, SNDCTL_DSP_SPEED, &hdl->rate) < 0) {
DPERROR("sio_oss_setpar: SPEED");
hdl->sio.eof = 1;
return 0;
}
if (ioctl(hdl->fd, SNDCTL_DSP_CHANNELS, &hdl->chan) < 0) {
DPERROR("sio_oss_setpar: CHANNELS");
hdl->sio.eof = 1;
return 0;
}
return 1;
}
static int
sio_oss_getpar(struct sio_hdl *sh, struct sio_par *par)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
unsigned int i, found = 0;
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
if (formats[i].fmt == hdl->fmt) {
par->sig = formats[i].sig;
par->le = formats[i].le;
par->bits = formats[i].bits;
par->bps = formats[i].bps;
par->msb = formats[i].msb;
found = 1;
break;
}
}
if (!found) {
DPRINTF("sio_oss_getpar: unknown format %d\n", hdl->fmt);
hdl->sio.eof = 1;
return 0;
}
par->rate = hdl->rate;
par->pchan = hdl->chan;
par->rchan = hdl->chan;
par->round = hdl->round;
par->appbufsz = par->bufsz = hdl->appbufsz;
par->xrun = SIO_IGNORE;
return 1;
}
static size_t
sio_oss_read(struct sio_hdl *sh, void *buf, size_t len)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
ssize_t n;
while ((n = read(hdl->fd, buf, len)) < 0) {
if (errno == EINTR)
continue;
if (errno != EAGAIN) {
DPERROR("sio_oss_read: read");
hdl->sio.eof = 1;
}
return 0;
}
if (n == 0) {
DPRINTF("sio_oss_read: eof\n");
hdl->sio.eof = 1;
return 0;
}
return n;
}
static size_t
sio_oss_write(struct sio_hdl *sh, const void *buf, size_t len)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
const unsigned char *data = buf;
ssize_t n, todo;
todo = len;
while ((n = write(hdl->fd, data, todo)) < 0) {
if (errno == EINTR)
continue;
if (errno != EAGAIN) {
DPERROR("sio_oss_write: write");
hdl->sio.eof = 1;
}
return 0;
}
return n;
}
static int
sio_oss_nfds(struct sio_hdl *hdl)
{
return 1;
}
static int
sio_oss_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
pfd->fd = hdl->fd;
pfd->events = events;
return 1;
}
static int
sio_oss_xrun(struct sio_oss_hdl *hdl)
{
int clk;
int wsil, rdrop, cmove;
int rbpf, rround;
int wbpf;
DPRINTFN(2, "sio_oss_xrun:\n");
if (_sndio_debug >= 2)
_sio_printpos(&hdl->sio);
/*
* we assume rused/wused are zero if rec/play modes are not
* selected. This allows us to keep the same formula for all
* modes, provided we set rbpf/wbpf to 1 to avoid division by
* zero.
*
* to understand the formula, draw a picture :)
*/
rbpf = (hdl->sio.mode & SIO_REC) ?
hdl->sio.par.bps * hdl->sio.par.rchan : 1;
wbpf = (hdl->sio.mode & SIO_PLAY) ?
hdl->sio.par.bps * hdl->sio.par.pchan : 1;
rround = hdl->sio.par.round * rbpf;
clk = hdl->sio.cpos % hdl->sio.par.round;
rdrop = (clk * rbpf - hdl->sio.rused) % rround;
if (rdrop < 0)
rdrop += rround;
cmove = (rdrop + hdl->sio.rused) / rbpf;
wsil = cmove * wbpf + hdl->sio.wused;
DPRINTFN(2, "wsil = %d, cmove = %d, rdrop = %d\n", wsil, cmove, rdrop);
if (!sio_oss_stop(&hdl->sio))
return 0;
if (!sio_oss_start(&hdl->sio))
return 0;
if (hdl->sio.mode & SIO_PLAY) {
hdl->odelta -= cmove;
hdl->sio.wsil = wsil;
}
if (hdl->sio.mode & SIO_REC) {
hdl->idelta -= cmove;
hdl->sio.rdrop = rdrop;
}
DPRINTFN(2, "xrun: corrected\n");
DPRINTFN(2, "wsil = %d, rdrop = %d, odelta = %d, idelta = %d\n",
wsil, rdrop, hdl->odelta, hdl->idelta);
return 1;
}
static int
sio_oss_revents(struct sio_hdl *sh, struct pollfd *pfd)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
audio_errinfo ei;
int delta;
int revents = pfd->revents;
long long play_pos, rec_pos;
oss_count_t optr, iptr;
if ((pfd->revents & POLLHUP) ||
(pfd->revents & (POLLIN | POLLOUT)) == 0)
return pfd->revents;
/* Hide xruns from clients */
if (ioctl(hdl->fd, SNDCTL_DSP_GETERROR, &ei) < 0) {
DPERROR("sio_oss_revents: GETERROR");
hdl->sio.eof = 1;
return POLLHUP;
}
if (ei.play_underruns > 0 || ei.rec_overruns > 0) {
if (!sio_oss_xrun(hdl))
return POLLHUP;
return 0;
}
if (hdl->sio.mode & SIO_PLAY) {
if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_OPTR, &optr) < 0) {
DPERROR("sio_oss_revents: CURRENT_OPTR");
hdl->sio.eof = 1;
return POLLHUP;
}
play_pos = optr.samples - optr.fifo_samples;
delta = play_pos - hdl->osamples;
hdl->osamples = play_pos;
hdl->odelta += delta;
if (!(hdl->sio.mode & SIO_REC)) {
hdl->idelta += delta;
}
}
if (hdl->sio.mode & SIO_REC) {
if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_IPTR, &iptr) < 0) {
DPERROR("sio_oss_revents: CURRENT_IPTR");
hdl->sio.eof = 1;
return POLLHUP;
}
rec_pos = iptr.samples - iptr.fifo_samples;
delta = rec_pos - hdl->isamples;
hdl->isamples = rec_pos;
hdl->idelta += delta;
if (!(hdl->sio.mode & SIO_PLAY)) {
hdl->odelta += delta;
}
}
delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta;
if (delta > 0) {
_sio_onmove_cb(&hdl->sio, delta);
hdl->idelta -= delta;
hdl->odelta -= delta;
}
return revents;
}
#endif /* defined USE_OSS */

View File

@ -69,6 +69,9 @@ struct sio_hdl *_sio_aucat_open(const char *, unsigned, int);
#ifdef USE_SUN
struct sio_hdl *_sio_sun_open(const char *, unsigned, int);
#endif
#ifdef USE_OSS
struct sio_hdl *_sio_oss_open(const char *, unsigned, int);
#endif
#ifdef USE_ALSA
struct sio_hdl *_sio_alsa_open(const char *, unsigned, int);
#endif