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; }