Why does MMAP access ignore start_threshold?
25 Feb
2026
25 Feb
'26
8:10 a.m.
It seems that start_threshold (swparams) is not honoured if MMAP access is used.
Whereas I expect that once a total of enough bytes have been committed the device automatically starts the consuming of the buffer, as it does with snd_pcm_writei().
Is this a bug, or intentional design?
It does not seem to be the subject of any documentation -- yet for many years I seem to be be working around it.
Perhaps I am consistently doing something wrong, here's a test case below.
--
Mark
#include <alsa/asoundlib.h>
#define always(r) _always(r, __LINE__)
#define FORMAT SND_PCM_FORMAT_S16
#define ACCESS SND_PCM_ACCESS_MMAP_INTERLEAVED
static void _always(int r, unsigned line)
{
if (r < 0) {
fprintf(stderr, "%d: %s\n", line, snd_strerror(r));
abort();
}
}
static void set_hw(snd_pcm_t *pcm,
unsigned rate,
unsigned channels,
snd_pcm_uframes_t buffer_size,
snd_pcm_uframes_t period_size)
{
int r;
snd_pcm_hw_params_t *hw;
snd_pcm_hw_params_alloca(&hw);
r = snd_pcm_hw_params_any(pcm, hw);
always(r);
r = snd_pcm_hw_params_set_access(pcm, hw, ACCESS);
always(r);
r = snd_pcm_hw_params_set_format(pcm, hw, FORMAT);
always(r);
r = snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
always(r);
r = snd_pcm_hw_params_set_channels(pcm, hw, channels);
always(r);
r = snd_pcm_hw_params_set_buffer_size(pcm, hw, buffer_size);
always(r);
r = snd_pcm_hw_params_set_period_size(pcm, hw, period_size, 0);
always(r);
r = snd_pcm_hw_params(pcm, hw);
always(r);
}
static void set_sw(snd_pcm_t *pcm,
snd_pcm_uframes_t start_threshold,
snd_pcm_uframes_t avail_min)
{
int r;
snd_pcm_sw_params_t *sw;
snd_pcm_sw_params_alloca(&sw);
r = snd_pcm_sw_params_current(pcm, sw);
always(r);
r = snd_pcm_sw_params_set_start_threshold(pcm, sw, start_threshold);
always(r);
r = snd_pcm_sw_params_set_avail_min(pcm, sw, avail_min);
always(r);
r = snd_pcm_sw_params(pcm, sw);
always(r);
}
snd_pcm_uframes_t do_mmap(snd_pcm_t *pcm)
{
int r;
snd_pcm_uframes_t frames, offset;
const snd_pcm_channel_area_t *area;
r = snd_pcm_wait(pcm, 1000);
always(r);
r = snd_pcm_mmap_begin(pcm, &area, &offset, &frames);
always(r);
r = snd_pcm_mmap_commit(pcm, offset, frames);
always(r);
return frames;
}
snd_pcm_uframes_t do_write(snd_pcm_t *pcm, unsigned channels, snd_pcm_uframes_t frames)
{
int r;
void *buf;
size_t len = channels * snd_pcm_format_size(FORMAT, frames);
buf = alloca(len);
bzero(buf, len);
r = snd_pcm_writei(pcm, buf, frames);
always(r);
return frames;
}
int main(int argc, char *argv[])
{
int r;
snd_pcm_t *pcm;
r = snd_pcm_open(&pcm, argv[1], SND_PCM_STREAM_PLAYBACK, 0);
always(r);
set_hw(pcm, 48000, 2, 2048, 512);
set_sw(pcm, 1024, 512);
r = snd_pcm_prepare(pcm);
always(r);
for (;;) {
snd_pcm_uframes_t frames;
if (ACCESS == SND_PCM_ACCESS_MMAP_INTERLEAVED)
frames = do_mmap(pcm);
else
frames = do_write(pcm, 2, 512);
fprintf(stderr, "written %lu\n", frames);
}
r = snd_pcm_close(pcm);
always(r);
return 0;
}
3
Age (days ago)
3
Last active (days ago)
0 comments
1 participants
participants (1)
-
Mark Hills