mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
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: 02d4eeabfd ("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
This commit is contained in:
1 parent
358fe149f5
commit
a7258157e1
1 file changed
+19
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user