diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2009-10-10 08:34:13 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2009-10-10 08:34:13 +0000 |
commit | 43f7b8ac4ce917215ef14cfee8b9eaad1278bac7 (patch) | |
tree | 84f7035632f521fdf7c542359889f55ee6ef1dec /lib/libsndio | |
parent | 29e527d288ae70e161ddb8d09e8993198cd6224d (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.c | 83 |
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); /* |