git: bbca3a75bb41 - main - sound: Include sound(4) channel information in sndstat nvlist
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 09 Jun 2024 15:30:34 UTC
The branch main has been updated by christos: URL: https://cgit.FreeBSD.org/src/commit/?id=bbca3a75bb412f7106a569b82c616404103be084 commit bbca3a75bb412f7106a569b82c616404103be084 Author: Christos Margiolis <christos@FreeBSD.org> AuthorDate: 2024-06-09 15:30:22 +0000 Commit: Christos Margiolis <christos@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