[alsa-devel] what is exactly pcm.boundary?
Hello. After some thoughts in ALSA internals (hw_ptr, appl_ptr, mmap'ed buffer, ioctls) I got me in many doubts. I would love if you help me understanding this.
Well, in src/pcm/pcm_local.h line ~469:
1 static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) 2 { 3 snd_pcm_sframes_t avail; 4 avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr; 5 if (avail < 0) 6 avail += pcm->boundary; 7 else if ((snd_pcm_uframes_t) avail >= pcm->boundary) 8 avail -= pcm->boundary; 9 return avail; 10 }
First, I assumed that both hw_ptr and appl_ptr always points to addresses inside a REGION of memory that is exactly the size of buffer = (period_size * periods).
I've also tried to imagine line 4 as: The forward distance between appl_ptr and hw_ptr where our application can write new samples: |s0|s1|s2|s3|s4|s5|s6|s7|s8|s9| buffer_size = 10 For example, if hw_ptr is on 's1' and appl_ptr is on 's7' we'll have ( 1 + 10 - 7 = 4 ) [s8,s9,s0,s1] available to write, right?
hw_ptr = Last sample that sound device has eaten up in ring buffer. appl_ptr = Last sample that application has written in ring buffer.
Ok, the problem comes, for example, when hw_ptr is on 's9' and appl_ptr is on 's4', so the sum is ( 9 + 10 - 4 = 15 ) -- a number greater than buffer_size. Although I expected pcm->boundary is equal buffer_size and then the test in 7th line would correct it: (9 + 10 - 4 = 15) (15 >= 10) 7th line condition test (15 - buffer_size = __5__) resulting in five [s5,s6,s7,s8,s9] samples available. But it's not.
Why? And what is exactly 'boundary' ? I read this http://www.mail-archive.com/alsa-user@lists.sourceforge.net/msg29891.html but doesn't help me
Another question ... can I thrust in hw_ptr value after a HWSYNC? will it be the exactly value of the current processed sample?
And to end ... is the latency of HWSYNC operation insignificant, or it could block or something that increases latency may happen?
Thank you very much! Cheers :-)
-- Ricardo Biehl Pasquali
Hi,
On Jan 6 2017 03:10, Ricardo Biehl wrote:
Well, in src/pcm/pcm_local.h line ~469:
1 static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) 2 { 3 snd_pcm_sframes_t avail; 4 avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr; 5 if (avail < 0) 6 avail += pcm->boundary; 7 else if ((snd_pcm_uframes_t) avail >= pcm->boundary) 8 avail -= pcm->boundary; 9 return avail; 10 }
First, I assumed that both hw_ptr and appl_ptr always points to addresses inside a REGION of memory that is exactly the size of buffer = (period_size * periods).
No. Both of the 'appl_ptr' and 'hw_ptr' is not within the size of buffer. They round up to the size of boundary. The size of boundary is calculated in these lines.
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/core...
590 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) 591 runtime->boundary *= 2;
You can also see current value of the boundary in PCM substream via procfs, like: $ cat /proc/asound/card0/pcm0p/sub0/sw_params tstamp_mode: ENABLE period_step: 1 avail_min: 1088 start_threshold: 18446744073709551615 stop_threshold: 4971973988617027584 silence_threshold: 0 silence_size: 0 boundary: 4971973988617027584
You can see it's not the size of allocated memory because it's quite large.
The size of boundary is always multiple of the size of period in intermediate buffer for user space, up to UINT_MAX. Both of 'hw_ptr' and 'appl_ptr' means total number of processed PCM frames in current PCM substream. They're not directly related to dedicated buffer for data transmission.
Regards
Takashi Sakamoto
2017-01-05 18:36 GMT-02:00, Takashi Sakamoto o-takashi@sakamocchi.jp:
Hi,
On Jan 6 2017 03:10, Ricardo Biehl wrote:
Well, in src/pcm/pcm_local.h line ~469:
1 static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) 2 { 3 snd_pcm_sframes_t avail; 4 avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr; 5 if (avail < 0) 6 avail += pcm->boundary; 7 else if ((snd_pcm_uframes_t) avail >= pcm->boundary) 8 avail -= pcm->boundary; 9 return avail; 10 }
First, I assumed that both hw_ptr and appl_ptr always points to addresses inside a REGION of memory that is exactly the size of buffer = (period_size * periods).
No. Both of the 'appl_ptr' and 'hw_ptr' is not within the size of buffer. They round up to the size of boundary. The size of boundary is calculated in these lines.
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/core...
590 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) 591 runtime->boundary *= 2;
You can also see current value of the boundary in PCM substream via procfs, like: $ cat /proc/asound/card0/pcm0p/sub0/sw_params tstamp_mode: ENABLE period_step: 1 avail_min: 1088 start_threshold: 18446744073709551615 stop_threshold: 4971973988617027584 silence_threshold: 0 silence_size: 0 boundary: 4971973988617027584
You can see it's not the size of allocated memory because it's quite large.
The size of boundary is always multiple of the size of period in intermediate buffer for user space, up to UINT_MAX. Both of 'hw_ptr' and 'appl_ptr' means total number of processed PCM frames in current PCM substream. They're not directly related to dedicated buffer for data transmission.
Oh Thanks :-) I was so far from the answer ...
In this way, can I get the offset of hardware pointer in my pcm char device mmaped area with:
offset_in_buffer = hw_ptr % buffer_size; ?
Regards
Takashi Sakamoto
-- Ricardo Biehl Pasquali
Ricardo Biehl wrote:
In this way, can I get the offset of hardware pointer in my pcm char device mmaped area with:
offset_in_buffer = hw_ptr % buffer_size; ?
Are you talking about code in your driver (where you are responsible for asking the hardware), or user space code (where you must not directly read hw_ptr)? What is the actual problem you're trying to solve?
Regards, Clemens
2017-01-06 6:09 GMT-02:00, Clemens Ladisch clemens@ladisch.de:
Are you talking about code in your driver (where you are responsible for asking the hardware), or user space code (where you must not directly read hw_ptr)? What is the actual problem you're trying to solve?
Hello! I'm developing a "live microphone system over local network" which are user space programs (clients => server) transferring audio nearly real-time (human imperceptible latency). I need to elaborate a good solution of implementation to have everything working as expected -- networking, scheduling, IO management etc -- However I need at first make sure I can get control over audio.
I decided to use ioctl() level of communication with ALSA in kernel, and what I need is synchronization :-) I must know which sample the hardware is currently processing to prevent a lot of losses or latency increasing.
Cheers!
-- Ricardo Biehl Pasquali
On 1/6/17 10:08 AM, Ricardo Biehl wrote:
2017-01-06 6:09 GMT-02:00, Clemens Ladisch clemens@ladisch.de:
Are you talking about code in your driver (where you are responsible for asking the hardware), or user space code (where you must not directly read hw_ptr)? What is the actual problem you're trying to solve?
Hello! I'm developing a "live microphone system over local network" which are user space programs (clients => server) transferring audio nearly real-time (human imperceptible latency). I need to elaborate a good solution of implementation to have everything working as expected -- networking, scheduling, IO management etc -- However I need at first make sure I can get control over audio.
I decided to use ioctl() level of communication with ALSA in kernel, and what I need is synchronization :-) I must know which sample the hardware is currently processing to prevent a lot of losses or latency increasing.
I would hate to sound pedantic but sample-accurate control (10us at 48kHz) is far from trivial. The hw_ptr points to the ring buffer, but you may have additional samples queued up in DMA transfers, FIFOS, codecs and last some analog delays. On a network-based solution the different components typically don't use the same audio clock and you will have to deal with drifts between source and sink. Best of luck.
Ricardo Biehl wrote:
I'm developing a "live microphone system over local network" which are user space programs (clients => server) transferring audio nearly real-time (human imperceptible latency). I need to elaborate a good solution of implementation to have everything working as expected -- networking, scheduling, IO management etc -- However I need at first make sure I can get control over audio.
I decided to use ioctl() level of communication with ALSA in kernel
Neither using ioctls directly nor using mmap will reduce latency.
First get it correct with the normal ALSA API.
Regards, Clemens
participants (4)
-
Clemens Ladisch
-
Pierre-Louis Bossart
-
Ricardo Biehl
-
Takashi Sakamoto