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