xref: /openbmc/qemu/audio/sndioaudio.c (revision d044b7c3)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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 
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 
467 static void sndio_enable_out(HWVoiceOut *hw, bool enable)
468 {
469     SndioVoice *self = (SndioVoice *) hw;
470 
471     sndio_enable(self, enable);
472 }
473 
474 static void sndio_enable_in(HWVoiceIn *hw, bool enable)
475 {
476     SndioVoice *self = (SndioVoice *) hw;
477 
478     sndio_enable(self, enable);
479 }
480 
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 
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 
507 static void sndio_fini_out(HWVoiceOut *hw)
508 {
509     SndioVoice *self = (SndioVoice *) hw;
510 
511     sndio_fini(self);
512 }
513 
514 static void sndio_fini_in(HWVoiceIn *hw)
515 {
516     SndioVoice *self = (SndioVoice *) hw;
517 
518     sndio_fini(self);
519 }
520 
521 static void *sndio_audio_init(Audiodev *dev)
522 {
523     assert(dev->driver == AUDIODEV_DRIVER_SNDIO);
524     return dev;
525 }
526 
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     .can_be_default = 1,
554     .max_voices_out = INT_MAX,
555     .max_voices_in  = INT_MAX,
556     .voice_size_out = sizeof(SndioVoice),
557     .voice_size_in  = sizeof(SndioVoice)
558 };
559 
560 static void register_audio_sndio(void)
561 {
562     audio_driver_register(&sndio_audio_driver);
563 }
564 
565 type_init(register_audio_sndio);
566