Fix guest sound playback XRUN issue
CU
2d ago+482+482+012345678901234567890123456789-180-180-012345678901234567890123456789
Fix guest OS sound playback XRUN (underrun, specifically) issue.
As using a concurrent queue with conditional variables holding PCM
frames, apply the famous self pipe trick so that the emulator can
safely handle asynchronous signals when virtio-snd is enabled.
Test Procedures
- Set these parameters to
=yin the Linux Kernel config:
CONFIG_SND_PCM_XRUN_DEBUG=y
CONFIG_SND_VERBOSE_PROCFS=y
CONFIG_SND_DEBUG=y
- Remove the existing config using
rm linux/.config. - Compile the Linux Kernel with
./scripts/build-image.sh --linux. - Run
make checkto run emulated guest OS. - After login into guest OS, run
echo 3 > /proc/asound/card0/pcmp0/xrun_debug. - Run
aplay /usr/share/sounds/alsa/Front_Center.wavthree times in guest OS. - In guest OS, run
dmesg.
Expected Results
- The
dmesgshould not produce any XRUN messages, for example:
# dmesg
...
[ 65.908925] ALSA: PCM: [Q] Lost interrupts?: (stream=1, delta=4000, new_hw_ptr=4000, old_hw_ptr=0)
[ 65.913926] CPU: 0 UID: 0 PID: 10 Comm: kworker/0:1 Not tainted 6.12.61 #1
[ 65.914926] Hardware name: semu (DT)
[ 65.914926] Workqueue: events virtsnd_pcm_period_elapsed
[ 65.915927] Call Trace:
[ 65.915927] [<c0004aa4>] dump_backtrace+0x2c/0x3c
[ 65.916927] [<c0419a74>] show_stack+0x40/0x54
[ 65.918927] [<c041f3d0>] dump_stack_lvl+0x74/0xa8
[ 65.919928] [<c041f420>] dump_stack+0x1c/0x2c
[ 65.920928] [<c030693c>] snd_pcm_update_hw_ptr0+0x46c/0x540
[ 65.921928] [<c0306a7c>] snd_pcm_period_elapsed_under_stream_lock+0x6c/0x9c
[ 65.923929] [<c0306ae0>] snd_pcm_period_elapsed+0x34/0x54
[ 65.924929] [<c030bc28>] virtsnd_pcm_period_elapsed+0x18/0x28
[ 65.926929] [<c0027760>] process_scheduled_works+0x1dc/0x2a4
[ 65.927930] [<c0027d74>] worker_thread+0x170/0x208
[ 65.928930] [<c002ff4c>] kthread+0xe0/0xe4
[ 65.929930] [<c04276c8>] ret_from_exception_end+0x14/0x20
Summary by cubic
Fixes guest audio playback XRUNs and the dropped final period by unblocking the emulator event loop on TX used-ring updates, honoring the guest's period size, and draining PortAudio buffers before stop.
- Enables the emulator self-pipe for
VIRTIOSND, with wake-pipe creation decoupled from the window backend forENABLE_SDL=0builds. - Updates the used-ring per element and validates PCM parameters in set-params and prepare, computing period frames from the guest's
period_bytes. - Clears the releasing flag on START, records START only after
Pa_StartStreamsucceeds, and blocks STOP until PortAudio drains on a wait capped at one period plus slack (minimum 2s). - Uses
tx_busyandvirtio_snd_tx_doneso STOP, PREPARE, and RELEASE wait for both in-flight TX submissions and queued buffers; enqueue failures now reportVIRTIO_SND_S_IO_ERR. - Allocates the device state and starts the TX worker before PortAudio init so headless audio failures leave MMIO state intact; guards
vsnd->privin status updates and register access. - Joins the TX thread and terminates PortAudio in
virtio_snd_cleanup, closingwake_fd[1]beforewake_fd[0], and removes the buffer-size workaround fromREADME.md.