1 /*
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2019 Alexandre Ratchov <alex@caoua.org>
5 */
6
7 /*
8 * TODO :
9 *
10 * Use a single device and open it in full-duplex rather than
11 * opening it twice (once for playback once for recording).
12 *
13 * This is the only way to ensure that playback doesn't drift with respect
14 * to recording, which is what guest systems expect.
15 */
16
17 #include "qemu/osdep.h"
18 #include <poll.h>
19 #include <sndio.h>
20 #include "qemu/main-loop.h"
21 #include "audio.h"
22 #include "trace.h"
23
24 #define AUDIO_CAP "sndio"
25 #include "audio_int.h"
26
27 /* default latency in microseconds if no option is set */
28 #define SNDIO_LATENCY_US 50000
29
30 typedef struct SndioVoice {
31 union {
32 HWVoiceOut out;
33 HWVoiceIn in;
34 } hw;
35 struct sio_par par;
36 struct sio_hdl *hdl;
37 struct pollfd *pfds;
38 struct pollindex {
39 struct SndioVoice *self;
40 int index;
41 } *pindexes;
42 unsigned char *buf;
43 size_t buf_size;
44 size_t sndio_pos;
45 size_t qemu_pos;
46 unsigned int mode;
47 unsigned int nfds;
48 bool enabled;
49 } SndioVoice;
50
51 typedef struct SndioConf {
52 const char *devname;
53 unsigned int latency;
54 } SndioConf;
55
56 /* needed for forward reference */
57 static void sndio_poll_in(void *arg);
58 static void sndio_poll_out(void *arg);
59
60 /*
61 * stop polling descriptors
62 */
sndio_poll_clear(SndioVoice * self)63 static void sndio_poll_clear(SndioVoice *self)
64 {
65 struct pollfd *pfd;
66 int i;
67
68 for (i = 0; i < self->nfds; i++) {
69 pfd = &self->pfds[i];
70 qemu_set_fd_handler(pfd->fd, NULL, NULL, NULL);
71 }
72
73 self->nfds = 0;
74 }
75
76 /*
77 * write data to the device until it blocks or
78 * all of our buffered data is written
79 */
sndio_write(SndioVoice * self)80 static void sndio_write(SndioVoice *self)
81 {
82 size_t todo, n;
83
84 todo = self->qemu_pos - self->sndio_pos;
85
86 /*
87 * transfer data to device, until it blocks
88 */
89 while (todo > 0) {
90 n = sio_write(self->hdl, self->buf + self->sndio_pos, todo);
91 if (n == 0) {
92 break;
93 }
94 self->sndio_pos += n;
95 todo -= n;
96 }
97
98 if (self->sndio_pos == self->buf_size) {
99 /*
100 * we complete the block
101 */
102 self->sndio_pos = 0;
103 self->qemu_pos = 0;
104 }
105 }
106
107 /*
108 * read data from the device until it blocks or
109 * there no room any longer
110 */
sndio_read(SndioVoice * self)111 static void sndio_read(SndioVoice *self)
112 {
113 size_t todo, n;
114
115 todo = self->buf_size - self->sndio_pos;
116
117 /*
118 * transfer data from the device, until it blocks
119 */
120 while (todo > 0) {
121 n = sio_read(self->hdl, self->buf + self->sndio_pos, todo);
122 if (n == 0) {
123 break;
124 }
125 self->sndio_pos += n;
126 todo -= n;
127 }
128 }
129
130 /*
131 * Set handlers for all descriptors libsndio needs to
132 * poll
133 */
sndio_poll_wait(SndioVoice * self)134 static void sndio_poll_wait(SndioVoice *self)
135 {
136 struct pollfd *pfd;
137 int events, i;
138
139 events = 0;
140 if (self->mode == SIO_PLAY) {
141 if (self->sndio_pos < self->qemu_pos) {
142 events |= POLLOUT;
143 }
144 } else {
145 if (self->sndio_pos < self->buf_size) {
146 events |= POLLIN;
147 }
148 }
149
150 /*
151 * fill the given array of descriptors with the events sndio
152 * wants, they are different from our 'event' variable because
153 * sndio may use descriptors internally.
154 */
155 self->nfds = sio_pollfd(self->hdl, self->pfds, events);
156
157 for (i = 0; i < self->nfds; i++) {
158 pfd = &self->pfds[i];
159 if (pfd->fd < 0) {
160 continue;
161 }
162 qemu_set_fd_handler(pfd->fd,
163 (pfd->events & POLLIN) ? sndio_poll_in : NULL,
164 (pfd->events & POLLOUT) ? sndio_poll_out : NULL,
165 &self->pindexes[i]);
166 pfd->revents = 0;
167 }
168 }
169
170 /*
171 * call-back called when one of the descriptors
172 * became readable or writable
173 */
sndio_poll_event(SndioVoice * self,int index,int event)174 static void sndio_poll_event(SndioVoice *self, int index, int event)
175 {
176 int revents;
177
178 /*
179 * ensure we're not called twice this cycle
180 */
181 sndio_poll_clear(self);
182
183 /*
184 * make self->pfds[] look as we're returning from poll syscal,
185 * this is how sio_revents expects events to be.
186 */
187 self->pfds[index].revents = event;
188
189 /*
190 * tell sndio to handle events and return whether we can read or
191 * write without blocking.
192 */
193 revents = sio_revents(self->hdl, self->pfds);
194 if (self->mode == SIO_PLAY) {
195 if (revents & POLLOUT) {
196 sndio_write(self);
197 }
198
199 if (self->qemu_pos < self->buf_size) {
200 audio_run(self->hw.out.s, "sndio_out");
201 }
202 } else {
203 if (revents & POLLIN) {
204 sndio_read(self);
205 }
206
207 if (self->qemu_pos < self->sndio_pos) {
208 audio_run(self->hw.in.s, "sndio_in");
209 }
210 }
211
212 /*
213 * audio_run() may have changed state
214 */
215 if (self->enabled) {
216 sndio_poll_wait(self);
217 }
218 }
219
220 /*
221 * return the upper limit of the amount of free play buffer space
222 */
sndio_buffer_get_free(HWVoiceOut * hw)223 static size_t sndio_buffer_get_free(HWVoiceOut *hw)
224 {
225 SndioVoice *self = (SndioVoice *) hw;
226
227 return self->buf_size - self->qemu_pos;
228 }
229
230 /*
231 * return a buffer where data to play can be stored,
232 * its size is stored in the location pointed by the size argument.
233 */
sndio_get_buffer_out(HWVoiceOut * hw,size_t * size)234 static void *sndio_get_buffer_out(HWVoiceOut *hw, size_t *size)
235 {
236 SndioVoice *self = (SndioVoice *) hw;
237
238 *size = self->buf_size - self->qemu_pos;
239 return self->buf + self->qemu_pos;
240 }
241
242 /*
243 * put back to sndio back-end a buffer returned by sndio_get_buffer_out()
244 */
sndio_put_buffer_out(HWVoiceOut * hw,void * buf,size_t size)245 static size_t sndio_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
246 {
247 SndioVoice *self = (SndioVoice *) hw;
248
249 self->qemu_pos += size;
250 sndio_poll_wait(self);
251 return size;
252 }
253
254 /*
255 * return a buffer from where recorded data is available,
256 * its size is stored in the location pointed by the size argument.
257 * it may not exceed the initial value of "*size".
258 */
sndio_get_buffer_in(HWVoiceIn * hw,size_t * size)259 static void *sndio_get_buffer_in(HWVoiceIn *hw, size_t *size)
260 {
261 SndioVoice *self = (SndioVoice *) hw;
262 size_t todo, max_todo;
263
264 /*
265 * unlike the get_buffer_out() method, get_buffer_in()
266 * must return a buffer of at most the given size, see audio.c
267 */
268 max_todo = *size;
269
270 todo = self->sndio_pos - self->qemu_pos;
271 if (todo > max_todo) {
272 todo = max_todo;
273 }
274
275 *size = todo;
276 return self->buf + self->qemu_pos;
277 }
278
279 /*
280 * discard the given amount of recorded data
281 */
sndio_put_buffer_in(HWVoiceIn * hw,void * buf,size_t size)282 static void sndio_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
283 {
284 SndioVoice *self = (SndioVoice *) hw;
285
286 self->qemu_pos += size;
287 if (self->qemu_pos == self->buf_size) {
288 self->qemu_pos = 0;
289 self->sndio_pos = 0;
290 }
291 sndio_poll_wait(self);
292 }
293
294 /*
295 * call-back called when one of our descriptors becomes writable
296 */
sndio_poll_out(void * arg)297 static void sndio_poll_out(void *arg)
298 {
299 struct pollindex *pindex = (struct pollindex *) arg;
300
301 sndio_poll_event(pindex->self, pindex->index, POLLOUT);
302 }
303
304 /*
305 * call-back called when one of our descriptors becomes readable
306 */
sndio_poll_in(void * arg)307 static void sndio_poll_in(void *arg)
308 {
309 struct pollindex *pindex = (struct pollindex *) arg;
310
311 sndio_poll_event(pindex->self, pindex->index, POLLIN);
312 }
313
sndio_fini(SndioVoice * self)314 static void sndio_fini(SndioVoice *self)
315 {
316 if (self->hdl) {
317 sio_close(self->hdl);
318 self->hdl = NULL;
319 }
320
321 g_free(self->pfds);
322 g_free(self->pindexes);
323 g_free(self->buf);
324 }
325
sndio_init(SndioVoice * self,struct audsettings * as,int mode,Audiodev * dev)326 static int sndio_init(SndioVoice *self,
327 struct audsettings *as, int mode, Audiodev *dev)
328 {
329 AudiodevSndioOptions *opts = &dev->u.sndio;
330 unsigned long long latency;
331 const char *dev_name;
332 struct sio_par req;
333 unsigned int nch;
334 int i, nfds;
335
336 dev_name = opts->dev ?: SIO_DEVANY;
337 latency = opts->has_latency ? opts->latency : SNDIO_LATENCY_US;
338
339 /* open the device in non-blocking mode */
340 self->hdl = sio_open(dev_name, mode, 1);
341 if (self->hdl == NULL) {
342 dolog("failed to open device\n");
343 return -1;
344 }
345
346 self->mode = mode;
347
348 sio_initpar(&req);
349
350 switch (as->fmt) {
351 case AUDIO_FORMAT_S8:
352 req.bits = 8;
353 req.sig = 1;
354 break;
355 case AUDIO_FORMAT_U8:
356 req.bits = 8;
357 req.sig = 0;
358 break;
359 case AUDIO_FORMAT_S16:
360 req.bits = 16;
361 req.sig = 1;
362 break;
363 case AUDIO_FORMAT_U16:
364 req.bits = 16;
365 req.sig = 0;
366 break;
367 case AUDIO_FORMAT_S32:
368 req.bits = 32;
369 req.sig = 1;
370 break;
371 case AUDIO_FORMAT_U32:
372 req.bits = 32;
373 req.sig = 0;
374 break;
375 default:
376 dolog("unknown audio sample format\n");
377 return -1;
378 }
379
380 if (req.bits > 8) {
381 req.le = as->endianness ? 0 : 1;
382 }
383
384 req.rate = as->freq;
385 if (mode == SIO_PLAY) {
386 req.pchan = as->nchannels;
387 } else {
388 req.rchan = as->nchannels;
389 }
390
391 /* set on-device buffer size */
392 req.appbufsz = req.rate * latency / 1000000;
393
394 if (!sio_setpar(self->hdl, &req)) {
395 dolog("failed set audio params\n");
396 goto fail;
397 }
398
399 if (!sio_getpar(self->hdl, &self->par)) {
400 dolog("failed get audio params\n");
401 goto fail;
402 }
403
404 nch = (mode == SIO_PLAY) ? self->par.pchan : self->par.rchan;
405
406 /*
407 * With the default setup, sndio supports any combination of parameters
408 * so these checks are mostly to catch configuration errors.
409 */
410 if (self->par.bits != req.bits || self->par.bps != req.bits / 8 ||
411 self->par.sig != req.sig || (req.bits > 8 && self->par.le != req.le) ||
412 self->par.rate != as->freq || nch != as->nchannels) {
413 dolog("unsupported audio params\n");
414 goto fail;
415 }
416
417 /*
418 * we use one block as buffer size; this is how
419 * transfers get well aligned
420 */
421 self->buf_size = self->par.round * self->par.bps * nch;
422
423 self->buf = g_malloc(self->buf_size);
424 if (self->buf == NULL) {
425 dolog("failed to allocate audio buffer\n");
426 goto fail;
427 }
428
429 nfds = sio_nfds(self->hdl);
430
431 self->pfds = g_malloc_n(nfds, sizeof(struct pollfd));
432 if (self->pfds == NULL) {
433 dolog("failed to allocate pollfd structures\n");
434 goto fail;
435 }
436
437 self->pindexes = g_malloc_n(nfds, sizeof(struct pollindex));
438 if (self->pindexes == NULL) {
439 dolog("failed to allocate pollindex structures\n");
440 goto fail;
441 }
442
443 for (i = 0; i < nfds; i++) {
444 self->pindexes[i].self = self;
445 self->pindexes[i].index = i;
446 }
447
448 return 0;
449 fail:
450 sndio_fini(self);
451 return -1;
452 }
453
sndio_enable(SndioVoice * self,bool enable)454 static void sndio_enable(SndioVoice *self, bool enable)
455 {
456 if (enable) {
457 sio_start(self->hdl);
458 self->enabled = true;
459 sndio_poll_wait(self);
460 } else {
461 self->enabled = false;
462 sndio_poll_clear(self);
463 sio_stop(self->hdl);
464 }
465 }
466
sndio_enable_out(HWVoiceOut * hw,bool enable)467 static void sndio_enable_out(HWVoiceOut *hw, bool enable)
468 {
469 SndioVoice *self = (SndioVoice *) hw;
470
471 sndio_enable(self, enable);
472 }
473
sndio_enable_in(HWVoiceIn * hw,bool enable)474 static void sndio_enable_in(HWVoiceIn *hw, bool enable)
475 {
476 SndioVoice *self = (SndioVoice *) hw;
477
478 sndio_enable(self, enable);
479 }
480
sndio_init_out(HWVoiceOut * hw,struct audsettings * as,void * opaque)481 static int sndio_init_out(HWVoiceOut *hw, struct audsettings *as, void *opaque)
482 {
483 SndioVoice *self = (SndioVoice *) hw;
484
485 if (sndio_init(self, as, SIO_PLAY, opaque) == -1) {
486 return -1;
487 }
488
489 audio_pcm_init_info(&hw->info, as);
490 hw->samples = self->par.round;
491 return 0;
492 }
493
sndio_init_in(HWVoiceIn * hw,struct audsettings * as,void * opaque)494 static int sndio_init_in(HWVoiceIn *hw, struct audsettings *as, void *opaque)
495 {
496 SndioVoice *self = (SndioVoice *) hw;
497
498 if (sndio_init(self, as, SIO_REC, opaque) == -1) {
499 return -1;
500 }
501
502 audio_pcm_init_info(&hw->info, as);
503 hw->samples = self->par.round;
504 return 0;
505 }
506
sndio_fini_out(HWVoiceOut * hw)507 static void sndio_fini_out(HWVoiceOut *hw)
508 {
509 SndioVoice *self = (SndioVoice *) hw;
510
511 sndio_fini(self);
512 }
513
sndio_fini_in(HWVoiceIn * hw)514 static void sndio_fini_in(HWVoiceIn *hw)
515 {
516 SndioVoice *self = (SndioVoice *) hw;
517
518 sndio_fini(self);
519 }
520
sndio_audio_init(Audiodev * dev,Error ** errp)521 static void *sndio_audio_init(Audiodev *dev, Error **errp)
522 {
523 assert(dev->driver == AUDIODEV_DRIVER_SNDIO);
524 return dev;
525 }
526
sndio_audio_fini(void * opaque)527 static void sndio_audio_fini(void *opaque)
528 {
529 }
530
531 static struct audio_pcm_ops sndio_pcm_ops = {
532 .init_out = sndio_init_out,
533 .fini_out = sndio_fini_out,
534 .enable_out = sndio_enable_out,
535 .write = audio_generic_write,
536 .buffer_get_free = sndio_buffer_get_free,
537 .get_buffer_out = sndio_get_buffer_out,
538 .put_buffer_out = sndio_put_buffer_out,
539 .init_in = sndio_init_in,
540 .fini_in = sndio_fini_in,
541 .read = audio_generic_read,
542 .enable_in = sndio_enable_in,
543 .get_buffer_in = sndio_get_buffer_in,
544 .put_buffer_in = sndio_put_buffer_in,
545 };
546
547 static struct audio_driver sndio_audio_driver = {
548 .name = "sndio",
549 .descr = "sndio https://sndio.org",
550 .init = sndio_audio_init,
551 .fini = sndio_audio_fini,
552 .pcm_ops = &sndio_pcm_ops,
553 .max_voices_out = INT_MAX,
554 .max_voices_in = INT_MAX,
555 .voice_size_out = sizeof(SndioVoice),
556 .voice_size_in = sizeof(SndioVoice)
557 };
558
register_audio_sndio(void)559 static void register_audio_sndio(void)
560 {
561 audio_driver_register(&sndio_audio_driver);
562 }
563
564 type_init(register_audio_sndio);
565