2 * SPDX-License-Identifier: ISC
4 * Copyright (c) 2019 Alexandre Ratchov <alex@caoua.org>
10 * Use a single device and open it in full-duplex rather than
11 * opening it twice (once for playback once for recording).
13 * This is the only way to ensure that playback doesn't drift with respect
14 * to recording, which is what guest systems expect.
19 #include "qemu/osdep.h"
20 #include "qemu/main-loop.h"
24 #define AUDIO_CAP "sndio"
25 #include "audio_int.h"
27 /* default latency in microseconds if no option is set */
28 #define SNDIO_LATENCY_US 50000
30 typedef struct SndioVoice
{
39 struct SndioVoice
*self
;
51 typedef struct SndioConf
{
56 /* needed for forward reference */
57 static void sndio_poll_in(void *arg
);
58 static void sndio_poll_out(void *arg
);
61 * stop polling descriptors
63 static void sndio_poll_clear(SndioVoice
*self
)
68 for (i
= 0; i
< self
->nfds
; i
++) {
70 qemu_set_fd_handler(pfd
->fd
, NULL
, NULL
, NULL
);
77 * write data to the device until it blocks or
78 * all of our buffered data is written
80 static void sndio_write(SndioVoice
*self
)
84 todo
= self
->qemu_pos
- self
->sndio_pos
;
87 * transfer data to device, until it blocks
90 n
= sio_write(self
->hdl
, self
->buf
+ self
->sndio_pos
, todo
);
98 if (self
->sndio_pos
== self
->buf_size
) {
100 * we complete the block
108 * read data from the device until it blocks or
109 * there no room any longer
111 static void sndio_read(SndioVoice
*self
)
115 todo
= self
->buf_size
- self
->sndio_pos
;
118 * transfer data from the device, until it blocks
121 n
= sio_read(self
->hdl
, self
->buf
+ self
->sndio_pos
, todo
);
125 self
->sndio_pos
+= n
;
131 * Set handlers for all descriptors libsndio needs to
134 static void sndio_poll_wait(SndioVoice
*self
)
140 if (self
->mode
== SIO_PLAY
) {
141 if (self
->sndio_pos
< self
->qemu_pos
) {
145 if (self
->sndio_pos
< self
->buf_size
) {
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.
155 self
->nfds
= sio_pollfd(self
->hdl
, self
->pfds
, events
);
157 for (i
= 0; i
< self
->nfds
; i
++) {
158 pfd
= &self
->pfds
[i
];
162 qemu_set_fd_handler(pfd
->fd
,
163 (pfd
->events
& POLLIN
) ? sndio_poll_in
: NULL
,
164 (pfd
->events
& POLLOUT
) ? sndio_poll_out
: NULL
,
171 * call-back called when one of the descriptors
172 * became readable or writable
174 static void sndio_poll_event(SndioVoice
*self
, int index
, int event
)
179 * ensure we're not called twice this cycle
181 sndio_poll_clear(self
);
184 * make self->pfds[] look as we're returning from poll syscal,
185 * this is how sio_revents expects events to be.
187 self
->pfds
[index
].revents
= event
;
190 * tell sndio to handle events and return whether we can read or
191 * write without blocking.
193 revents
= sio_revents(self
->hdl
, self
->pfds
);
194 if (self
->mode
== SIO_PLAY
) {
195 if (revents
& POLLOUT
) {
199 if (self
->qemu_pos
< self
->buf_size
) {
200 audio_run(self
->hw
.out
.s
, "sndio_out");
203 if (revents
& POLLIN
) {
207 if (self
->qemu_pos
< self
->sndio_pos
) {
208 audio_run(self
->hw
.in
.s
, "sndio_in");
213 * audio_run() may have changed state
216 sndio_poll_wait(self
);
221 * return the upper limit of the amount of free play buffer space
223 static size_t sndio_buffer_get_free(HWVoiceOut
*hw
)
225 SndioVoice
*self
= (SndioVoice
*) hw
;
227 return self
->buf_size
- self
->qemu_pos
;
231 * return a buffer where data to play can be stored,
232 * its size is stored in the location pointed by the size argument.
234 static void *sndio_get_buffer_out(HWVoiceOut
*hw
, size_t *size
)
236 SndioVoice
*self
= (SndioVoice
*) hw
;
238 *size
= self
->buf_size
- self
->qemu_pos
;
239 return self
->buf
+ self
->qemu_pos
;
243 * put back to sndio back-end a buffer returned by sndio_get_buffer_out()
245 static size_t sndio_put_buffer_out(HWVoiceOut
*hw
, void *buf
, size_t size
)
247 SndioVoice
*self
= (SndioVoice
*) hw
;
249 self
->qemu_pos
+= size
;
250 sndio_poll_wait(self
);
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".
259 static void *sndio_get_buffer_in(HWVoiceIn
*hw
, size_t *size
)
261 SndioVoice
*self
= (SndioVoice
*) hw
;
262 size_t todo
, max_todo
;
265 * unlike the get_buffer_out() method, get_buffer_in()
266 * must return a buffer of at most the given size, see audio.c
270 todo
= self
->sndio_pos
- self
->qemu_pos
;
271 if (todo
> max_todo
) {
276 return self
->buf
+ self
->qemu_pos
;
280 * discard the given amount of recorded data
282 static void sndio_put_buffer_in(HWVoiceIn
*hw
, void *buf
, size_t size
)
284 SndioVoice
*self
= (SndioVoice
*) hw
;
286 self
->qemu_pos
+= size
;
287 if (self
->qemu_pos
== self
->buf_size
) {
291 sndio_poll_wait(self
);
295 * call-back called when one of our descriptors becomes writable
297 static void sndio_poll_out(void *arg
)
299 struct pollindex
*pindex
= (struct pollindex
*) arg
;
301 sndio_poll_event(pindex
->self
, pindex
->index
, POLLOUT
);
305 * call-back called when one of our descriptors becomes readable
307 static void sndio_poll_in(void *arg
)
309 struct pollindex
*pindex
= (struct pollindex
*) arg
;
311 sndio_poll_event(pindex
->self
, pindex
->index
, POLLIN
);
314 static void sndio_fini(SndioVoice
*self
)
317 sio_close(self
->hdl
);
322 g_free(self
->pindexes
);
326 static int sndio_init(SndioVoice
*self
,
327 struct audsettings
*as
, int mode
, Audiodev
*dev
)
329 AudiodevSndioOptions
*opts
= &dev
->u
.sndio
;
330 unsigned long long latency
;
331 const char *dev_name
;
336 dev_name
= opts
->has_dev
? opts
->dev
: SIO_DEVANY
;
337 latency
= opts
->has_latency
? opts
->latency
: SNDIO_LATENCY_US
;
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");
351 case AUDIO_FORMAT_S8
:
355 case AUDIO_FORMAT_U8
:
359 case AUDIO_FORMAT_S16
:
363 case AUDIO_FORMAT_U16
:
367 case AUDIO_FORMAT_S32
:
371 case AUDIO_FORMAT_U32
:
376 dolog("unknown audio sample format\n");
381 req
.le
= as
->endianness
? 0 : 1;
385 if (mode
== SIO_PLAY
) {
386 req
.pchan
= as
->nchannels
;
388 req
.rchan
= as
->nchannels
;
391 /* set on-device buffer size */
392 req
.appbufsz
= req
.rate
* latency
/ 1000000;
394 if (!sio_setpar(self
->hdl
, &req
)) {
395 dolog("failed set audio params\n");
399 if (!sio_getpar(self
->hdl
, &self
->par
)) {
400 dolog("failed get audio params\n");
404 nch
= (mode
== SIO_PLAY
) ? self
->par
.pchan
: self
->par
.rchan
;
407 * With the default setup, sndio supports any combination of parameters
408 * so these checks are mostly to catch configuration errors.
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");
418 * we use one block as buffer size; this is how
419 * transfers get well aligned
421 self
->buf_size
= self
->par
.round
* self
->par
.bps
* nch
;
423 self
->buf
= g_malloc(self
->buf_size
);
424 if (self
->buf
== NULL
) {
425 dolog("failed to allocate audio buffer\n");
429 nfds
= sio_nfds(self
->hdl
);
431 self
->pfds
= g_malloc_n(nfds
, sizeof(struct pollfd
));
432 if (self
->pfds
== NULL
) {
433 dolog("failed to allocate pollfd structures\n");
437 self
->pindexes
= g_malloc_n(nfds
, sizeof(struct pollindex
));
438 if (self
->pindexes
== NULL
) {
439 dolog("failed to allocate pollindex structures\n");
443 for (i
= 0; i
< nfds
; i
++) {
444 self
->pindexes
[i
].self
= self
;
445 self
->pindexes
[i
].index
= i
;
454 static void sndio_enable(SndioVoice
*self
, bool enable
)
457 sio_start(self
->hdl
);
458 self
->enabled
= true;
459 sndio_poll_wait(self
);
461 self
->enabled
= false;
462 sndio_poll_clear(self
);
467 static void sndio_enable_out(HWVoiceOut
*hw
, bool enable
)
469 SndioVoice
*self
= (SndioVoice
*) hw
;
471 sndio_enable(self
, enable
);
474 static void sndio_enable_in(HWVoiceIn
*hw
, bool enable
)
476 SndioVoice
*self
= (SndioVoice
*) hw
;
478 sndio_enable(self
, enable
);
481 static int sndio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
, void *opaque
)
483 SndioVoice
*self
= (SndioVoice
*) hw
;
485 if (sndio_init(self
, as
, SIO_PLAY
, opaque
) == -1) {
489 audio_pcm_init_info(&hw
->info
, as
);
490 hw
->samples
= self
->par
.round
;
494 static int sndio_init_in(HWVoiceIn
*hw
, struct audsettings
*as
, void *opaque
)
496 SndioVoice
*self
= (SndioVoice
*) hw
;
498 if (sndio_init(self
, as
, SIO_REC
, opaque
) == -1) {
502 audio_pcm_init_info(&hw
->info
, as
);
503 hw
->samples
= self
->par
.round
;
507 static void sndio_fini_out(HWVoiceOut
*hw
)
509 SndioVoice
*self
= (SndioVoice
*) hw
;
514 static void sndio_fini_in(HWVoiceIn
*hw
)
516 SndioVoice
*self
= (SndioVoice
*) hw
;
521 static void *sndio_audio_init(Audiodev
*dev
)
523 assert(dev
->driver
== AUDIODEV_DRIVER_SNDIO
);
527 static void sndio_audio_fini(void *opaque
)
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
,
547 static struct audio_driver sndio_audio_driver
= {
549 .descr
= "sndio https://sndio.org",
550 .init
= sndio_audio_init
,
551 .fini
= sndio_audio_fini
,
552 .pcm_ops
= &sndio_pcm_ops
,
554 .max_voices_out
= INT_MAX
,
555 .max_voices_in
= INT_MAX
,
556 .voice_size_out
= sizeof(SndioVoice
),
557 .voice_size_in
= sizeof(SndioVoice
)
560 static void register_audio_sndio(void)
562 audio_driver_register(&sndio_audio_driver
);
565 type_init(register_audio_sndio
);