mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-02 22:54:52 +00:00
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
This commit is contained in:
parent
da925fcebf
commit
bbca3a75bb
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue