git: 9d8b93bc9cce - main - sound: Refactor sndstat_get_caps()

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Sat, 06 Jul 2024 18:24:17 UTC
The branch main has been updated by christos:

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

commit 9d8b93bc9ccea82b648ffa9354200c9e4d3f211b
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-07-06 18:23:09 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-07-06 18:23:09 +0000

    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
---
 sys/dev/sound/pcm/sndstat.c | 44 +++++++++++++++++---------------------------
 1 file changed, 17 insertions(+), 27 deletions(-)

diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
index 3be376e1da01..5b770810d19b 100644
--- a/sys/dev/sound/pcm/sndstat.c
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -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)
+	CHN_FOREACH(c, d, channels.pcm) {
+		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);