Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)
Am 28.08.23 um 21:55 schrieb Emmanouil Pitsidianakis: To perform audio capture we duplicate the TX logic of the previous commit with the following difference: we receive data from the QEMU audio backend and write it in the virt queue IO buffers the guest sends to QEMU. When they are full (i.e. they have `period_bytes` amount of data) or when recording stops in QEMU's audio backend, the buffer is returned to the guest by notifying it. Signed-off-by: Emmanouil Pitsidianakis --- hw/virtio/trace-events | 3 +- hw/virtio/virtio-snd.c | 245 +++-- 2 files changed, 215 insertions(+), 33 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 3b95e745c2..9b7fbffedc 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -172,4 +172,5 @@ virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PR virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" virtio_snd_pcm_stream_flush(uint32_t stream) "flushing stream %"PRIu32 -virtio_snd_handle_xfer(void) "tx/rx queue callback called" +virtio_snd_handle_tx_xfer(void) "tx queue callback called" +virtio_snd_handle_rx_xfer(void) "rx queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 4859ce4bf6..70e8a73072 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -1002,26 +1073,119 @@ static void virtio_snd_pcm_out_cb(void *data, int available) } /* - * Flush all buffer data from this stream's queue into the driver's virtual - * queue. + * AUD_* input callback. * - * @stream: VirtIOSoundPCMStream *stream + * @data: VirtIOSoundPCMStream stream + * @available: number of bytes that can be read with AUD_read() */ -static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream) +static void virtio_snd_pcm_in_cb(void *data, int available) { +VirtIOSoundPCMStream *stream = data; VirtIOSoundPCMBlock *block; -VirtIOSoundPCMBlock *next; +uint32_t sz; +virtio_snd_pcm_status resp = { 0 }; +size_t size; WITH_QEMU_LOCK_GUARD(>queue_mutex) { -QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) { -AUD_write(stream->voice.out, block->data + block->offset, block->size); -virtqueue_push(block->vq, block->elem, sizeof(block->elem)); -virtio_notify(VIRTIO_DEVICE(stream->s), block->vq); -QSIMPLEQ_REMOVE(>queue, block, VirtIOSoundPCMBlock, entry); +while (!QSIMPLEQ_EMPTY(>queue)) { +block = QSIMPLEQ_FIRST(>queue); + +for (;;) { +size = AUD_read(stream->voice.in, +block->data + block->offset, +MIN(stream->period_bytes - block->offset, available)); +block->offset += size; +block->size += size; +if (size == 0 || block->size >= stream->period_bytes) { +resp.status = VIRTIO_SND_S_OK; Hi Manos, the type of resp.status is le32. I doubt that the virtio-sound device will work on a big endian host at the moment. There are more issues like this in virtio-snd.c. + sz = iov_from_buf(block->elem->in_sg, + block->elem->in_num, + 0, + , + sizeof(resp)); + +/* Copy data -if any- to guest */ +if (block->size) { +iov_from_buf(block->elem->in_sg, + block->elem->in_num, + sz, + block->data, + MIN(stream->period_bytes, block->size)); +} The order of the parts of the PCM input stream message is wrong. The buffer comes first, then the status part. See virtio-v1.2-cs01 5.14.6.8PCM I/O Messages. The correct order fixes the problem with the wrong audio frames every 25ms. The two wrong audio frames were the status part of the message. +virtqueue_push(block->vq, +block->elem, +sizeof(block->elem)); sizeof(block->elem)? This is the size of a pointer. The PCM I/O Message is much larger. The other virtqueue_push() call sites also don't look right. With best regards, Volker +virtio_notify(VIRTIO_DEVICE(stream->s), +block->vq); +QSIMPLEQ_REMOVE_HEAD(>queue, entry); +g_free(block); +available -= size; +break; +} + +available -= size; +if (!available) { +break; +} +} +if (!available) { +break; +} }
Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)
Am 28.08.23 um 21:55 schrieb Emmanouil Pitsidianakis: To perform audio capture we duplicate the TX logic of the previous commit with the following difference: we receive data from the QEMU audio backend and write it in the virt queue IO buffers the guest sends to QEMU. When they are full (i.e. they have `period_bytes` amount of data) or when recording stops in QEMU's audio backend, the buffer is returned to the guest by notifying it. Signed-off-by: Emmanouil Pitsidianakis --- hw/virtio/trace-events | 3 +- hw/virtio/virtio-snd.c | 245 +++-- 2 files changed, 215 insertions(+), 33 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 3b95e745c2..9b7fbffedc 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -172,4 +172,5 @@ virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PR virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" virtio_snd_pcm_stream_flush(uint32_t stream) "flushing stream %"PRIu32 -virtio_snd_handle_xfer(void) "tx/rx queue callback called" +virtio_snd_handle_tx_xfer(void) "tx queue callback called" +virtio_snd_handle_rx_xfer(void) "rx queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 4859ce4bf6..70e8a73072 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -1002,26 +1073,119 @@ static void virtio_snd_pcm_out_cb(void *data, int available) } /* - * Flush all buffer data from this stream's queue into the driver's virtual - * queue. + * AUD_* input callback. * - * @stream: VirtIOSoundPCMStream *stream + * @data: VirtIOSoundPCMStream stream + * @available: number of bytes that can be read with AUD_read() */ -static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream) +static void virtio_snd_pcm_in_cb(void *data, int available) { +VirtIOSoundPCMStream *stream = data; VirtIOSoundPCMBlock *block; -VirtIOSoundPCMBlock *next; +uint32_t sz; +virtio_snd_pcm_status resp = { 0 }; +size_t size; WITH_QEMU_LOCK_GUARD(>queue_mutex) { -QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) { -AUD_write(stream->voice.out, block->data + block->offset, block->size); -virtqueue_push(block->vq, block->elem, sizeof(block->elem)); -virtio_notify(VIRTIO_DEVICE(stream->s), block->vq); -QSIMPLEQ_REMOVE(>queue, block, VirtIOSoundPCMBlock, entry); +while (!QSIMPLEQ_EMPTY(>queue)) { +block = QSIMPLEQ_FIRST(>queue); + +for (;;) { +size = AUD_read(stream->voice.in, +block->data + block->offset, +MIN(stream->period_bytes - block->offset, available)); For the -audiodev in.mixing-engine=off case, 'available' is much larger than the available bytes AUD_read() can actually read. 'size' is 0 when the upstream buffer is empty. + if (size == 0) { + available = 0; + break; + } This fixes audio recording with -audiodev pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0. The issue with two wrong audio frames every 25ms remains. +block->offset += size; +block->size += size; +if (size == 0 || block->size >= stream->period_bytes) { - if (size == 0 || block->size >= stream->period_bytes) { + if (block->size >= stream->period_bytes) { With best regards, Volker +resp.status = VIRTIO_SND_S_OK; + sz = iov_from_buf(block->elem->in_sg, + block->elem->in_num, + 0, + , + sizeof(resp)); + +/* Copy data -if any- to guest */ +if (block->size) { +iov_from_buf(block->elem->in_sg, + block->elem->in_num, + sz, + block->data, + MIN(stream->period_bytes, block->size)); +} +virtqueue_push(block->vq, +block->elem, +sizeof(block->elem)); +virtio_notify(VIRTIO_DEVICE(stream->s), +block->vq); +QSIMPLEQ_REMOVE_HEAD(>queue, entry); +g_free(block); +available -= size; +break; +} + +available -= size; +if (!available) { +break; +} +} +if (!available) { +break; +} } } }
Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)
Emmanouil Pitsidianakis writes: > To perform audio capture we duplicate the TX logic of the previous > commit with the following difference: we receive data from the QEMU > audio backend and write it in the virt queue IO buffers the guest sends > to QEMU. When they are full (i.e. they have `period_bytes` amount of > data) or when recording stops in QEMU's audio backend, the buffer is > returned to the guest by notifying it. > > Signed-off-by: Emmanouil Pitsidianakis > Reviewed-by: Alex Bennée -- Alex Bennée Virtualisation Tech Lead @ Linaro
[PATCH v8 11/12] virtio-sound: implement audio capture (RX)
To perform audio capture we duplicate the TX logic of the previous commit with the following difference: we receive data from the QEMU audio backend and write it in the virt queue IO buffers the guest sends to QEMU. When they are full (i.e. they have `period_bytes` amount of data) or when recording stops in QEMU's audio backend, the buffer is returned to the guest by notifying it. Signed-off-by: Emmanouil Pitsidianakis --- hw/virtio/trace-events | 3 +- hw/virtio/virtio-snd.c | 245 +++-- 2 files changed, 215 insertions(+), 33 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 3b95e745c2..9b7fbffedc 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -172,4 +172,5 @@ virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PR virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" virtio_snd_pcm_stream_flush(uint32_t stream) "flushing stream %"PRIu32 -virtio_snd_handle_xfer(void) "tx/rx queue callback called" +virtio_snd_handle_tx_xfer(void) "tx queue callback called" +virtio_snd_handle_rx_xfer(void) "rx queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 4859ce4bf6..70e8a73072 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -27,18 +27,21 @@ #define VIRTIO_SOUND_VM_VERSION 1 #define VIRTIO_SOUND_JACK_DEFAULT 0 -#define VIRTIO_SOUND_STREAM_DEFAULT 1 +#define VIRTIO_SOUND_STREAM_DEFAULT 2 #define VIRTIO_SOUND_CHMAP_DEFAULT 0 #define VIRTIO_SOUND_HDA_FN_NID 0 static void virtio_snd_pcm_out_cb(void *data, int available); static void virtio_snd_process_cmdq(VirtIOSound *s); -static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream); -static uint32_t -virtio_snd_pcm_read_write(VirtIOSoundPCMStream *stream, - VirtQueue *vq, - VirtQueueElement *element, - bool read); +static void virtio_snd_pcm_out_flush(VirtIOSoundPCMStream *stream); +static void virtio_snd_pcm_in_flush(VirtIOSoundPCMStream *stream); +static void virtio_snd_pcm_in_cb(void *data, int available); +static uint32_t virtio_snd_pcm_write(VirtIOSoundPCMStream *stream, + VirtQueue *vq, + VirtQueueElement *element); +static uint32_t virtio_snd_pcm_read(VirtIOSoundPCMStream *stream, +VirtQueue *vq, +VirtQueueElement *element); static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8) | BIT(VIRTIO_SND_PCM_FMT_U8) @@ -394,6 +397,9 @@ static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream) if (stream->direction == VIRTIO_SND_D_OUTPUT) { AUD_close_out(>pcm->snd->card, stream->voice.out); stream->voice.out = NULL; +} else if (stream->direction == VIRTIO_SND_D_INPUT) { +AUD_close_in(>pcm->snd->card, stream->voice.in); +stream->voice.in = NULL; } qemu_mutex_destroy(>queue_mutex); g_free(stream); @@ -456,7 +462,12 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) virtio_snd_pcm_out_cb, ); } else { -qemu_log_mask(LOG_UNIMP, "virtio_snd: input/capture is unimplemented."); +stream->voice.in = AUD_open_in(>card, +stream->voice.in, +"virtio-sound.in", +stream, +virtio_snd_pcm_in_cb, +); } stream->as = as; @@ -522,6 +533,8 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s, if (stream) { if (stream->direction == VIRTIO_SND_D_OUTPUT) { AUD_set_active_out(stream->voice.out, start); +} else { +AUD_set_active_in(stream->voice.in, start); } /* remove previous buffers. */ WITH_QEMU_LOCK_GUARD(>queue_mutex) { @@ -604,7 +617,11 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s, */ virtio_snd_process_cmdq(stream->s); trace_virtio_snd_pcm_stream_flush(stream_id); -virtio_snd_pcm_flush(stream); +if (stream->direction == VIRTIO_SND_D_OUTPUT) { +virtio_snd_pcm_out_flush(stream); +} else { +virtio_snd_pcm_in_flush(stream); +} } cmd->resp.code = VIRTIO_SND_S_OK; @@ -763,7 +780,7 @@ static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq) * @vdev: VirtIOSound device * @vq: tx virtqueue */ -static void virtio_snd_handle_tx(VirtIODevice *vdev, VirtQueue *vq) +static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)