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

Takashi Iwai tiwai at suse.de
Fri May 22 08:41:00 CEST 2009

At Thu, 21 May 2009 14:44:27 -0400,
Jon Smirl wrote:
> I've been reading Lennart's article on glitch free audio....
> On my scatter/gather DMA hardware I generate an interrupt at the end
> of each period. On the last period this causes ALSA to issue a
> trigger(STOP). However, there is a latency from when that interrupt is
> generated and when ALSA does the trigger(STOP). During that latency my
> hardware starts playing the next buffer (which contains stale data).
> Playing stale data causes a noise burst. I fixed this by programming
> my DMA hardware to not overrun appl_ptr.
> There's another solution. ALSA already knows the stream ends
> mid-period and pads out the partial period with silence. If it simply
> padded out the next period with silence too the overrun problem would
> become non-audible and there would time to process trigger(STOP).
> If padding out two periods at end of stream is possible, it then
> becomes possible for me to turn off interrupts in my audio driver.

This can be another interesting feature.  For example, you could add
a soft-mute padding to avoid a click noise at the end instead of a
whole silence.

But, this kind of hack really depends on the hardware implementation.
If a hardware has no DMA but require explicit writes, adding two
periods is too much.  Just a few samples would be enough.

Or, in the case of normal PCI DMA transfer, how can it be stopped?
That is, the stream is still running although it's claimed to be
stopped.  If a period size is big (say over one second), the stop at
the next interrupt doesn't sound good.

So, it's an interesting idea and I also thought of that.  But, the
implementation isn't that straightforward.

BTW, regarding the problem of trigger(STOP) timing:  I think the
proper solution is to change the sequence in ISR.  The current code
flow in ISR for a "queue-up style" hardware is like:
 - update h/w and queue the next chunk
 - call snd_pcm_period_elapsed():
    in snd_pcm_period_elapsed,
     - calling pointer callback
     - update hw_ptr
     - call trigger(STOP) if needed

Actually, the trigger(STOP) condition should be checked before
queuing the next chunk so that the trigger won't be called after
the new chunk.  Not sure which change would be most feasible, but
there should be a room to improve the code flow there.


More information about the Alsa-devel mailing list