Skip to content

Conversation

@Cuda-Chen
Copy link
Collaborator

@Cuda-Chen Cuda-Chen commented Nov 17, 2025

Summary by cubic

Implements VirtIO sound capture (RX) with PortAudio input, RX virtqueue handling, and circular buffering so input audio can be delivered to the guest. Also exposes separate input/output streams with accurate device info.

  • New Features
    • Added RX virtqueue handlers (normal/flush) with default flush stream_id = 1.
    • Opened PortAudio input stream and RX callback to capture frames and enqueue to the driver.
    • Implemented circular intermediate buffer (buf_sz, buf_idx) and RX enqueue/dequeue helpers.
    • Exposed two streams (output + input), mono S16, with per-stream jack/pcm/chmap info.
    • Added RX worker thread, mutex/cond vars, and VSND_QUEUE_RX notifications.
    • Applied direction-aware flush in pcm_release and set RX response length/status.
    • Added CI sound tests for playback and capture and wired them into GitHub Actions.

Written for commit fd4f538. Summary will update automatically on new commits.

Copy link
Collaborator

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase to avoid unnecessary merge commits.

@jserv

This comment was marked as resolved.

@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch 2 times, most recently from 54a45b5 to 05b22f9 Compare November 17, 2025 10:31
virtio-snd.c Outdated
Comment on lines 1200 to 1217
static void __virtio_snd_rx_frame_enqueue(void *payload,
uint32_t n,
uint32_t stream_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__virtio_snd_rx_frame_enqueue() never increments buf_ev_notity or signals the condition variable, but __virtio_snd_rx_frame_dequeue() waits on it:

  // In __virtio_snd_rx_frame_dequeue:
  while (props->lock.buf_ev_notity < 1)
      pthread_cond_wait(&props->lock.readable, ...);  // BLOCKS FOREVER

The TX path correctly does:

  props->lock.buf_ev_notity++;
  pthread_cond_signal(&props->lock.readable);

Fix: Add after list_push() in __virtio_snd_rx_frame_enqueue:

  props->lock.buf_ev_notity++;
  pthread_cond_signal(&props->lock.readable);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The buf_ev_notity will be increased and then signals the update of CV after consuming all the virtq elements when calling virtio_snd_rx_desc_normal_handler():

// In VSND_GEN_RX_QUEUE_HANDLER macro

virtio_snd_prop_t *props = &vsnd_props[stream_id];                   
props->lock.buf_ev_notity--;                                         
pthread_cond_signal(&props->lock.writable);

The virtio_snd_tx_desc_normal_handler() also has the same design.

The reason is that the driver should populate a period size of PCM frames (except the end of stream) as mentioned by VirtIO standard:

5.14.6.8.2.2 Driver Requirements: Input Stream

  • The driver SHOULD populate the rx queue with period_bytes sized empty buffers before starting the stream.
  • The driver MUST NOT place device-readable buffers into the rx queue.

Comment on lines +995 to +1018
static void __virtio_snd_rx_frame_dequeue(void *out,
uint32_t n,
uint32_t stream_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__virtio_snd_rx_frame_dequeue() does list_del(&node->q) but never free(node):

  if (node->pos >= node->len)
      list_del(&node->q);  // Missing: free(node);

virtio-snd.c Outdated
Comment on lines 1218 to 1232
memcpy(props->intermediate + idx, payload, base);
if (left != 0)
memcpy(props->intermediate, payload + base, left);
props->buf_idx = (props->buf_idx + n) % sz;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RX circular buffer design stores node->addr = props->intermediate + idx, meaning multiple nodes can point to overlapping regions. When the buffer wraps, older data gets overwritten while nodes still reference it.

If enqueue outruns dequeue, later writes corrupt earlier node data. The TX path copies data differently (uses the queue nodes as independent buffers).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jserv ,

Thanks for the suggestion.
Though it will take some time, I think let's stick the list of frames rather than the circular buffer design.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it will take some time, I think let's stick the list of frames rather than the circular buffer design.

You should express with strong reasons.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jserv ,

The circular buffer design requires no further memory allocation, whereas the list of frames design requires one memory allocation every time the device stores the content of a frame.

@jserv
Copy link
Collaborator

jserv commented Dec 17, 2025

Debug Printf Pollution
Multiple fprintf(stderr, ...) debug statements throughout the RX path should be removed before merge.

@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch 2 times, most recently from be341b2 to 1a14913 Compare December 17, 2025 06:16
@jserv
Copy link
Collaborator

jserv commented Dec 17, 2025

Can we perform loopback tests with virtio sound device?

@Cuda-Chen
Copy link
Collaborator Author

Cuda-Chen commented Dec 17, 2025

Can we perform loopback tests with virtio sound device?

You mean aloop or a device loopback testing command like arecord -C | aplay -?

@jserv
Copy link
Collaborator

jserv commented Dec 17, 2025

You mean aloop of a device loopback testing command like arecord -C | aplay -?

The headless verification is crucial for CI/CD integration.

Implement VirtIO sound device capture, with adding notice
that the capture usually doesn't work for the reason of 'semu'
emulation part.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants