mirror of https://github.com/ericonr/sndio.git
switch to new obsd audio api
This commit is contained in:
parent
d6bc5ae04f
commit
85c75911dc
|
@ -42,7 +42,7 @@
|
||||||
struct sio_sun_hdl {
|
struct sio_sun_hdl {
|
||||||
struct sio_hdl sio;
|
struct sio_hdl sio;
|
||||||
int fd;
|
int fd;
|
||||||
int filling;
|
int filltodo;
|
||||||
unsigned int ibpf, obpf; /* bytes per frame */
|
unsigned int ibpf, obpf; /* bytes per frame */
|
||||||
unsigned int ibytes, obytes; /* bytes the hw transferred */
|
unsigned int ibytes, obytes; /* bytes the hw transferred */
|
||||||
unsigned int ierr, oerr; /* frames the hw dropped */
|
unsigned int ierr, oerr; /* frames the hw dropped */
|
||||||
|
@ -77,127 +77,68 @@ static struct sio_ops sio_sun_ops = {
|
||||||
NULL, /* getvol */
|
NULL, /* getvol */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* convert sun encoding to sio_par encoding
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
sio_sun_infotoenc(struct sio_sun_hdl *hdl, struct audio_prinfo *ai,
|
sio_sun_adjpar(struct sio_sun_hdl *hdl, struct audio_swpar *ap)
|
||||||
struct sio_par *par)
|
|
||||||
{
|
{
|
||||||
par->msb = ai->msb;
|
if (hdl->sio.eof)
|
||||||
par->bits = ai->precision;
|
return 0;
|
||||||
par->bps = ai->bps;
|
if (ioctl(hdl->fd, AUDIO_SETPAR, ap)) {
|
||||||
switch (ai->encoding) {
|
DPERROR("AUDIO_SETPAR");
|
||||||
case AUDIO_ENCODING_SLINEAR_LE:
|
hdl->sio.eof = 1;
|
||||||
par->le = 1;
|
return 0;
|
||||||
par->sig = 1;
|
}
|
||||||
break;
|
if (ioctl(hdl->fd, AUDIO_GETPAR, ap)) {
|
||||||
case AUDIO_ENCODING_SLINEAR_BE:
|
DPERROR("AUDIO_GETPAR");
|
||||||
par->le = 0;
|
|
||||||
par->sig = 1;
|
|
||||||
break;
|
|
||||||
case AUDIO_ENCODING_ULINEAR_LE:
|
|
||||||
par->le = 1;
|
|
||||||
par->sig = 0;
|
|
||||||
break;
|
|
||||||
case AUDIO_ENCODING_ULINEAR_BE:
|
|
||||||
par->le = 0;
|
|
||||||
par->sig = 0;
|
|
||||||
break;
|
|
||||||
case AUDIO_ENCODING_SLINEAR:
|
|
||||||
par->le = SIO_LE_NATIVE;
|
|
||||||
par->sig = 1;
|
|
||||||
break;
|
|
||||||
case AUDIO_ENCODING_ULINEAR:
|
|
||||||
par->le = SIO_LE_NATIVE;
|
|
||||||
par->sig = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DPRINTF("sio_sun_infotoenc: unsupported encoding\n");
|
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* convert sio_par encoding to sun encoding
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
sio_sun_enctoinfo(struct sio_sun_hdl *hdl,
|
|
||||||
unsigned int *renc, struct sio_par *par)
|
|
||||||
{
|
|
||||||
if (par->le == ~0U && par->sig == ~0U) {
|
|
||||||
*renc = ~0U;
|
|
||||||
} else if (par->le == ~0U || par->sig == ~0U) {
|
|
||||||
*renc = AUDIO_ENCODING_SLINEAR;
|
|
||||||
} else if (par->le && par->sig) {
|
|
||||||
*renc = AUDIO_ENCODING_SLINEAR_LE;
|
|
||||||
} else if (!par->le && par->sig) {
|
|
||||||
*renc = AUDIO_ENCODING_SLINEAR_BE;
|
|
||||||
} else if (par->le && !par->sig) {
|
|
||||||
*renc = AUDIO_ENCODING_ULINEAR_LE;
|
|
||||||
} else {
|
|
||||||
*renc = AUDIO_ENCODING_ULINEAR_BE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* try to set the device to the given parameters and check that the
|
* try to set the device to the given parameters and check that the
|
||||||
* device can use them; return 1 on success, 0 on failure or error
|
* device can use them; return 1 on success, 0 on failure or error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
sio_sun_tryinfo(struct sio_sun_hdl *hdl, struct sio_enc *enc,
|
sio_sun_testpar(struct sio_sun_hdl *hdl, struct sio_enc *enc,
|
||||||
unsigned int pchan, unsigned int rchan, unsigned int rate)
|
unsigned int pchan, unsigned int rchan, unsigned int rate)
|
||||||
{
|
{
|
||||||
struct audio_info aui;
|
struct audio_swpar ap;
|
||||||
struct audio_prinfo *pr;
|
|
||||||
|
|
||||||
pr = (hdl->sio.mode & SIO_PLAY) ? &aui.play : &aui.record;
|
AUDIO_INITPAR(&ap);
|
||||||
|
if (enc != NULL) {
|
||||||
AUDIO_INITINFO(&aui);
|
ap.sig = enc->sig;
|
||||||
if (enc) {
|
ap.bits = enc->bits;
|
||||||
if (enc->le && enc->sig) {
|
ap.bps = enc->bps;
|
||||||
pr->encoding = AUDIO_ENCODING_SLINEAR_LE;
|
if (ap.bps > 1)
|
||||||
} else if (!enc->le && enc->sig) {
|
ap.le = enc->le;
|
||||||
pr->encoding = AUDIO_ENCODING_SLINEAR_BE;
|
if (ap.bps * 8 > ap.bits)
|
||||||
} else if (enc->le && !enc->sig) {
|
ap.msb = enc->msb;
|
||||||
pr->encoding = AUDIO_ENCODING_ULINEAR_LE;
|
|
||||||
} else {
|
|
||||||
pr->encoding = AUDIO_ENCODING_ULINEAR_BE;
|
|
||||||
}
|
|
||||||
pr->precision = enc->bits;
|
|
||||||
}
|
}
|
||||||
if (rate)
|
if (rate)
|
||||||
pr->sample_rate = rate;
|
ap.rate = rate;
|
||||||
if ((hdl->sio.mode & (SIO_PLAY | SIO_REC)) == (SIO_PLAY | SIO_REC))
|
|
||||||
aui.record = aui.play;
|
|
||||||
if (pchan && (hdl->sio.mode & SIO_PLAY))
|
if (pchan && (hdl->sio.mode & SIO_PLAY))
|
||||||
aui.play.channels = pchan;
|
ap.pchan = pchan;
|
||||||
if (rchan && (hdl->sio.mode & SIO_REC))
|
if (rchan && (hdl->sio.mode & SIO_REC))
|
||||||
aui.record.channels = rchan;
|
ap.rchan = rchan;
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
if (!sio_sun_adjpar(hdl, &ap))
|
||||||
if (errno == EINVAL)
|
return 0;
|
||||||
|
if (pchan && ap.pchan != pchan)
|
||||||
|
return 0;
|
||||||
|
if (rchan && ap.rchan != rchan)
|
||||||
|
return 0;
|
||||||
|
if (rate && ap.rate != rate)
|
||||||
|
return 0;
|
||||||
|
if (enc) {
|
||||||
|
if (ap.sig != enc->sig)
|
||||||
return 0;
|
return 0;
|
||||||
DPERROR("sio_sun_tryinfo: setinfo");
|
if (ap.bits != enc->bits)
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_tryinfo: getinfo");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (pchan && aui.play.channels != pchan)
|
|
||||||
return 0;
|
|
||||||
if (rchan && aui.record.channels != rchan)
|
|
||||||
return 0;
|
|
||||||
if (rate) {
|
|
||||||
if ((hdl->sio.mode & SIO_PLAY) &&
|
|
||||||
(aui.play.sample_rate != rate))
|
|
||||||
return 0;
|
return 0;
|
||||||
if ((hdl->sio.mode & SIO_REC) &&
|
if (ap.bps != enc->bps)
|
||||||
(aui.record.sample_rate != rate))
|
return 0;
|
||||||
|
if (ap.bps > 1 && ap.le != enc->le)
|
||||||
|
return 0;
|
||||||
|
if (ap.bits < ap.bps * 8 && ap.msb != enc->msb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -209,8 +150,6 @@ sio_sun_tryinfo(struct sio_sun_hdl *hdl, struct sio_enc *enc,
|
||||||
static int
|
static int
|
||||||
sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
||||||
{
|
{
|
||||||
#define NCHANS (sizeof(chans) / sizeof(chans[0]))
|
|
||||||
#define NRATES (sizeof(rates) / sizeof(rates[0]))
|
|
||||||
static unsigned int chans[] = {
|
static unsigned int chans[] = {
|
||||||
1, 2, 4, 6, 8, 10, 12
|
1, 2, 4, 6, 8, 10, 12
|
||||||
};
|
};
|
||||||
|
@ -218,56 +157,38 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
||||||
8000, 11025, 12000, 16000, 22050, 24000,
|
8000, 11025, 12000, 16000, 22050, 24000,
|
||||||
32000, 44100, 48000, 64000, 88200, 96000
|
32000, 44100, 48000, 64000, 88200, 96000
|
||||||
};
|
};
|
||||||
|
static unsigned int encs[] = {
|
||||||
|
8, 16, 24, 32
|
||||||
|
};
|
||||||
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
||||||
struct sio_par savepar;
|
struct audio_swpar savepar, ap;
|
||||||
struct audio_encoding ae;
|
unsigned int nconf = 0;
|
||||||
unsigned int nenc = 0, nconf = 0;
|
|
||||||
unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
|
unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
|
||||||
unsigned int i, j, conf;
|
unsigned int i, j, conf;
|
||||||
|
|
||||||
if (!sio_sun_getpar(&hdl->sio, &savepar))
|
if (ioctl(hdl->fd, AUDIO_GETPAR, &savepar)) {
|
||||||
|
DPERROR("AUDIO_GETPAR");
|
||||||
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fill encoding list
|
* get a subset of supported encodings
|
||||||
*/
|
*/
|
||||||
for (ae.index = 0; nenc < SIO_NENC; ae.index++) {
|
for (i = 0; i < sizeof(encs) / sizeof(encs[0]); i++) {
|
||||||
if (ioctl(hdl->fd, AUDIO_GETENC, &ae) < 0) {
|
AUDIO_INITPAR(&ap);
|
||||||
if (errno == EINVAL)
|
ap.bits = encs[i];
|
||||||
break;
|
ap.sig = (ap.bits > 8) ? 1 : 0;
|
||||||
DPERROR("sio_sun_getcap: getenc");
|
if (!sio_sun_adjpar(hdl, &ap))
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
if (ap.bits == encs[i]) {
|
||||||
|
cap->enc[i].sig = ap.sig;
|
||||||
|
cap->enc[i].bits = ap.bits;
|
||||||
|
cap->enc[i].le = ap.le;
|
||||||
|
cap->enc[i].bps = ap.bps;
|
||||||
|
cap->enc[i].msb = ap.msb;
|
||||||
|
enc_map |= 1 << i;
|
||||||
}
|
}
|
||||||
if (ae.flags & AUDIO_ENCODINGFLAG_EMULATED)
|
|
||||||
continue;
|
|
||||||
if (ae.encoding == AUDIO_ENCODING_SLINEAR_LE) {
|
|
||||||
cap->enc[nenc].le = 1;
|
|
||||||
cap->enc[nenc].sig = 1;
|
|
||||||
} else if (ae.encoding == AUDIO_ENCODING_SLINEAR_BE) {
|
|
||||||
cap->enc[nenc].le = 0;
|
|
||||||
cap->enc[nenc].sig = 1;
|
|
||||||
} else if (ae.encoding == AUDIO_ENCODING_ULINEAR_LE) {
|
|
||||||
cap->enc[nenc].le = 1;
|
|
||||||
cap->enc[nenc].sig = 0;
|
|
||||||
} else if (ae.encoding == AUDIO_ENCODING_ULINEAR_BE) {
|
|
||||||
cap->enc[nenc].le = 0;
|
|
||||||
cap->enc[nenc].sig = 0;
|
|
||||||
} else if (ae.encoding == AUDIO_ENCODING_SLINEAR) {
|
|
||||||
cap->enc[nenc].le = SIO_LE_NATIVE;
|
|
||||||
cap->enc[nenc].sig = 1;
|
|
||||||
} else if (ae.encoding == AUDIO_ENCODING_ULINEAR) {
|
|
||||||
cap->enc[nenc].le = SIO_LE_NATIVE;
|
|
||||||
cap->enc[nenc].sig = 0;
|
|
||||||
} else {
|
|
||||||
/* unsipported encoding */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cap->enc[nenc].bits = ae.precision;
|
|
||||||
cap->enc[nenc].bps = ae.bps;
|
|
||||||
cap->enc[nenc].msb = ae.msb;
|
|
||||||
enc_map |= (1 << nenc);
|
|
||||||
nenc++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -278,17 +199,27 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
||||||
* use the current encoding and try various channels.
|
* use the current encoding and try various channels.
|
||||||
*/
|
*/
|
||||||
if (hdl->sio.mode & SIO_PLAY) {
|
if (hdl->sio.mode & SIO_PLAY) {
|
||||||
memcpy(&cap->pchan, chans, NCHANS * sizeof(unsigned int));
|
for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
|
||||||
for (i = 0; i < NCHANS; i++) {
|
AUDIO_INITPAR(&ap);
|
||||||
if (sio_sun_tryinfo(hdl, NULL, chans[i], 0, 0))
|
ap.pchan = chans[i];
|
||||||
|
if (!sio_sun_adjpar(hdl, &ap))
|
||||||
|
return 0;
|
||||||
|
if (ap.pchan == chans[i]) {
|
||||||
|
cap->pchan[i] = chans[i];
|
||||||
pchan_map |= (1 << i);
|
pchan_map |= (1 << i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hdl->sio.mode & SIO_REC) {
|
if (hdl->sio.mode & SIO_REC) {
|
||||||
memcpy(&cap->rchan, chans, NCHANS * sizeof(unsigned int));
|
for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
|
||||||
for (i = 0; i < NCHANS; i++) {
|
AUDIO_INITPAR(&ap);
|
||||||
if (sio_sun_tryinfo(hdl, NULL, 0, chans[i], 0))
|
ap.pchan = chans[i];
|
||||||
|
if (!sio_sun_adjpar(hdl, &ap))
|
||||||
|
return 0;
|
||||||
|
if (ap.rchan == chans[i]) {
|
||||||
|
cap->rchan[i] = chans[i];
|
||||||
rchan_map |= (1 << i);
|
rchan_map |= (1 << i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,12 +230,16 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
||||||
* uaudio devices), so certain rates may not be allowed with
|
* uaudio devices), so certain rates may not be allowed with
|
||||||
* certain encodings. We have to check rates for all encodings
|
* certain encodings. We have to check rates for all encodings
|
||||||
*/
|
*/
|
||||||
memcpy(&cap->rate, rates, NRATES * sizeof(unsigned int));
|
for (j = 0; j < sizeof(encs) / sizeof(encs[0]); j++) {
|
||||||
for (j = 0; j < nenc; j++) {
|
|
||||||
rate_map = 0;
|
rate_map = 0;
|
||||||
for (i = 0; i < NRATES; i++) {
|
if ((enc_map & (1 << j)) == 0)
|
||||||
if (sio_sun_tryinfo(hdl, &cap->enc[j], 0, 0, rates[i]))
|
continue;
|
||||||
|
for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
|
||||||
|
if (sio_sun_testpar(hdl,
|
||||||
|
&cap->enc[j], 0, 0, rates[i])) {
|
||||||
|
cap->rate[i] = rates[i];
|
||||||
rate_map |= (1 << i);
|
rate_map |= (1 << i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (conf = 0; conf < nconf; conf++) {
|
for (conf = 0; conf < nconf; conf++) {
|
||||||
if (cap->confs[conf].rate == rate_map) {
|
if (cap->confs[conf].rate == rate_map) {
|
||||||
|
@ -323,11 +258,13 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cap->nconf = nconf;
|
cap->nconf = nconf;
|
||||||
if (!sio_sun_setpar(&hdl->sio, &savepar))
|
|
||||||
|
if (ioctl(hdl->fd, AUDIO_SETPAR, &savepar)) {
|
||||||
|
DPERROR("AUDIO_SETPAR");
|
||||||
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
#undef NCHANS
|
|
||||||
#undef NRATES
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -373,9 +310,7 @@ sio_sun_getfd(const char *str, unsigned int mode, int nbio)
|
||||||
static struct sio_hdl *
|
static struct sio_hdl *
|
||||||
sio_sun_fdopen(int fd, unsigned int mode, int nbio)
|
sio_sun_fdopen(int fd, unsigned int mode, int nbio)
|
||||||
{
|
{
|
||||||
struct audio_info aui;
|
|
||||||
struct sio_sun_hdl *hdl;
|
struct sio_sun_hdl *hdl;
|
||||||
struct sio_par par;
|
|
||||||
|
|
||||||
hdl = malloc(sizeof(struct sio_sun_hdl));
|
hdl = malloc(sizeof(struct sio_sun_hdl));
|
||||||
if (hdl == NULL)
|
if (hdl == NULL)
|
||||||
|
@ -385,36 +320,13 @@ sio_sun_fdopen(int fd, unsigned int mode, int nbio)
|
||||||
/*
|
/*
|
||||||
* pause the device
|
* pause the device
|
||||||
*/
|
*/
|
||||||
AUDIO_INITINFO(&aui);
|
if (ioctl(fd, AUDIO_STOP) < 0) {
|
||||||
if (mode & SIO_PLAY)
|
DPERROR("AUDIO_STOP");
|
||||||
aui.play.pause = 1;
|
free(hdl);
|
||||||
if (mode & SIO_REC)
|
return NULL;
|
||||||
aui.record.pause = 1;
|
|
||||||
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_open_sun: setinfo");
|
|
||||||
goto bad_free;
|
|
||||||
}
|
}
|
||||||
hdl->fd = fd;
|
hdl->fd = fd;
|
||||||
|
|
||||||
/*
|
|
||||||
* Default parameters may not be compatible with libsndio (eg. mulaw
|
|
||||||
* encodings, different playback and recording parameters, etc...), so
|
|
||||||
* set parameters to a random value. If the requested parameters are
|
|
||||||
* not supported by the device, then sio_setpar() will pick supported
|
|
||||||
* ones.
|
|
||||||
*/
|
|
||||||
sio_initpar(&par);
|
|
||||||
par.rate = 48000;
|
|
||||||
par.le = SIO_LE_NATIVE;
|
|
||||||
par.sig = 1;
|
|
||||||
par.bits = 16;
|
|
||||||
par.appbufsz = 1200;
|
|
||||||
if (!sio_setpar(&hdl->sio, &par))
|
|
||||||
goto bad_free;
|
|
||||||
return (struct sio_hdl *)hdl;
|
return (struct sio_hdl *)hdl;
|
||||||
bad_free:
|
|
||||||
free(hdl);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sio_hdl *
|
struct sio_hdl *
|
||||||
|
@ -448,7 +360,6 @@ static int
|
||||||
sio_sun_start(struct sio_hdl *sh)
|
sio_sun_start(struct sio_hdl *sh)
|
||||||
{
|
{
|
||||||
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
||||||
struct audio_info aui;
|
|
||||||
|
|
||||||
hdl->obpf = hdl->sio.par.pchan * hdl->sio.par.bps;
|
hdl->obpf = hdl->sio.par.pchan * hdl->sio.par.bps;
|
||||||
hdl->ibpf = hdl->sio.par.rchan * hdl->sio.par.bps;
|
hdl->ibpf = hdl->sio.par.rchan * hdl->sio.par.bps;
|
||||||
|
@ -464,20 +375,17 @@ sio_sun_start(struct sio_hdl *sh)
|
||||||
* keep the device paused and let sio_sun_write() trigger the
|
* keep the device paused and let sio_sun_write() trigger the
|
||||||
* start later, to avoid buffer underruns
|
* start later, to avoid buffer underruns
|
||||||
*/
|
*/
|
||||||
hdl->filling = 1;
|
hdl->filltodo = hdl->sio.par.bufsz * hdl->obpf;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* no play buffers to fill, start now!
|
* no play buffers to fill, start now!
|
||||||
*/
|
*/
|
||||||
AUDIO_INITINFO(&aui);
|
if (ioctl(hdl->fd, AUDIO_START) < 0) {
|
||||||
if (hdl->sio.mode & SIO_REC)
|
DPERROR("AUDIO_START");
|
||||||
aui.record.pause = 0;
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_start: setinfo");
|
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
hdl->filling = 0;
|
hdl->filltodo = 0;
|
||||||
_sio_onmove_cb(&hdl->sio, 0);
|
_sio_onmove_cb(&hdl->sio, 0);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -487,35 +395,11 @@ static int
|
||||||
sio_sun_stop(struct sio_hdl *sh)
|
sio_sun_stop(struct sio_hdl *sh)
|
||||||
{
|
{
|
||||||
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
||||||
struct audio_info aui;
|
|
||||||
int mode;
|
|
||||||
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
if (hdl->filltodo > 0)
|
||||||
DPERROR("sio_sun_stop: getinfo");
|
return 1;
|
||||||
hdl->sio.eof = 1;
|
if (ioctl(hdl->fd, AUDIO_STOP) < 0) {
|
||||||
return 0;
|
DPERROR("AUDIO_STOP");
|
||||||
}
|
|
||||||
mode = aui.mode;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* there's no way to drain the device without blocking, so just
|
|
||||||
* stop it until the kernel driver get fixed
|
|
||||||
*/
|
|
||||||
AUDIO_INITINFO(&aui);
|
|
||||||
aui.mode = 0;
|
|
||||||
if (hdl->sio.mode & SIO_PLAY)
|
|
||||||
aui.play.pause = 1;
|
|
||||||
if (hdl->sio.mode & SIO_REC)
|
|
||||||
aui.record.pause = 1;
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_stop: setinfo1");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
AUDIO_INITINFO(&aui);
|
|
||||||
aui.mode = mode;
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_stop: setinfo2");
|
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -525,210 +409,59 @@ sio_sun_stop(struct sio_hdl *sh)
|
||||||
static int
|
static int
|
||||||
sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
|
sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
|
||||||
{
|
{
|
||||||
#define NRETRIES 8
|
|
||||||
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
||||||
struct audio_info aui;
|
struct audio_swpar ap;
|
||||||
unsigned int i, infr, ibpf, onfr, obpf;
|
|
||||||
unsigned int bufsz, round;
|
|
||||||
unsigned int rate, req_rate, prec, enc;
|
|
||||||
|
|
||||||
/*
|
AUDIO_INITPAR(&ap);
|
||||||
* try to set parameters until the device accepts
|
ap.sig = par->sig;
|
||||||
* a common encoding and rate for play and record
|
ap.le = par->le;
|
||||||
*/
|
ap.bits = par->bits;
|
||||||
rate = par->rate;
|
ap.bps = par->bps;
|
||||||
prec = par->bits;
|
ap.msb = par->msb;
|
||||||
sio_sun_enctoinfo(hdl, &enc, par);
|
ap.rate = par->rate;
|
||||||
for (i = 0;; i++) {
|
if (hdl->sio.mode & SIO_PLAY)
|
||||||
if (i == NRETRIES) {
|
ap.pchan = par->pchan;
|
||||||
DPRINTF("sio_sun_setpar: couldn't set parameters\n");
|
if (hdl->sio.mode & SIO_REC)
|
||||||
hdl->sio.eof = 1;
|
ap.rchan = par->rchan;
|
||||||
return 0;
|
if (par->round != ~0U && par->appbufsz != ~0U) {
|
||||||
}
|
ap.round = par->round;
|
||||||
AUDIO_INITINFO(&aui);
|
ap.nblks = par->appbufsz / par->round;
|
||||||
if (hdl->sio.mode & SIO_PLAY) {
|
} else if (par->round != ~0U) {
|
||||||
aui.play.sample_rate = rate;
|
ap.round = par->round;
|
||||||
aui.play.precision = prec;
|
ap.nblks = 2;
|
||||||
aui.play.encoding = enc;
|
} else if (par->appbufsz != ~0U) {
|
||||||
aui.play.channels = par->pchan;
|
ap.round = par->appbufsz / 2;
|
||||||
}
|
ap.nblks = 2;
|
||||||
if (hdl->sio.mode & SIO_REC) {
|
|
||||||
aui.record.sample_rate = rate;
|
|
||||||
aui.record.precision = prec;
|
|
||||||
aui.record.encoding = enc;
|
|
||||||
aui.record.channels = par->rchan;
|
|
||||||
}
|
|
||||||
DPRINTFN(2, "sio_sun_setpar: %i: trying pars = %u/%u/%u\n",
|
|
||||||
i, rate, prec, enc);
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 &&
|
|
||||||
errno != EINVAL) {
|
|
||||||
DPERROR("sio_sun_setpar: setinfo(pars)");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_setpar: getinfo(pars)");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
enc = (hdl->sio.mode & SIO_REC) ?
|
|
||||||
aui.record.encoding : aui.play.encoding;
|
|
||||||
switch (enc) {
|
|
||||||
case AUDIO_ENCODING_SLINEAR_LE:
|
|
||||||
case AUDIO_ENCODING_SLINEAR_BE:
|
|
||||||
case AUDIO_ENCODING_ULINEAR_LE:
|
|
||||||
case AUDIO_ENCODING_ULINEAR_BE:
|
|
||||||
case AUDIO_ENCODING_SLINEAR:
|
|
||||||
case AUDIO_ENCODING_ULINEAR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DPRINTF("sio_sun_setpar: couldn't find encoding\n");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (hdl->sio.mode != (SIO_REC | SIO_PLAY))
|
|
||||||
break;
|
|
||||||
if (aui.play.sample_rate == aui.record.sample_rate &&
|
|
||||||
aui.play.precision == aui.record.precision &&
|
|
||||||
aui.play.encoding == aui.record.encoding)
|
|
||||||
break;
|
|
||||||
if (i < NRETRIES / 2) {
|
|
||||||
rate = aui.play.sample_rate;
|
|
||||||
prec = aui.play.precision;
|
|
||||||
enc = aui.play.encoding;
|
|
||||||
} else {
|
|
||||||
rate = aui.record.sample_rate;
|
|
||||||
prec = aui.record.precision;
|
|
||||||
enc = aui.record.encoding;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (ioctl(hdl->fd, AUDIO_SETPAR, &ap) < 0) {
|
||||||
/*
|
DPERROR("AUDIO_SETPAR");
|
||||||
* If the rate that the hardware is using is different than
|
|
||||||
* the requested rate, scale buffer sizes so they will be the
|
|
||||||
* same time duration as what was requested. This just gets
|
|
||||||
* the rates to use for scaling, that actual scaling is done
|
|
||||||
* later.
|
|
||||||
*/
|
|
||||||
rate = (hdl->sio.mode & SIO_REC) ? aui.record.sample_rate :
|
|
||||||
aui.play.sample_rate;
|
|
||||||
req_rate = rate;
|
|
||||||
if (par->rate && par->rate != ~0U)
|
|
||||||
req_rate = par->rate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if block size and buffer size are not both set then
|
|
||||||
* set the blocksize to half the buffer size
|
|
||||||
*/
|
|
||||||
bufsz = par->appbufsz;
|
|
||||||
round = par->round;
|
|
||||||
if (bufsz != ~0U) {
|
|
||||||
bufsz = bufsz * rate / req_rate;
|
|
||||||
if (round == ~0U)
|
|
||||||
round = (bufsz + 1) / 2;
|
|
||||||
else
|
|
||||||
round = round * rate / req_rate;
|
|
||||||
} else if (round != ~0U) {
|
|
||||||
round = round * rate / req_rate;
|
|
||||||
bufsz = round * 2;
|
|
||||||
} else
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get the play/record frame size in bytes
|
|
||||||
*/
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_setpar: GETINFO");
|
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ibpf = (hdl->sio.mode & SIO_REC) ?
|
return 1;
|
||||||
aui.record.channels * aui.record.bps : 1;
|
|
||||||
obpf = (hdl->sio.mode & SIO_PLAY) ?
|
|
||||||
aui.play.channels * aui.play.bps : 1;
|
|
||||||
|
|
||||||
DPRINTFN(2, "sio_sun_setpar: bpf = (%u, %u)\n", ibpf, obpf);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to set parameters until the device accepts
|
|
||||||
* a common block size for play and record
|
|
||||||
*/
|
|
||||||
for (i = 0; i < NRETRIES; i++) {
|
|
||||||
AUDIO_INITINFO(&aui);
|
|
||||||
aui.hiwat = (bufsz + round - 1) / round;
|
|
||||||
aui.lowat = aui.hiwat;
|
|
||||||
if (hdl->sio.mode & SIO_REC)
|
|
||||||
aui.record.block_size = round * ibpf;
|
|
||||||
if (hdl->sio.mode & SIO_PLAY)
|
|
||||||
aui.play.block_size = round * obpf;
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_setpar2: SETINFO");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_setpar2: GETINFO");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
infr = aui.record.block_size / ibpf;
|
|
||||||
onfr = aui.play.block_size / obpf;
|
|
||||||
DPRINTFN(2, "sio_sun_setpar: %i: round = %u -> (%u, %u)\n",
|
|
||||||
i, round, infr, onfr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if half-duplex or both block sizes match, we're done
|
|
||||||
*/
|
|
||||||
if (hdl->sio.mode != (SIO_REC | SIO_PLAY) || infr == onfr) {
|
|
||||||
DPRINTFN(2, "sio_sun_setpar: blocksize ok\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* half of the retries, retry with the smaller value,
|
|
||||||
* then with the larger returned value
|
|
||||||
*/
|
|
||||||
if (i < NRETRIES / 2)
|
|
||||||
round = infr < onfr ? infr : onfr;
|
|
||||||
else
|
|
||||||
round = infr < onfr ? onfr : infr;
|
|
||||||
}
|
|
||||||
DPRINTFN(2, "sio_sun_setpar: couldn't find a working blocksize\n");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
#undef NRETRIES
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sio_sun_getpar(struct sio_hdl *sh, struct sio_par *par)
|
sio_sun_getpar(struct sio_hdl *sh, struct sio_par *par)
|
||||||
{
|
{
|
||||||
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
|
||||||
struct audio_info aui;
|
struct audio_swpar ap;
|
||||||
|
|
||||||
if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
|
if (ioctl(hdl->fd, AUDIO_GETPAR, &ap) < 0) {
|
||||||
DPERROR("sio_sun_getpar: getinfo");
|
DPERROR("AUDIO_GETPAR");
|
||||||
hdl->sio.eof = 1;
|
hdl->sio.eof = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (hdl->sio.mode & SIO_PLAY) {
|
par->sig = ap.sig;
|
||||||
par->rate = aui.play.sample_rate;
|
par->le = ap.le;
|
||||||
if (!sio_sun_infotoenc(hdl, &aui.play, par))
|
par->bits = ap.bits;
|
||||||
return 0;
|
par->bps = ap.bps;
|
||||||
} else if (hdl->sio.mode & SIO_REC) {
|
par->msb = ap.msb;
|
||||||
par->rate = aui.record.sample_rate;
|
par->rate = ap.rate;
|
||||||
if (!sio_sun_infotoenc(hdl, &aui.record, par))
|
par->pchan = ap.pchan;
|
||||||
return 0;
|
par->rchan = ap.rchan;
|
||||||
} else
|
par->round = ap.round;
|
||||||
return 0;
|
par->appbufsz = par->bufsz = ap.nblks * ap.round;
|
||||||
par->pchan = (hdl->sio.mode & SIO_PLAY) ?
|
|
||||||
aui.play.channels : 0;
|
|
||||||
par->rchan = (hdl->sio.mode & SIO_REC) ?
|
|
||||||
aui.record.channels : 0;
|
|
||||||
par->round = (hdl->sio.mode & SIO_REC) ?
|
|
||||||
aui.record.block_size / (par->bps * par->rchan) :
|
|
||||||
aui.play.block_size / (par->bps * par->pchan);
|
|
||||||
par->appbufsz = aui.hiwat * par->round;
|
|
||||||
par->bufsz = par->appbufsz;
|
|
||||||
par->xrun = SIO_IGNORE;
|
par->xrun = SIO_IGNORE;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -756,38 +489,6 @@ sio_sun_read(struct sio_hdl *sh, void *buf, size_t len)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
|
||||||
sio_sun_autostart(struct sio_sun_hdl *hdl)
|
|
||||||
{
|
|
||||||
struct audio_info aui;
|
|
||||||
struct pollfd pfd;
|
|
||||||
|
|
||||||
pfd.fd = hdl->fd;
|
|
||||||
pfd.events = POLLOUT;
|
|
||||||
while (poll(&pfd, 1, 0) < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
DPERROR("sio_sun_autostart: poll");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!(pfd.revents & POLLOUT)) {
|
|
||||||
hdl->filling = 0;
|
|
||||||
AUDIO_INITINFO(&aui);
|
|
||||||
if (hdl->sio.mode & SIO_PLAY)
|
|
||||||
aui.play.pause = 0;
|
|
||||||
if (hdl->sio.mode & SIO_REC)
|
|
||||||
aui.record.pause = 0;
|
|
||||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
|
|
||||||
DPERROR("sio_sun_autostart: setinfo");
|
|
||||||
hdl->sio.eof = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_sio_onmove_cb(&hdl->sio, 0);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len)
|
sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -805,10 +506,6 @@ sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (hdl->filling) {
|
|
||||||
if (!sio_sun_autostart(hdl))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,6 +522,15 @@ sio_sun_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
|
||||||
|
|
||||||
pfd->fd = hdl->fd;
|
pfd->fd = hdl->fd;
|
||||||
pfd->events = events;
|
pfd->events = events;
|
||||||
|
if (hdl->filltodo > 0 && hdl->sio.wused == hdl->filltodo) {
|
||||||
|
hdl->filltodo = 0;
|
||||||
|
if (ioctl(hdl->fd, AUDIO_START) < 0) {
|
||||||
|
DPERROR("AUDIO_START");
|
||||||
|
hdl->sio.eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_sio_onmove_cb(&hdl->sio, 0);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,7 +542,8 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
||||||
int dierr = 0, doerr = 0, offset, delta;
|
int dierr = 0, doerr = 0, offset, delta;
|
||||||
int revents = pfd->revents;
|
int revents = pfd->revents;
|
||||||
|
|
||||||
if (!hdl->sio.started)
|
if ((pfd->revents & POLLHUP) ||
|
||||||
|
(pfd->revents & (POLLIN | POLLOUT)) == 0)
|
||||||
return pfd->revents;
|
return pfd->revents;
|
||||||
if (ioctl(hdl->fd, AUDIO_GETPOS, &ap) < 0) {
|
if (ioctl(hdl->fd, AUDIO_GETPOS, &ap) < 0) {
|
||||||
DPERROR("sio_sun_revents: GETPOS");
|
DPERROR("sio_sun_revents: GETPOS");
|
||||||
|
@ -894,9 +601,6 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
||||||
hdl->idelta -= delta;
|
hdl->idelta -= delta;
|
||||||
hdl->odelta -= delta;
|
hdl->odelta -= delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdl->filling)
|
|
||||||
revents |= POLLOUT; /* XXX: is this necessary ? */
|
|
||||||
return revents;
|
return revents;
|
||||||
}
|
}
|
||||||
#endif /* defined USE_SUN */
|
#endif /* defined USE_SUN */
|
||||||
|
|
Loading…
Reference in New Issue