summaryrefslogtreecommitdiff
path: root/lib/libsndio
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2009-10-10 08:34:13 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2009-10-10 08:34:13 +0000
commit43f7b8ac4ce917215ef14cfee8b9eaad1278bac7 (patch)
tree84f7035632f521fdf7c542359889f55ee6ef1dec /lib/libsndio
parent29e527d288ae70e161ddb8d09e8993198cd6224d (diff)
since AUDIO_INITINFO() may set parameters to whatever is supported
by the device, we may end up with different recording and playback parameters, which will break almost all full duplex apps on such devices. For instance, this should fix full-duplex apps not working on devices that can record at any sample rate but can play at 48kHz only.
Diffstat (limited to 'lib/libsndio')
-rw-r--r--lib/libsndio/sun.c83
1 files changed, 59 insertions, 24 deletions
diff --git a/lib/libsndio/sun.c b/lib/libsndio/sun.c
index c15d1a67fc9..192b8449348 100644
--- a/lib/libsndio/sun.c
+++ b/lib/libsndio/sun.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sun.c,v 1.21 2009/07/26 15:50:04 ratchov Exp $ */
+/* $OpenBSD: sun.c,v 1.22 2009/10/10 08:34:12 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -128,18 +128,17 @@ sun_infotoenc(struct sun_hdl *hdl, struct audio_prinfo *ai, struct sio_par *par)
* convert sio_par encoding to sun encoding
*/
static void
-sun_enctoinfo(struct sun_hdl *hdl, struct audio_prinfo *ai, struct sio_par *par)
+sun_enctoinfo(struct sun_hdl *hdl, unsigned *renc, struct sio_par *par)
{
if (par->le && par->sig) {
- ai->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ *renc = AUDIO_ENCODING_SLINEAR_LE;
} else if (!par->le && par->sig) {
- ai->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ *renc = AUDIO_ENCODING_SLINEAR_BE;
} else if (par->le && !par->sig) {
- ai->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ *renc = AUDIO_ENCODING_ULINEAR_LE;
} else {
- ai->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ *renc = AUDIO_ENCODING_ULINEAR_BE;
}
- ai->precision = par->bits;
}
/*
@@ -520,25 +519,61 @@ sun_setpar(struct sio_hdl *sh, struct sio_par *par)
struct audio_info aui;
unsigned i, infr, ibpf, onfr, obpf;
unsigned bufsz, round;
+ unsigned rate, prec, enc;
/*
- * first, set encoding, rate and channels
+ * try to set parameters until the device accepts
+ * a common encoding and rate for play and record
*/
- AUDIO_INITINFO(&aui);
- if (hdl->sio.mode & SIO_PLAY) {
- aui.play.sample_rate = par->rate;
- aui.play.channels = par->pchan;
- sun_enctoinfo(hdl, &aui.play, par);
- }
- if (hdl->sio.mode & SIO_REC) {
- aui.record.sample_rate = par->rate;
- aui.record.channels = par->rchan;
- sun_enctoinfo(hdl, &aui.record, par);
- }
- if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) {
- DPERROR("sun_setpar: setinfo");
- hdl->sio.eof = 1;
- return 0;
+ rate = par->rate;
+ prec = par->bits;
+ sun_enctoinfo(hdl, &enc, par);
+ for (i = 0;; i++) {
+ if (i == NRETRIES) {
+ DPRINTF("sun_setpar: couldn't set parameters\n");
+ hdl->sio.eof = 1;
+ return 0;
+ }
+ AUDIO_INITINFO(&aui);
+ if (hdl->sio.mode & SIO_PLAY) {
+ aui.play.sample_rate = rate;
+ aui.play.precision = prec;
+ aui.play.encoding = enc;
+ aui.play.channels = par->pchan;
+ }
+ if (hdl->sio.mode & SIO_REC) {
+ aui.record.sample_rate = rate;
+ aui.record.precision = prec;
+ aui.record.encoding = enc;
+ aui.record.channels = par->rchan;
+ }
+ DPRINTF("sun_setpar: %i: trying pars = %u/%u/%u\n",
+ i, rate, prec, enc);
+ if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) {
+ DPERROR("sun_setpar: setinfo(pars)");
+ hdl->sio.eof = 1;
+ return 0;
+ }
+ if (hdl->sio.mode != (SIO_REC | SIO_PLAY))
+ break;
+ if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
+ DPERROR("sun_setpar: getinfo(pars)");
+ hdl->sio.eof = 1;
+ return 0;
+ }
+ 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;
+ }
}
/*
@@ -595,7 +630,7 @@ sun_setpar(struct sio_hdl *sh, struct sio_par *par)
}
infr = aui.record.block_size / ibpf;
onfr = aui.play.block_size / obpf;
- DPRINTF("sun_setpar: %i: trying rond = %u -> (%u, %u)\n",
+ DPRINTF("sun_setpar: %i: trying round = %u -> (%u, %u)\n",
i, round, infr, onfr);
/*