pcm_meter: let the s16 scope degrade instead of killing the caller#516
Open
Gjuju wants to merge 1 commit into
Open
pcm_meter: let the s16 scope degrade instead of killing the caller#516Gjuju wants to merge 1 commit into
Gjuju wants to merge 1 commit into
Conversation
s16_enable() returns -EINVAL for any format it cannot convert to S16 - DSD, the 3-byte packed formats, float. snd_pcm_scope_enable() records that as "not enabled" and carries on, so the buffer is never allocated. Any other scope stays enabled, though, and scopes reach the s16 buffer through snd_pcm_scope_s16_get_channel_buffer(), which asserts on exactly that never-allocated pointer. The application dies. Our own level scope does this, so alsa-lib kills its own caller; the same happens to libpeppyalsa, where a DSD track aborts the music player mid-playback. Allocate the buffer anyway and leave it zero, so a scope reads silence on a format the s16 conversion cannot see. Callers need no change and none can be made to abort. The condition is reported once through SNDERR rather than being swallowed. The neighbouring S16/MMAP_NONINTERLEAVED branch returns -EINVAL after assigning s16->buf and reaches the same dead end; it is left alone here because its intent is unclear. Signed-off-by: Julien Gainza <gainza.julien@gmail.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gjuju
force-pushed
the
scope-silence-instead-of-abort
branch
from
July 21, 2026 23:14
fee0a47 to
cccbb24
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
s16_enable()returns-EINVALfor any format it cannot convert to S16 — the DSDformats, the 3-byte packed ones (
S24_3LE/S24_3BE/S20_3LE), float.snd_pcm_scope_enable()records that as "not enabled" and carries on:But every other scope stays enabled, and scopes reach the s16 buffer through
snd_pcm_scope_s16_get_channel_buffer(), which asserts on exactly the pointers16_enable()never allocated:The application dies. This is not hypothetical and not third-party only: alsa-lib's own
src/pcm/scopes/level.ccalls the accessor the same way, so the library aborts its owncaller. Downstream,
libpeppyalsa(the VU-meter scope used by moOde audio player) makesa music player abort mid-playback the moment a DSD track starts.
Note the failure is not DSD-specific — any format outside the 17 the switch lists
triggers it, including
S24_3LE, which plenty of USB DACs expose natively. A chain thathappens to have a
plugin front of the meter is merely lucky.The fix
Allocate the buffer anyway and leave it zero, so a scope reads silence on a format
the s16 conversion cannot see. Callers need no change, and none can be made to abort —
which matters, since returning
NULLinstead would only move an unfixed caller fromSIGABRTtoSIGSEGV. The condition is now reported once throughSNDERR()instead ofbeing swallowed.
Testing
x86-64, Debian 13, USB DAC with a native DSD path, moOde audio player with its VU meter
scope in the chain. Playing a DSD64
.dsfwithdop=no:DSD_U32_BE @ 88200bit-perfect, MPD stays up(
NRestarts: 0), needles read zero, and the log carriess16 scope: no S16 conversion for format DSD_U32_BE, scopes will read silenceLeft alone
The neighbouring
S16+MMAP_NONINTERLEAVEDbranch assignss16->bufand then alsoreturns
-EINVAL, reaching the same dead end. It looks unfinished rather thandeliberate, so this patch does not touch it — happy to follow up if you can confirm the
intent.