I have a upnp streaming app, written in C, in which I use alsa-lib to get and set the ALSA Master output volume.
I use the APIs snd_mixer_selem_get_playback_volume
and snd_mixer_selem_set_playback_volume_all
to do so.
As long as I only get/set the volume from my app, everything is OK: there is no volume shifts between the "real" Master volume level and the value I get from alsa-lib API.
However, I have an issue if I modify the Master volume from outside my app (from alsamixer for example).
Let's take the following sequence as example:
Is it the expected behavior?
I expected the last step to return 100% but it looks like the mixer instance of my app is not updated when the ALSA Master volume is updated from elsewhere. I didn't find anything about the need of reloading/refreshing/updating my mixer instance.
I noticed that if I create a new instance of the mixer element on the fly each time I need to get the volume level, I get the right value. But I would prefer to avoid such a solution that looks more like a workaround than a clean solution.
Basically, here is how I create an instance and get/set volume:
// variables
long volume;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
const char *name = "default";
const char *selem_name = "Master";
// create instance
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, name);
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);
// get set volume.
// get as MONO assuming all channels are at the same level.
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &volume);
snd_mixer_selem_set_playback_volume_all(elem, volume);
The code runs under openstlinux Yocto image on Cortex-A7
What do I miss or do wrong?
After browsing again and again the internet, I found what I needed and it is quite simple in the end.
I needed to call snd_mixer_handle_events
function before calling snd_mixer_selem_get_playback_volume
in order to handle external events that occured on the mixer and "refresh" my app instance.
// variables
long volume;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
const char *name = "default";
const char *selem_name = "Master";
// create instance
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, name);
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);
// get/set volume
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &volume); // for instance returns 50
volume = 70;
snd_mixer_selem_set_playback_volume_all(elem, volume);
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &volume); // returns 70
// Set the volume to 100 from outside the code, from alsamixer for example
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &volume); // returns 70 instead of 100
snd_mixer_handle_events(handle);
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &volume); // returns 100