SNDSTAT(4)

πŸ“¦
version 15.1 Β· 2 versions
, in freebsd 15.1, nixpkgs unstable

πŸ’… sndstat(4) β€” nvlist-based PCM audio device enumeration interface ✨

🌸 NAME

sndstat β€” nvlist-based PCM audio device enumeration interface πŸ’–

πŸŽ€ SYNOPSIS

To compile the driver into the kernel, place the following lines in the kernel configuration file:

device sound

πŸ¦‹ DESCRIPTION

okay so the ioctl interface that /dev/sndstat hands you lets callers enumerate PCM audio devices available for use. In other words, it's the plug for getting the list of all audio devices available to the system. no cap, it's giving "inventory check but make it audio" πŸ’…

πŸ‘‘ IOCTLS

For ioctl calls that take an argument, the following structure is used:

struct sndstioc_nv_arg {
        size_t nbytes;
        void *buf;
};

Here's an nvlist object example with the common fields explained, bestie β€” this is the whole vibe of what comes back 🫢

dsps (NVLIST ARRAY): 1
        from_user (BOOL): FALSE
        nameunit (STRING): [pcm0]
        devnode (STRING): [dsp0]
        desc (STRING): [Generic (0x8086) (Analog Line-out)]
        pchan (NUMBER): 1
        rchan (NUMBER): 0
        info_play (NVLIST):
                min_rate (NUMBER): 48000
                max_rate (NUMBER): 48000
                formats (NUMBER): 16
                min_chn (NUMBER): 2
                max_chn (NUMBER): 2
        provider_info (NVLIST):
                unit (NUMBER): 0
                status (STRING): on hdaa0
                bitperfect (BOOL): FALSE
                pvchan (BOOL): TRUE
                pvchanrate (NUMBER): 48000
                pvchanformat (NUMBER): 0x00000010
                rvchan (BOOL): TRUE
                rvchanrate (NUMBER): 48000
                rvchanformat (NUMBER): 0x00000010
                channel_info (NVLIST_ARRAY): 1
                        name (STRING): dsp0.virtual_play.0
                        parentchan (STRING): dsp0.play.0
                        unit (NUMBER): 1
                        caps (NUMBER): 0x073200
                        latency (NUMBER): 2
                        rate (NUMBER): 48000
                        format (NUMBER): 0x201000
                        pid (NUMBER): 1234
                        comm (STRING): mpv
                        interrupts (NUMBER): 0
                        feedcount (NUMBER): 0
                        xruns (NUMBER): 0
                        left_volume (NUMBER): 45
                        right_volume (NUMBER): 45
                        hwbuf_fmt (NUMBER): 0x200010
                        hwbuf_rate (NUMBER): 48000
                        hwbuf_size (NUMBER): 0
                        hwbuf_blksz (NUMBER): 0
                        hwbuf_blkcnt (NUMBER): 0
                        hwbuf_free (NUMBER): 0
                        hwbuf_ready (NUMBER): 0
                        swbuf_fmt (NUMBER): 0x201000
                        swbuf_rate (NUMBER): 48000
                        swbuf_size (NUMBER): 16384
                        swbuf_blksz (NUMBER): 2048
                        swbuf_blkcnt (NUMBER): 8
                        swbuf_free (NUMBER): 16384
                        swbuf_ready (NUMBER): 0
                        feederchain (STRING):
                                [userland ->
                                feeder_root(0x00201000) ->
                                feeder_format(0x00201000 -> 0x00200010) ->
                                feeder_volume(0x00200010) -> hardware]
        provider (STRING): [sound(4)]
  • from_user β€” whether the PCM audio device node is made by the in-kernel audio subsystem or by userspace providers. lowkey important context πŸ‘€
  • nameunit β€” the device identification, shaped like subsystem plus a unit number.
  • devnode β€” the PCM audio device node relative path in devfs.
  • desc β€” the description of the PCM audio device.
  • pchan β€” the number of playback channels supported by hardware. This can be 0 if this PCM audio device does not support playback at all.
  • rchan β€” the number of recording channels supported by hardware. This can be 0 if this PCM audio device does not support recording at all.
  • info_play β€” supported configurations in playback direction. This exists only if this PCM audio device supports playback. There are a number of name/value pairs inside this field:
    • min_rate β€” minimum supported sampling rate.
    • max_rate β€” maximum supported sampling rate.
    • formats β€” supported sample formats.
    • min_chn β€” minimum supported number of channels in channel layout.
    • max_chn β€” maximum supported number of channels in channel layout.
  • info_rec β€” supported configurations in recording direction. This exists only if this PCM audio device supports recording. There are a number of name/value pairs inside this field:
    • min_rate β€” minimum supported sampling rate.
    • max_rate β€” maximum supported sampling rate.
    • formats β€” supported sample formats.
    • min_chn β€” minimum supported number of channels in channel layout.
    • max_chn β€” maximum supported number of channels in channel layout.
  • provider_info β€” provider-specific fields. This field may not exist if the PCM audio device is not provided by in-kernel interface. This field will not exist if the provider field is an empty string. For the sound(4) provider, there are a number of name/value pairs inside this field:
    • unit β€” sound card unit.
    • status β€” status string. Usually reports the driver the device is attached on.
    • bitperfect β€” whether the sound card has bit-perfect mode enabled.
    • pvchan β€” playback virtual channels enabled.
    • pvchanrate β€” playback virtual channel sample rate.
    • pvchanformat β€” playback virtual channel format.
    • rvchan β€” recording virtual channels enabled.
    • rvchanrate β€” recording virtual channel sample rate.
    • rvchanformat β€” recording virtual channel format.
    • channel_info β€” channel information. There are a number of name/value pairs inside this field:
      • name β€” channel name.
      • parentchan β€” parent channel name (e.g., in the case of virtual channels).
      • unit β€” channel unit.
      • caps β€” OSS capabilities.
      • latency β€” latency.
      • rate β€” sampling rate.
      • format β€” sampling format.
      • pid β€” PID of the process consuming the channel.
      • comm β€” name of the process consuming the channel.
      • interrupts β€” number of interrupts since the channel has been opened.
      • xruns β€” number of overruns/underruns, depending on channel direction.
      • feedcount β€” number of read/written bytes since the channel has been opened.
      • left_volume β€” left volume.
      • right_volume β€” right volume.
      • hwbuf_format β€” hardware buffer format.
      • hwbuf_rate β€” hardware buffer sample rate.
      • hwbuf_size β€” hardware buffer size.
      • hwbuf_blksz β€” hardware buffer block size.
      • hwbuf_blkcnt β€” hardware buffer block count.
      • hwbuf_free β€” free space in hardware buffer (in bytes).
      • hwbuf_ready β€” number of bytes ready to be read/written from hardware buffer.
      • swbuf_format β€” software buffer format.
      • swbuf_rate β€” software buffer sample rate.
      • swbuf_size β€” software buffer size.
      • swbuf_blksz β€” software buffer block size.
      • swbuf_blkcnt β€” software buffer block count.
      • swbuf_free β€” free space in software buffer (in bytes).
      • swbuf_ready β€” number of bytes ready to be read/written from software buffer.
      • feederchain β€” channel feeder chain.
  • provider β€” a string specifying the provider of the PCm audio device. yes bestie, it's literally just the provider name in string form πŸŽ€

The following ioctls are provided for use:

  • SNDSTIOC_REFRESH_DEVS β€” drop any previously fetched PCM audio devices list snapshots. This ioctl takes no arguments. clean slate energy, periodt ✨
  • SNDSTIOC_GET_DEVS β€” okay so this one generates and/or returns PCM audio device list snapshots to whoever's calling. It takes a pointer to struct sndstioc_nv_arg as the first and the only argument. You gotta hand it a buffer that's big enough to hold a serialized nvlist. If there's no existing PCM audio device list snapshot sitting in the internal structure of the opened sndstat fd, a brand new PCM audio device list snapshot gets auto-generated for you (slay, no extra work πŸ’…). Callers have to set nbytes to either 0 or the size of the buffer provided. In case nbytes is 0, the buffer size required to hold a serialized nvlist stream of the current snapshot comes back in nbytes, and buf is literally ignored πŸ™ˆ. Otherwise, if the buffer isn't sufficiently large, the ioctl returns success and nbytes gets set to 0 (sneaky but true). If the buffer provided is sufficiently large, nbytes gets set to the size of the serialized nvlist written to the provided buffer. And once a PCM audio device list snapshot is returned to user-space successfully, the snapshot stored in the subsystem's internal structure of the given fd is freed. Cleanup queen behavior πŸ‘‘
  • SNDSTIOC_ADD_USER_DEVS β€” adds a list of PCM audio devices provided by callers to the /dev/sndstat device 🫢. Takes a pointer to struct sndstioc_nv_arg as the first and the only argument. Callers have to provide a buffer holding a serialized nvlist. nbytes should be set to the length in bytes of the serialized nvlist, and buf should be pointed to a buffer storing that serialized nvlist. Userspace-backed PCM audio device nodes should be listed inside the serialized nvlist, iykyk ✨
  • SNDSTIOC_FLUSH_USER_DEVS β€” flushes any PCM audio devices previously added by callers. Takes no arguments, zero notes, just vibes πŸ’€

πŸŽ€ FILES πŸŽ€

  • /dev/sndstat

🌸 EXAMPLES 🌸

The following code enumerates all available PCM audio devices β€” bestie this whole block is iconic, don't touch a single character of it fr fr:

#include <sys/types.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/nv.h>
#include <sys/sndstat.h>
#include <sysexits.h>
#include <unistd.h>

int
main()
{
        int fd;
        struct sndstioc_nv_arg arg;
        const nvlist_t * const *di;
        size_t i, nitems;
        nvlist_t *nvl;

        /* Open sndstat node in read-only first */
        fd = open("/dev/sndstat", O_RDONLY);

        if (ioctl(fd, SNDSTIOC_REFRESH_DEVS, NULL))
                err(1, "ioctl(fd, SNDSTIOC_REFRESH_DEVS, NULL)");

        /* Get the size of snapshot, when nbytes = 0 */
        arg.nbytes = 0;
        arg.buf = NULL;
        if (ioctl(fd, SNDSTIOC_GET_DEVS, &arg))
                err(1, "ioctl(fd, SNDSTIOC_GET_DEVS, &arg)");

        /* Get snapshot data */
        arg.buf = malloc(arg.nbytes);
        if (arg.buf == NULL)
                err(EX_OSERR, "malloc");
        if (ioctl(fd, SNDSTIOC_GET_DEVS, &arg))
                err(1, "ioctl(fd, SNDSTIOC_GET_DEVS, &arg)");

        /* Deserialize the nvlist stream */
        nvl = nvlist_unpack(arg.buf, arg.nbytes, 0);
        free(arg.buf);

        /* Get DSPs array */
        di = nvlist_get_nvlist_array(nvl, SNDST_DSPS, &nitems);
        for (i = 0; i < nitems; i++) {
                const char *nameunit, *devnode, *desc;

                /*
                 * Examine each device nvlist item
                 */

                nameunit = nvlist_get_string(di[i], SNDST_DSPS_NAMEUNIT);
                devnode = nvlist_get_string(di[i], SNDST_DSPS_DEVNODE);
                desc = nvlist_get_string(di[i], SNDST_DSPS_DESC);
                printf("Name unit: `%s`, Device node: `%s`, Description: `%s`0,
                    nameunit, devnode, desc);
        }

        nvlist_destroy(nvl);
        return (0);
}

πŸ¦‹ SEE ALSO πŸ¦‹

sound(4), nv(9)


⭐ HISTORY ⭐

The nvlist-based ioctls support for sndstat device first appeared in FreeBSD 13.0 ✨ like, ancient history bestie, but we respect the origin story πŸ‘‘


πŸ’œ AUTHORS πŸ’œ

This manual page was written by Ka Ho Ng <khng@FreeBSD.org> β€” thank you for your service 🫢


and that's a wrap on SNDSTAT(4), bestie πŸ’– This little beauty hit the streets via Debian on July 26, 2024, so go forth, read your device lists, and slay βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from