[alsa-devel] PCM buffering ussues ( or probably the lack of understanding )
I am working on a PCM driver, have some issues and thing which are unclear to me, hopefully somebody here can clarify something for me.
My PCM driver is straigh forward:
- Copy callback copies the frames received in the callback into a small ringbuffer and starts a DMA transfer to the hardware. - DMA interrupt each times take the next chunk from the ringbuffer. - In the DMA interrupt the number of frames is counted, if te number >= period_size reported in runtime_struct pcm_period_elapsed() is called. - the pointer which is read by the pcm_pointer() callback is updated in each DMA interrupt.
When using mplayer this works without problems, however with other applications like mpg123 its causes a lot of problems, for some reaosns I do not understand yet. It has something to do with buffer handling.
basically in the cm driver I can influence a few parameters:
periods_min/periods_max period_bytes_min, period_bytes_max buffer_size ( should be sufficient to hold periods_max with period_bytes_max I assume )
As far as I understand periods_min/periods_max is the size (number of buffer entries) of the internal ringbuffer Alsa uses. - Why is there both a min and a max ? How is chosen what will be used ? - Currently my period_min is set to 1 and my period_max set to 4, If I increase the period_max value it does not start properly, it seems that the samples are not deliverered in time. Is there any explanation for this, does the Alsa layer not any pre-buffering before the first copy() is called ? - Is there any advice / guidline for period min/max values ? I checked sourecs of severl drivers, some use 1 and some use values like 32 or more for period_max.
The same applies to buffer_bytes min/max, currently my min is set to 128bytes , max to 2kB, larger values of max seem to cause more problems.
From the documentation I understand that it does not matter if pcm_period_elapsed() is not always called, How dows the ALSA layer then know how many samples are played. the pointer value read the pcm_pointer() only counts from [0..period_max] so what if 2 or more calls to period_elapsed() are skipped ?
Suppose I want to have some buffering inside my pcm driver, how will I be able to get some samples in advance before starting playback ? Can I just call pcm_period_elapsed() a few times in a row to get the buffer filled before starting the actual playcback, or does this cause side effects ?
I noticed that the number of frames passed to pcm_copy is often less than the periods_size, is this determined by the application ?
Lots of questions, but I try to understand the odd behaviour with certain applications ( and the best settings for a pcm driver which will work with most applications )
Any help would be appreciated.
Marcel
On 04/20/2013 09:13 AM, marcelg wrote:
I am working on a PCM driver, have some issues and thing which are unclear to me, hopefully somebody here can clarify something for me.
My PCM driver is straigh forward:
It's always easier to comment on potential issues if you provide the code.
- Copy callback copies the frames received in the callback into a small
ringbuffer and starts a DMA transfer to the hardware.
If you have DMA support your probably shouldn't implement the copy callback, but rather let also write directly to your hardware buffer.
- DMA interrupt each times take the next chunk from the ringbuffer.
- In the DMA interrupt the number of frames is counted, if te number >=
period_size reported in runtime_struct pcm_period_elapsed() is called.
- the pointer which is read by the pcm_pointer() callback is updated in each
DMA interrupt.
When using mplayer this works without problems, however with other applications like mpg123 its causes a lot of problems, for some reaosns I do not understand yet. It has something to do with buffer handling.
basically in the cm driver I can influence a few parameters:
periods_min/periods_max period_bytes_min, period_bytes_max buffer_size ( should be sufficient to hold periods_max with period_bytes_max I assume )
As far as I understand periods_min/periods_max is the size (number of buffer entries) of the internal ringbuffer Alsa uses.
There is no ALSA internal ringbuffer. The only buffer is the buffer your driver allocates.
- Why is there both a min and a max ? How is chosen what will be used ?
This expresses the hardware limitations. The minimum and maximum number of periods per buffer supported by the hardware. When starting playback/capture userspace may choose any number between min and max for the actual number of
- Currently my period_min is set to 1 and my period_max set to 4, If I
increase the period_max value it does not start properly, it seems that the samples are not deliverered in time. Is there any explanation for this, does the Alsa layer not any pre-buffering before the first copy() is called ?
Well that probably means there is a bug in your driver so that it does not support more than 4 periods.
- Is there any advice / guidline for period min/max values ? I checked
sourecs of severl drivers, some use 1 and some use values like 32 or more for period_max.
Yes, set them according to the limitations of your hw.
The same applies to buffer_bytes min/max, currently my min is set to 128bytes , max to 2kB, larger values of max seem to cause more problems.
Same here.
From the documentation I understand that it does not matter if pcm_period_elapsed() is not always called, How dows the ALSA layer then know how many samples are played. the pointer value read the pcm_pointer() only counts from [0..period_max] so what if 2 or more calls to period_elapsed() are skipped ?
pcm_pointer goes from 0 to buffer_size. Since you usually have multiple periods per buffer it is possible to recover from a situation where pcm_period_elapsed() was skipped.
Suppose I want to have some buffering inside my pcm driver, how will I be able to get some samples in advance before starting playback ? Can I just call pcm_period_elapsed() a few times in a row to get the buffer filled before starting the actual playcback, or does this cause side effects ?
Why'd you want to do that?
- Lars
participants (3)
-
Clemens Ladisch
-
Lars-Peter Clausen
-
marcelg