[alsa-devel] more on appl_ptr and DMA overrun at end of stream
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.
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.
Takashi
On Fri, 22 May 2009, Takashi Iwai wrote:
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.
I agree to leave such things to lowlevel drivers.
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.
I would suggest to improve drain() logic in kernel with snd_pcm_update_hw_ptr() calls and using proper timeouts for schedule_timeout().
Note that this situation were handled with dead and removed pcm tick API - although it required assistance (setup) from application.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
At Fri, 22 May 2009 09:07:43 +0200 (CEST), Jaroslav Kysela wrote:
On Fri, 22 May 2009, Takashi Iwai wrote:
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.
I agree to leave such things to lowlevel drivers.
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.
I would suggest to improve drain() logic in kernel with snd_pcm_update_hw_ptr() calls and using proper timeouts for schedule_timeout().
Note that this situation were handled with dead and removed pcm tick API - although it required assistance (setup) from application.
... and, the results was no one used it :) Apps don't want to set up such details at all -- that's the lesson we had to learn...
Takashi
On Fri, May 22, 2009 at 3:14 AM, Takashi Iwai tiwai@suse.de wrote:
At Fri, 22 May 2009 09:07:43 +0200 (CEST), Jaroslav Kysela wrote:
On Fri, 22 May 2009, Takashi Iwai wrote:
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.
I agree to leave such things to lowlevel drivers.
The core problem is that the lowlevel driver does not have sufficient information to know where the end of stream is. If ALSA just told me the end address of the stream I'd program the DMA hardware to stop after the last sample played. I can easily program the hardware to play a partially filled period. Instead I have to take interrupts and go looking for the address of end of stream. I can usually get that info from appl_ptr but there are modes where appl_ptr doesn't provide end of stream.
trigger(stop) is worthless in that I receive it long after I needed to stop playing. How am I supposed to make trigger(stop) work? Last period plays and has been padded with silence. I get an interrupt when it is done. Unless there is zero latency (which there is not) I am going to start playing the next period before trigger(stop) can turn me off. This period is always full of stale data and it always makes a noise burst.
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.
I would suggest to improve drain() logic in kernel with snd_pcm_update_hw_ptr() calls and using proper timeouts for schedule_timeout().
Note that this situation were handled with dead and removed pcm tick API - although it required assistance (setup) from application.
... and, the results was no one used it :) Apps don't want to set up such details at all -- that's the lesson we had to learn...
Takashi
At Fri, 22 May 2009 09:58:29 -0400, Jon Smirl wrote:
On Fri, May 22, 2009 at 3:14 AM, Takashi Iwai tiwai@suse.de wrote:
At Fri, 22 May 2009 09:07:43 +0200 (CEST), Jaroslav Kysela wrote:
On Fri, 22 May 2009, Takashi Iwai wrote:
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.
I agree to leave such things to lowlevel drivers.
The core problem is that the lowlevel driver does not have sufficient information to know where the end of stream is.
Yes. In other words, it's because of the current code flow in ISR as I pointed. Issuing trigger(STOP) after queuing is simply stupid, if we know beforehand that the stream will be stopped anyway...
Takashi
participants (3)
-
Jaroslav Kysela
-
Jon Smirl
-
Takashi Iwai