commit 35a334b

hovercats  ·  2026-01-22 02:58:24 +0000 UTC
parent 994ffce
sndio: import
10 files changed,  +1464, -0
+4, -0
1@@ -338,3 +338,7 @@
2 	path = pkg/hevel/src
3 	url = https://git.sr.ht/~dlm/hevel
4 	ignore = all
5+[submodule "pkg/sndio/src"]
6+	path = pkg/sndio/src
7+	url = https://caoua.org/git/sndio
8+	ignore =  all
+1, -0
1@@ -93,6 +93,7 @@ subgen 'scdoc'
2 subgen 'sdhcp'
3 subgen 'skeleton'
4 subgen 'smu'
5+subgen 'sndio'
6 subgen 'squashfs-tools-ng'
7 subgen 'st'
8 subgen 'strace'
+5, -0
1@@ -0,0 +1,5 @@
2+#define HAVE_ISSETUGID 1
3+#define HAVE_STRLCAT 1
4+#define HAVE_STRLCPY 1
5+#define HAVE_CLOCK_GETTIME 1
6+#define HAVE_SOCK_CLOEXEC 1
+56, -0
 1@@ -0,0 +1,56 @@
 2+cflags{
 3+	'-std=c99', '-Wall', '-Wpedantic',
 4+	'-Wno-format-truncation', '-Wno-maybe-uninitialized',
 5+	'-D _GNU_SOURCE',
 6+	'-I $srcdir/libsndio',
 7+	'-I $srcdir/bsd-compat',
 8+	'-isystem $builddir/pkg/tinyalsa/include',
 9+	'-include $dir/config.h',
10+}
11+
12+pkg.deps = {
13+	'pkg/tinyalsa/headers',
14+}
15+pkg.hdrs = copy('$outdir/include', '$srcdir/libsndio', {'sndio.h'})
16+
17+-- everything but mio.c and sio.c
18+local objs = objects[[
19+	libsndio/(
20+		debug.c aucat.c
21+		mio.c mio_aucat.c
22+		sio_aucat.c
23+		sioctl.c sioctl_aucat.c
24+	)
25+	bsd-compat/(getpeereid.c issetugid.c strlcat.c strlcpy.c strtonum.c clock_gettime.c)
26+	$builddir/pkg/tinyalsa/libtinyalsa.a
27+]]
28+
29+-- build mio.c and sio.c for sndiod with alsa support
30+for _, src in ipairs{'sio.c', 'sio_alsa.c'} do
31+	build('cc', '$outdir/sndiod/'..src..'.o', {'$srcdir/libsndio/'..src, '||', '$gendir/deps'}, {
32+		cflags='$cflags -D USE_ALSA',
33+	})
34+end
35+lib('libsndio.a', {objs, 'libsndio/sio.c'})
36+
37+exe('bin/sndiod', {objs, paths[[
38+	sndiod/(
39+		abuf.c utils.c dev.c dev_sioctl.c dsp.c file.c listen.c midi.c miofile.c
40+		opt.c siofile.c sndiod.c sock.c
41+
42+		sio.c.o sio_alsa.c.o
43+	)
44+	$builddir/pkg/tinyalsa/libtinyalsa.a
45+]]})
46+file('bin/sndiod', '755', '$outdir/bin/sndiod')
47+man{'sndiod/sndiod.8'}
48+
49+exe('bin/sndioctl', 'sndioctl/sndioctl.c libsndio.a')
50+file('bin/sndioctl', '755', '$outdir/bin/sndioctl')
51+man{'sndioctl/sndioctl.1'}
52+
53+exe('bin/aucat', 'aucat/(abuf.c afile.c aucat.c dsp.c utils.c) libsndio.a')
54+file('bin/aucat', '755', '$outdir/bin/aucat')
55+man{'aucat/aucat.1'}
56+
57+fetch 'git'
+58, -0
 1@@ -0,0 +1,58 @@
 2+From 4ee56f07ef8be718bb1f24f5b73c440527c93bc9 Mon Sep 17 00:00:00 2001
 3+From: Michael Forney <mforney@mforney.org>
 4+Date: Thu, 5 Nov 2020 00:28:06 -0800
 5+Subject: [PATCH] sndiod: Fix build without DEBUG
 6+
 7+---
 8+ aucat/afile.c   | 4 ++--
 9+ sndiod/listen.c | 4 ++++
10+ 2 files changed, 6 insertions(+), 2 deletions(-)
11+
12+diff --git a/aucat/afile.c b/aucat/afile.c
13+index b880878..3e400ce 100644
14+--- a/aucat/afile.c
15++++ b/aucat/afile.c
16+@@ -743,13 +743,13 @@ afile_au_writehdr(struct afile *f)
17+ 	case 32:
18+ 		fmt = AU_FMT_PCM32;
19+ 		break;
20+-#ifdef DEBUG
21+ 	default:
22++#ifdef DEBUG
23+ 		log_puts(f->path);
24+ 		log_puts(": wrong precision\n");
25+ 		panic();
26+-		return 0;
27+ #endif
28++		return 0;
29+ 	}
30+ 	be32_set(&hdr.fmt, fmt);
31+ 	be32_set(&hdr.rate, f->rate);
32+diff --git a/sndiod/listen.c b/sndiod/listen.c
33+index 54c9684..c87f600 100644
34+--- a/sndiod/listen.c
35++++ b/sndiod/listen.c
36+@@ -254,16 +254,20 @@ listen_in(void *arg)
37+ 		return;
38+ 	}
39+ 	if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
40++#ifdef DEBUG
41+ 		file_log(f->file);
42+ 		log_puts(": failed to set non-blocking mode\n");
43++#endif
44+ 		goto bad_close;
45+ 	}
46+ 	if (f->path == NULL) {
47+ 		opt = 1;
48+ 		if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
49+ 		    &opt, sizeof(int)) == -1) {
50++#ifdef DEBUG
51+ 			file_log(f->file);
52+ 			log_puts(": failed to set TCP_NODELAY flag\n");
53++#endif
54+ 			goto bad_close;
55+ 		}
56+ 	}
57+-- 
58+2.29.2
59+
+26, -0
 1@@ -0,0 +1,26 @@
 2+From 7c55a1db6eb0334e3e5902cb52272abd668019df Mon Sep 17 00:00:00 2001
 3+From: Michael Forney <mforney@mforney.org>
 4+Date: Thu, 5 Nov 2020 00:58:34 -0800
 5+Subject: [PATCH] aucat: Use unsigned char for wav_guid to prevent overflow
 6+
 7+0x80 is not representable as char.
 8+---
 9+ aucat/afile.c | 2 +-
10+ 1 file changed, 1 insertion(+), 1 deletion(-)
11+
12+diff --git a/aucat/afile.c b/aucat/afile.c
13+index fce69f3..1a37463 100644
14+--- a/aucat/afile.c
15++++ b/aucat/afile.c
16+@@ -135,7 +135,7 @@ const char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
17+ const char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
18+ const char wav_id_data[4] = {'d', 'a', 't', 'a'};
19+ const char wav_id_fmt[4] = {'f', 'm', 't', ' '};
20+-const char wav_guid[14] = {
21++const unsigned char wav_guid[14] = {
22+ 	0x00, 0x00, 0x00, 0x00,
23+ 	0x10, 0x00, 0x80, 0x00,
24+ 	0x00, 0xAA, 0x00, 0x38,
25+-- 
26+2.30.0
27+
+1171, -0
   1@@ -0,0 +1,1171 @@
   2+From 39ec20119841c84500e589fee15c10e9fe6c0c97 Mon Sep 17 00:00:00 2001
   3+From: Michael Forney <mforney@mforney.org>
   4+Date: Tue, 31 Aug 2021 14:30:07 -0700
   5+Subject: [PATCH] alsa: Port to tinyalsa
   6+
   7+---
   8+ libsndio/debug.c    |   2 +-
   9+ libsndio/sio_alsa.c | 747 +++++++++++++++-----------------------------
  10+ 2 files changed, 247 insertions(+), 502 deletions(-)
  11+
  12+diff --git a/libsndio/debug.c b/libsndio/debug.c
  13+index 304975a..40fdc92 100644
  14+--- a/libsndio/debug.c
  15++++ b/libsndio/debug.c
  16+@@ -35,7 +35,7 @@ _sndio_debug_init(void)
  17+ 
  18+ 	if (_sndio_debug < 0) {
  19+ 		dbg = issetugid() ? NULL : getenv("SNDIO_DEBUG");
  20+-		if (!dbg || sscanf(dbg, "%u", &_sndio_debug) != 1)
  21++		if (!dbg || sscanf(dbg, "%d", &_sndio_debug) != 1)
  22+ 			_sndio_debug = 0;
  23+ 	}
  24+ }
  25+diff --git a/libsndio/sio_alsa.c b/libsndio/sio_alsa.c
  26+index 6107617..e460bf6 100644
  27+--- a/libsndio/sio_alsa.c
  28++++ b/libsndio/sio_alsa.c
  29+@@ -29,31 +29,28 @@
  30+ #include <string.h>
  31+ #include <unistd.h>
  32+ #include <values.h>
  33+-#include <alsa/asoundlib.h>
  34++#include <tinyalsa/asoundlib.h>
  35+ 
  36+ #include "debug.h"
  37+ #include "sio_priv.h"
  38+ #include "bsd-compat.h"
  39+ 
  40+-#define DEVNAME_PREFIX "hw:"
  41+-
  42+ #ifdef DEBUG
  43+-static snd_output_t *output = NULL;
  44+-#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
  45++#define DALSA(str, pcm) fprintf(stderr, "%s: %s\n", str, pcm_get_error(pcm))
  46+ #else
  47+-#define DALSA(str, err) do {} while (0)
  48++#define DALSA(str, pcm) do {} while (0)
  49+ #endif
  50+ 
  51+ struct sio_alsa_hdl {
  52+ 	struct sio_hdl sio;
  53+ 	struct sio_par par;
  54+-	char *devname;
  55+-	snd_pcm_t *opcm;
  56+-	snd_pcm_t *ipcm;
  57++	struct pcm_params *opar;
  58++	struct pcm_params *ipar;
  59++	struct pcm *opcm;
  60++	struct pcm *ipcm;
  61+ 	unsigned ibpf, obpf;		/* bytes per frame */
  62+ 	int iused, oused;		/* frames used in hardware fifos */
  63+ 	int idelta, odelta;		/* position reported to client */
  64+-	int nfds, infds, onfds;
  65+ 	int running;
  66+ 	int events;
  67+ 	int ipartial, opartial;
  68+@@ -102,90 +99,56 @@ static unsigned int cap_rates[] = {
  69+ 	 8000, 11025, 12000, 16000, 22050, 24000,
  70+ 	32000, 44100, 48000, 64000, 88200, 96000
  71+ };
  72+-static snd_pcm_format_t cap_fmts[] = {
  73++static enum pcm_format cap_fmts[] = {
  74+ 	/* XXX add s24le3 and s24be3 */
  75+-	SND_PCM_FORMAT_S32_LE,	SND_PCM_FORMAT_S32_BE,
  76+-	SND_PCM_FORMAT_S24_LE,	SND_PCM_FORMAT_S24_BE,
  77+-	SND_PCM_FORMAT_S16_LE,	SND_PCM_FORMAT_S16_BE,
  78+-	SND_PCM_FORMAT_U8
  79++	PCM_FORMAT_S32_LE,	PCM_FORMAT_S32_BE,
  80++	PCM_FORMAT_S24_LE,	PCM_FORMAT_S24_BE,
  81++	PCM_FORMAT_S16_LE,	PCM_FORMAT_S16_BE,
  82++	PCM_FORMAT_S8
  83+ };
  84+ 
  85+ /*
  86+  * convert ALSA format to sio_par encoding
  87+  */
  88+ static int
  89+-sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, snd_pcm_format_t fmt,
  90++sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, enum pcm_format fmt,
  91+     unsigned int *bits, unsigned int *sig, unsigned int *le)
  92+ {
  93+ 	switch (fmt) {
  94+-	case SND_PCM_FORMAT_U8:
  95+-		*bits = 8;
  96+-		*sig = 0;
  97+-		break;
  98+-	case SND_PCM_FORMAT_S8:
  99++	case PCM_FORMAT_S8:
 100+ 		*bits = 8;
 101+ 		*sig = 1;
 102+ 		break;
 103+-	case SND_PCM_FORMAT_S16_LE:
 104++	case PCM_FORMAT_S16_LE:
 105+ 		*bits = 16;
 106+ 		*sig = 1;
 107+ 		*le = 1;
 108+ 		break;
 109+-	case SND_PCM_FORMAT_S16_BE:
 110++	case PCM_FORMAT_S16_BE:
 111+ 		*bits = 16;
 112+ 		*sig = 1;
 113+ 		*le = 0;
 114+ 		break;
 115+-	case SND_PCM_FORMAT_U16_LE:
 116+-		*bits = 16;
 117+-		*sig = 0;
 118+-		*le = 1;
 119+-		break;
 120+-	case SND_PCM_FORMAT_U16_BE:
 121+-		*bits = 16;
 122+-		*sig = 0;
 123+-		*le = 0;
 124+-		break;
 125+-	case SND_PCM_FORMAT_S24_LE:
 126++	case PCM_FORMAT_S24_LE:
 127+ 		*bits = 24;
 128+ 		*sig = 1;
 129+ 		*le = 1;
 130+ 		break;
 131+-	case SND_PCM_FORMAT_S24_BE:
 132++	case PCM_FORMAT_S24_BE:
 133+ 		*bits = 24;
 134+ 		*sig = 1;
 135+ 		*le = 0;
 136+ 		break;
 137+-	case SND_PCM_FORMAT_U24_LE:
 138+-		*bits = 24;
 139+-		*sig = 0;
 140+-		*le = 1;
 141+-		break;
 142+-	case SND_PCM_FORMAT_U24_BE:
 143+-		*bits = 24;
 144+-		*sig = 0;
 145+-		*le = 0;
 146+-		break;
 147+-	case SND_PCM_FORMAT_S32_LE:
 148++	case PCM_FORMAT_S32_LE:
 149+ 		*bits = 32;
 150+ 		*sig = 1;
 151+ 		*le = 1;
 152+ 		break;
 153+-	case SND_PCM_FORMAT_S32_BE:
 154++	case PCM_FORMAT_S32_BE:
 155+ 		*bits = 32;
 156+ 		*sig = 1;
 157+ 		*le = 0;
 158+ 		break;
 159+-	case SND_PCM_FORMAT_U32_LE:
 160+-		*bits = 32;
 161+-		*sig = 0;
 162+-		*le = 1;
 163+-		break;
 164+-	case SND_PCM_FORMAT_U32_BE:
 165+-		*bits = 32;
 166+-		*sig = 0;
 167+-		*le = 0;
 168+-		break;
 169+ 	default:
 170+ 		DPRINTF("sio_alsa_fmttopar: 0x%x: unsupported format\n", fmt);
 171+ 		hdl->sio.eof = 1;
 172+@@ -199,78 +162,19 @@ sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, snd_pcm_format_t fmt,
 173+  * convert sio_par encoding to ALSA format
 174+  */
 175+ static void
 176+-sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, snd_pcm_format_t *rfmt,
 177++sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, enum pcm_format *rfmt,
 178+     unsigned int bits, unsigned int sig, unsigned int le)
 179+ {
 180+-	if (bits == 8) {
 181+-		if (sig == ~0U || !sig)
 182+-			*rfmt = SND_PCM_FORMAT_U8;
 183+-		else
 184+-			*rfmt = SND_PCM_FORMAT_S8;
 185+-	} else if (bits == 16) {
 186+-		if (sig == ~0U || sig) {
 187+-			if (le == ~0U) {
 188+-				*rfmt = SIO_LE_NATIVE ?
 189+-				    SND_PCM_FORMAT_S16_LE :
 190+-				    SND_PCM_FORMAT_S16_BE;
 191+-			} else if (le)
 192+-				*rfmt = SND_PCM_FORMAT_S16_LE;
 193+-			else
 194+-				*rfmt = SND_PCM_FORMAT_S16_BE;
 195+-		} else {
 196+-			if (le == ~0U) {
 197+-				*rfmt = SIO_LE_NATIVE ?
 198+-				    SND_PCM_FORMAT_U16_LE :
 199+-				    SND_PCM_FORMAT_U16_BE;
 200+-			} else if (le)
 201+-				*rfmt = SND_PCM_FORMAT_U16_LE;
 202+-			else
 203+-				*rfmt = SND_PCM_FORMAT_U16_BE;
 204+-		}
 205+-	} else if (bits == 24) {
 206+-		if (sig == ~0U || sig) {
 207+-			if (le == ~0U) {
 208+-				*rfmt = SIO_LE_NATIVE ?
 209+-				    SND_PCM_FORMAT_S24_LE :
 210+-				    SND_PCM_FORMAT_S24_BE;
 211+-			 } else if (le)
 212+-				*rfmt = SND_PCM_FORMAT_S24_LE;
 213+-			else
 214+-				*rfmt = SND_PCM_FORMAT_S24_BE;
 215+-		} else {
 216+-			if (le == ~0U) {
 217+-				*rfmt = SIO_LE_NATIVE ?
 218+-				    SND_PCM_FORMAT_U24_LE :
 219+-				    SND_PCM_FORMAT_U24_BE;
 220+-			} else if (le)
 221+-				*rfmt = SND_PCM_FORMAT_U24_LE;
 222+-			else
 223+-				*rfmt = SND_PCM_FORMAT_U24_BE;
 224+-		}
 225+-	} else if (bits == 32) {
 226+-		if (sig == ~0U || sig) {
 227+-			if (le == ~0U) {
 228+-				*rfmt = SIO_LE_NATIVE ?
 229+-				    SND_PCM_FORMAT_S32_LE :
 230+-				    SND_PCM_FORMAT_S32_BE;
 231+-			 } else if (le)
 232+-				*rfmt = SND_PCM_FORMAT_S32_LE;
 233+-			else
 234+-				*rfmt = SND_PCM_FORMAT_S32_BE;
 235+-		} else {
 236+-			if (le == ~0U) {
 237+-				*rfmt = SIO_LE_NATIVE ?
 238+-				    SND_PCM_FORMAT_U32_LE :
 239+-				    SND_PCM_FORMAT_U32_BE;
 240+-			} else if (le)
 241+-				*rfmt = SND_PCM_FORMAT_U32_LE;
 242+-			else
 243+-				*rfmt = SND_PCM_FORMAT_U32_BE;
 244+-		}
 245+-	} else {
 246+-		*rfmt = SIO_LE_NATIVE ?
 247+-		    SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S16_BE;
 248+-	}
 249++	if (le == ~0U)
 250++		le = SIO_LE_NATIVE;
 251++	if (bits == 8)
 252++		*rfmt = PCM_FORMAT_S8;
 253++	else if (bits == 24)
 254++		*rfmt = le ? PCM_FORMAT_S24_LE : PCM_FORMAT_S24_BE;
 255++	else if (bits == 32)
 256++		*rfmt = le ? PCM_FORMAT_S32_LE : PCM_FORMAT_S32_BE;
 257++	else
 258++		*rfmt = le ? PCM_FORMAT_S16_LE : PCM_FORMAT_S16_BE;
 259+ }
 260+ 
 261+ struct sio_hdl *
 262+@@ -279,8 +183,7 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
 263+ 	const char *p;
 264+ 	struct sio_alsa_hdl *hdl;
 265+ 	struct sio_par par;
 266+-	size_t len;
 267+-	int err;
 268++	unsigned card, dev;
 269+ 
 270+ 	p = _sndio_parsetype(str, "rsnd");
 271+ 	if (p == NULL) {
 272+@@ -300,42 +203,45 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
 273+ 		return NULL;
 274+ 	_sio_create(&hdl->sio, &sio_alsa_ops, mode, nbio);
 275+ 
 276+-#ifdef DEBUG
 277+-	err = snd_output_stdio_attach(&output, stderr, 0);
 278+-	if (err < 0)
 279+-		DALSA("couldn't attach to stderr", err);
 280+-#endif
 281+-	if (strcmp(p, "default") == 0)
 282+-		p = "0";
 283+-	len = strlen(p);
 284+-	hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
 285+-	if (hdl->devname == NULL)
 286+-		goto bad_free_hdl;
 287+-	memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1);
 288+-	memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, p, len + 1);
 289++	if (strcmp(p, "default") == 0) {
 290++		card = 0;
 291++		dev = 0;
 292++	} else {
 293++		switch (sscanf(p, "%u,%u", &card, &dev)) {
 294++		case 1:
 295++			dev = 0;
 296++			break;
 297++		case 2:
 298++			break;
 299++		default:
 300++			DPRINTF("invalid device name\n");
 301++		}
 302++	}
 303+ 	if (mode & SIO_PLAY) {
 304+-		err = snd_pcm_open(&hdl->opcm, hdl->devname,
 305+-		    SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
 306+-		if (err < 0) {
 307+-			DALSA("couldn't open play stream", err);
 308+-			goto bad_free;
 309++		hdl->opar = pcm_params_get(card, dev, PCM_OUT);
 310++		if (hdl->opar == NULL) {
 311++			DPRINTF("couldn't get play params\n");
 312++			goto bad_free_hdl;
 313++		}
 314++		hdl->opcm = pcm_open(card, dev, PCM_OUT | PCM_NONBLOCK, NULL);
 315++		if (!pcm_is_ready(hdl->opcm)) {
 316++			DALSA("couldn't open play stream", hdl->opcm);
 317++			goto bad_free_opar;
 318+ 		}
 319+ 	}
 320+ 	if (mode & SIO_REC) {
 321+-		err = snd_pcm_open(&hdl->ipcm, hdl->devname,
 322+-		    SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
 323+-		if (err < 0) {
 324+-			DALSA("couldn't open rec stream", err);
 325++		hdl->ipar = pcm_params_get(card, dev, PCM_IN);
 326++		if (hdl->ipar == NULL) {
 327++			DPRINTF("couldn't get rec params\n");
 328+ 			goto bad_free_opcm;
 329+ 		}
 330++		hdl->ipcm = pcm_open(card, dev, PCM_IN | PCM_NONBLOCK, NULL);
 331++		if (!pcm_is_ready(hdl->ipcm)) {
 332++			DALSA("couldn't open rec stream", hdl->ipcm);
 333++			goto bad_free_ipar;
 334++		}
 335+ 	}
 336+ 
 337+-	/*
 338+-	 * snd_pcm_poll_descriptors_count returns a small value
 339+-	 * that grows later, after the stream is started
 340+-	 */
 341+-	hdl->nfds = SIO_MAXNFDS;
 342+-
 343+ 	/*
 344+ 	 * Default parameters may not be compatible with libsndio (eg. mulaw
 345+ 	 * encodings, different playback and recording parameters, etc...), so
 346+@@ -356,12 +262,16 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
 347+ 	return (struct sio_hdl *)hdl;
 348+ bad_free_ipcm:
 349+ 	if (mode & SIO_REC)
 350+-		snd_pcm_close(hdl->ipcm);
 351++		pcm_close(hdl->ipcm);
 352++bad_free_ipar:
 353++	if (mode & SIO_REC)
 354++		free(hdl->ipar);
 355+ bad_free_opcm:
 356+ 	if (mode & SIO_PLAY)
 357+-		snd_pcm_close(hdl->opcm);
 358+-bad_free:
 359+-	free(hdl->devname);
 360++		pcm_close(hdl->opcm);
 361++bad_free_opar:
 362++	if (mode & SIO_PLAY)
 363++		free(hdl->opar);
 364+ bad_free_hdl:
 365+ 	free(hdl);
 366+ 	return NULL;
 367+@@ -372,11 +282,14 @@ sio_alsa_close(struct sio_hdl *sh)
 368+ {
 369+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 370+ 
 371+-	if (hdl->sio.mode & SIO_PLAY)
 372+-		snd_pcm_close(hdl->opcm);
 373+-	if (hdl->sio.mode & SIO_REC)
 374+-		snd_pcm_close(hdl->ipcm);
 375+-	free(hdl->devname);
 376++	if (hdl->sio.mode & SIO_PLAY) {
 377++		free(hdl->opar);
 378++		pcm_close(hdl->opcm);
 379++	}
 380++	if (hdl->sio.mode & SIO_REC) {
 381++		free(hdl->ipar);
 382++		pcm_close(hdl->ipcm);
 383++	}
 384+ 	free(hdl);
 385+ }
 386+ 
 387+@@ -394,14 +307,12 @@ sio_alsa_start(struct sio_hdl *sh)
 388+ 	hdl->oused = 0;
 389+ 	hdl->idelta = 0;
 390+ 	hdl->odelta = 0;
 391+-	hdl->infds = 0;
 392+-	hdl->onfds = 0;
 393+ 	hdl->running = 0;
 394+ 
 395+ 	if (hdl->sio.mode & SIO_PLAY) {
 396+-		err = snd_pcm_prepare(hdl->opcm);
 397++		err = pcm_prepare(hdl->opcm);
 398+ 		if (err < 0) {
 399+-			DALSA("couldn't prepare play stream", err);
 400++			DALSA("couldn't prepare play stream", hdl->opcm);
 401+ 			hdl->sio.eof = 1;
 402+ 			return 0;
 403+ 		}
 404+@@ -413,9 +324,9 @@ sio_alsa_start(struct sio_hdl *sh)
 405+ 		hdl->opartial = 0;
 406+ 	}
 407+ 	if (hdl->sio.mode & SIO_REC) {
 408+-		err = snd_pcm_prepare(hdl->ipcm);
 409++		err = pcm_prepare(hdl->ipcm);
 410+ 		if (err < 0) {
 411+-			DALSA("couldn't prepare rec stream", err);
 412++			DALSA("couldn't prepare rec stream", hdl->ipcm);
 413+ 			hdl->sio.eof = 1;
 414+ 			return 0;
 415+ 		}
 416+@@ -427,17 +338,17 @@ sio_alsa_start(struct sio_hdl *sh)
 417+ 		hdl->ipartial = 0;
 418+ 	}
 419+ 	if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) {
 420+-		err = snd_pcm_link(hdl->ipcm, hdl->opcm);
 421++		err = pcm_link(hdl->ipcm, hdl->opcm);
 422+ 		if (err < 0) {
 423+-			DALSA("couldn't link streams", err);
 424++			DALSA("couldn't link streams", hdl->ipcm);
 425+ 			hdl->sio.eof = 1;
 426+ 			return 0;
 427+ 		}
 428+ 	}
 429+ 	if (!(hdl->sio.mode & SIO_PLAY)) {
 430+-		err = snd_pcm_start(hdl->ipcm);
 431++		err = pcm_start(hdl->ipcm);
 432+ 		if (err < 0) {
 433+-			DALSA("couldn't start rec stream", err);
 434++			DALSA("couldn't start rec stream", hdl->ipcm);
 435+ 			hdl->sio.eof = 1;
 436+ 			return 0;
 437+ 		}
 438+@@ -449,30 +360,26 @@ static int
 439+ sio_alsa_flush(struct sio_hdl *sh)
 440+ {
 441+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 442+-	int err;
 443+ 
 444+ 	if (hdl->sio.mode & SIO_PLAY) {
 445+-		err = snd_pcm_drop(hdl->opcm);
 446+-		if (err < 0) {
 447+-			DALSA("couldn't stop play stream", err);
 448++		if (pcm_stop(hdl->opcm) != 0) {
 449++			DALSA("couldn't stop play stream", hdl->opcm);
 450+ 			hdl->sio.eof = 1;
 451+ 			return 0;
 452+ 		}
 453+ 		free(hdl->otmpbuf);
 454+ 	}
 455+ 	if (hdl->sio.mode & SIO_REC) {
 456+-		err = snd_pcm_drop(hdl->ipcm);
 457+-		if (err < 0) {
 458+-			DALSA("couldn't stop rec stream", err);
 459++		if (pcm_stop(hdl->ipcm) != 0) {
 460++			DALSA("couldn't stop rec stream", hdl->ipcm);
 461+ 			hdl->sio.eof = 1;
 462+ 			return 0;
 463+ 		}
 464+ 		free(hdl->itmpbuf);
 465+ 	}
 466+ 	if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) {
 467+-		err = snd_pcm_unlink(hdl->ipcm);
 468+-		if (err < 0) {
 469+-			DALSA("couldn't unlink streams", err);
 470++		if (pcm_unlink(hdl->ipcm) != 0) {
 471++			DALSA("couldn't unlink streams", hdl->ipcm);
 472+ 			hdl->sio.eof = 1;
 473+ 			return 0;
 474+ 		}
 475+@@ -537,143 +444,110 @@ sio_alsa_xrun(struct sio_alsa_hdl *hdl)
 476+ }
 477+ 
 478+ static int
 479+-sio_alsa_setpar_hw(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwp,
 480+-    snd_pcm_format_t *reqfmt, unsigned int *rate, unsigned int *chans,
 481+-    snd_pcm_uframes_t *round, unsigned int *periods)
 482++sio_alsa_setpar_hw(struct pcm *pcm, struct pcm_params *par,
 483++    struct pcm_config *cfg)
 484+ {
 485+-	static snd_pcm_format_t fmts[] = {
 486+-		SND_PCM_FORMAT_S32_LE,	SND_PCM_FORMAT_S32_BE,
 487+-		SND_PCM_FORMAT_U32_LE,	SND_PCM_FORMAT_U32_BE,
 488+-		SND_PCM_FORMAT_S24_LE,	SND_PCM_FORMAT_S24_BE,
 489+-		SND_PCM_FORMAT_U24_LE,	SND_PCM_FORMAT_U24_BE,
 490+-		SND_PCM_FORMAT_S16_LE,	SND_PCM_FORMAT_S16_BE,
 491+-		SND_PCM_FORMAT_U16_LE,	SND_PCM_FORMAT_U16_BE,
 492+-		SND_PCM_FORMAT_U8,	SND_PCM_FORMAT_S8
 493++	static enum pcm_format fmts[] = {
 494++		PCM_FORMAT_S32_LE,	PCM_FORMAT_S32_BE,
 495++		PCM_FORMAT_S24_LE,	PCM_FORMAT_S24_BE,
 496++		PCM_FORMAT_S16_LE,	PCM_FORMAT_S16_BE,
 497++		PCM_FORMAT_S8
 498+ 	};
 499+-	int i, err, dir = 0;
 500+-	unsigned req_rate, min_periods = 2;
 501++	int i, err;
 502++	unsigned req_rate;
 503++	unsigned min, max;
 504+ 
 505+-	req_rate = *rate;
 506++	/* XXX: HW_FREE */
 507+ 
 508+-	err = snd_pcm_hw_free(pcm);
 509+-	if (err < 0) {
 510+-		DALSA("couldn't reset hw configuration", err);
 511+-		return 0;
 512+-	}
 513+-	err = snd_pcm_hw_params_any(pcm, hwp);
 514+-	if (err < 0) {
 515+-		DALSA("couldn't init pars", err);
 516+-		return 0;
 517+-	}
 518+-	err = snd_pcm_hw_params_set_access(pcm, hwp,
 519+-	    SND_PCM_ACCESS_RW_INTERLEAVED);
 520+-	if (err < 0) {
 521+-		DALSA("couldn't set interleaved access", err);
 522+-		return 0;
 523+-	}
 524+-	err = snd_pcm_hw_params_test_format(pcm, hwp, *reqfmt);
 525+-	if (err < 0) {
 526++	if (pcm_params_format_test(par, cfg->format) == 0) {
 527+ 		for (i = 0; ; i++) {
 528+-			if (i == sizeof(fmts) / sizeof(snd_pcm_format_t)) {
 529++			if (i == sizeof(fmts) / sizeof(fmts[0])) {
 530+ 				DPRINTF("no known format found\n");
 531+ 				return 0;
 532+ 			}
 533+-			err = snd_pcm_hw_params_test_format(pcm, hwp, fmts[i]);
 534+-			if (err)
 535++			if (pcm_params_format_test(par, fmts[i]) == 0)
 536+ 				continue;
 537+-			*reqfmt = fmts[i];
 538++			cfg->format = fmts[i];
 539+ 			break;
 540+ 		}
 541+ 	}
 542+-	err = snd_pcm_hw_params_set_format(pcm, hwp, *reqfmt);
 543+-	if (err < 0) {
 544+-		DALSA("couldn't set fmt", err);
 545+-		return 0;
 546+-	}
 547+-	err = snd_pcm_hw_params_set_rate_resample(pcm, hwp, 0);
 548+-	if (err < 0) {
 549+-		DALSA("couldn't turn resampling off", err);
 550+-		return 0;
 551+-	}
 552+-	err = snd_pcm_hw_params_set_rate_near(pcm, hwp, rate, 0);
 553+-	if (err < 0) {
 554+-		DALSA("couldn't set rate", err);
 555+-		return 0;
 556+-	}
 557+-	err = snd_pcm_hw_params_set_channels_near(pcm, hwp, chans);
 558+-	if (err < 0) {
 559+-		DALSA("couldn't set channel count", err);
 560+-		return 0;
 561+-	}
 562+-	err = snd_pcm_hw_params_set_periods_integer(pcm, hwp);
 563+-	if (err < 0) {
 564+-		DALSA("couldn't set periods to integer", err);
 565+-		return 0;
 566+-	}
 567+-	err = snd_pcm_hw_params_set_periods_min(pcm, hwp, &min_periods, NULL);
 568+-	if (err < 0) {
 569+-		DALSA("couldn't set minimum periods", err);
 570+-		return 0;
 571+-	}
 572+-	err = snd_pcm_hw_params_set_period_size_integer(pcm, hwp);
 573+-	if (err < 0) {
 574+-		DALSA("couldn't set period to integer", err);
 575+-		return 0;
 576+-	}
 577+-
 578+-	*round = *round * *rate / req_rate;
 579+-	*round = (*round + 31) & ~31;
 580+ 
 581+-	err = snd_pcm_hw_params_set_period_size_near(pcm, hwp, round, &dir);
 582+-	if (err < 0) {
 583+-		DALSA("couldn't set period size failed", err);
 584+-		return 0;
 585+-	}
 586+-	err = snd_pcm_hw_params_set_periods_near(pcm, hwp, periods, &dir);
 587+-	if (err < 0) {
 588+-		DALSA("couldn't set period count", err);
 589+-		return 0;
 590+-	}
 591+-	err = snd_pcm_hw_params(pcm, hwp);
 592++	req_rate = cfg->rate;
 593++	min = pcm_params_get_min(par, PCM_PARAM_RATE);
 594++	if (cfg->rate < min)
 595++		cfg->rate = min;
 596++	max = pcm_params_get_max(par, PCM_PARAM_RATE);
 597++	if (cfg->rate > max)
 598++		cfg->rate = max;
 599++
 600++	min = pcm_params_get_min(par, PCM_PARAM_CHANNELS);
 601++	if (cfg->channels < min)
 602++		cfg->channels = min;
 603++	max = pcm_params_get_max(par, PCM_PARAM_CHANNELS);
 604++	if (cfg->channels > max)
 605++		cfg->channels = max;
 606++
 607++	cfg->period_size = cfg->period_size * cfg->rate / req_rate;
 608++	cfg->period_size = (cfg->period_size + 31) & ~31;
 609++
 610++	min = pcm_params_get_min(par, PCM_PARAM_PERIOD_SIZE);
 611++	if (min < 2)
 612++		min = 2;
 613++	if (cfg->period_size < min)
 614++		cfg->period_size = min;
 615++	max = pcm_params_get_max(par, PCM_PARAM_PERIOD_SIZE);
 616++	if (cfg->period_size > max)
 617++		cfg->period_size = max;
 618++
 619++	min = pcm_params_get_min(par, PCM_PARAM_PERIODS);
 620++	if (cfg->period_count < min)
 621++		cfg->period_count = min;
 622++	max = pcm_params_get_max(par, PCM_PARAM_PERIODS);
 623++	if (cfg->period_count > max)
 624++		cfg->period_count = max;
 625++
 626++	cfg->start_threshold = 0;
 627++	cfg->stop_threshold = cfg->period_count * cfg->period_size;
 628++	cfg->avail_min = 1;
 629++	cfg->silence_size = 0;
 630++	cfg->silence_threshold = 0;
 631++
 632++	/* XXX: period_event=1, silence?, silence_threshold? */
 633++
 634++	err = pcm_set_config(pcm, cfg);
 635+ 	if (err < 0) {
 636+-		DALSA("couldn't commit params", err);
 637++		DALSA("couldn't set config", pcm);
 638+ 		return 0;
 639+ 	}
 640+ 	return 1;
 641+ }
 642+ 
 643+ static int
 644+-sio_alsa_getcap_hw(snd_pcm_t *pcm, int *rates, int *fmts, int *chans)
 645++sio_alsa_getcap_hw(struct pcm_params *par, int *rates, int *fmts, int *chans)
 646+ {
 647+ 	int i, err;
 648+-	snd_pcm_hw_params_t *hwp;
 649+-
 650+-	snd_pcm_hw_params_alloca(&hwp);
 651+-
 652+-	err = snd_pcm_hw_params_any(pcm, hwp);
 653+-	if (err < 0) {
 654+-		DALSA("sio_alsa_trypar: couldn't init pars", err);
 655+-		return 0;
 656+-	}
 657++	unsigned min, max;
 658+ 
 659+ 	*fmts = 0;
 660+ 	for (i = 0; i < CAP_NFMTS; i++) {
 661+-		err = snd_pcm_hw_params_test_format(pcm, hwp, cap_fmts[i]);
 662++		err = pcm_params_format_test(par, cap_fmts[i]);
 663+ 		if (err == 0) {
 664+ 			*fmts |= 1 << i;
 665+ 		}
 666+ 	}
 667+ 	*rates = 0;
 668++	min = pcm_params_get_min(par, PCM_PARAM_RATE);
 669++	max = pcm_params_get_max(par, PCM_PARAM_RATE);
 670+ 	for (i = 0; i < CAP_NRATES; i++) {
 671+-		err = snd_pcm_hw_params_test_rate(pcm, hwp, cap_rates[i], 0);
 672+-		if (err == 0) {
 673++		if (min <= cap_rates[i] && cap_rates[i] <= max) {
 674+ 			*rates |= 1 << i;
 675+ 		}
 676+ 	}
 677+ 	*chans = 0;
 678++	min = pcm_params_get_min(par, PCM_PARAM_CHANNELS);
 679++	max = pcm_params_get_max(par, PCM_PARAM_CHANNELS);
 680+ 	for (i = 0; i < CAP_NCHANS; i++) {
 681+-		err = snd_pcm_hw_params_test_channels(pcm, hwp, cap_chans[i]);
 682+-		if (err == 0) {
 683++		if (min <= cap_chans[i] && cap_chans[i] <= max) {
 684+ 			*chans |= 1 << i;
 685+ 		}
 686+ 	}
 687+@@ -693,13 +567,13 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap)
 688+ 	irates = orates = ifmts = ofmts = ichans = ochans = 0;
 689+ 
 690+ 	if (hdl->sio.mode & SIO_PLAY) {
 691+-		if (!sio_alsa_getcap_hw(hdl->opcm,
 692++		if (!sio_alsa_getcap_hw(hdl->opar,
 693+ 			&orates, &ofmts, &ochans)) {
 694+ 			return 0;
 695+ 		}
 696+ 	}
 697+ 	if (hdl->sio.mode & SIO_REC) {
 698+-		if (!sio_alsa_getcap_hw(hdl->ipcm,
 699++		if (!sio_alsa_getcap_hw(hdl->ipar,
 700+ 			&irates, &ifmts, &ichans)) {
 701+ 			return 0;
 702+ 		}
 703+@@ -711,7 +585,7 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap)
 704+ 		    &cap->enc[i].sig,
 705+ 		    &cap->enc[i].le);
 706+ 		cap->enc[i].bps = SIO_BPS(cap->enc[0].bits);
 707+-		cap->enc[i].msb = 1;
 708++		cap->enc[i].msb = 0;
 709+ 	}
 710+ 	for (i = 0; i < CAP_NRATES; i++) {
 711+ 		cap->rate[i] = cap_rates[i];
 712+@@ -744,186 +618,72 @@ static int
 713+ sio_alsa_setpar(struct sio_hdl *sh, struct sio_par *par)
 714+ {
 715+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 716+-	snd_pcm_hw_params_t *ohwp, *ihwp;
 717+-	snd_pcm_sw_params_t *oswp, *iswp;
 718+-	snd_pcm_uframes_t iround, oround;
 719+-	snd_pcm_format_t ifmt, ofmt;
 720+-	unsigned int iperiods, operiods;
 721+-	unsigned irate, orate;
 722+-	int err;
 723+-
 724+-	snd_pcm_hw_params_alloca(&ohwp);
 725+-	snd_pcm_sw_params_alloca(&oswp);
 726+-	snd_pcm_hw_params_alloca(&ihwp);
 727+-	snd_pcm_sw_params_alloca(&iswp);
 728++	struct pcm_config icfg, ocfg;
 729+ 
 730+-	sio_alsa_enctofmt(hdl, &ifmt, par->bits, par->sig, par->le);
 731+-	irate = (par->rate == ~0U) ? 48000 : par->rate;
 732++	sio_alsa_enctofmt(hdl, &icfg.format, par->bits, par->sig, par->le);
 733++	icfg.rate = (par->rate == ~0U) ? 48000 : par->rate;
 734+ 	if (par->appbufsz != ~0U) {
 735+-		iround = (par->round != ~0U) ?
 736++		icfg.period_size = (par->round != ~0U) ?
 737+ 		    par->round : (par->appbufsz + 1) / 2;
 738+-		iperiods = par->appbufsz / iround;
 739+-		if (iperiods < 2)
 740+-			iperiods = 2;
 741++		icfg.period_count = par->appbufsz / icfg.period_size;
 742++		if (icfg.period_count < 2)
 743++			icfg.period_count = 2;
 744+ 	} else if (par->round != ~0U) {
 745+-		iround = par->round;
 746+-		iperiods = 2;
 747++		icfg.period_size = par->round;
 748++		icfg.period_count = 2;
 749+ 	} else {
 750+-		iperiods = 2;
 751+-		iround = irate / 100;
 752++		icfg.period_count = 2;
 753++		icfg.period_size = icfg.rate / 100;
 754+ 	}
 755+ 
 756+ 	if (hdl->sio.mode & SIO_REC) {
 757+ 		hdl->par.rchan = par->rchan;
 758+-		if (!sio_alsa_setpar_hw(hdl->ipcm, ihwp,
 759+-			&ifmt, &irate, &hdl->par.rchan,
 760+-			&iround, &iperiods)) {
 761++		if (!sio_alsa_setpar_hw(hdl->ipcm, hdl->ipar, &icfg)) {
 762+ 			hdl->sio.eof = 1;
 763+ 			return 0;
 764+ 		}
 765+ 	}
 766+-	ofmt = ifmt;
 767+-	orate = irate;
 768+-	oround = iround;
 769+-	operiods = iperiods;
 770++	ocfg = icfg;
 771+ 	if (hdl->sio.mode & SIO_PLAY) {
 772+ 		hdl->par.pchan = par->pchan;
 773+-		if (!sio_alsa_setpar_hw(hdl->opcm, ohwp,
 774+-			&ofmt, &orate, &hdl->par.pchan,
 775+-			&oround, &operiods)) {
 776++		if (!sio_alsa_setpar_hw(hdl->opcm, hdl->opar, &ocfg)) {
 777+ 			hdl->sio.eof = 1;
 778+ 			return 0;
 779+ 		}
 780+-		if (!(hdl->sio.mode & SIO_REC)) {
 781+-			ifmt = ofmt;
 782+-			irate = orate;
 783+-			iround = oround;
 784+-			iperiods = operiods;
 785+-		}
 786++		if (!(hdl->sio.mode & SIO_REC))
 787++			icfg = ocfg;
 788+ 	}
 789+ 
 790+ 	DPRINTFN(2, "ofmt = %u, orate = %u, oround = %u, operiods = %u\n",
 791+-	    ofmt, orate, (unsigned int)oround, operiods);
 792++	    ocfg.format, ocfg.rate, ocfg.period_size, ocfg.period_count);
 793+ 	DPRINTFN(2, "ifmt = %u, irate = %u, iround = %u, iperiods = %u\n",
 794+-	    ifmt, irate, (unsigned int)iround, iperiods);
 795++	    icfg.format, icfg.rate, icfg.period_size, icfg.period_count);
 796+ 
 797+-	if (ifmt != ofmt) {
 798++	if (icfg.format != ocfg.format) {
 799+ 		DPRINTF("play and rec formats differ\n");
 800+ 		hdl->sio.eof = 1;
 801+ 		return 0;
 802+ 	}
 803+-	if (irate != orate) {
 804++	if (icfg.rate != ocfg.rate) {
 805+ 		DPRINTF("play and rec rates differ\n");
 806+ 		hdl->sio.eof = 1;
 807+ 		return 0;
 808+ 	}
 809+-	if (iround != oround) {
 810++	if (icfg.period_size != ocfg.period_size) {
 811+ 		DPRINTF("play and rec block sizes differ\n");
 812+ 		hdl->sio.eof = 1;
 813+ 		return 0;
 814+ 	}
 815+-	if (!sio_alsa_fmttopar(hdl, ifmt,
 816++	if (!sio_alsa_fmttopar(hdl, icfg.format,
 817+ 		&hdl->par.bits, &hdl->par.sig, &hdl->par.le))
 818+ 		return 0;
 819+-	hdl->par.msb = 1;
 820++	hdl->par.msb = 0;
 821+ 	hdl->par.bps = SIO_BPS(hdl->par.bits);
 822+-	hdl->par.rate = orate;
 823+-	hdl->par.round = oround;
 824+-	hdl->par.bufsz = oround * operiods;
 825++	hdl->par.rate = ocfg.rate;
 826++	hdl->par.round = ocfg.period_size;
 827++	hdl->par.bufsz = ocfg.period_size * ocfg.period_count;
 828+ 	hdl->par.appbufsz = hdl->par.bufsz;
 829+ 
 830+-	/* software params */
 831+-
 832+-	if (hdl->sio.mode & SIO_REC) {
 833+-		err = snd_pcm_sw_params_current(hdl->ipcm, iswp);
 834+-		if (err < 0) {
 835+-			DALSA("couldn't get current rec params", err);
 836+-			hdl->sio.eof = 1;
 837+-			return 0;
 838+-		}
 839+-		err = snd_pcm_sw_params_set_start_threshold(hdl->ipcm,
 840+-		    iswp, 0);
 841+-		if (err < 0) {
 842+-			DALSA("couldn't set rec start threshold", err);
 843+-			hdl->sio.eof = 1;
 844+-			return 0;
 845+-		}
 846+-		err = snd_pcm_sw_params_set_stop_threshold(hdl->ipcm,
 847+-		    iswp, hdl->par.bufsz);
 848+-		if (err < 0) {
 849+-			DALSA("couldn't set rec stop threshold", err);
 850+-			hdl->sio.eof = 1;
 851+-			return 0;
 852+-		}
 853+-		err = snd_pcm_sw_params_set_avail_min(hdl->ipcm,
 854+-		    iswp, 1);
 855+-		if (err < 0) {
 856+-			DALSA("couldn't set rec avail min", err);
 857+-			hdl->sio.eof = 1;
 858+-			return 0;
 859+-		}
 860+-		err = snd_pcm_sw_params_set_period_event(hdl->ipcm, iswp, 1);
 861+-		if (err < 0) {
 862+-			DALSA("couldn't set rec period event", err);
 863+-			hdl->sio.eof = 1;
 864+-			return 0;
 865+-		}
 866+-		err = snd_pcm_sw_params(hdl->ipcm, iswp);
 867+-		if (err < 0) {
 868+-			DALSA("couldn't commit rec sw params", err);
 869+-			hdl->sio.eof = 1;
 870+-			return 0;
 871+-		}
 872+-	}
 873+-	if (hdl->sio.mode & SIO_PLAY) {
 874+-		err = snd_pcm_sw_params_current(hdl->opcm, oswp);
 875+-		if (err < 0) {
 876+-			DALSA("couldn't get current play params", err);
 877+-			hdl->sio.eof = 1;
 878+-			return 0;
 879+-		}
 880+-		err = snd_pcm_sw_params_set_start_threshold(hdl->opcm,
 881+-		    oswp, hdl->par.bufsz - hdl->par.round);
 882+-		if (err < 0) {
 883+-			DALSA("couldn't set play start threshold", err);
 884+-			hdl->sio.eof = 1;
 885+-			return 0;
 886+-		}
 887+-		err = snd_pcm_sw_params_set_stop_threshold(hdl->opcm,
 888+-		    oswp, hdl->par.bufsz);
 889+-		if (err < 0) {
 890+-			DALSA("couldn't set play stop threshold", err);
 891+-			hdl->sio.eof = 1;
 892+-			return 0;
 893+-		}
 894+-		err = snd_pcm_sw_params_set_avail_min(hdl->opcm,
 895+-		    oswp, 1);
 896+-		if (err < 0) {
 897+-			DALSA("couldn't set play avail min", err);
 898+-			hdl->sio.eof = 1;
 899+-			return 0;
 900+-		}
 901+-		err = snd_pcm_sw_params_set_period_event(hdl->opcm, oswp, 1);
 902+-		if (err < 0) {
 903+-			DALSA("couldn't set play period event", err);
 904+-			hdl->sio.eof = 1;
 905+-			return 0;
 906+-		}
 907+-		err = snd_pcm_sw_params(hdl->opcm, oswp);
 908+-		if (err < 0) {
 909+-			DALSA("couldn't commit play sw params", err);
 910+-			hdl->sio.eof = 1;
 911+-			return 0;
 912+-		}
 913+-	}
 914+-#ifdef DEBUG
 915+-	if (_sndio_debug >= 2) {
 916+-		if (hdl->sio.mode & SIO_REC)
 917+-			snd_pcm_dump(hdl->ipcm, output);
 918+-		if (hdl->sio.mode & SIO_PLAY)
 919+-			snd_pcm_dump(hdl->opcm, output);
 920+-	}
 921+-#endif
 922+ 	return 1;
 923+ }
 924+ 
 925+@@ -940,7 +700,7 @@ static size_t
 926+ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len)
 927+ {
 928+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 929+-	snd_pcm_sframes_t n;
 930++	int n;
 931+ 	size_t todo;
 932+ 
 933+ 	if (hdl->ipartial > 0) {
 934+@@ -959,7 +719,7 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len)
 935+ 	todo = len / hdl->ibpf;
 936+ 	if (todo == 0)
 937+ 		return 0;
 938+-	while ((n = snd_pcm_readi(hdl->ipcm, buf, todo)) < 0) {
 939++	while ((n = pcm_readi(hdl->ipcm, buf, todo)) < 0) {
 940+ 		if (n == -EINTR)
 941+ 			continue;
 942+ 		if (n == -EPIPE || n == -ESTRPIPE) {
 943+@@ -967,7 +727,7 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len)
 944+ 			return 0;
 945+ 		}
 946+ 		if (n != -EAGAIN) {
 947+-			DALSA("couldn't read data", n);
 948++			DALSA("couldn't read data", hdl->ipcm);
 949+ 			hdl->sio.eof = 1;
 950+ 		}
 951+ 		return 0;
 952+@@ -989,7 +749,7 @@ static size_t
 953+ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len)
 954+ {
 955+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 956+-	snd_pcm_sframes_t n;
 957++	int n;
 958+ 	size_t todo;
 959+ 
 960+ 	if (len < hdl->obpf || hdl->opartial > 0) {
 961+@@ -1007,7 +767,7 @@ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len)
 962+ 	todo = len / hdl->obpf;
 963+ 	if (todo == 0)
 964+ 		return 0;
 965+-	while ((n = snd_pcm_writei(hdl->opcm, buf, todo)) < 0) {
 966++	while ((n = pcm_writei(hdl->opcm, buf, todo)) < 0) {
 967+ 		if (n == -EINTR)
 968+ 			continue;
 969+ 		if (n == -ESTRPIPE || n == -EPIPE) {
 970+@@ -1015,7 +775,7 @@ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len)
 971+ 			return 0;
 972+ 		}
 973+ 		if (n != -EAGAIN) {
 974+-			DALSA("couldn't write data", n);
 975++			DALSA("couldn't write data", hdl->opcm);
 976+ 			hdl->sio.eof = 1;
 977+ 		}
 978+ 		return 0;
 979+@@ -1062,16 +822,14 @@ sio_alsa_onmove(struct sio_alsa_hdl *hdl)
 980+ static int
 981+ sio_alsa_nfds(struct sio_hdl *sh)
 982+ {
 983+-	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 984+-
 985+-	return hdl->nfds;
 986++	return 2;
 987+ }
 988+ 
 989+ static int
 990+ sio_alsa_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
 991+ {
 992+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
 993+-	int i;
 994++	int i, nfds;
 995+ 
 996+ 	if (hdl->sio.eof)
 997+ 		return 0;
 998+@@ -1083,100 +841,86 @@ sio_alsa_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
 999+ 		hdl->events &= ~POLLIN;
1000+ 	if (!hdl->sio.started)
1001+ 		hdl->events = 0;
1002+-	memset(pfd, 0, sizeof(struct pollfd) * hdl->nfds);
1003+-	hdl->onfds = hdl->infds = 0;
1004++	memset(pfd, 0, sizeof(struct pollfd) * 2);
1005++	nfds = 0;
1006+ 	if (hdl->events & POLLOUT) {
1007+ 		if (!hdl->running &&
1008+-		    snd_pcm_state(hdl->opcm) == SND_PCM_STATE_RUNNING)
1009++		    pcm_state(hdl->opcm) == PCM_STATE_RUNNING)
1010+ 			sio_alsa_onmove(hdl);
1011+-		hdl->onfds = snd_pcm_poll_descriptors(hdl->opcm,
1012+-		    pfd, hdl->nfds);
1013+-		if (hdl->onfds < 0) {
1014+-			DALSA("couldn't poll play descriptors",
1015+-			    hdl->onfds);
1016+-			hdl->sio.eof = 1;
1017+-			return 0;
1018+-		}
1019++
1020++		pfd[0].fd = pcm_get_poll_fd(hdl->opcm);
1021++		pfd[0].events = POLLOUT;
1022++		nfds++;
1023+ 	}
1024+ 	if (hdl->events & POLLIN) {
1025+ 		if (!hdl->running &&
1026+-		    snd_pcm_state(hdl->ipcm) == SND_PCM_STATE_RUNNING)
1027++		    pcm_state(hdl->ipcm) == PCM_STATE_RUNNING)
1028+ 			sio_alsa_onmove(hdl);
1029+-		hdl->infds = snd_pcm_poll_descriptors(hdl->ipcm,
1030+-		    pfd + hdl->onfds, hdl->nfds - hdl->onfds);
1031+-		if (hdl->infds < 0) {
1032+-			DALSA("couldn't poll rec descriptors",
1033+-			    hdl->infds);
1034+-			hdl->sio.eof = 1;
1035+-			return 0;
1036+-		}
1037++
1038++		pfd[nfds].fd = pcm_get_poll_fd(hdl->ipcm);
1039++		pfd[nfds].events = POLLIN;
1040++		nfds++;
1041+ 	}
1042+-	DPRINTFN(4, "sio_alsa_pollfd: events = %x, nfds = %d + %d\n",
1043+-	    events, hdl->onfds, hdl->infds);
1044++	DPRINTFN(4, "sio_alsa_pollfd: events = %x, nfds = %d\n",
1045++	    events, nfds);
1046+ 
1047+-	for (i = 0; i < hdl->onfds + hdl->infds; i++) {
1048++	for (i = 0; i < nfds; i++) {
1049+ 		DPRINTFN(4, "sio_alsa_pollfd: pfds[%d].events = %x\n",
1050+ 		    i, pfd[i].events);
1051+ 	}
1052+-	return hdl->onfds + hdl->infds;
1053++	return nfds;
1054+ }
1055+ 
1056+ int
1057+ sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd)
1058+ {
1059+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
1060+-	snd_pcm_sframes_t iused, oavail, oused;
1061+-	snd_pcm_state_t istate, ostate;
1062+-	unsigned short revents, r;
1063+-	int nfds, err, i;
1064++	struct timespec ts;
1065++	unsigned iused, oavail, oused;
1066++	int istate, ostate;
1067++	unsigned short revents;
1068++	int nfds, i;
1069+ 
1070+ 	if (hdl->sio.eof)
1071+ 		return POLLHUP;
1072+ 
1073+-	for (i = 0; i < hdl->onfds + hdl->infds; i++) {
1074++	nfds = 0;
1075++	if (hdl->events & POLLOUT)
1076++		nfds++;
1077++	if (hdl->events & POLLIN)
1078++		nfds++;
1079++
1080++	for (i = 0; i < nfds; i++) {
1081+ 		DPRINTFN(4, "sio_alsa_revents: pfds[%d].revents = %x\n",
1082+ 		    i, pfd[i].revents);
1083+ 	}
1084+ 	revents = nfds = 0;
1085+ 	if (hdl->events & POLLOUT) {
1086+-		err = snd_pcm_poll_descriptors_revents(hdl->opcm,
1087+-		    pfd, hdl->onfds, &r);
1088+-		if (err < 0) {
1089+-			DALSA("couldn't get play events", err);
1090+-			hdl->sio.eof = 1;
1091+-			return POLLHUP;
1092+-		}
1093+-		revents |= r;
1094+-		nfds += hdl->onfds;
1095++		revents |= pfd[0].revents;
1096++		++nfds;
1097+ 	}
1098+ 	if (hdl->events & POLLIN) {
1099+-		err = snd_pcm_poll_descriptors_revents(hdl->ipcm,
1100+-		    pfd + nfds, hdl->infds, &r);
1101+-		if (err < 0) {
1102+-			DALSA("couldn't get rec events", err);
1103+-			hdl->sio.eof = 1;
1104+-			return POLLHUP;
1105+-		}
1106+-		revents |= r;
1107+-		nfds += hdl->infds;
1108++		revents |= pfd[nfds].revents;
1109++		++nfds;
1110+ 	}
1111+ 	if (hdl->sio.mode & SIO_PLAY) {
1112+-		ostate = snd_pcm_state(hdl->opcm);
1113+-		if (ostate == SND_PCM_STATE_XRUN) {
1114++		ostate = pcm_state(hdl->opcm);
1115++		if (ostate == PCM_STATE_XRUN) {
1116+ 			if (!sio_alsa_xrun(hdl))
1117+ 				return POLLHUP;
1118+ 			return 0;
1119+ 		}
1120+-		if (ostate == SND_PCM_STATE_RUNNING ||
1121+-		    ostate == SND_PCM_STATE_PREPARED) {
1122+-			oavail = snd_pcm_avail_update(hdl->opcm);
1123+-			if (oavail < 0) {
1124++		if (ostate == PCM_STATE_RUNNING ||
1125++		    ostate == PCM_STATE_PREPARED) {
1126++			if (pcm_get_htimestamp(hdl->opcm, &oavail, &ts) != 0) {
1127++				/*
1128+ 				if (oavail == -EPIPE || oavail == -ESTRPIPE) {
1129+ 					if (!sio_alsa_xrun(hdl))
1130+ 						return POLLHUP;
1131+ 					return 0;
1132+ 				}
1133+-				DALSA("couldn't get play buffer ptr", oavail);
1134++				*/
1135++				DPRINTF("couldn't get play buffer ptr\n");
1136+ 				hdl->sio.eof = 1;
1137+ 				return POLLHUP;
1138+ 			}
1139+@@ -1186,22 +930,23 @@ sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd)
1140+ 		}
1141+ 	}
1142+ 	if (hdl->sio.mode & SIO_REC) {
1143+-		istate = snd_pcm_state(hdl->ipcm);
1144+-		if (istate == SND_PCM_STATE_XRUN) {
1145++		istate = pcm_state(hdl->ipcm);
1146++		if (istate == PCM_STATE_XRUN) {
1147+ 			if (!sio_alsa_xrun(hdl))
1148+ 				return POLLHUP;
1149+ 			return 0;
1150+ 		}
1151+-		if (istate == SND_PCM_STATE_RUNNING ||
1152+-		    istate == SND_PCM_STATE_PREPARED) {
1153+-			iused = snd_pcm_avail_update(hdl->ipcm);
1154+-			if (iused < 0) {
1155++		if (istate == PCM_STATE_RUNNING ||
1156++		    istate == PCM_STATE_PREPARED) {
1157++			if (pcm_get_htimestamp(hdl->ipcm, &iused, &ts) != 0) {
1158++				/*
1159+ 				if (iused == -EPIPE || iused == -ESTRPIPE) {
1160+ 					if (!sio_alsa_xrun(hdl))
1161+ 						return POLLHUP;
1162+ 					return 0;
1163+ 				}
1164+-				DALSA("couldn't get rec buffer ptr", iused);
1165++				*/
1166++				DPRINTF("couldn't get rec buffer ptr\n");
1167+ 				hdl->sio.eof = 1;
1168+ 				return POLLHUP;
1169+ 			}
1170+-- 
1171+2.37.3
1172+
+141, -0
  1@@ -0,0 +1,141 @@
  2+From 7472a43ccf2f5bae14cd736102daab8b4be0df31 Mon Sep 17 00:00:00 2001
  3+From: Michael Forney <mforney@mforney.org>
  4+Date: Mon, 31 Oct 2022 03:47:44 -0700
  5+Subject: [PATCH] alsa: Add support for s24le3/s24be3
  6+
  7+---
  8+ libsndio/sio_alsa.c | 41 +++++++++++++++++++++++++++++++++--------
  9+ 1 file changed, 33 insertions(+), 8 deletions(-)
 10+
 11+diff --git a/libsndio/sio_alsa.c b/libsndio/sio_alsa.c
 12+index e460bf6..9a65288 100644
 13+--- a/libsndio/sio_alsa.c
 14++++ b/libsndio/sio_alsa.c
 15+@@ -112,40 +112,60 @@ static enum pcm_format cap_fmts[] = {
 16+  */
 17+ static int
 18+ sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, enum pcm_format fmt,
 19+-    unsigned int *bits, unsigned int *sig, unsigned int *le)
 20++    unsigned int *bits, unsigned int *bps, unsigned int *sig, unsigned int *le)
 21+ {
 22+ 	switch (fmt) {
 23+ 	case PCM_FORMAT_S8:
 24+ 		*bits = 8;
 25++		*bps = 1;
 26+ 		*sig = 1;
 27++		*le = 1;
 28+ 		break;
 29+ 	case PCM_FORMAT_S16_LE:
 30+ 		*bits = 16;
 31++		*bps = 2;
 32+ 		*sig = 1;
 33+ 		*le = 1;
 34+ 		break;
 35+ 	case PCM_FORMAT_S16_BE:
 36+ 		*bits = 16;
 37++		*bps = 2;
 38++		*sig = 1;
 39++		*le = 0;
 40++		break;
 41++	case PCM_FORMAT_S24_3LE:
 42++		*bits = 24;
 43++		*bps = 3;
 44++		*sig = 1;
 45++		*le = 1;
 46++		break;
 47++	case PCM_FORMAT_S24_3BE:
 48++		*bits = 24;
 49++		*bps = 3;
 50+ 		*sig = 1;
 51+ 		*le = 0;
 52+ 		break;
 53+ 	case PCM_FORMAT_S24_LE:
 54+ 		*bits = 24;
 55++		*bps = 4;
 56+ 		*sig = 1;
 57+ 		*le = 1;
 58+ 		break;
 59+ 	case PCM_FORMAT_S24_BE:
 60+ 		*bits = 24;
 61++		*bps = 4;
 62+ 		*sig = 1;
 63+ 		*le = 0;
 64+ 		break;
 65+ 	case PCM_FORMAT_S32_LE:
 66+ 		*bits = 32;
 67++		*bps = 4;
 68+ 		*sig = 1;
 69+ 		*le = 1;
 70+ 		break;
 71+ 	case PCM_FORMAT_S32_BE:
 72+ 		*bits = 32;
 73++		*bps = 4;
 74+ 		*sig = 1;
 75+ 		*le = 0;
 76+ 		break;
 77+@@ -163,13 +183,17 @@ sio_alsa_fmttopar(struct sio_alsa_hdl *hdl, enum pcm_format fmt,
 78+  */
 79+ static void
 80+ sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, enum pcm_format *rfmt,
 81+-    unsigned int bits, unsigned int sig, unsigned int le)
 82++    unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le)
 83+ {
 84++	if (bps == ~0U)
 85++		bps = SIO_BPS(bits);
 86+ 	if (le == ~0U)
 87+ 		le = SIO_LE_NATIVE;
 88+ 	if (bits == 8)
 89+ 		*rfmt = PCM_FORMAT_S8;
 90+-	else if (bits == 24)
 91++	else if (bits == 24 && bps == 3)
 92++		*rfmt = le ? PCM_FORMAT_S24_3LE : PCM_FORMAT_S24_3BE;
 93++	else if (bits == 24 && bps == 4)
 94+ 		*rfmt = le ? PCM_FORMAT_S24_LE : PCM_FORMAT_S24_BE;
 95+ 	else if (bits == 32)
 96+ 		*rfmt = le ? PCM_FORMAT_S32_LE : PCM_FORMAT_S32_BE;
 97+@@ -450,6 +474,7 @@ sio_alsa_setpar_hw(struct pcm *pcm, struct pcm_params *par,
 98+ 	static enum pcm_format fmts[] = {
 99+ 		PCM_FORMAT_S32_LE,	PCM_FORMAT_S32_BE,
100+ 		PCM_FORMAT_S24_LE,	PCM_FORMAT_S24_BE,
101++		PCM_FORMAT_S24_3LE,	PCM_FORMAT_S24_3BE,
102+ 		PCM_FORMAT_S16_LE,	PCM_FORMAT_S16_BE,
103+ 		PCM_FORMAT_S8
104+ 	};
105+@@ -582,9 +607,9 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap)
106+ 	for (i = 0; i < CAP_NFMTS; i++) {
107+ 		sio_alsa_fmttopar(hdl, cap_fmts[i],
108+ 		    &cap->enc[i].bits,
109++		    &cap->enc[i].bps,
110+ 		    &cap->enc[i].sig,
111+ 		    &cap->enc[i].le);
112+-		cap->enc[i].bps = SIO_BPS(cap->enc[0].bits);
113+ 		cap->enc[i].msb = 0;
114+ 	}
115+ 	for (i = 0; i < CAP_NRATES; i++) {
116+@@ -620,7 +645,8 @@ sio_alsa_setpar(struct sio_hdl *sh, struct sio_par *par)
117+ 	struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
118+ 	struct pcm_config icfg, ocfg;
119+ 
120+-	sio_alsa_enctofmt(hdl, &icfg.format, par->bits, par->sig, par->le);
121++	sio_alsa_enctofmt(hdl, &icfg.format, par->bits, par->bps, par->sig,
122++	    par->le);
123+ 	icfg.rate = (par->rate == ~0U) ? 48000 : par->rate;
124+ 	if (par->appbufsz != ~0U) {
125+ 		icfg.period_size = (par->round != ~0U) ?
126+@@ -674,11 +700,10 @@ sio_alsa_setpar(struct sio_hdl *sh, struct sio_par *par)
127+ 		hdl->sio.eof = 1;
128+ 		return 0;
129+ 	}
130+-	if (!sio_alsa_fmttopar(hdl, icfg.format,
131+-		&hdl->par.bits, &hdl->par.sig, &hdl->par.le))
132++	if (!sio_alsa_fmttopar(hdl, icfg.format, &hdl->par.bits, &hdl->par.bps,
133++	    &hdl->par.sig, &hdl->par.le))
134+ 		return 0;
135+ 	hdl->par.msb = 0;
136+-	hdl->par.bps = SIO_BPS(hdl->par.bits);
137+ 	hdl->par.rate = ocfg.rate;
138+ 	hdl->par.round = ocfg.period_size;
139+ 	hdl->par.bufsz = ocfg.period_size * ocfg.period_count;
140+-- 
141+2.37.3
142+
+1, -0
1@@ -0,0 +1 @@
2+Subproject commit 584d41515a981818f6f60e9d9dca97af3657a640
+1, -0
1@@ -0,0 +1 @@
2+1.9.0 r0