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