Sample Header Ad - 728x90

Why is ALSA often not reading the audio card state

1 vote
0 answers
108 views
I'm having a terrible time with ALSA on a PI5. It will play and record sound, but the control interface seems to only work sometimes. I cannot find a cause for this. I could use some help understanding what is going on. My objective is to have a USB speaker (Polycom P3200M) reset its volume to the last volume setting on a boot. This should work with alsactl rdaemon. Further, there is a canned service in alsa-state.service that should do that. It is not working. I already have /etc/asla/state-daemon.conf in place, so the rdaemon option should be running. A look at ps -ef shows:
root         660       1  0 20:06 ?        00:00:00 /usr/sbin/alsactl -E HOME=/run/alsa -E XDG_RUNTIME_DIR=/run/alsa/runtime -s -n 19 -c rdaemon
So, I have to assume the service is running correctly. The problem is that if I execute amixer -c2 I don't get the correct output. For example it will show:
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 20
  Mono: Playback 9 [45%] [-22.00dB] [on]
Simple mixer control 'Headset',0
  Capabilities: cswitch cswitch-joined
  Capture channels: Mono
  Mono: Capture [on]
If I then change the volume on the speaker by pushing the buttons, and rerun axmixer -c2, I get the exact same output. By looking at the timestamp on /var/lib/alsa/asound.state I can see that the file is only touched at boot, and then never again. Finally, in a fit of frustration, I wrote my own code to monitor the device, and determine when the volume was changed.
#include 
#include 

int elem_callback(snd_mixer_elem_t *elem,unsigned int mask);

int main(int argc, char* argv[])
{
	long min, max;
	snd_mixer_t *handle;
	snd_mixer_selem_id_t *sid;
    	const char *selem_name = "PCM";
	long curVolume;
	int res;
	
	if(argc!=2)
	{
		return(1);
	}
	snd_mixer_open(&handle, 0);
	snd_mixer_attach(handle, argv);
	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);

	printf("Name: %s\n",snd_mixer_selem_get_name(elem));


	snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
	printf("max: %d\nmin:%d\n",max,min);
	snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_MONO,&curVolume);
	printf("Current Volume: %d\n",curVolume);

	snd_mixer_elem_set_callback(elem,elem_callback);

	while(1)
	{
		res=snd_mixer_wait(handle,-1);
		res=snd_mixer_handle_events(handle);
	}
    	snd_mixer_close(handle);

    return(0);
}


int elem_callback(snd_mixer_elem_t *elem,unsigned int mask)
{
	long curVolume;

	switch(mask)
	{
		case 1:
			snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_MONO,&curVolume);
			printf("Current Volume: %d\n",curVolume);
			printf("\tmask:  %d\n",mask);
			break;
		default:
			printf("Unrecognized mask: %d\n",mask);
			break;
	}
	return (0);
}
I lifted most of this code from [link](https://stackoverflow.com/questions/6787318/set-alsa-master-volume-from-c-code) What is truly bothersome is the above code worked. I could press the volume button on the speaker and the callback would get triggered. All was good. Then I rebooted the system and came back a day later. Now the code does nothing. It will output what it thinks the current settings are (which are not correct) but it will not react to the button presses. I'm at a loss. Why is ALSA sometimes working?
Asked by knottied (21 rep)
Feb 17, 2024, 06:15 PM