qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sndioaudio.c (13132B)


      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 <poll.h>
     18 #include <sndio.h>
     19 #include "qemu/osdep.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->has_dev ? 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);