diff --git a/share/man/man4/snd_hdspe.4 b/share/man/man4/snd_hdspe.4 --- a/share/man/man4/snd_hdspe.4 +++ b/share/man/man4/snd_hdspe.4 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 8, 2024 +.Dd January 19, 2024 .Dt SND_HDSPE 4 .Os .Sh NAME @@ -76,6 +76,11 @@ the respective device number in place of .Ql 0 . .Bl -tag -width indent +.It Va dev.hdspe.0.period +The number of samples processed per interrupt, from 32, 64, 128, up to 4096. +Setting a lower value here results in less latency, but increases system load +due to frequent interrupt processing. +Extreme values may cause audio gaps and glitches. .It Va dev.hdspe.0.clock_list Lists possible clock sources to sync with, depending on the hardware model. This includes internal and external master clocks as well as incoming digital diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c --- a/sys/dev/sound/pci/hdspe-pcm.c +++ b/sys/dev/sound/pci/hdspe-pcm.c @@ -891,6 +891,9 @@ blocksize /= 4 /* samples */; + if (sc->force_period > 0) + blocksize = sc->force_period; + /* First look for equal latency. */ for (i = 0; latency_map[i].period != 0; i++) { if (latency_map[i].period == blocksize) diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h --- a/sys/dev/sound/pci/hdspe.h +++ b/sys/dev/sound/pci/hdspe.h @@ -227,6 +227,7 @@ bus_dmamap_t rmap; uint32_t period; uint32_t speed; + uint32_t force_period; }; #define hdspe_read_1(sc, regno) \ diff --git a/sys/dev/sound/pci/hdspe.c b/sys/dev/sound/pci/hdspe.c --- a/sys/dev/sound/pci/hdspe.c +++ b/sys/dev/sound/pci/hdspe.c @@ -228,6 +228,31 @@ } } +static int +hdspe_sysctl_period(SYSCTL_HANDLER_ARGS) +{ + struct sc_info *sc = oidp->oid_arg1; + int error; + unsigned int period; + + period = sc->force_period; + + /* Process sysctl (unsigned) integer request. */ + error = sysctl_handle_int(oidp, &period, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + /* Period is from 2^5 to 2^14, 0 falls back to pcm latency settings. */ + sc->force_period = 0; + if (period > 0) { + sc->force_period = 32; + while (sc->force_period < period && sc->force_period < 4096) + sc->force_period <<= 1; + } + + return (0); +} + static int hdspe_sysctl_clock_preference(SYSCTL_HANDLER_ARGS) { @@ -419,6 +444,13 @@ /* Set latency. */ sc->period = 32; + /* + * The pcm channel latency settings propagate unreliable blocksizes, + * different for recording and playback, and skewed due to rounding + * and total buffer size limits. + * Force period to a consistent default until these issues are fixed. + */ + sc->force_period = 256; sc->ctrl_register = hdspe_encode_latency(7); /* Set rate. */ @@ -524,6 +556,12 @@ sc, 0, hdspe_sysctl_clock_list, "A", "List of supported clock sources"); + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, + sc, 0, hdspe_sysctl_period, "A", + "Force period of samples per interrupt (32, 64, ... 4096)"); + return (bus_generic_attach(dev)); }