Can't resample into ALSA plugin
I've written an ALSA plugin (ioplug) of the form below.
My plugin offers only S16, 48000Hz.
I expected a "plug" device would take the application's request and resample to 48000Hz, but instead it fails:
$ aplay -D plug:mytest cd-audio.wav Playing WAVE 'cd-audio.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo aplay: set_params:1456: Unable to install hw params: ACCESS: RW_INTERLEAVED FORMAT: S16_LE SUBFORMAT: STD SAMPLE_BITS: 16 FRAME_BITS: 32 CHANNELS: 2 RATE: 44100 PERIOD_TIME: 125000 PERIOD_SIZE: (5512 5513) PERIOD_BYTES: (22048 22052) PERIODS: (3 5) BUFFER_TIME: 500000 BUFFER_SIZE: 22050 BUFFER_BYTES: 88200 TICK_TIME: 0
It doesn't call .hw_params, so the negotiation has failed based on snd_pcm_ioplug_set_param_*.
Without the plug:
$ aplay -D mytest cd-audio.wav Playing WAVE 'cd-audio.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo Warning: rate is not accurate (requested = 44100Hz, got = 48000Hz) please, try the plug plugin (-Dplug:mytest) hw_params: format=S16_LE channels=2 rate=48000 period_size=6000 buffer_size=2400
Modify the plugin 48000Hz to be 44100Hz and negotiation passes, so it suggests the rate is the problem (not some other parameter like period size)
I tried a variety of things including directing aplay to use specific period and buffer size.
Thanks
---
/* * Code extracts, error checks removed for brevity */
static snd_pcm_ioplug_callback_t callback = { .close = _close, .hw_params = hw_params, /* prints them */ .start = start, .stop = stop, .pointer = pointer, .transfer = transfer, .delay = delay, .pause = _pause, .resume = resume, .prepare = prepare, };
static snd_pcm_ioplug_t initialise = { .version = SND_PCM_IOPLUG_VERSION, .name = "My test", .callback = &callback, };
SND_PCM_PLUGIN_DEFINE_FUNC(mytest) { struct state *s; snd_pcm_ioplug_t *io; unsigned access = SND_PCM_ACCESS_RW_INTERLEAVED; unsigned format = SND_PCM_FORMAT_S16; unsigned rate = 48000;
s = malloc(sizeof(*s)); ...
s->io = initialise; s->io.private_data = s; io = &s->io;
snd_pcm_ioplug_create(io, name, stream, mode); snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, 1, &access); snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, 1, &format); snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, 1, &rate);
*pcmp = io->pcm; return 0; }
On Sun, 11 Jan 2026, Mark Hills wrote:
I've written an ALSA plugin (ioplug) of the form below.
My plugin offers only S16, 48000Hz.
I expected a "plug" device would take the application's request and resample to 48000Hz, but instead it fails:
$ aplay -D plug:mytest cd-audio.wav Playing WAVE 'cd-audio.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo aplay: set_params:1456: Unable to install hw params: ACCESS: RW_INTERLEAVED FORMAT: S16_LE SUBFORMAT: STD
[...]
Modify the plugin 48000Hz to be 44100Hz and negotiation passes, so it suggests the rate is the problem (not some other parameter like period size)
Following up my own mail to help the others looking at these archives:
The root cause seems to be my plugin not offering SND_PCM_ACCESS_MMAP_INTERLEAVED, which I assume is required by the "plug" to do rate resampling and feed into it.
I couldn't find this in any documentation, searching or AI chat, and the ALSA code for negotiating the plug is non-trivial so perhaps someone has an explanation or rationale if it could fall into this for some other reason.
Here's the culprit code:
SND_PCM_PLUGIN_DEFINE_FUNC(mytest) { struct state *s; snd_pcm_ioplug_t *io; unsigned access = SND_PCM_ACCESS_RW_INTERLEAVED;
[...]
snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, 1, &access);
Many thanks,
participants (1)
-
Mark Hills