mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	alsa-mixer: fix the re-attach code for the mixer control element
The new helem must be tracked and old helem must be cleared
to make the code work properly. Introduce the pointer to helem
as the private value for melem and add the necessary code.
Also, add a check for the duplicate mixer elements. The duplicate
mixer element invokes the abort check in alsa-lib. Print a warning
instead and handle the exit gracefully.
Link: d1675df0cd
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
			
			
This commit is contained in:
		
							parent
							
								
									3177f41cb4
								
							
						
					
					
						commit
						4066bbaf09
					
				
					 2 changed files with 51 additions and 10 deletions
				
			
		|  | @ -675,7 +675,7 @@ struct temp_port_avail { | |||
| static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) | ||||
| { | ||||
| 	pa_card *impl = snd_mixer_elem_get_callback_private(melem); | ||||
| 	snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); | ||||
| 	snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; | ||||
| 	snd_ctl_elem_value_t *elem_value; | ||||
| 	bool plugged_in, any_input_port_available; | ||||
| 	void *state; | ||||
|  | @ -685,6 +685,8 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) | |||
| 	enum acp_available active_available = ACP_AVAILABLE_UNKNOWN; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	pa_assert(_elem); | ||||
| 	elem = *_elem; | ||||
| #if 0 | ||||
| 	/* Changing the jack state may cause a port change, and a port change will
 | ||||
| 	 * make the sink or source change the mixer settings. If there are multiple | ||||
|  | @ -953,13 +955,17 @@ static pa_device_port* find_port_with_eld_device(pa_card *impl, int device) | |||
| static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) | ||||
| { | ||||
| 	pa_card *impl = snd_mixer_elem_get_callback_private(melem); | ||||
| 	snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); | ||||
| 	int device = snd_hctl_elem_get_device(elem); | ||||
| 	snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; | ||||
| 	int device; | ||||
| 	const char *old_monitor_name; | ||||
| 	pa_device_port *p; | ||||
| 	pa_hdmi_eld eld; | ||||
| 	bool changed = false; | ||||
| 
 | ||||
| 	pa_assert(_elem); | ||||
| 	elem = *_elem; | ||||
| 	device = snd_hctl_elem_get_device(elem); | ||||
| 
 | ||||
| 	if (mask == SND_CTL_EVENT_MASK_REMOVE) | ||||
| 		return 0; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1604,10 +1604,11 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, | |||
|     snd_mixer_elem_t *elem; | ||||
| 
 | ||||
|     for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) { | ||||
|         snd_hctl_elem_t *helem; | ||||
|         snd_hctl_elem_t **_helem, *helem; | ||||
|         if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO) | ||||
|             continue; | ||||
|         helem = snd_mixer_elem_get_private(elem); | ||||
|         _helem = snd_mixer_elem_get_private(elem); | ||||
|         helem = *_helem; | ||||
|         if (snd_hctl_elem_get_interface(helem) != iface) | ||||
|             continue; | ||||
|         if (!pa_streq(snd_hctl_elem_get_name(helem), name)) | ||||
|  | @ -1635,15 +1636,25 @@ static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_ | |||
|     return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1); | ||||
| } | ||||
| 
 | ||||
| static void mixer_melem_free(snd_mixer_elem_t *elem) | ||||
| { | ||||
|     snd_hctl_elem_t **_helem; | ||||
|     _helem = snd_mixer_elem_get_private(elem); | ||||
|     pa_xfree(_helem); | ||||
| } | ||||
| 
 | ||||
| static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, | ||||
| 			snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) | ||||
| { | ||||
|     int err; | ||||
|     const char *name = snd_hctl_elem_get_name(helem); | ||||
|     snd_hctl_elem_t **_helem; | ||||
|     // NOTE: The remove event defined as '~0U`.
 | ||||
|     if (mask == SND_CTL_EVENT_MASK_REMOVE) { | ||||
|         // NOTE: unless remove pointer to melem from link-list at private_data of helem, hits
 | ||||
| 	// assersion in alsa-lib since the list is not empty.
 | ||||
|         _helem = snd_mixer_elem_get_private(melem); | ||||
|         *_helem = NULL; | ||||
|         snd_mixer_elem_detach(melem, helem); | ||||
|     } else if (mask & SND_CTL_EVENT_MASK_ADD) { | ||||
|         snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); | ||||
|  | @ -1655,13 +1666,35 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, | |||
|             const int device = snd_hctl_elem_get_device(helem); | ||||
|             snd_mixer_elem_t *new_melem; | ||||
| 
 | ||||
|             bool found = true; | ||||
| 
 | ||||
|             new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device); | ||||
|             if (!new_melem) { | ||||
|                 _helem = pa_xmalloc(sizeof(snd_hctl_elem_t *)); | ||||
|                 *_helem = helem; | ||||
|                 /* Put the hctl pointer as our private data - it will be useful for callbacks */ | ||||
|                 if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) { | ||||
|                 if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, _helem, mixer_melem_free)) < 0) { | ||||
|                     pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err)); | ||||
|                     return 0; | ||||
|                 } | ||||
|                 found = false; | ||||
|             } else { | ||||
|                 _helem = snd_mixer_elem_get_private(new_melem); | ||||
|                 if (_helem) { | ||||
|                     char *s1, *s2; | ||||
|                     snd_ctl_elem_id_t *id1, *id2; | ||||
|                     snd_ctl_elem_id_alloca(&id1); | ||||
|                     snd_ctl_elem_id_alloca(&id2); | ||||
|                     snd_hctl_elem_get_id(helem, id1); | ||||
|                     snd_hctl_elem_get_id(*_helem, id2); | ||||
|                     s1 = snd_ctl_ascii_elem_id_get(id1); | ||||
|                     s2 = snd_ctl_ascii_elem_id_get(id2); | ||||
|                     pa_log_warn("mixer_class_event - duplicate mixer controls: %s | %s", s1, s2); | ||||
|                     free(s2); | ||||
|                     free(s1); | ||||
|                     return 0; | ||||
|                 } | ||||
|                 *_helem = helem; | ||||
|             } | ||||
| 
 | ||||
|             if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) { | ||||
|  | @ -1670,12 +1703,14 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, | |||
|                 return 0; | ||||
|             } | ||||
| 
 | ||||
|             if (!found) { | ||||
|                 if ((err = snd_mixer_elem_add(new_melem, class)) < 0) { | ||||
|                     pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err)); | ||||
|                     return 0; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else if (mask & SND_CTL_EVENT_MASK_VALUE) { | ||||
|         snd_mixer_elem_value(melem); /* Calls the element callback */ | ||||
|         return 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jaroslav Kysela
						Jaroslav Kysela