1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-19 02:29:40 +00:00

sound: Refactor sndstat_get_caps()

The current implementation of sndstat_get_caps() does not work properly
when VCHANs are enabled, as it skips all information about physical
channels, and also assigns the min/max rates and channels to same
values, which is usually not the case. A device either supports any
sample rate within the [feeder_rate_min, feeder_rate_max] range, or
[hw_rate_min, hw_rate_max] range when the device is opened in exclusive
or bitperfect mode. The number of channels can also vary and is not
always the same for both min and max.

Refactor the whole function to resemble the way we handle fetching of
these values in dsp_oss_audioinfo() and dsp_oss_engineinfo().

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch
Differential Revision:	https://reviews.freebsd.org/D45872
This commit is contained in:
Christos Margiolis 2024-07-06 20:23:09 +02:00
parent 86585210fd
commit 9d8b93bc9c

View File

@ -323,47 +323,37 @@ sndstat_write(struct cdev *i_dev, struct uio *buf, int flag)
}
static void
sndstat_get_caps(struct snddev_info *d, bool play, uint32_t *min_rate,
sndstat_get_caps(struct snddev_info *d, int dir, uint32_t *min_rate,
uint32_t *max_rate, uint32_t *fmts, uint32_t *minchn, uint32_t *maxchn)
{
struct pcm_channel *c;
int dir;
dir = play ? PCMDIR_PLAY : PCMDIR_REC;
if (play && d->pvchancount > 0) {
*min_rate = *max_rate = d->pvchanrate;
*fmts = AFMT_ENCODING(d->pvchanformat);
*minchn = *maxchn = AFMT_CHANNEL(d->pvchanformat);
return;
} else if (!play && d->rvchancount > 0) {
*min_rate = *max_rate = d->rvchanrate;
*fmts = AFMT_ENCODING(d->rvchanformat);
*minchn = *maxchn = AFMT_CHANNEL(d->rvchanformat);
return;
}
struct pcmchan_caps *caps;
int i;
*fmts = 0;
*min_rate = UINT32_MAX;
*max_rate = 0;
*minchn = UINT32_MAX;
*maxchn = 0;
CHN_FOREACH(c, d, channels.pcm) {
struct pcmchan_caps *caps;
int i;
if (c->direction != dir || (c->flags & CHN_F_VIRTUAL) != 0)
if (c->direction != dir)
continue;
CHN_LOCK(c);
caps = chn_getcaps(c);
*min_rate = min(caps->minspeed, *min_rate);
*max_rate = max(caps->maxspeed, *max_rate);
for (i = 0; caps->fmtlist[i]; i++) {
*fmts |= AFMT_ENCODING(caps->fmtlist[i]);
*minchn = min(AFMT_CHANNEL(caps->fmtlist[i]), *minchn);
*maxchn = max(AFMT_CHANNEL(caps->fmtlist[i]), *maxchn);
}
if ((c->flags & CHN_F_EXCLUSIVE) ||
(pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
*min_rate = min(*min_rate, caps->minspeed);
*max_rate = max(*max_rate, caps->maxspeed);
} else {
*min_rate = min(*min_rate, feeder_rate_min);
*max_rate = max(*max_rate, feeder_rate_max);
}
CHN_UNLOCK(c);
}
if (*min_rate == UINT32_MAX)
@ -422,8 +412,8 @@ sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
nvlist_add_number(di, SNDST_DSPS_PCHAN, d->playcount);
nvlist_add_number(di, SNDST_DSPS_RCHAN, d->reccount);
if (d->playcount > 0) {
sndstat_get_caps(d, true, &minrate, &maxrate, &fmts, &minchn,
&maxchn);
sndstat_get_caps(d, PCMDIR_PLAY, &minrate, &maxrate, &fmts,
&minchn, &maxchn);
nvlist_add_number(di, "pminrate", minrate);
nvlist_add_number(di, "pmaxrate", maxrate);
nvlist_add_number(di, "pfmts", fmts);
@ -435,8 +425,8 @@ sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
nvlist_move_nvlist(di, SNDST_DSPS_INFO_PLAY, diinfo);
}
if (d->reccount > 0) {
sndstat_get_caps(d, false, &minrate, &maxrate, &fmts, &minchn,
&maxchn);
sndstat_get_caps(d, PCMDIR_REC, &minrate, &maxrate, &fmts,
&minchn, &maxchn);
nvlist_add_number(di, "rminrate", minrate);
nvlist_add_number(di, "rmaxrate", maxrate);
nvlist_add_number(di, "rfmts", fmts);