mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	spa: alsa: Read ctl events instead of doing a global diff
This does a couple of things: first, we implement revents demangling, which seems to be required (although hw: devices work fine without it). The second is to actually read the ctl events so we can tell when elements we care about have changed, instead of reading everything and trying to do a diff. The latter is also required from a correctness perspective, as otherwise the ctl might keep triggering wakeups while the fd is ready to be read.
This commit is contained in:
		
							parent
							
								
									8a1ed01923
								
							
						
					
					
						commit
						46e6fd2ae4
					
				
					 2 changed files with 66 additions and 25 deletions
				
			
		|  | @ -674,16 +674,53 @@ static void fill_card_name(struct state *state, const char *params, char *card_n | |||
| 
 | ||||
| static void bind_ctl_event(struct spa_source *source) | ||||
| { | ||||
| 	// We don't know if a bound element changed or not, so let's find out
 | ||||
| 	struct state *state = source->data; | ||||
| 	snd_ctl_event_t *ev; | ||||
| 	snd_ctl_elem_id_t *id, *bound_id; | ||||
| 	snd_ctl_elem_value_t *old_value; | ||||
| 	unsigned short revents; | ||||
| 	int err; | ||||
| 
 | ||||
| 	// Do the same demangling of revents we do for PCM pollfds
 | ||||
| 	for (int i = 0; i < state->ctl_n_fds; i++) { | ||||
| 		state->ctl_pfds[i].revents = state->ctl_sources[i].rmask; | ||||
| 		state->ctl_sources[i].rmask = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	err = snd_ctl_poll_descriptors_revents(state->ctl, state->ctl_pfds, state->ctl_n_fds, &revents); | ||||
| 	if (SPA_UNLIKELY(err < 0)) { | ||||
| 		spa_log_warn(state->log, "Could not read ctl revents: %s", snd_strerror(err)); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!revents) { | ||||
| 		spa_log_trace(state->log, "Got a bind ctl wakeup but no actual event"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	snd_ctl_event_alloca(&ev); | ||||
| 	snd_ctl_elem_id_alloca(&id); | ||||
| 	snd_ctl_elem_id_alloca(&bound_id); | ||||
| 	snd_ctl_elem_value_alloca(&old_value); | ||||
| 
 | ||||
| 	while ((err = snd_ctl_read(state->ctl, ev) > 0)) { | ||||
| 		bool changed = false; | ||||
| 
 | ||||
| 	snd_ctl_elem_value_alloca(&old_value); | ||||
| 		if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM) | ||||
| 			continue; | ||||
| 
 | ||||
| 		snd_ctl_event_elem_get_id(ev, id); | ||||
| 
 | ||||
| 		for (unsigned int i = 0; i < state->num_bind_ctls; i++) { | ||||
| 			int err; | ||||
| 
 | ||||
| 			// Check if we have the right element
 | ||||
| 			snd_ctl_elem_value_get_id(state->bound_ctls[i].value, bound_id); | ||||
| 			if (snd_ctl_elem_id_compare_set(id, bound_id) || | ||||
| 					snd_ctl_elem_id_compare_numid(id, bound_id)) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			snd_ctl_elem_value_copy(old_value, state->bound_ctls[i].value); | ||||
| 
 | ||||
| 			err = snd_ctl_elem_read(state->ctl, state->bound_ctls[i].value); | ||||
|  | @ -710,6 +747,10 @@ static void bind_ctl_event(struct spa_source *source) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (err < 0 && err != -EAGAIN) | ||||
| 		spa_log_warn(state->log, "Could not read ctl: %s", snd_strerror(err)); | ||||
| } | ||||
| 
 | ||||
| static void fetch_bind_ctls(struct state *state) | ||||
| { | ||||
| 	snd_ctl_elem_list_t* element_list; | ||||
|  | @ -791,7 +832,6 @@ cleanup: | |||
| 
 | ||||
| static void bind_ctls_for_params(struct state *state) | ||||
| { | ||||
| 	struct pollfd pfds[16]; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (state->num_bind_ctls == 0) | ||||
|  | @ -817,7 +857,7 @@ static void bind_ctls_for_params(struct state *state) | |||
| 		state->ctl_n_fds = SPA_N_ELEMENTS(state->ctl_sources); | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_ctl_poll_descriptors(state->ctl, pfds, state->ctl_n_fds)) < 0) { | ||||
| 	if ((err = snd_ctl_poll_descriptors(state->ctl, state->ctl_pfds, state->ctl_n_fds)) < 0) { | ||||
| 		spa_log_warn(state->log, "Could not get poll descriptors: %s", snd_strerror(err)); | ||||
| 		return; | ||||
| 	} | ||||
|  | @ -827,7 +867,7 @@ static void bind_ctls_for_params(struct state *state) | |||
| 	for (int i = 0; i < state->ctl_n_fds; i++) { | ||||
| 		state->ctl_sources[i].func = bind_ctl_event; | ||||
| 		state->ctl_sources[i].data = state; | ||||
| 		state->ctl_sources[i].fd = pfds[i].fd; | ||||
| 		state->ctl_sources[i].fd = state->ctl_pfds[i].fd; | ||||
| 		state->ctl_sources[i].mask = SPA_IO_IN; | ||||
| 		state->ctl_sources[i].rmask = 0; | ||||
| 		spa_loop_add_source(state->main_loop, &state->ctl_sources[i]); | ||||
|  |  | |||
|  | @ -259,6 +259,7 @@ struct state { | |||
| 	/* ALSA ctls exposed as params */ | ||||
| 	unsigned int num_bind_ctls; | ||||
| 	struct bound_ctl bound_ctls[16]; | ||||
| 	struct pollfd ctl_pfds[MAX_POLL]; | ||||
| 	struct spa_source ctl_sources[MAX_POLL]; | ||||
| 	int ctl_n_fds; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Arun Raghavan
						Arun Raghavan