[alsa-devel] appl_ptr and DMA overrun at end of stream

Jon Smirl jonsmirl at gmail.com
Mon May 11 15:03:14 CEST 2009

On Mon, May 11, 2009 at 5:53 AM, Takashi Iwai <tiwai at suse.de> wrote:
> At Thu, 7 May 2009 12:23:51 -0400,
> Jon Smirl wrote:
>> I am having problem with DMA overrun at the end of the audio stream.
>> Is there an official way to know the address of the last valid audio
>> sample?
>> mpc5200 ac97 is keeping a bunch of descriptors queued in a loop to
>> continuously play music. I believe this is the way ALSA wants it. Now
>> say the last period is
>> half full. ALSA fills the other half with silence. When that period
>> finishes playing it will generate an interrupt. ALSA comes back from
>> that interrupt with trigger(STOP).
>> But, our CPU is slow compared to a 3Ghz desktop, there is considerable
>> latency from the period end interrupt to trigger(STOP) getting called.
>>  So the DMA hardware starts playing the next period before
>> trigger(STOP) can get the DMA stopped.  I turned off tried turning off
>> BestComm, flushing the FIFO, and turning off the audio clocks.  None
>> can be done fast enough. That next period contains stale data from
>> further back in the stream. When the front part of it plays it makes a
>> burst of noise.
>> What I need is the address of the end of valid data in the buffer. I
>> need that address so that I can program the DMA automatically stop at
>> end of stream and not overrun. Search around in the guys of ALSA I
>> found appl_ptr. I can use appl_ptr to determine the location of end of
>> stream and prevent DMA overrun. When there is no valid data I don't
>> enqueue the
>> descriptor.
> Right.  This is the value to check in your case.

What do think about redesigning the ALSA DMA interface to support
detection of over and under run? Leaving the DMA engine in a loop and
not coordinating with ALSA as to where the valid data is does not seem
to be a safe way of exchanging data. That interface may be a source of
the problems pulseaudio is encountering.

A simple solution would be for snd_pcm_period_elapsed() to return
physical address of the last valid sample. That would let me avoid
playing with  s->runtime->control->appl_ptr. You could provide the
same data in the pointer() function.

If I know where the end of valid data is, I can program the hardware
to play silence instead of stale data. Don't other embedded systems
suffer from this same problem? Seems to me like every system has this
problem, but desktop machines are fast enough that you can't hear it.

>>  s->appl_ptr track the previous value of  s->runtime->control->appl_ptr.
>> The difference between these two is the amount of valid data in the buffer.
>> When this difference goes to zero, I stop queueing new buffers to ALSA.
> Yes, that'll work, I guess.
>> That fixes the DMA overrun.
>> static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
>> {
>>        struct bcom_bd *bd;
>>        while (s->appl_ptr < s->runtime->control->appl_ptr) {
> You'd need to think of boundary overlap, too.
> It's a bit nasty because we wrap the value at runtime->boundary...
> thanks,
> Takashi

Jon Smirl
jonsmirl at gmail.com

More information about the Alsa-devel mailing list