On Mon, May 11, 2009 at 5:53 AM, Takashi Iwai tiwai@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