Date: Sat, 24 Sep 2005 13:13:32 +0800 From: Ariff Abdullah <skywizard@MyBSD.org.my> To: jos@catnook.com Cc: multimedia@freebsd.org Subject: Re: Curious sound playback slowdown Message-ID: <20050924131332.49fc7f34.skywizard@MyBSD.org.my> In-Reply-To: <20050921171740.62f09414.skywizard@MyBSD.org.my> References: <20050917054421.GA93917@lizzy.catnook.local> <20050921051839.GA39942@lizzy.catnook.local> <20050921171740.62f09414.skywizard@MyBSD.org.my>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --Multipart=_Sat__24_Sep_2005_13_13_32_+0800_MeagRO0kLx3ATcY9 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Wed, 21 Sep 2005 17:17:40 +0800 Ariff Abdullah <skywizard@MyBSD.org.my> wrote: > On Tue, 20 Sep 2005 22:18:17 -0700 > Jos Backus <jos@catnook.com> wrote: > > On Fri, Sep 16, 2005 at 10:43:59PM -0701, Jos Backus wrote: > > ... > > > 92231 firefox-bin CALL ioctl(0x13,SNDCTL_DSP_STEREO,0xbfbf6ca0) > > > 92231 firefox-bin RET ioctl 0 > > > 92231 firefox-bin CALL ioctl(0x13,SNDCTL_DSP_SPEED,0xbfbf6cdc) > > > 92231 firefox-bin RET ioctl 0 > > > 92231 firefox-bin CALL > > > ioctl(0x13,SNDCTL_DSP_SETFRAGMENT,0xbfbf6d08) 92231 firefox-bin > > > RET > > > ioctl 0 > > > 92231 firefox-bin CALL ioctl(0x13,SNDCTL_DSP_GETCAPS,0xbfbf6d04) > > > 92231 firefox-bin RET ioctl 0 > > > 92231 firefox-bin CALL fcntl(0x13,0x4,0) > > > 92231 firefox-bin RET fcntl 0 > > > 92231 firefox-bin CALL close(0x13) > > ... > > > > It's unclear to me why the SNDCTL_DSP_SPEED ioctl is stuffing the > > wrong value into the device. Running the program below as > > `set-samplerate 22050' appears to mimic the change the Flash plugin > > effects. Running `set-samplerate' restores sound pitch to a normal > > value. So I have a workaround for now at least. > > > Luckily I have this card and do realize this problem. That's because > flash plugin trying to set speed for recording that differ from > playback speed. > > I will examine this issue later this day. > Please try this attached patch. es1370 locked both playback (dac) and recording (adc), conflicting each other while doing full duplex operation, so the only way to solve this conflicting sampling rate is to treat the chip as a single fixed rate codec. Fortunately our soft sample rate converter is quite decent to handle varying sample rate both for playback and recording operation, not a big issue unless you're *extremely* picky about sound quality with hearing beyond average. Note that you can return to the old behaviour either with hint.pcm.0.fixed_rate=0 (/boot/device.hints) or simply sysctl hw.snd.pcm0.fixed_rate=0. You can set you prefered default fixed rate with these settings, but pay attention on hw.snd.pcm0.vchanrate too. -- Ariff Abdullah MyBSD http://www.MyBSD.org.my (IPv6/IPv4) http://staff.MyBSD.org.my (IPv6/IPv4) http://tomoyo.MyBSD.org.my (IPv6/IPv4) --Multipart=_Sat__24_Sep_2005_13_13_32_+0800_MeagRO0kLx3ATcY9 Content-Type: text/plain; name="es137x.c.diff" Content-Disposition: attachment; filename="es137x.c.diff" Content-Transfer-Encoding: 7bit --- sys/dev/sound/pci/es137x.c.orig Sun Jul 31 21:19:38 2005 +++ sys/dev/sound/pci/es137x.c Sat Sep 24 11:04:48 2005 @@ -111,6 +111,7 @@ int num; int spdif_en; unsigned int bufsz; + struct pcmchan_caps caps; /* Contents of board's registers */ u_long ctrl; @@ -128,27 +129,18 @@ static void es1371_src_write(struct es_info *, u_short, unsigned short); static u_int es1371_adc_rate(struct es_info *, u_int, int); static u_int es1371_dac_rate(struct es_info *, u_int, int); -static int es1371_init(struct es_info *, device_t); +static int es1371_init(struct es_info *); static int es1370_init(struct es_info *); static int es1370_wrcodec(struct es_info *, u_char, u_char); -static u_int32_t es_playfmt[] = { +static u_int32_t es_fmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; -static struct pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0}; - -static u_int32_t es_recfmt[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 -}; -static struct pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0}; +static struct pcmchan_caps es_caps = {4000, 48000, es_fmt, 0}; static const struct { unsigned volidx:4; @@ -309,15 +301,7 @@ snd_mtxunlock(es->lock); if (sndbuf_alloc(ch->buffer, es->parent_dmat, ch->bufsz) != 0) return NULL; - return ch; -} - -static int -eschan_setdir(kobj_t obj, void *data, int dir) -{ - struct es_chinfo *ch = data; - struct es_info *es = ch->parent; - + snd_mtxlock(es->lock); if (dir == PCMDIR_PLAY) { es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC2_FRAMEADR >> 8, 1); es_wr(es, ES1370_REG_DAC2_FRAMEADR & 0xff, sndbuf_getbufaddr(ch->buffer), 4); @@ -328,7 +312,8 @@ es_wr(es, ES1370_REG_ADC_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4); } ch->dir = dir; - return 0; + snd_mtxunlock(es->lock); + return ch; } static int @@ -357,6 +342,13 @@ struct es_chinfo *ch = data; struct es_info *es = ch->parent; + /* XXX Fixed rate , do nothing. */ + if (es->caps.minspeed == es->caps.maxspeed) + return es->caps.maxspeed; + if (speed < es->caps.minspeed) + speed = es->caps.minspeed; + if (speed > es->caps.maxspeed) + speed = es->caps.maxspeed; es->ctrl &= ~CTRL_PCLKDIV; es->ctrl |= DAC2_SRTODIV(speed) << CTRL_SH_PCLKDIV; es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4); @@ -452,12 +444,13 @@ eschan_getcaps(kobj_t obj, void *data) { struct es_chinfo *ch = data; - return (ch->dir == PCMDIR_PLAY)? &es_playcaps : &es_reccaps; + struct es_info *es = ch->parent; + + return &es->caps; } static kobj_method_t eschan1370_methods[] = { KOBJMETHOD(channel_init, eschan_init), - KOBJMETHOD(channel_setdir, eschan_setdir), KOBJMETHOD(channel_setformat, eschan_setformat), KOBJMETHOD(channel_setspeed, eschan1370_setspeed), KOBJMETHOD(channel_setblocksize, eschan_setblocksize), @@ -470,7 +463,6 @@ static kobj_method_t eschan1371_methods[] = { KOBJMETHOD(channel_init, eschan_init), - KOBJMETHOD(channel_setdir, eschan_setdir), KOBJMETHOD(channel_setformat, eschan_setformat), KOBJMETHOD(channel_setspeed, eschan1371_setspeed), KOBJMETHOD(channel_setblocksize, eschan_setblocksize), @@ -515,8 +507,26 @@ static int es1370_init(struct es_info *es) { + int r; + + /* XXX ES1370 default to fixed rate operation */ + if (resource_int_value(device_get_name(es->dev), + device_get_unit(es->dev), "fixed_rate", &r) == 0) { + if (r != 0) { + if (r < es_caps.minspeed) + r = es_caps.minspeed; + if (r > es_caps.maxspeed) + r = es_caps.maxspeed; + } + } else + r = es_caps.maxspeed; + es->caps = es_caps; + if (r != 0) { + es->caps.minspeed = r; + es->caps.maxspeed = r; + } es->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | - (DAC2_SRTODIV(DSP_DEFAULT_SPEED) << CTRL_SH_PCLKDIV); + (DAC2_SRTODIV(es->caps.maxspeed) << CTRL_SH_PCLKDIV); es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4); es->sctrl = 0; @@ -534,16 +544,17 @@ /* ES1371 specific */ int -es1371_init(struct es_info *es, device_t dev) +es1371_init(struct es_info *es) { u_long cssr; int idx; - int devid = pci_get_devid(dev); - int revid = pci_get_revid(dev); + int devid = pci_get_devid(es->dev); + int revid = pci_get_revid(es->dev); es->num = 0; es->ctrl = 0; es->sctrl = 0; + es->caps = es_caps; cssr = 0; if (devid == CT4730_PCI_ID) { /* XXX amplifier hack? */ @@ -870,7 +881,7 @@ #ifdef SND_DYNSYSCTL static int -sysctl_es1371x_spdif_enable(SYSCTL_HANDLER_ARGS) +sysctl_es137x_spdif_enable(SYSCTL_HANDLER_ARGS) { struct es_info *es; device_t dev; @@ -907,7 +918,7 @@ } static int -sysctl_es1371x_latency_timer(SYSCTL_HANDLER_ARGS) +sysctl_es137x_latency_timer(SYSCTL_HANDLER_ARGS) { struct es_info *es; device_t dev; @@ -930,6 +941,43 @@ snd_mtxunlock(es->lock); return 0; } + +static int +sysctl_es137x_fixed_rate(SYSCTL_HANDLER_ARGS) +{ + struct es_info *es; + device_t dev; + int err, val; + + dev = oidp->oid_arg1; + es = pcm_getdevinfo(dev); + snd_mtxlock(es->lock); + if (es->caps.minspeed == es->caps.maxspeed) + val = es->caps.maxspeed; + else + val = 0; + snd_mtxunlock(es->lock); + err = sysctl_handle_int(oidp, &val, sizeof(val), req); + + if (err || req->newptr == NULL) + return err; + if (val != 0 && (val < es_caps.minspeed || val> es_caps.maxspeed)) + return EINVAL; + + snd_mtxlock(es->lock); + if (val) { + es->caps.minspeed = val; + es->caps.maxspeed = val; + es->ctrl &= ~CTRL_PCLKDIV; + es->ctrl |= DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV; + es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4); + } else { + es->caps.minspeed = es_caps.minspeed; + es->caps.maxspeed = es_caps.maxspeed; + } + snd_mtxunlock(es->lock); + return 0; +} #endif /* SND_DYNSYSCTL */ static void @@ -953,8 +1001,15 @@ SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), OID_AUTO, "spdif_enabled", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), - sysctl_es1371x_spdif_enable, "I", + sysctl_es137x_spdif_enable, "I", "Enable S/PDIF output on primary playback channel"); + } else if (devid == ES1370_PCI_ID) { + SYSCTL_ADD_PROC(snd_sysctl_tree(dev), + SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), + OID_AUTO, "fixed_rate", + CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), + sysctl_es137x_fixed_rate, "I", + "Enable fixed rate playback/recording"); } if (resource_int_value(device_get_name(dev), device_get_unit(dev), "latency_timer", &r) == 0 && @@ -964,7 +1019,7 @@ SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), OID_AUTO, "latency_timer", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), - sysctl_es1371x_latency_timer, "I", + sysctl_es137x_latency_timer, "I", "PCI Latency Timer configuration"); #endif /* SND_DYNSYSCTL */ } @@ -1025,7 +1080,7 @@ if (devid == ES1371_PCI_ID || devid == ES1371_PCI_ID2 || devid == CT5880_PCI_ID || devid == CT4730_PCI_ID) { - if(-1 == es1371_init(es, dev)) { + if(-1 == es1371_init(es)) { device_printf(dev, "unable to initialize the card\n"); goto bad; } --Multipart=_Sat__24_Sep_2005_13_13_32_+0800_MeagRO0kLx3ATcY9--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050924131332.49fc7f34.skywizard>