From 24645f4f70036f007c730d7874982b12e15d05c1 Mon Sep 17 00:00:00 2001 From: netchild Date: Mon, 7 Aug 2006 22:44:01 +0000 Subject: [PATCH] "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 --- sys/dev/sound/pci/emu10kx-pcm.c | 7 ++++--- sys/dev/sound/pci/emu10kx.c | 18 ++++++++---------- sys/dev/sound/pci/emu10kx.h | 17 +++++++++++------ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c index b20a978af738..9c25a785cca2 100644 --- a/sys/dev/sound/pci/emu10kx-pcm.c +++ b/sys/dev/sound/pci/emu10kx-pcm.c @@ -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); } diff --git a/sys/dev/sound/pci/emu10kx.c b/sys/dev/sound/pci/emu10kx.c index 8071efa9e1b9..fb728e8f3c06 100644 --- a/sys/dev/sound/pci/emu10kx.c +++ b/sys/dev/sound/pci/emu10kx.c @@ -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++) { diff --git a/sys/dev/sound/pci/emu10kx.h b/sys/dev/sound/pci/emu10kx.h index 1458f81a6ecf..7075ef937b31 100644 --- a/sys/dev/sound/pci/emu10kx.h +++ b/sys/dev/sound/pci/emu10kx.h @@ -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