Bug 296325 - OSS: RODECaster 2 returns ENOSPC when opened with bitperfect=0
Summary: OSS: RODECaster 2 returns ENOSPC when opened with bitperfect=0
Status: Closed Works As Intended
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 15.1-STABLE
Hardware: Any Any
: --- Affects Only Me
Assignee: Christos Margiolis
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2026-06-27 16:42 UTC by Nicolas Goy
Modified: 2026-07-14 14:08 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nicolas Goy 2026-06-27 16:42:42 UTC
I have a RODECaster 2 which I want to use with OSS.

It works with `sysctl dev.pcm.n.bitperfect=1` (with the bitperfect caveats) I can then use pulseaudio or jack with it, but if I set bitperfect to 0, then `open("/dev/dspN", O_WRONLY);`  returns ENOSPC.

fuser shows no other process using the device
Comment 1 Christos Margiolis freebsd_committer freebsd_triage 2026-06-29 07:48:28 UTC
sound(4) does not return ENOSPC anywhere. Is this coming from pulseaudio? Also whatis the output of sndctl -v?
Comment 2 Nicolas Goy 2026-06-29 12:23:35 UTC
(In reply to Christos Margiolis from comment #1)

The ENOSPC comes from the open() call.

I wrote a sample c program that does only:

int fd = open(path, O_WRONLY);

where path is /dev/dsp6

and this returns ENOSPC

I am doing that, because I am working on the multichannel support for pipewire pw-oss rust module.


Here is the output from sndctl with bitperfect=0

pcm6: <RDE RODECaster Pro II> on uaudio0 (play/rec)
    name                = pcm6
    desc                = RDE RODECaster Pro II
    status              = on uaudio0
    devnode             = dsp6
    from_user           = 0
    unit                = 6
    caps                = INPUT,MMAP,OUTPUT,REALTIME,TRIGGER,VIRTUAL
    bitperfect          = 0
    autoconv            = 1
    realtime            = 0
    play.format         = s32le:10.0
    play.rate           = 48000
    play.vchans         = 1
    play.min_rate       = 1
    play.max_rate       = 2016000
    play.min_chans      = 10
    play.max_chans      = 10
    play.formats        = s32le
    rec.rate            = 48000
    rec.format          = s32le:16.0
    rec.vchans          = 1
    rec.min_rate        = 1
    rec.max_rate        = 2016000
    rec.min_chans       = 16
    rec.max_chans       = 16
    rec.formats         = s32le
    dsp6.play.0
        parentchan          = 
        unit                = 0
        caps                = MMAP,OUTPUT,REALTIME,TRIGGER
        latency             = 2
        rate                = 48000
        format              = s32le:10.0
        pid                 = -1
        proc                = <UNUSED>
        interrupts          = 35008086
        xruns               = 0
        feedcount           = 35008085
        volume              = 0.45:0.45
        hwbuf.format        = s32le:10.0
        hwbuf.rate          = 48000
        hwbuf.size_bytes    = 15360
        hwbuf.size_frames   = 384
        hwbuf.blksz         = 7680
        hwbuf.blkcnt        = 2
        hwbuf.free          = 0
        hwbuf.ready         = 15360
        swbuf.format        = s32le:10.0
        swbuf.rate          = 48000
        swbuf.size_bytes    = 16320
        swbuf.size_frames   = 408
        swbuf.blksz         = 8160
        swbuf.blkcnt        = 2
        swbuf.free          = 16320
        swbuf.ready         = 0
        feederchain         = [userland -> feeder_mixer(s32le:10.0) -> hardware]
    dsp6.virtual_play.1
        parentchan          = dsp6.play.0
        unit                = 1
        caps                = MMAP,OUTPUT,REALTIME,TRIGGER,VIRTUAL
        latency             = -1
        rate                = 48000
        format              = s32le:10.0
        pid                 = 59828
        proc                = chatterino
        interrupts          = 0
        xruns               = 34291308
        feedcount           = 34383046
        volume              = 0.45:0.45
        hwbuf.format        = s32le:10.0
        hwbuf.rate          = 48000
        hwbuf.size_bytes    = 0
        hwbuf.size_frames   = 0
        hwbuf.blksz         = 0
        hwbuf.blkcnt        = 0
        hwbuf.free          = 0
        hwbuf.ready         = 0
        swbuf.format        = s32le:10.0
        swbuf.rate          = 48000
        swbuf.size_bytes    = 130880
        swbuf.size_frames   = 3272
        swbuf.blksz         = 16360
        swbuf.blkcnt        = 8
        swbuf.free          = 130880
        swbuf.ready         = 0
        feederchain         = [userland -> feeder_root(s32le:10.0) -> dsp6.play.0]
    dsp6.record.0
        parentchan          = 
        unit                = 2
        caps                = INPUT,MMAP,REALTIME,TRIGGER
        latency             = 2
        rate                = 48000
        format              = s32le:16.0
        pid                 = -1
        proc                = <UNUSED>
        interrupts          = 0
        xruns               = 0
        feedcount           = 0
        volume              = 0.45:0.45
        hwbuf.format        = s32le:16.0
        hwbuf.rate          = 48000
        hwbuf.size_bytes    = 24576
        hwbuf.size_frames   = 384
        hwbuf.blksz         = 12288
        hwbuf.blkcnt        = 2
        hwbuf.free          = 24576
        hwbuf.ready         = 0
        swbuf.format        = s32le:16.0
        swbuf.rate          = 48000
        swbuf.size_bytes    = 131072
        swbuf.size_frames   = 2048
        swbuf.blksz         = 1024
        swbuf.blkcnt        = 128
        swbuf.free          = 131072
        swbuf.ready         = 0
        feederchain         = [hardware -> feeder_root(s32le:16.0) -> userland]
Comment 3 Christos Margiolis freebsd_committer freebsd_triage 2026-06-30 11:10:38 UTC
I looked a bit at this again, I suspect this is coming from some feeder_add() and the ENOSPC gets propagated back to dsp_open(). In other words, my theory is that at some point the processing chain for the channel which the open() call tries to create, fails.

Could you run attach the output of dmesg once open() has failed?
Comment 4 Nicolas Goy 2026-06-30 11:25:17 UTC
(In reply to Christos Margiolis from comment #3)

I forgot to mention that I see nothing in dmesg when open fails. Is there any knob I could turn to display more verbose output?

I have a bunch of

pcm6: feeder_build_matrix(): can't add feeder_matrix

but this doesn't happen when I try to open the device, I just noticed them now.
Comment 5 Christos Margiolis freebsd_committer freebsd_triage 2026-06-30 11:34:38 UTC
(In reply to Nicolas Goy from comment #4)
There is the hw.snd.verbose sysctl, but I don't think you'll see something useful in this case. The dmesg tracks kernel messages, so these won't show up in your terminal normally (unless you are in a tty).

You can however run this in a separate terminal:

tail -f /var/log/messages

And see the messages as they come. Try this and let me know if the error comes when you try to open().
Comment 6 Nicolas Goy 2026-06-30 11:43:26 UTC
(In reply to Christos Margiolis from comment #5)


I have to correct what I said, the rode presents 2 device to usb port and it got renumbered and I didn't realize.

The feeder matrix error IS actually generated every time I want to open the device

feeder_init(0xfffff802f178fa80) on feeder_matrix returned 22
pcm6: feeder_build_matrix(): can't add feeder_matrix
Comment 7 Christos Margiolis freebsd_committer freebsd_triage 2026-07-03 13:06:26 UTC
(In reply to Nicolas Goy from comment #6)
It seems like your devices has 10 channels, and sound(4)'s channel matrixing supports up to 7.1. I think if we define the 10-channel matrix your device will work. Do you have any information on RODECaster's 10 channel matrix configuration, as in, which channel is which (front, back, etc)?
Comment 8 Nicolas Goy 2026-07-03 16:14:44 UTC
The device has 10 playback channels and 16 recording channels.

Those channels don't have "positions", they can be assigned on the device as wanted, for example, I can route mic one to channel 4 for recording.

Playback channels are usually grouped by 2 for stereo, but this is not an absolute requirements.

That is why in my pw-oss patch:

https://github.com/shkhln/pw-oss/pull/4

I use AUX0..n for channel names, and then I link them in pipewire as required.
Comment 9 Christos Margiolis freebsd_committer freebsd_triage 2026-07-06 12:28:54 UTC
Just out of curiosity, what happens if you limit the channels to 7.1?

# sndctl play.format=s32:7.1 rec.format=s32:7.1
Comment 10 Nicolas Goy 2026-07-06 13:14:04 UTC
(In reply to Christos Margiolis from comment #9)

It is strange because sndctl reports 20 rec channel, but it is 16 in reality.

$ doas sndctl -f /dev/dsp6 play.format=s32:7.1 rec.format=s32:7.1
dev.pcm.6.play.vchanformat: s32le:10.0 -> s32le:10.0
dev.pcm.6.rec.vchanformat: s32le:20.0 -> s32le:20.0
pcm6: <RDE RODECaster Pro II> on uaudio0 (play/rec)
    name                = pcm6
    desc                = RDE RODECaster Pro II
    status              = on uaudio0
    devnode             = dsp6
    from_user           = 0
    unit                = 6
    caps                = INPUT,MMAP,OUTPUT,REALTIME,TRIGGER,VIRTUAL
    bitperfect          = 1
    autoconv            = 0
    realtime            = 0
    play.format         = s32le:10.0
    play.rate           = 48000
    play.vchans         = 1
    play.min_rate       = 48000
    play.max_rate       = 48000
    play.min_chans      = 10
    play.max_chans      = 10
    play.formats        = s32le
    rec.rate            = 48000
    rec.format          = s32le:20.0
    rec.vchans          = 1
    rec.min_rate        = 48000
    rec.max_rate        = 48000
    rec.min_chans       = 20
    rec.max_chans       = 20
    rec.formats         = s32le
Comment 11 Christos Margiolis freebsd_committer freebsd_triage 2026-07-07 17:17:59 UTC
(In reply to Nicolas Goy from comment #10)
This is strange indeed, and I see that in your previous sndctl output it did indeed have 16 channels, although I'm not sure if the fact that you had bitperfect off and autoconv on affected things.

Does something change if you run this?

# sndctl bitperfect=0 autoconv=1 play.format=s32:7.1 rec.format=s32:7.1
Comment 12 Nicolas Goy 2026-07-10 09:25:59 UTC
(In reply to Christos Margiolis from comment #11)
oas sndctl -f /dev/dsp6 bitperfect=0 autoconv=1 play.format=s32:7.1 rec.format=s32:7.1
dev.pcm.6.bitperfect: 1 -> 0
dev.pcm.6.play.vchans: 1 -> 1
dev.pcm.6.rec.vchans: 1 -> 1
dev.pcm.6.bitperfect: 0 -> 0
sndctl: sysctlbyname(dev.pcm.6.play.vchanformat, s32:7.1): No space left on device
sndctl: play.format(s32:7.1) failed
sndctl: sysctlbyname(dev.pcm.6.rec.vchanformat, s32:7.1): No space left on device
sndctl: rec.format(s32:7.1) failed
pcm6: <RDE RODECaster Pro II> on uaudio0 (play/rec)
    name                = pcm6
    desc                = RDE RODECaster Pro II
    status              = on uaudio0
    devnode             = dsp6
    from_user           = 0
    unit                = 6
    caps                = INPUT,MMAP,OUTPUT,REALTIME,TRIGGER
    bitperfect          = 0
    autoconv            = 1
    realtime            = 0
    play.format         = s32le:10.0
    play.rate           = 48000
    play.vchans         = 1
    play.min_rate       = 1
    play.max_rate       = 2016000
    play.min_chans      = 10
    play.max_chans      = 10
    play.formats        = s32le
    rec.rate            = 48000
    rec.format          = s32le:20.0
    rec.vchans          = 1
    rec.min_rate        = 1
    rec.max_rate        = 2016000
    rec.min_chans       = 20
    rec.max_chans       = 20
    rec.formats         = s32le
Comment 13 Christos Margiolis freebsd_committer freebsd_triage 2026-07-10 13:59:02 UTC
(In reply to Nicolas Goy from comment #12)
Hmm, I suppose the "No space left on device" errors are coming from the same place as before, and dmesg shows the same error from sound(4).

Can the device be opened when you have bitperfect=1 and autoconv=0? This should skip the channel matrixing chain (and the processing chain in general).
Comment 14 Nicolas Goy 2026-07-10 14:13:11 UTC
(In reply to Christos Margiolis from comment #13)

Yes with bitperfect=1 the device works fine.
Comment 15 Christos Margiolis freebsd_committer freebsd_triage 2026-07-10 14:33:39 UTC
(In reply to Nicolas Goy from comment #14)
Right, this is kind of a known thing. If the device has more than 8 channels, then bitperfect gets automatically set. To be completely honest though, I do not know what the rationale is behind this, as in, I don't know if it's because we have not defined channel configurations above 8 channels, or if its something else. I will look into this. But the default behavior for >8 channel devices is to have bitperfect enabled.
Comment 16 Christos Margiolis freebsd_committer freebsd_triage 2026-07-10 14:41:09 UTC
What I said happens in snd_uaudio(4) (your device driver):

        if (chan_alt->channels > UAUDIO_MATRIX_MAX)
	        sc->sc_pcm_bitperfect = 1;

UAUDIO_MATRIX_MAX is set to 8. Again, I don't have the background knowledge right now to tell you why this is the case. I will look into it.

I think we could close this PR as "Works As intended".