The branch main has been updated by christos:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=bbca3a75bb412f7106a569b82c616404103be084

commit bbca3a75bb412f7106a569b82c616404103be084
Author:     Christos Margiolis <chris...@freebsd.org>
AuthorDate: 2024-06-09 15:30:22 +0000
Commit:     Christos Margiolis <chris...@freebsd.org>
CommitDate: 2024-06-09 15:30:22 +0000

    sound: Include sound(4) channel information in sndstat nvlist
    
    Extend SNDST_DSPS_PROVIDER_INFO for sound(4) to include information
    about each channel in a given device, similar to how cat'ing
    /dev/sndstat with hw.snd.verbose=2 works.
    
    While here, document all provider_info fields.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
    Reviewed by:    dev_submerge.ch, markj
    Differential Revision:  https://reviews.freebsd.org/D45501
---
 share/man/man4/sndstat.4    | 140 +++++++++++++++++++++++++++++++++++++-------
 sys/dev/sound/pcm/sndstat.c | 115 +++++++++++++++++++++++++++++++++++-
 sys/sys/sndstat.h           |  37 ++++++++++--
 3 files changed, 265 insertions(+), 27 deletions(-)

diff --git a/share/man/man4/sndstat.4 b/share/man/man4/sndstat.4
index 8325490da162..2af0619961d8 100644
--- a/share/man/man4/sndstat.4
+++ b/share/man/man4/sndstat.4
@@ -29,7 +29,7 @@
 .\"
 .\" Note: The date here should be updated whenever a non-trivial
 .\" change is made to the manual page.
-.Dd April 15, 2021
+.Dd June 5, 2024
 .Dt SNDSTAT 4
 .Os
 .Sh NAME
@@ -60,25 +60,55 @@ struct sndstioc_nv_arg {
 Here is an example of an nvlist object with explanations of the common fields:
 .Bd -literal -offset indent
 dsps (NVLIST ARRAY): 1
-    from_user (BOOL): FALSE
-    nameunit (STRING): [pcm0]
-    devnode (STRING): [dsp0]
-    desc (STRING): [Generic (0x8086) (Analog Line-out)]
-    pchan (NUMBER): 1 (1) (0x1)
-    rchan (NUMBER): 0 (0) (0x0)
-    info_play (NVLIST):
-        min_rate (NUMBER): 48000 (48000) (0xbb80)
-        max_rate (NUMBER): 48000 (48000) (0xbb80)
-        formats (NUMBER): 16 (16) (0x10)
-        min_chn (NUMBER): 2 (2) (0x2)
-        max_chn (NUMBER): 2 (2) (0x2)
-    provider_info (NVLIST):
-        unit (NUMBER): 0 (0) (0x0)
-        bitperfect (BOOL): FALSE
-        pvchan (NUMBER): 1 (1) (0x1)
-        rvchan (NUMBER): 0 (0) (0x0)
-    provider (STRING): [sound(4)]
-    ,
+       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
+               bitperfect (BOOL): FALSE
+               pvchan (NUMBER): 1
+               rvchan (NUMBER): 0
+               channel_info (NVLIST_ARRAY): 1
+                       name (STRING): pcm0:virtual_play:dsp0.vp0
+                       parentchan (STRING): pcm0:play:dsp0.p0
+                       unit (NUMBER): 1
+                       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_size (NUMBER): 0
+                       hwbuf_blksz (NUMBER): 0
+                       hwbuf_blkcnt (NUMBER): 0
+                       hwbuf_free (NUMBER): 0
+                       hwbuf_ready (NUMBER): 0
+                       swbuf_fmt (NUMBER): 0x201000
+                       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)]
 .Ed
 .Bl -tag -width ".Dv provider_info"
 .It Dv from_user
@@ -133,6 +163,76 @@ 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
+.Xr sound 4
+provider, there are a number of name/value pairs inside this field:
+.Bl -tag -width ".Dv channel_info"
+.It Dv unit
+Sound card unit.
+.It Dv bitperfect
+Whether the sound card has bit-perfect mode enabled.
+.It Dv pvchan
+Number of playback virtual channels.
+.It Dv rvchan
+Number of recording virtual channels.
+.It Dv channel_info
+Channel information.
+There are a number of name/value pairs inside this field:
+.Bl -tag -width ".Dv hwbuf_blkcnt"
+.It Dv name
+Channel name.
+.It Dv parenchan
+Parent channel name (e.g., in the case of virtual channels).
+.It Dv unit
+Channel unit.
+.It Dv latency
+Latency.
+.It Dv rate
+Sampling rate.
+.It Dv format
+Sampling format.
+.It Dv pid
+PID of the process consuming the channel.
+.It Dv comm
+Name of the process consuming the channel.
+.It Dv interrupts
+Number of interrupts since the channel has been opened.
+.It Dv xruns
+Number of overruns/underruns, depending on channel direction.
+.It Dv feedcount
+Number of read/written bytes since the channel has been opened.
+.It Dv left_volume
+Left volume.
+.It Dv right_volume
+Right volume.
+.It Dv hwbuf_format
+Hardware buffer format.
+.It Dv hwbuf_size
+Hardware buffer size.
+.It Dv hwbuf_blksz
+Hardware buffer block size.
+.It Dv hwbuf_blkcnt
+Hardware buffer block count.
+.It Dv hwbuf_free
+Free space in hardware buffer (in bytes).
+.It Dv hwbuf_ready
+Number of bytes ready to be read/written from hardware buffer.
+.It Dv swbuf_format
+Software buffer format.
+.It Dv swbuf_size
+Software buffer size.
+.It Dv swbuf_blksz
+Software buffer block size.
+.It Dv swbuf_blkcnt
+Software buffer block count.
+.It Dv swbuf_free
+Free space in software buffer (in bytes).
+.It Dv swbuf_ready
+Number of bytes ready to be read/written from software buffer.
+.It Dv feederchain
+Channel feeder chain.
+.El
+.El
 .It Dv provider
 A string specifying the provider of the PCm audio device.
 .El
diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
index 6670a1e43aac..3be376e1da01 100644
--- a/sys/dev/sound/pcm/sndstat.c
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -392,9 +392,12 @@ sndstat_create_diinfo_nv(uint32_t min_rate, uint32_t 
max_rate, uint32_t formats,
 static int
 sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
 {
+       struct pcm_channel *c;
+       struct pcm_feeder *f;
+       struct sbuf sb;
        uint32_t maxrate, minrate, fmts, minchn, maxchn;
-       nvlist_t *di = NULL, *sound4di = NULL, *diinfo = NULL;
-       int err;
+       nvlist_t *di = NULL, *sound4di = NULL, *diinfo = NULL, *cdi = NULL;
+       int err, nchan;
 
        di = nvlist_create(0);
        if (di == NULL) {
@@ -451,8 +454,116 @@ sndstat_build_sound4_nvlist(struct snddev_info *d, 
nvlist_t **dip)
            sound4di, SNDST_DSPS_SOUND4_BITPERFECT, d->flags & SD_F_BITPERFECT);
        nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_PVCHAN, d->pvchancount);
        nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_RVCHAN, d->rvchancount);
+
+       nchan = 0;
+       CHN_FOREACH(c, d, channels.pcm) {
+               sbuf_new(&sb, NULL, 4096, SBUF_AUTOEXTEND);
+               cdi = nvlist_create(0);
+               if (cdi == NULL) {
+                       sbuf_delete(&sb);
+                       PCM_RELEASE_QUICK(d);
+                       err = ENOMEM;
+                       goto done;
+               }
+
+               nvlist_add_string(cdi, SNDST_DSPS_SOUND4_CHAN_NAME, c->name);
+               nvlist_add_string(cdi, SNDST_DSPS_SOUND4_CHAN_PARENTCHAN,
+                   c->parentchannel != NULL ? c->parentchannel->name : "");
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_UNIT, nchan++);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_LATENCY,
+                   c->latency);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_RATE, c->speed);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_FORMAT,
+                   c->format);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_PID, c->pid);
+               nvlist_add_string(cdi, SNDST_DSPS_SOUND4_CHAN_COMM, c->comm);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_INTR,
+                   c->interrupts);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_FEEDCNT,
+                   c->feedcount);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_XRUNS, c->xruns);
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_LEFTVOL,
+                   CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_RIGHTVOL,
+                   CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_FORMAT,
+                   sndbuf_getfmt(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_SIZE,
+                   sndbuf_getsize(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_BLKSZ,
+                   sndbuf_getblksz(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_BLKCNT,
+                   sndbuf_getblkcnt(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_FREE,
+                   sndbuf_getfree(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_HWBUF_READY,
+                   sndbuf_getready(c->bufhard));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_FORMAT,
+                   sndbuf_getfmt(c->bufsoft));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_SIZE,
+                   sndbuf_getsize(c->bufsoft));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_BLKSZ,
+                   sndbuf_getblksz(c->bufsoft));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_BLKCNT,
+                   sndbuf_getblkcnt(c->bufsoft));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_FREE,
+                   sndbuf_getfree(c->bufsoft));
+               nvlist_add_number(cdi, SNDST_DSPS_SOUND4_CHAN_SWBUF_READY,
+                   sndbuf_getready(c->bufsoft));
+
+               sbuf_printf(&sb, "[%s",
+                   (c->direction == PCMDIR_REC) ? "hardware" : "userland");
+               sbuf_printf(&sb, " -> ");
+               f = c->feeder;
+               while (f->source != NULL)
+                       f = f->source;
+               while (f != NULL) {
+                       sbuf_printf(&sb, "%s", f->class->name);
+                       if (f->desc->type == FEEDER_FORMAT) {
+                               sbuf_printf(&sb, "(0x%08x -> 0x%08x)",
+                                   f->desc->in, f->desc->out);
+                       } else if (f->desc->type == FEEDER_MATRIX) {
+                               sbuf_printf(&sb, "(%d.%d -> %d.%d)",
+                                   AFMT_CHANNEL(f->desc->in) -
+                                   AFMT_EXTCHANNEL(f->desc->in),
+                                   AFMT_EXTCHANNEL(f->desc->in),
+                                   AFMT_CHANNEL(f->desc->out) -
+                                   AFMT_EXTCHANNEL(f->desc->out),
+                                   AFMT_EXTCHANNEL(f->desc->out));
+                       } else if (f->desc->type == FEEDER_RATE) {
+                               sbuf_printf(&sb,
+                                   "(0x%08x q:%d %d -> %d)",
+                                   f->desc->out,
+                                   FEEDER_GET(f, FEEDRATE_QUALITY),
+                                   FEEDER_GET(f, FEEDRATE_SRC),
+                                   FEEDER_GET(f, FEEDRATE_DST));
+                       } else {
+                               sbuf_printf(&sb, "(0x%08x)",
+                                   f->desc->out);
+                       }
+                       sbuf_printf(&sb, " -> ");
+                       f = f->parent;
+               }
+               sbuf_printf(&sb, "%s]",
+                   (c->direction == PCMDIR_REC) ? "userland" : "hardware");
+
+               sbuf_finish(&sb);
+               nvlist_add_string(cdi, SNDST_DSPS_SOUND4_CHAN_FEEDERCHAIN,
+                   sbuf_data(&sb));
+               sbuf_delete(&sb);
+
+               nvlist_append_nvlist_array(sound4di,
+                   SNDST_DSPS_SOUND4_CHAN_INFO, cdi);
+               nvlist_destroy(cdi);
+               err = nvlist_error(sound4di);
+               if (err) {
+                       PCM_RELEASE_QUICK(d);
+                       goto done;
+               }
+       }
        nvlist_move_nvlist(di, SNDST_DSPS_PROVIDER_INFO, sound4di);
        sound4di = NULL;
+
        PCM_RELEASE_QUICK(d);
        nvlist_add_string(di, SNDST_DSPS_PROVIDER, SNDST_DSPS_SOUND4_PROVIDER);
 
diff --git a/sys/sys/sndstat.h b/sys/sys/sndstat.h
index e0e403b1a72a..6fef6502ec89 100644
--- a/sys/sys/sndstat.h
+++ b/sys/sys/sndstat.h
@@ -68,11 +68,38 @@ struct sndstioc_nv_arg {
 /*
  * sound(4)-specific name/value pair names
  */
-#define SNDST_DSPS_SOUND4_PROVIDER     "sound(4)"
-#define SNDST_DSPS_SOUND4_UNIT         "unit"
-#define SNDST_DSPS_SOUND4_BITPERFECT   "bitperfect"
-#define SNDST_DSPS_SOUND4_PVCHAN       "pvchan"
-#define SNDST_DSPS_SOUND4_RVCHAN       "rvchan"
+#define SNDST_DSPS_SOUND4_PROVIDER             "sound(4)"
+#define SNDST_DSPS_SOUND4_UNIT                 "unit"
+#define SNDST_DSPS_SOUND4_BITPERFECT           "bitperfect"
+#define SNDST_DSPS_SOUND4_PVCHAN               "pvchan"
+#define SNDST_DSPS_SOUND4_RVCHAN               "rvchan"
+#define SNDST_DSPS_SOUND4_CHAN_INFO            "channel_info"
+#define SNDST_DSPS_SOUND4_CHAN_NAME            "name"
+#define SNDST_DSPS_SOUND4_CHAN_PARENTCHAN      "parentchan"
+#define SNDST_DSPS_SOUND4_CHAN_UNIT            "unit"
+#define SNDST_DSPS_SOUND4_CHAN_LATENCY         "latency"
+#define SNDST_DSPS_SOUND4_CHAN_RATE            "rate"
+#define SNDST_DSPS_SOUND4_CHAN_FORMAT          "format"
+#define SNDST_DSPS_SOUND4_CHAN_PID             "pid"
+#define SNDST_DSPS_SOUND4_CHAN_COMM            "comm"
+#define SNDST_DSPS_SOUND4_CHAN_INTR            "interrupts"
+#define SNDST_DSPS_SOUND4_CHAN_FEEDCNT         "feedcount"
+#define SNDST_DSPS_SOUND4_CHAN_XRUNS           "xruns"
+#define SNDST_DSPS_SOUND4_CHAN_LEFTVOL         "left_volume"
+#define SNDST_DSPS_SOUND4_CHAN_RIGHTVOL                "right_volume"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_FORMAT    "hwbuf_format"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_SIZE      "hwbuf_size"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_BLKSZ     "hwbuf_blksz"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_BLKCNT    "hwbuf_blkcnt"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_FREE      "hwbuf_free"
+#define SNDST_DSPS_SOUND4_CHAN_HWBUF_READY     "hwbuf_ready"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_FORMAT    "swbuf_format"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_SIZE      "swbuf_size"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_BLKSZ     "swbuf_blksz"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_BLKCNT    "swbuf_blkcnt"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_FREE      "swbuf_free"
+#define SNDST_DSPS_SOUND4_CHAN_SWBUF_READY     "swbuf_ready"
+#define SNDST_DSPS_SOUND4_CHAN_FEEDERCHAIN     "feederchain"
 
 /*
  * Maximum user-specified nvlist buffer size

Reply via email to