This appears to answer my problem: How to set periods and buffer size in ALSA? but I have an example which doesn't work.
frames = 1024;
int dir;
snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &frames, &dir);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("Frames: %zd\n", frames);
Regardless of frames being a high or a low number, when I fetch what it actually was set to with snd_pcm_hw_params_get_period_size(), it always shows me 512 frames.
I understand that the exact number I'm trying to set might not be available. However, shouldn't it set it to the nearest value of what I'm requesting?
I'm expecting to see it at least get increased when I request a higher number, or get lowered when I request a lower number, not remain exactly the same.
hw_params.c output for the "hw" device:
Device: hw (type: HW)
Access types: MMAP_INTERLEAVED RW_INTERLEAVED
Formats: S16_LE S32_LE
Channels: 2 4 6 8
Sample rates: 44100 48000 96000 192000
Interrupt interval: 20-5944309 us
Buffer size: 41-11888617 us
hw_params.c output for the "default" device:
Device: default (type: IOPLUG)
Access types: RW_INTERLEAVED
Formats: U8 S16_LE S16_BE S24_LE S24_BE S32_LE S32_BE FLOAT_LE FLOAT_BE MU_LAW A_LAW S24_3LE S24_3BE
Channels: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Sample rates: 1-192000
Interrupt interval: 5-4294967295 us
Buffer size: 15-4294967295 us
Minimal reproducible example where I attempt to set both the period of the buffer size:
/**
* Attempting to set some parameters.
*
* Using the template from: http://equalarea.com/paul/alsa-audio.html
*
**/
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#define PCM_DEVICE "default"
int main(int argc, char **argv)
{
unsigned int pcm;
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
/* Open the PCM device in playback mode */
if(pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm));
return 1;
}
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */
if(pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
return 1;
}
if(pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_FLOAT) < 0) {
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
return 1;
}
int channels = 2;
if(pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0) {
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
return 1;
}
int rate = 44100;
if(pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) {
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
return 1;
}
/* Write parameters */
if(pcm = snd_pcm_hw_params(pcm_handle, params) < 0) {
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
return 1;
}
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
int ch;
snd_pcm_hw_params_get_channels(params, &ch);
if(ch > 1) {
printf("Channels: %i, stereo\n", ch);
}
else if(ch == 1) {
printf("Channels: %i, mono\n", ch);
}
snd_pcm_hw_params_get_rate(params, &ch, 0);
printf("Rate: %d bps\n", ch);
int dir;
snd_pcm_uframes_t frames = 1024;
printf("Attempting to set frames to %d\n", frames);
snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &frames, &dir);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("Frames is now: %zd\n", frames);
snd_pcm_hw_params_get_period_time(params, &ch, NULL);
int buffer_size = 52430;
printf("Attempting to set the buffer size to: %d\n", buffer_size);
snd_pcm_hw_params_set_buffer_size(pcm_handle, params, buffer_size);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_uframes_t temp;
snd_pcm_hw_params_get_buffer_size(params, &temp);
printf("Buffer size is now: %d\n", temp);
return 0;
}
Compile with: gcc set_params_fail.c -lasound
Output:
PCM name: 'default'
PCM state: PREPARED
Channels: 2, stereo
Rate: 44100 bps
Attempting to set frames to 1024
Frames is now: 512
Attempting to set the buffer size to: 52430
Buffer size is now: 524288
After calling snd_pcm_hw_params()
, all parameters are fixed. You have to call snd_pcm_hw_params_set_period_size_near()
before the first (and only) call to snd_pcm_hw_params()
.