Skip to content

Implement VirtIO sound device capture#115

Open
Cuda-Chen wants to merge 2 commits into
sysprog21:masterfrom
Cuda-Chen:add-virtio-snd-rx
Open

Implement VirtIO sound device capture#115
Cuda-Chen wants to merge 2 commits into
sysprog21:masterfrom
Cuda-Chen:add-virtio-snd-rx

Conversation

@Cuda-Chen

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

Copy link
Copy Markdown
Collaborator

Summary by cubic

Implements VirtIO sound capture (RX) with PortAudio input and full RX virtqueue support so mic audio reaches the guest. Adds wake-fd IRQ signaling and keeps TX/RX fully split with separate paths and threads.

  • New Features
    • RX virtqueue handler and TX/RX flush handlers; default flush streams: TX=0, RX=1.
    • Separate PortAudio callbacks; RX opens the default input device and uses the guest’s period_bytes.
    • TX/RX buffer queues with enqueue/dequeue helpers; RX dequeues only while the stream is running.
    • Dedicated TX and RX worker threads with separate mutex/cond vars and VSND_QUEUE_TX/RX notifications; added wake_fd to signal IRQs and wake the host loop.
    • Two streams (output + input), mono S16; README adds an ALSA XRUN note for capture.

Written for commit 352b5e2. Summary will update on new commits.

Review in cubic

jserv

This comment was marked as resolved.

@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
Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c
Comment on lines +995 to +997
static void __virtio_snd_rx_frame_dequeue(void *out,
uint32_t n,
uint32_t stream_id)

Copy link
Copy Markdown
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);

Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c Outdated
@jserv

This comment was marked as resolved.

@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
Comment thread Makefile Outdated
Comment thread virtio-snd.c Outdated
@jserv

jserv commented Dec 17, 2025

Copy link
Copy Markdown
Collaborator

Can we perform loopback tests with virtio sound device?

@Cuda-Chen

Cuda-Chen commented Dec 17, 2025

Copy link
Copy Markdown
Collaborator Author

Can we perform loopback tests with virtio sound device?

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

@jserv

jserv commented Dec 17, 2025

Copy link
Copy Markdown
Collaborator

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

The headless verification is crucial for CI/CD integration.

@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch 3 times, most recently from fd4f538 to a2348ec Compare December 18, 2025 11:02
@Cuda-Chen Cuda-Chen marked this pull request as ready for review December 18, 2025 11:46
@Cuda-Chen Cuda-Chen requested a review from jserv December 18, 2025 11:46
cubic-dev-ai[bot]

This comment was marked as resolved.

Comment thread .ci/test-sound.sh Outdated
cubic-dev-ai[bot]

This comment was marked as resolved.

@sysprog21 sysprog21 deleted a comment from cubic-dev-ai Bot Dec 19, 2025

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 issues found across 4 files

Prompt for AI agents (all 5 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="README.md">

<violation number="1" location="README.md:17">
P3: Grammar issue: &#39;stuck&#39; should be &#39;to get stuck&#39; and &#39;being rebooted&#39; should be &#39;is rebooted&#39;.</violation>

<violation number="2" location="README.md:21">
P3: Subject-verb agreement error: &quot;ALSA usually get stuck&quot; should be &quot;ALSA usually gets stuck&quot;.</violation>
</file>

<file name=".github/workflows/main.yml">

<violation number="1" location=".github/workflows/main.yml:72">
P1: The sound test runs unconditionally for all matrix variants, including when `matrix.dependency == &#39;none&#39;` where no sound library is installed. This will likely cause the test to fail. Consider adding a condition similar to the install step.</violation>
</file>

<file name="virtio-snd.c">

<violation number="1" location="virtio-snd.c:857">
P1: Potential double-free: `props-&gt;intermediate` is freed in error path but not set to NULL. If `virtio_snd_read_pcm_release` is called later (state is already PREPARE), it will free the same pointer again.</violation>

<violation number="2" location="virtio-snd.c:1225">
P1: Missing NULL checks after malloc. If memory allocation fails, dereferencing `node` or `node-&gt;addr` will cause a crash.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

Comment thread README.md Outdated
Comment thread README.md Outdated
run: sudo .ci/test-netdev.sh
shell: bash
timeout-minutes: 10
- name: sound test

@cubic-dev-ai cubic-dev-ai Bot Dec 19, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: The sound test runs unconditionally for all matrix variants, including when matrix.dependency == 'none' where no sound library is installed. This will likely cause the test to fail. Consider adding a condition similar to the install step.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/main.yml, line 72:

<comment>The sound test runs unconditionally for all matrix variants, including when `matrix.dependency == &#39;none&#39;` where no sound library is installed. This will likely cause the test to fail. Consider adding a condition similar to the install step.</comment>

<file context>
@@ -69,6 +69,10 @@ jobs:
       run: sudo .ci/test-netdev.sh
       shell: bash
       timeout-minutes: 10
+    - name: sound test
+      run: .ci/test-sound.sh
+      shell: bash
</file context>
Suggested change
- name: sound test
- name: sound test
if: matrix.dependency != 'none'
Fix with Cubic

Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c Outdated
cubic-dev-ai[bot]

This comment was marked as resolved.

cubic-dev-ai[bot]

This comment was marked as resolved.

cubic-dev-ai[bot]

This comment was marked as resolved.

@sysprog21 sysprog21 deleted a comment from cubic-dev-ai Bot Dec 22, 2025
@sysprog21 sysprog21 deleted a comment from cubic-dev-ai Bot Dec 22, 2025
cubic-dev-ai[bot]

This comment was marked as resolved.

cubic-dev-ai[bot]

This comment was marked as resolved.

Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c Outdated
Comment thread virtio-snd.c Outdated

@jserv jserv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

VSND_GEN_RX_QUEUE_HANDLER is 116 lines of macro that's 95% identical to VSND_GEN_TX_QUEUE_HANDLER. This is not "good taste."

@jserv

jserv commented Dec 24, 2025

Copy link
Copy Markdown
Collaborator

commit message:

Due to 'semu' emulation part thus 'semu' cannot send or receive PCM frames in time, the capture feature usually
doesn't work.

You're adding 400+ lines of code that "usually doesn't work"? This should be a draft/experimental branch, not a merge candidate. If it doesn't work, why are we adding CI tests that codify broken behavior?

@jserv

jserv commented Dec 24, 2025

Copy link
Copy Markdown
Collaborator

Missing Lock on TX Notify Path:

  case VSND_QUEUE_TX:
      tx_ev_notify++;  // NO LOCK!
      pthread_cond_signal(&virtio_snd_tx_cond);
      break;

  // virtio-snd.c:1455 - RX path (new code)
  case VSND_QUEUE_RX:
      pthread_mutex_lock(&virtio_snd_rx_mutex);  // HAS LOCK
      rx_ev_notify++;
      pthread_cond_signal(&virtio_snd_rx_cond);
      pthread_mutex_unlock(&virtio_snd_rx_mutex);
      break;

Inconsistent synchronization patterns between TX and RX. TX is already racy - RX is correct but highlights the TX bug.

cubic-dev-ai[bot]

This comment was marked as resolved.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 1 file (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="virtio-snd.c">

<violation number="1" location="virtio-snd.c:1132">
P1: Using `pthread_mutex_trylock` silently drops audio frames when the lock is unavailable. This will cause audio data loss and artifacts in the capture stream. Consider either using blocking `pthread_mutex_lock` with a timeout, or implementing a lock-free ring buffer for the real-time audio callback.</violation>

<violation number="2" location="virtio-snd.c:1133">
P2: Debug `fprintf` in the real-time audio callback path should be removed. Calling `fprintf` from a PortAudio callback can cause audio glitches as it may block.</violation>

<violation number="3" location="virtio-snd.c:1152">
P2: Debug `fprintf` in the real-time audio callback path should be removed.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

Comment thread virtio-snd.c
pthread_cond_signal(&props->lock.readable);

rx_frame_enque_finally:
fprintf(stderr, "enque end\n");

@cubic-dev-ai cubic-dev-ai Bot Dec 24, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Debug fprintf in the real-time audio callback path should be removed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At virtio-snd.c, line 1152:

<comment>Debug `fprintf` in the real-time audio callback path should be removed.</comment>

<file context>
@@ -1119,29 +1126,32 @@ static void __virtio_snd_rx_frame_enqueue(const void *payload,
-rx_frame_enque_finally:
-    pthread_mutex_unlock(&amp;props-&gt;lock.lock);
+    rx_frame_enque_finally:
+        fprintf(stderr, &quot;enque end\n&quot;);
+        pthread_mutex_unlock(&amp;props-&gt;lock.lock);
+    }
</file context>
Fix with Cubic

Comment thread virtio-snd.c
while (props->lock.buf_ev_notity > 0)
pthread_cond_wait(&props->lock.writable, &props->lock.lock);*/
if (pthread_mutex_trylock(&props->lock.lock) == 0) {
fprintf(stderr, "enque start \n");

@cubic-dev-ai cubic-dev-ai Bot Dec 24, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Debug fprintf in the real-time audio callback path should be removed. Calling fprintf from a PortAudio callback can cause audio glitches as it may block.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At virtio-snd.c, line 1133:

<comment>Debug `fprintf` in the real-time audio callback path should be removed. Calling `fprintf` from a PortAudio callback can cause audio glitches as it may block.</comment>

<file context>
@@ -1119,29 +1126,32 @@ static void __virtio_snd_rx_frame_enqueue(const void *payload,
-    list_push(&amp;node-&gt;q, &amp;props-&gt;buf_queue_head);
+        pthread_cond_wait(&amp;props-&gt;lock.writable, &amp;props-&gt;lock.lock);*/
+    if (pthread_mutex_trylock(&amp;props-&gt;lock.lock) == 0) {
+        fprintf(stderr, &quot;enque start \n&quot;);
+        /* Add a PCM frame to queue */
+        vsnd_buf_queue_node_t *node = malloc(sizeof(*node));
</file context>
Fix with Cubic

Comment thread virtio-snd.c
/*pthread_mutex_lock(&props->lock.lock);
while (props->lock.buf_ev_notity > 0)
pthread_cond_wait(&props->lock.writable, &props->lock.lock);*/
if (pthread_mutex_trylock(&props->lock.lock) == 0) {

@cubic-dev-ai cubic-dev-ai Bot Dec 24, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Using pthread_mutex_trylock silently drops audio frames when the lock is unavailable. This will cause audio data loss and artifacts in the capture stream. Consider either using blocking pthread_mutex_lock with a timeout, or implementing a lock-free ring buffer for the real-time audio callback.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At virtio-snd.c, line 1132:

<comment>Using `pthread_mutex_trylock` silently drops audio frames when the lock is unavailable. This will cause audio data loss and artifacts in the capture stream. Consider either using blocking `pthread_mutex_lock` with a timeout, or implementing a lock-free ring buffer for the real-time audio callback.</comment>

<file context>
@@ -1119,29 +1126,32 @@ static void __virtio_snd_rx_frame_enqueue(const void *payload,
-    node-&gt;pos = 0;
-    list_push(&amp;node-&gt;q, &amp;props-&gt;buf_queue_head);
+        pthread_cond_wait(&amp;props-&gt;lock.writable, &amp;props-&gt;lock.lock);*/
+    if (pthread_mutex_trylock(&amp;props-&gt;lock.lock) == 0) {
+        fprintf(stderr, &quot;enque start \n&quot;);
+        /* Add a PCM frame to queue */
</file context>
Fix with Cubic

@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch 3 times, most recently from 782e188 to 93ebde8 Compare January 7, 2026 04:04
Comment thread virtio-snd.c
#include "virtio.h"

#define VSND_DEV_CNT_MAX 1
#define VSND_DEV_CNT_MAX 2

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Provide comments to explain.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This PR is going to add capture device. As each VirtIO sound device can have only one direction when initialization (VIRTIO_SND_D_OUTPUT or VIRTIO_SND_D_INPUT), I set VSND_DEV_CNT_MAX to 2 (one for playback, and the other for capture).

Comment thread virtio-snd.c
Comment on lines +755 to +759
err = Pa_OpenStream(&props->pa_stream, &params, NULL /* no output */,
rate, cnfa_period_frames, paClipOff,
virtio_snd_rx_stream_cb, &props->v);
if (err != paNoError)
goto pa_err;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you provide early diagnosis when PortAudio fails?

Comment thread virtio-snd.c Outdated
@jserv jserv force-pushed the master branch 2 times, most recently from a40042a to 07c7618 Compare April 25, 2026 16:41
@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch 2 times, most recently from 055f60a to 429d9d2 Compare May 1, 2026 02:29
@Cuda-Chen Cuda-Chen force-pushed the add-virtio-snd-rx branch from 429d9d2 to a5b8265 Compare May 19, 2026 15:20
@cubic-dev-ai

cubic-dev-ai Bot commented May 31, 2026

Copy link
Copy Markdown

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

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