Skip to content

Conversation

@roderickvd
Copy link
Member

Fixes device enumeration on systems where ALSA hints don't include physical devices.

  • Now combines ALSA hints with physical card probing, so all hardware is discovered even when hints don't list it
  • Devices now report DeviceDirection::Input/Output/Duplex/Unknown based on hint metadata and hardware capabilities (previously all devices reported None)
  • Added Default implementation that returns the ALSA "default" device

Fixes #1079

This comment was marked as resolved.

@roderickvd roderickvd force-pushed the fix/alsa-card-enumeration branch from 10aa237 to c4d9996 Compare December 27, 2025 17:26
Combines ALSA hints with physical card probing to ensure all hardware
devices are enumerated, even when hints don't list them.
- Add hybrid enumeration: hints (virtual/configured) + physical probing
- Add direction detection from hint metadata and physical hardware
- Add Default implementation for Device
- Remove unused StreamType enum

Fixes #1079

This comment was marked as resolved.

@roderickvd roderickvd force-pushed the fix/alsa-card-enumeration branch from e2f8abf to 2ad6603 Compare December 27, 2025 17:45
Copy link

@calwe calwe left a comment

Choose a reason for hiding this comment

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

While I obviously don't feel qualified to give a technical review in this code base, these changes do in fact work for me - and correctly show both the virtual devices from hints, and now the same hardware devices that would appear in 0.16. Cheers!

Per ALSA docs, NULL IOID indicates both input and output; mark hints
with NULL as DeviceDirection::Duplex. Whether a stream actually works in
a direction must be determined by attempting to open it.
@roderickvd roderickvd force-pushed the fix/alsa-card-enumeration branch 2 times, most recently from 39541ba to bab2fdd Compare December 30, 2025 21:01
* Don't open devices during enumeration to avoid leaking file
descriptors from failed snd_pcm_open (e.g. alsaequal returning EPERM).

* Treat EPERM and EAGAIN like ENOENT/EBUSY and return DeviceNotAvailable.
* Map ENOENT, EBUSY, EPERM and EAGAIN returned when taking a PCM
handle to DeviceNotAvailable.

* Add a comment to clarify reuse of cached device handles to avoid
opening the device twice.

* Minor documentation improvements.
@roderickvd roderickvd force-pushed the fix/alsa-card-enumeration branch from bab2fdd to dfec6ac Compare December 30, 2025 21:06
@roderickvd
Copy link
Member Author

While I obviously don't feel qualified to give a technical review in this code base, these changes do in fact work for me - and correctly show both the virtual devices from hints, and now the same hardware devices that would appear in 0.16.

Thank you for the feedback and testing! Your confirmation helped uncover two additional issues that needed addressing:

  • ALSA hint direction handling: When ALSA returns NULL for a PCM hint's IOID, it indicates the device supports both playback and capture directions. However, you cannot determine whether either direction actually works without attempting to open the device. I initially mapped this to DeviceDirection::Unknown, but that conflicted with the supports_input/output trait methods.

    The solution was to align with ALSA's semantics and report it as DeviceDirection::Duplex.

  • ALSA library bug: During testing on a system with an alsaequal device that returned EPERM (disabled), I discovered that output_devices() failed to enumerate any hardware devices, even though devices() enumerated them correctly. The root cause is an ALSA library bug: when snd_pcm_open() fails during plugin initialization, it can leak file descriptors to hardware devices, poisoning the ALSA backend for the process lifetime.

    To avoid this, I overrode the default supports_input/output trait implementations to check DeviceDirection metadata instead of querying for supported configs. This is less precise but more robust against such library bugs.

None of this is ideal. Applications will need to attempt opening a stream to be certain that a particular direction works. But it provides better compatibility across real-world ALSA configurations.

If you could give this a final whirl on your systems too, this could warrant releasing a patch release sometime soon.

@roderickvd roderickvd merged commit eb213b4 into master Dec 30, 2025
31 checks passed
@roderickvd roderickvd deleted the fix/alsa-card-enumeration branch December 30, 2025 21:41
@roderickvd
Copy link
Member Author

For posterity I want to mention that this'll show most virtual devices are capture devices. Typically most of them won't actually be capture devices, but, the fact that arecord does the same is proof that we're doing the right thing:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
$ arecord -L
null
    Discard all samples (playback) or generate zero samples (capture)
default
    Default Audio Device
sysdefault
    Default Audio Device
_audioout
_audioout__
alsaequal
plug_alsaequal
btstream
camilladsp
crossfeed
plug_bs2b
eqfa12p
plug_eqfa12p
invpolarity
trx_send

And for playback, output from aplay:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Y1 [Yggdrasil+ 384 1], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: vc4hdmi0 [vc4-hdmi-0], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: vc4hdmi1 [vc4-hdmi-1], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default
    Default Audio Device
sysdefault
    Default Audio Device
_audioout
_audioout__
alsaequal
plug_alsaequal
btstream
camilladsp
crossfeed
plug_bs2b
eqfa12p
plug_eqfa12p
invpolarity
trx_send
hw:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    Direct hardware device without any conversions
plughw:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    Hardware device with all software conversions
default:CARD=Y1
    Yggdrasil+ 384 1, USB Audio
    Default Audio Device
sysdefault:CARD=Y1
    Yggdrasil+ 384 1, USB Audio
    Default Audio Device
front:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    Front output / input
surround21:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    2.1 Surround output to Front and Subwoofer speakers
surround40:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    4.0 Surround output to Front and Rear speakers
surround41:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    4.1 Surround output to Front, Rear and Subwoofer speakers
surround50:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    5.0 Surround output to Front, Center and Rear speakers
surround51:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
surround71:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
iec958:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    IEC958 (S/PDIF) Digital Audio Output
dmix:CARD=Y1,DEV=0
    Yggdrasil+ 384 1, USB Audio
    Direct sample mixing device
hw:CARD=vc4hdmi0,DEV=0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    Direct hardware device without any conversions
plughw:CARD=vc4hdmi0,DEV=0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    Hardware device with all software conversions
default:CARD=vc4hdmi0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    Default Audio Device
sysdefault:CARD=vc4hdmi0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    Default Audio Device
hdmi:CARD=vc4hdmi0,DEV=0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    HDMI Audio Output
dmix:CARD=vc4hdmi0,DEV=0
    vc4-hdmi-0, MAI PCM i2s-hifi-0
    Direct sample mixing device
hw:CARD=vc4hdmi1,DEV=0
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    Direct hardware device without any conversions
plughw:CARD=vc4hdmi1,DEV=0
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    Hardware device with all software conversions
default:CARD=vc4hdmi1
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    Default Audio Device
sysdefault:CARD=vc4hdmi1
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    Default Audio Device
hdmi:CARD=vc4hdmi1,DEV=0
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    HDMI Audio Output
dmix:CARD=vc4hdmi1,DEV=0
    vc4-hdmi-1, MAI PCM i2s-hifi-0
    Direct sample mixing device

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enumerating ALSA devices by hints does not guarantee getting physical devices

3 participants