mirror of https://github.com/ericonr/sndio.git
Add support for OSS/FreeBSD. From Tobias Kortkamp <t@tobik.me>.
This commit is contained in:
parent
dd3f3ee5ee
commit
02c2d1521c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue