I'm working on C program that uses the ALSA sound library, and I'm trying to set the volume to a specific percentage value. I've tried to follow an implementation based on the pyalsaaudio library and this SO answer. My issue starts when I set the element name to "Master" I encounter the following error when running my program (attached below): snd_mixer_selem_get_playback_volume_range: Assertion 'elem' failed. However if I set element name to "PCM" the volume range retrieval works fine, but I'm not able to set the percentage properly since the values are in a logarithmic scale and cannot figure out the transformation function (is not the dB one).
I'm working on a Raspberry Pi 4 with Raspberry Pi OS 64bit. Also tried in Ubuntu 23.04 64bit with same results.
Also when I run amixer scontrols in the terminal the output is:
Simple mixer control 'Master',0
Simple mixer control 'Capture',0
Here's the code that I'm using:
#include <stdio.h>
#include <alsa/asoundlib.h>
int main(int argc, char *argv[])
{
long min, max;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
const char *card = "default";
const char *selem_name = "Master";
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, card);
snd_mixer_selem_register(handle, NULL, NULL);
snd_mixer_load(handle);
snd_mixer_selem_id_alloca(&sid);
snd_mixer_selem_id_set_index(sid, 0);
snd_mixer_selem_id_set_name(sid, selem_name);
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
long range = max - min;
// setting the volume to 58%
long volume = min + (range * 58/100);
snd_mixer_selem_set_playback_volume_all(elem, volume);
printf("volume min: %ld - max: %ld\n", min, max);
}
I'm using the following command to compile it gcc -o audio audio.c -lasound
I finally figured out my problem. I was executing the script with sudo:
However the ALSA behavior is not the same as if you run it without sudo, so the solution was to run it just like:
The reason why I was running with sudo was because I'm also accessing to the GPIO in the same program, which requires root privileges. In case it helps someone, the complete solution to access GPIO but run the program without sudo was to change its ownership and permissions.