On Sat, 25 Apr 2009, Jon Smirl wrote:
This appears to be a bug in this code...
if (delta < 0) { delta += runtime->period_size * runtime->periods;
it was adding, buffer_size. But buffer_size is not correct when the periods don't evenly fit into the buffer
Could you show real values what you're getting here with your driver?
The buffer_size is always a wrap point. For example:
buffer_size = 4096 period_size = 1536
hw_ptr_interrupt => 1536, 3072, 4608
For example, if we receive update_hw_interrupt for second period late when pos (.pointer callback) = 100 and hw_ptr_interrupt = 3072 (hw_base is 0 at the moment):
new_hw_ptr = 100 hw_ptr_interrupt = 3072 delta = -2972
delta += buffer_size -> delta = 1124 - seems correct
Appearently, your .pointer callback returns wrong values.
if (delta < 0) { hw_ptr_error(substream, "Unexpected hw_pointer value " "(stream=%i, pos=%ld, intr_ptr=%ld)\n", substream->stream, (long)pos, (long)hw_ptr_interrupt); /* rebase to interrupt position */ hw_base = new_hw_ptr = hw_ptr_interrupt; /* align hw_base to buffer_size */ hw_base -= hw_base % runtime->buffer_size; delta = 0; } else { hw_base += runtime->period_size * runtime->periods;
same here
hw_base is always aligned to buffer_size (start of ring buffer)
delta = jiffies - s->jiffies; /* s->jiffies recorded at DMA interrrupt at end of buffer */ delta = delta * runtime->rate / HZ;
Using jiffies to correct stream position seems correct to me.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.