"Workaround for sound lag in current snd_emu10kx driver. Real problem

is interaction between in-kernel sound buffer handling and hardware.
 With small buffer, there are times when both harwdare reads and
 kernel writes to the same buffer (it is only visible on slow machines, i
 think). I'm digging in channel.c and buffer.c to find a solution that
 allow use of large hardware buffers without sound lags - hardware can
 handle buffers up to 32Mb."

Submitted by:	Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
This commit is contained in:
netchild 2006-08-07 22:44:01 +00:00
parent 1c0399f798
commit 24645f4f70
3 changed files with 23 additions and 19 deletions

View File

@ -432,7 +432,8 @@ emupchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm
ch->buffer = b;
ch->pcm = sc;
ch->channel = c;
ch->blksz = sc->bufsz;
/* XXX blksz should not be modified, see emu10kx.h for reasons */
ch->blksz = EMU_PLAY_BUFSZ;
ch->fmt = AFMT_U8;
ch->spd = 8000;
ch->master = emu_valloc(sc->card);
@ -442,7 +443,7 @@ emupchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm
*/
ch->slave = emu_valloc(sc->card);
ch->timer = emu_timer_create(sc->card);
r = (emu_vinit(sc->card, ch->master, ch->slave, sc->bufsz, ch->buffer)) ? NULL : ch;
r = (emu_vinit(sc->card, ch->master, ch->slave, EMU_PLAY_BUFSZ, ch->buffer)) ? NULL : ch;
return (r);
}
@ -749,7 +750,7 @@ emu_pcm_intr(void *pcm, uint32_t stat)
static int
emu_pcm_init(struct emu_pcm_info *sc)
{
sc->bufsz = pcm_getbuffersize(sc->dev, 4096, EMU_DEFAULT_BUFSZ, EMU_MAX_BUFSZ);
sc->bufsz = pcm_getbuffersize(sc->dev, EMUPAGESIZE, EMU_REC_BUFSZ, EMU_MAX_BUFSZ);
return (0);
}

View File

@ -250,7 +250,7 @@ struct emu_memblk {
};
struct emu_mem {
uint8_t bmap[MAXPAGES / 8];
uint8_t bmap[EMU_MAXPAGES / 8];
uint32_t *ptb_pages;
void *silent_page;
bus_addr_t silent_page_addr;
@ -336,7 +336,6 @@ struct emu_sc_info {
int timerinterval;
struct emu_rm *rm;
struct emu_mem mem; /* memory */
int bufsz;
/* Mixer */
int mixer_gpr[NUM_MIXERS];
@ -975,10 +974,12 @@ emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *ow
blksz = sz / EMUPAGESIZE;
if (sz > (blksz * EMUPAGESIZE))
blksz++;
if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE)
return (NULL);
/* find a free block in the bitmap */
found = 0;
start = 1;
while (!found && start + blksz < MAXPAGES) {
while (!found && start + blksz < EMU_MAXPAGES) {
found = 1;
for (idx = start; idx < start + blksz; idx++)
if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
@ -1439,7 +1440,7 @@ emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id,
if (mix_name != NULL) {
/* Temporary sysctls should start with underscore,
* see freebsd-current mailing list, emu10kx driver
* discussion around May, 24th. */
* discussion around 2006-05-24. */
snprintf(sysctl_name, 32, "_%s", mix_name);
SYSCTL_ADD_PROC(sc->ctx,
SYSCTL_CHILDREN(sc->root),
@ -2278,14 +2279,11 @@ emu_init(struct emu_sc_info *sc)
emu_wrptr(sc, 0, SPBYPASS, 0xf00); /* What will happen if
* we write 1 here? */
sc->bufsz = EMU_DEFAULT_BUFSZ; /* FIXME: pcm code can change this... */
if (bus_dma_tag_create( /* parent */ NULL, /* alignment */ 2, /* boundary */ 0,
/* lowaddr */ 1 << 31, /* can only access 0-2gb */
/* highaddr */ BUS_SPACE_MAXADDR,
/* filter */ NULL, /* filterarg */ NULL,
/* maxsize */ sc->bufsz, /* nsegments */ 1, /* maxsegz */ 0x3ffff,
/* maxsize */ EMU_MAX_BUFSZ, /* nsegments */ 1, /* maxsegz */ 0x3ffff,
/* flags */ 0, /* lockfunc */ busdma_lock_mutex,
/* lockarg */ &Giant, &(sc->mem.dmat)) != 0) {
device_printf(sc->dev, "unable to create dma tag\n");
@ -2294,7 +2292,7 @@ emu_init(struct emu_sc_info *sc)
}
SLIST_INIT(&sc->mem.blocks);
sc->mem.ptb_pages = emu_malloc(&sc->mem, MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr);
sc->mem.ptb_pages = emu_malloc(&sc->mem, EMU_MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr);
if (sc->mem.ptb_pages == NULL)
return (ENOMEM);
@ -2306,7 +2304,7 @@ emu_init(struct emu_sc_info *sc)
/* Clear page with silence & setup all pointers to this page */
bzero(sc->mem.silent_page, EMUPAGESIZE);
tmp = (uint32_t) (sc->mem.silent_page_addr) << 1;
for (i = 0; i < MAXPAGES; i++)
for (i = 0; i < EMU_MAXPAGES; i++)
sc->mem.ptb_pages[i] = tmp | i;
for (ch = 0; ch < NUM_G; ch++) {

View File

@ -39,12 +39,17 @@
#define EMUPAGESIZE 4096
#define NUM_G 64
/* XXX */
/* There is a problem playing sound files less then EMU_DEFAULT_BUFSZ in
* size. But using large buffer decreases interrupt rate and allow better
* sound quality on ATA systems... */
#define EMU_DEFAULT_BUFSZ EMUPAGESIZE*4
#define EMU_MAX_BUFSZ EMUPAGESIZE*8
#define MAXPAGES (EMU_MAX_BUFSZ * NUM_G / EMUPAGESIZE)
/*
* There are some problems when EMU_PLAY_BUFSZ is larger then EMU_PAGESIZE
* 1) there is a sound lag, because first round of playback is silence
* 2) the end of large file (equal to the lag duration) is lost
* 3) as a result of 1) and 2) no sound at all, when file size is less than
* EMU_PLAY_BUFSZ (it plays silence and then stops)
*/
#define EMU_PLAY_BUFSZ EMUPAGESIZE
#define EMU_REC_BUFSZ EMUPAGESIZE*16
#define EMU_MAX_BUFSZ EMUPAGESIZE*16
#define EMU_MAXPAGES 8192
#define EMU_VAR_FUNC 0