Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)

2023-09-09 Thread Volker Rümelin

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)

2023-09-08 Thread Volker Rümelin

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)

2023-08-30 Thread Alex Bennée


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)

2023-08-28 Thread 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
@@ -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)