From owner-svn-src-all@FreeBSD.ORG Mon Mar 19 07:24:27 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 63E11106566B; Mon, 19 Mar 2012 07:24:27 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 1111A8FC12; Mon, 19 Mar 2012 07:24:27 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q2J7OQuD056799; Mon, 19 Mar 2012 07:24:26 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q2J7OQ3i056795; Mon, 19 Mar 2012 07:24:26 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201203190724.q2J7OQ3i056795@svn.freebsd.org> From: Alexander Motin Date: Mon, 19 Mar 2012 07:24:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r233164 - stable/9/sys/dev/sound/pcm X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Mar 2012 07:24:28 -0000 Author: mav Date: Mon Mar 19 07:24:26 2012 New Revision: 233164 URL: http://svn.freebsd.org/changeset/base/233164 Log: MFC r230845: Make sound(4) more flexible in setting soft buffer and block sizes when hardware imposes strict limitations on hard buffer and block sizes. Previous code set soft buffer to be no smaller then hard buffer. On some cards with fixed 64K physical buffer that caused up to 800ms play latency. New code allows to set soft buffer size down to just two blocks of the hard buffer and to not write more then that size ahead to the hardware buffer. As result of that change I was able to reduce full practically measured record-playback loop delay in those conditions down to only about 115ms with theoretical playback latency of only about 50ms. New code works fine for both vchans and direct cases. In both cases sound(4) tries to follow hw.snd.latency_profile and hw.snd.latency values and application-requested buffer and block sizes as much as limitation of two hardware blocks allows. Modified: stable/9/sys/dev/sound/pcm/buffer.c stable/9/sys/dev/sound/pcm/buffer.h stable/9/sys/dev/sound/pcm/channel.c Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/dev/sound/pcm/buffer.c ============================================================================== --- stable/9/sys/dev/sound/pcm/buffer.c Mon Mar 19 07:15:42 2012 (r233163) +++ stable/9/sys/dev/sound/pcm/buffer.c Mon Mar 19 07:24:26 2012 (r233164) @@ -301,6 +301,15 @@ sndbuf_fillsilence(struct snd_dbuf *b) b->rl = b->bufsize; } +void +sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl) +{ + if (b->bufsize > 0) + memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); + b->rp = 0; + b->rl = min(b->bufsize, rl); +} + /** * @brief Reset buffer w/o flushing statistics * Modified: stable/9/sys/dev/sound/pcm/buffer.h ============================================================================== --- stable/9/sys/dev/sound/pcm/buffer.h Mon Mar 19 07:15:42 2012 (r233163) +++ stable/9/sys/dev/sound/pcm/buffer.h Mon Mar 19 07:24:26 2012 (r233164) @@ -74,6 +74,7 @@ int sndbuf_remalloc(struct snd_dbuf *b, void sndbuf_reset(struct snd_dbuf *b); void sndbuf_clear(struct snd_dbuf *b, unsigned int length); void sndbuf_fillsilence(struct snd_dbuf *b); +void sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl); void sndbuf_softreset(struct snd_dbuf *b); void sndbuf_clearshadow(struct snd_dbuf *b); Modified: stable/9/sys/dev/sound/pcm/channel.c ============================================================================== --- stable/9/sys/dev/sound/pcm/channel.c Mon Mar 19 07:15:42 2012 (r233163) +++ stable/9/sys/dev/sound/pcm/channel.c Mon Mar 19 07:24:26 2012 (r233164) @@ -395,24 +395,28 @@ chn_wrfeed(struct pcm_channel *c) { struct snd_dbuf *b = c->bufhard; struct snd_dbuf *bs = c->bufsoft; - unsigned int amt; + unsigned int amt, want, wasfree; CHN_LOCKASSERT(c); if ((c->flags & CHN_F_MMAP) && !(c->flags & CHN_F_CLOSING)) sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); - amt = sndbuf_getfree(b); + wasfree = sndbuf_getfree(b); + want = min(sndbuf_getsize(b), + imax(0, sndbuf_xbytes(sndbuf_getsize(bs), bs, b) - + sndbuf_getready(b))); + amt = min(wasfree, want); if (amt > 0) sndbuf_feed(bs, b, c, c->feeder, amt); /* * Possible xruns. There should be no empty space left in buffer. */ - if (sndbuf_getfree(b) > 0) + if (sndbuf_getready(b) < want) c->xruns++; - if (sndbuf_getfree(b) < amt) + if (sndbuf_getfree(b) < wasfree) chn_wakeup(c); } @@ -721,7 +725,8 @@ chn_start(struct pcm_channel *c, int for } if (c->parentchannel == NULL) { if (c->direction == PCMDIR_PLAY) - sndbuf_fillsilence(b); + sndbuf_fillsilence_rl(b, + sndbuf_xbytes(sndbuf_getsize(bs), bs, b)); if (snd_verbose > 3) device_printf(c->dev, "%s(): %s starting! (%s/%s) " @@ -1728,7 +1733,7 @@ chn_resizebuf(struct pcm_channel *c, int int blkcnt, int blksz) { struct snd_dbuf *b, *bs, *pb; - int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1; + int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt; int ret; CHN_LOCKASSERT(c); @@ -1748,7 +1753,6 @@ chn_resizebuf(struct pcm_channel *c, int return EINVAL; else { c->latency = latency; - limit = 0; } bs = c->bufsoft; @@ -1783,19 +1787,22 @@ chn_resizebuf(struct pcm_channel *c, int */ sblksz = round_blksz(blksz, sndbuf_getalign(bs)); sblkcnt = round_pow2(blkcnt); - limit = 0; } if (c->parentchannel != NULL) { - pb = CHN_BUF_PARENT(c, NULL); + pb = c->parentchannel->bufsoft; CHN_UNLOCK(c); CHN_LOCK(c->parentchannel); chn_notify(c->parentchannel, CHN_N_BLOCKSIZE); CHN_UNLOCK(c->parentchannel); CHN_LOCK(c); - limit = (limit != 0 && pb != NULL) ? - sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0; - c->timeout = c->parentchannel->timeout; + if (c->direction == PCMDIR_PLAY) { + limit = (pb != NULL) ? + sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0; + } else { + limit = (pb != NULL) ? + sndbuf_xbytes(sndbuf_getblksz(pb), pb, bs) * 2 : 0; + } } else { hblkcnt = 2; if (c->flags & CHN_F_HAS_SIZE) { @@ -1836,21 +1843,22 @@ chn_resizebuf(struct pcm_channel *c, int CHN_LOCK(c); if (!CHN_EMPTY(c, children)) { - sblksz = round_blksz( - sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs), + nsblksz = round_blksz( + sndbuf_xbytes(sndbuf_getblksz(b), b, bs), sndbuf_getalign(bs)); - sblkcnt = 2; + nsblkcnt = sndbuf_getblkcnt(b); + if (c->direction == PCMDIR_PLAY) { + do { + nsblkcnt--; + } while (nsblkcnt >= 2 && + nsblksz * nsblkcnt >= sblksz * sblkcnt); + nsblkcnt++; + } + sblksz = nsblksz; + sblkcnt = nsblkcnt; limit = 0; - } else if (limit != 0) - limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs); - - /* - * Interrupt timeout - */ - c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) / - ((u_int64_t)sndbuf_getspd(b) * sndbuf_getalign(b)); - if (c->timeout < 1) - c->timeout = 1; + } else + limit = sndbuf_xbytes(sndbuf_getblksz(b), b, bs) * 2; } if (limit > CHN_2NDBUFMAXSIZE) @@ -1887,6 +1895,16 @@ chn_resizebuf(struct pcm_channel *c, int } /* + * Interrupt timeout + */ + c->timeout = ((u_int64_t)hz * sndbuf_getsize(bs)) / + ((u_int64_t)sndbuf_getspd(bs) * sndbuf_getalign(bs)); + if (c->parentchannel != NULL) + c->timeout = min(c->timeout, c->parentchannel->timeout); + if (c->timeout < 1) + c->timeout = 1; + + /* * OSSv4 docs: "By default OSS will set the low water level equal * to the fragment size which is optimal in most cases." */