The branch main has been updated by christos: URL: https://cgit.FreeBSD.org/src/commit/?id=a7258157e1a20957af23332814197ea723f5778d
commit a7258157e1a20957af23332814197ea723f5778d Author: Christos Margiolis <[email protected]> AuthorDate: 2026-09-07 14:48:21 +0000 Commit: Christos Margiolis <[email protected]> CommitDate: 2026-09-07 14:48:21 +0000 snd_emu10kx: Make sure the block count and size cover the whole buffer The playback voices always loop over the whole EMU_PLAY_BUFSZ buffer, but emupchan_setblocksize() only recorded the new block size and left the block count as it was set up by emu_vinit(). The blocks then no longer covered the whole buffer, and the part they left out was played without ever being written to, which became audible as distortion once playback started going through a virtual channel. Resize the buffer, so that the block count and size always cover it. Fixes: 02d4eeabfd73 ("sound: Allocate vchans on-demand") PR: 287687 MFC after: 1 week Sponsored by: The FreeBSD Foundation Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D59444 --- sys/dev/sound/pci/emu10kx-pcm.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c index 7cb371d82d39..0a15b8ba3448 100644 --- a/sys/dev/sound/pci/emu10kx-pcm.c +++ b/sys/dev/sound/pci/emu10kx-pcm.c @@ -768,13 +768,30 @@ emupchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize) { struct emu_pcm_pchinfo *ch = c_devinfo; struct emu_pcm_info *sc = ch->pcm; + uint32_t blkcnt; + + /* + * The channel always plays the whole EMU_PLAY_BUFSZ buffer, so the + * blocks have to cover it exactly, or the part they do not cover is + * "played" without ever being written to. + * + * sndbuf_resize() needs at least two blocks, so a block can be at most + * half the buffer's size. The block count has to be a power of two as + * well, because only then does the division come out exact. + */ + if (blocksize == 0 || blocksize > EMU_PLAY_BUFSZ / 2) + blocksize = EMU_PLAY_BUFSZ / 2; + blkcnt = 1 << (fls(EMU_PLAY_BUFSZ / blocksize) - 1); + blocksize = EMU_PLAY_BUFSZ / blkcnt; + + if (sndbuf_resize(ch->buffer, blkcnt, blocksize) != 0) + return (ch->blksz); - if (blocksize > ch->pcm->bufsz) - blocksize = ch->pcm->bufsz; mtx_lock(&sc->lock); ch->blksz = blocksize; emu_timer_set(sc->card, ch->timer, ch->blksz / ch->buffer->align); mtx_unlock(&sc->lock); + return (ch->blksz); }
