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