Note: CC list has been trimmed, and moved to -current from -committers
as there are related comments on this issue on -current.

On Sat, Jun 10, 2000 at 07:15:58AM -0700, Jordan K. Hubbard wrote:
> I'm also finding that applications like mpg123 don't play audio
> anymore whereas that very application does with a May 15th kernel,
> that being the most recent "old" kernel I have lying around on this
> laptop.  If I play a WAV file with waveplay, it works fine.  That
> does tend to suggest that the speed at which you can cram data down
> the audio subsystem's throat is a factor.
> 
> - Jordan
> 
> > On Fri, Jun 09, 2000 at 02:11:29PM -0500, Richard Seaman, Jr. wrote:
> > 
> > > > If I just cat a .au file into /dev/audio, I get about 1/4 of a second 
> > > > of plan and then silence, with & without the patch.
> > > 
> > > Your symptoms are different then.  Don't know if the cause is the
> > > same.
> > 
> > Thinking about this some more, and as a followup to my last message, here's
> > what I'm guessing is happening to you.
> > 
> > You fill the device buffers very rapidly.  Since chn_wrintr is not getting
> > called as dma activity occurs, the only time the dma pointers can get updated
> > and therefore indicate that the buffers aren't full is when you write to
> > the buffers -- but you can't because they're already marked full.  ie.
> > you're deadlocked. The sound you hear is the dma buffers emptying, but your
> > app never knows it happened because the buffers are still marked full.
> > 
> > My case is the opposite side of the problem.  My app doesn't always fill the
> > buffers fast enough, and the dma pointers get corruped.
> > 
> > I'd guess that those that don't have problems either a) are getting
> > dma interrupts, or b) manage to fill the buffers at a rate that is
> > neither too fast nor too slow.

I don't know if all the reported pcm problems are related.  In my case
it appears that the pcm driver expects to get dma interrupts, but isn't
getting them.  Don't know if thats a hardware problem that is unique
to my old Gus PnP Pro that I just recently pulled off the scrap heap
and installed.  However, a number of the problems others have reported
were reproducable here.  

I've been running the attached patch to channel.c in sys/dev/sound/pcm.
With this, I am able to play mp3 files with both mpq123 and RealPlayer7,
wav files with waveplay, and 'cat XXX.au > /dev/audio' works fine. 

These patches don't solve the lack of dma interrupts, but appear to
work around them.  If you are getting dma interrupts, you will get
a flood of "chn_wrintr" messages, and you will probably want to
disable the related printf in this case.  Also, your problem in this
case is probably different than mine.  Also, the "DEB(x) x" statement
will generate some debugging junk in your log files, so you might
want to comment this out if you don't want it.

I haven't tried these for recording, so I have no idea if they work
for recording.  From comments Brian Somers has made, I gather this
will probably still not solve his problems.

I wonder if Cameron Grant could confirm whether the driver expects
dma interrupts in all cases?

-- 
Richard Seaman, Jr.        email:    [EMAIL PROTECTED]
5182 N. Maple Lane         phone:    262-367-5450
Nashotah WI 53058            fax:    262-367-5852
Index: channel.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pcm/channel.c,v
retrieving revision 1.28
diff -u -r1.28 channel.c
--- channel.c   2000/06/06 22:30:22     1.28
+++ channel.c   2000/06/11 16:25:26
@@ -35,10 +35,10 @@
 
 #define ISA_DMA(b) (((b)->chan >= 0 && (b)->chan != 4 && (b)->chan < 8))
 #define CANCHANGE(c) (!(c)->buffer.dl)
-/*
+
 #define DEB(x) x
-*/
-static void buf_clear(snd_dbuf *b, u_int32_t fmt, int length);
+
+static void buf_clear(snd_dbuf *b, u_int32_t fmt, int start, int length);
 static void chn_dmaupdate(pcm_channel *c);
 static void chn_wrintr(pcm_channel *c);
 static void chn_rdintr(pcm_channel *c);
@@ -187,15 +187,20 @@
        hwptr = chn_getptr(c);
        if (c->direction == PCMDIR_PLAY) {
                delta = (b->bufsize + hwptr - b->rp) % b->bufsize;
+               buf_clear(b, b->fmt, b->rp, delta);
                b->rp = hwptr;
                b->rl -= delta;
                b->fl += delta;
-
                if (b->rl < 0) {
+                   b->rl = 0;
+                   b->fl = b->bufsize;
+               }
+               if (b->rl < 0) {
                        DEB(printf("OUCH!(%d) rl %d(%d) delta %d bufsize %d hwptr %d 
rp %d(%d)\n", chn_updatecount++, b->rl, b_rl, delta, b->bufsize, hwptr, b->rp, b_rp));
                }
        } else {
                delta = (b->bufsize + hwptr - b->fp) % b->bufsize;
+               buf_clear(b, b->fmt, b->fp, delta);
                b->fp = hwptr;
                b->rl += delta;
                b->fl -= delta;
@@ -233,7 +238,7 @@
                b->fl = b->bufsize - b->rl;
                b->underflow = 0;
        } else {
-               /* chn_dmaupdate(c); */
+               chn_dmaupdate(c);
        }
 }
 
@@ -275,7 +280,7 @@
                b->fl -= l;
                b->fp = (b->fp + l) % b->bufsize;
                /* Clear the new space in the secondary buffer. */
-               buf_clear(bs, bs->fmt, l);
+               /* buf_clear(bs, bs->fmt, l); */
                /* Accumulate the total bytes of the moved samples. */
                lacc += l;
                /* A feed to the DMA buffer is equivalent to an interrupt. */
@@ -340,7 +345,8 @@
 chn_wrintr(pcm_channel *c)
 {
        snd_dbuf *b = &c->buffer;
-
+       
+       printf ("chn_wrintr hit\n");
        if (b->underflow && !(c->flags & CHN_F_MAPPED)) {
 /*             printf("underflow return\n");
 */             return; /* nothing new happened */
@@ -369,7 +375,7 @@
                chn_wrfeed(c);
        else {
                while (chn_wrfeed(c) > 0);
-               buf_clear(b, b->fmt, b->fl);
+               /*buf_clear(b, b->fmt, b->fp, b->fl);*/
        }
        chn_dmawakeup(c);
        if (c->flags & CHN_F_TRIGGERED) {
@@ -394,7 +400,7 @@
                         * we are near to underflow condition, so to prevent
                         * audio 'clicks' clear next b->fl bytes
                         */
-                       buf_clear(b, b->fmt, b->fl);
+                       buf_clear(b, b->fmt, b->fp, b->fl);
                        if (b->rl < DMA_ALIGN_THRESHOLD)
                                b->underflow = 1;
                }
@@ -403,7 +409,7 @@
                DEB(printf("underflow, flags 0x%08x rp %d rl %d\n", c->flags, b->rp, 
b->rl));
                if (b->dl) { /* DMA was active */
                        b->underflow = 1; /* set underflow flag */
-                       buf_clear(b, b->fmt, b->bufsize);
+                       buf_clear(b, b->fmt, 0, b->bufsize);
                }
        }
 }
@@ -498,8 +504,9 @@
                        if (ret == EINTR || ret == ERESTART)
                                break;
                }
-       } else
+       } /*  else
                ret = 0;
+         */
        c->flags &= ~CHN_F_WRITING;
        splx(s);
        return ret;
@@ -611,7 +618,7 @@
                bs->rl -= w;
                bs->rp = (bs->rp + w) % bs->bufsize;
                /* Clear the new space in the secondary buffer. */
-               buf_clear(bs, bs->fmt, l);
+               /*buf_clear(bs, bs->fmt, bs->fp, l);*/
                /* Accumulate the total bytes of the moved samples. */
                bs->total += w;
                wacc += w;
@@ -823,7 +830,7 @@
 }
 
 static void
-buf_clear(snd_dbuf *b, u_int32_t fmt, int length)
+buf_clear(snd_dbuf *b, u_int32_t fmt, int start, int length)
 {
        int i;
        u_int16_t data, *p;
@@ -846,8 +853,8 @@
        if (fmt & AFMT_BIGENDIAN)
                data = ((data >> 8) & 0x00ff) | ((data << 8) & 0xff00);
 
-       i = b->fp;
-       p = (u_int16_t *)(b->buf + b->fp);
+       i = start;
+       p = (u_int16_t *)(b->buf + start);
        while (length > 0) {
                *p++ = data;
                length -= 2;
@@ -873,7 +880,7 @@
        b->prev_int_count = b->int_count = 0;
        b->underflow = 0;
        if (b->buf && b->bufsize > 0)
-               buf_clear(b, b->fmt, b->bufsize);
+               buf_clear(b, b->fmt, b->fp, b->bufsize);
 
        bs->rp = bs->fp = 0;
        bs->dl = bs->rl = 0;
@@ -882,7 +889,7 @@
        bs->prev_int_count = bs->int_count = 0;
        bs->underflow = 0;
        if (bs->buf && bs->bufsize > 0)
-               buf_clear(bs, bs->fmt, bs->bufsize);
+               buf_clear(bs, bs->fmt, bs->fp, bs->bufsize);
 }
 
 void
@@ -1214,7 +1221,7 @@
        bs->bufsize = bufsz;
        bs->rl = bs->rp = bs->fp = 0;
        bs->fl = bs->bufsize;
-       buf_clear(bs, bs->fmt, bs->bufsize);
+       buf_clear(bs, bs->fmt, bs->fp, bs->bufsize);
        bs->blkcnt = blkcnt;
        bs->blksz = blksz;
        b->blksz = c->setblocksize(c->devinfo, blksz);

Reply via email to