Hi Hal,
first of all, thanks for your answer.
On Thursday 14 May 2009 20:18:07 Hal Murray wrote:
I need an API to transfer audio data from userspace to kernelspace. I initially thought about ALSA, but it turns out some assumptions made by ALSA are not fulfilled by my system. One of the most serious problems is that the UAC gadget driver doesn't have any audio clock. The only hardware clock available is the USB device controller interrupts generated at the USB transfer rate, and those are much faster than the audio sample rate. This will cause buffer underruns that I need to handle.
You don't need a clock. The data will come to you at the right rate. All you need to do is pass it on when you have enough to fill up a buffer. The buffer size is fixed. It's part of the spec for the device you are emulating.
I'm not emulating any device. The buffer size is up to me, and I actually have a fixed number of small buffers, but that shouldn't make a difference.
Assume that you get samples one at a time each time the source clock ticked. The normal state of your system would be to have a buffer that is partially filled. When a new sample fills up the buffer, you would move it from the input side to the ready-for-USB queue and setup a new buffer for future input samples.
Soon the USB side will read the queued buffer, you free that buffer and you are now back to the normal state of collecting input data.
You are in trouble if that doesn't happen before the nest buffer is ready, that is the ready-for-USB queue should normally be empty. If you can't keep it empty it will eventually overflow. Short chunks of time where the queue builds up might be OK. For debugging, you should probably count them.
Now consider the case where you get several samples at a time rather than one. Logically, copy them over one at a time. That turns into a burst of source clocks, but the average will work out right. Your ready-for-USB queue should still be empty most of the time.
If that doesn't make sense, I'll try again. Consider something like audio over a network. There is no audio clock on the network. The receiver can derive the source clock by watching the data stream.
This is more or less what I'm trying to do, with the difference that I don't move samples from the ALSA ring buffer when they arrive but when the USB layer asks for more data.
My trouble is that I don't get notified when new samples are written to the ALSA ring buffer, and I'm not sure to find out how many samples are present in the buffer. If I could get some kind of "sample written" notification, or better, compute the size of data present in the ring buffer, my problem would be (mostly) solved. From what I understand, such a notification isn't possible when the ALSA ring buffer is mmap'ed, as ALSA itself doesn't get notified.
This makes the second approach (reading the number of available samples) better, except that some kind of "free-wheeling" mode makes it impossible under some circumstances. From what Takashi Iwai explained in a mail to Jon Smirl on alsa-devel ("appl_ptr and DMA overrun at end of stream"), "we have also mode when appl_ptr is not updated at all (when stop_threshold == boundary)". This free-wheeling mode seems to be used by dmix.
Best regards,
Laurent Pinchart