summaryrefslogtreecommitdiffstats
path: root/lib/libsndio
diff options
context:
space:
mode:
authorratchov <ratchov@openbsd.org>2009-10-10 08:34:12 +0000
committerratchov <ratchov@openbsd.org>2009-10-10 08:34:12 +0000
commit7a5ff78ab741d11becb401fb3a19a54e2237ea69 (patch)
treeb61ea1c9e3b0cb5327e5eb75946e313881c0ca86 /lib/libsndio
parentAgain, in detatch... call whatever disconnects our interrupt, before we (diff)
downloadwireguard-openbsd-7a5ff78ab741d11becb401fb3a19a54e2237ea69.tar.xz
wireguard-openbsd-7a5ff78ab741d11becb401fb3a19a54e2237ea69.zip
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);
/*