[alsa-devel] alsa buffer underrun

邱昇譽 m943040028 at gmail.com
Tue Oct 20 06:39:51 CEST 2009


Dear Alsa developers:

I enconter a problem about alsa buffer underrun, and have no idea how to
solve it.
It's great if you can spent a little of your spare time to read this.
Thanks.

Our CPU, (a arm processor running at 162Mhz) using I2S to communicate with
codec.
The i2s hardware is simply a FIFO which generates an interrupt when the FIFO
data is below the
programed watermark(and relevant bit in status register will be set),
then we re-fill data into FIFO in interrupt handler

the interrupt handler code fragment will like this

static irqreturn_t dw_tdm_handler(int irq, void *data)
{
        struct dw_tdm_dev *dev = (struct dw_tdm_dev *)data;
        struct platform_device *pdev = dev->pdev;
        struct snd_pcm_substream *substream = dev->substream;
        struct snd_pcm_runtime *runtime = substream->runtime;

        u16 *buf = (u16 *)runtime->dma_area;
        u32 status = dw_tdm_read_reg(TDM_INT_ STATUS);
        unsigned int bytes_remain =
                runtime->dma_bytes - dev->dma_pos;
        buf += dev->dma_pos / sizeof(u16);

        /* tx fifo is running low, reload new data for it */
        if (status & TX_INT) {
                int i;
                unsigned int empty_banks =
                        TX_EMPTY_BANKS(dw_tdm_read_reg(TDM_STATUS));
                /* 2 FIFO lines each bank */
                unsigned int bytes_to_write = empty_banks * 4;
                bytes_to_write = min(bytes_remain, bytes_to_write);

                dev_dbg(&pdev->dev, "dma_pos = %d\n",
                        dev->dma_pos);
                dev_dbg(&pdev->dev, "hw_ptr = %d\n",
                        frames_to_bytes(runtime, runtime->status->hw_ptr));

                /* re-fill data, 1 sample contains 4 bytes */
                for (i = 0; i < bytes_to_write / 4; i++) {
                        dw_tdm_write_reg(TDM_TX_FIFO, *buf++); /* left
channel */
                        dw_tdm_write_reg(TDM_TX_FIFO, *buf++); /* right
channel */
                }

                dev->dma_pos += bytes_to_write;

                if (bytes_remain == bytes_to_write)
                        dev->dma_pos = 0;
        }

        /* rx fifo is running full, consume data from it */
        if (status & RX_INT) {
                /* TODO */
        }

        dev_dbg(&pdev->dev, "period elapsed\n");
        snd_pcm_period_elapsed(substream);

        /* clear interupt status */
        dw_tdm_write_reg(TDM_INT_CLR, status);

        return IRQ_HANDLED;
}

This runs into buffer underflow problem, when I use aplay to play a wav
file,
it seems user-space process doesn't accquire any cpu time, after out i2s h/w
start to work(, and generate interrupts)

output look like below: (strings in <> is my comments)

# aplay /1.wav
Playing WAVE '/1.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
snd_pcm_lib_write1: avail = 8160 <aplay start to fill buffer>
snd_pcm_lib_write1: avail = 7904
snd_pcm_lib_write1: avail = 7648
snd_pcm_lib_write1: avail = 7392
snd_pcm_lib_write1: avail = 7136
snd_pcm_lib_write1: avail = 6880
snd_pcm_lib_write1: avail = 6624
snd_pcm_lib_write1: avail = 6368
snd_pcm_lib_write1: avail = 6112
snd_pcm_lib_write1: avail = 5856
snd_pcm_lib_write1: avail = 5600
snd_pcm_lib_write1: avail = 5344
snd_pcm_lib_write1: avail = 5088
snd_pcm_lib_write1: avail = 4832
snd_pcm_lib_write1: avail = 4576
snd_pcm_lib_write1: avail = 4320
snd_pcm_lib_write1: avail = 4064
snd_pcm_lib_write1: avail = 3808
snd_pcm_lib_write1: avail = 3552
snd_pcm_lib_write1: avail = 3296
snd_pcm_lib_write1: avail = 3040
snd_pcm_lib_write1: avail = 2784
snd_pcm_lib_write1: avail = 2528
snd_pcm_lib_write1: avail = 2272
snd_pcm_lib_write1: avail = 2016
snd_pcm_lib_write1: avail = 1760
snd_pcm_lib_write1: avail = 1504
snd_pcm_lib_write1: avail = 1248
snd_pcm_lib_write1: avail = 992
snd_pcm_lib_write1: avail = 736
snd_pcm_lib_write1: avail = 480
snd_pcm_lib_write1: avail = 224
snd_pcm_lib_write1: avail = 0   <write completed, trigger pcm stream>
<i2s h/w start to work, and consume all the buffers, in this period, aplay
has no chance to re-fill buffer, and underrun occurs>
underrun!!! (at least 19.991 ms long)
snd_pcm_lib_write1: avail = 8160
snd_pcm_lib_write1: avail = 8128
snd_pcm_lib_write1: avail = 7872
snd_pcm_lib_write1: avail = 7616
snd_pcm_lib_write1: avail = 7360
snd_pcm_lib_write1: avail = 7104
snd_pcm_lib_write1: avail = 6848
snd_pcm_lib_write1: avail = 6592
snd_pcm_lib_write1: avail = 6336
snd_pcm_lib_write1: avail = 6080
snd_pcm_lib_write1: avail = 5824
snd_pcm_lib_write1: avail = 5568
snd_pcm_lib_write1: avail = 5312
snd_pcm_lib_write1: avail = 5056
snd_pcm_lib_write1: avail = 4800
snd_pcm_lib_write1: avail = 4544
snd_pcm_lib_write1: avail = 4288
snd_pcm_lib_write1: avail = 4032
snd_pcm_lib_write1: avail = 3776
snd_pcm_lib_write1: avail = 3520
snd_pcm_lib_write1: avail = 3264
snd_pcm_lib_write1: avail = 3008
snd_pcm_lib_write1: avail = 2752
snd_pcm_lib_write1: avail = 2496
snd_pcm_lib_write1: avail = 2240
snd_pcm_lib_write1: avail = 1984
snd_pcm_lib_write1: avail = 1728
snd_pcm_lib_write1: avail = 1472
snd_pcm_lib_write1: avail = 1216
snd_pcm_lib_write1: avail = 960
snd_pcm_lib_write1: avail = 704
snd_pcm_lib_write1: avail = 448
snd_pcm_lib_write1: avail = 192
snd_pcm_lib_write1: avail = 0
underrun!!! (at least 18.479 ms long)


Any ideas or suggestions?


More information about the Alsa-devel mailing list