[vlc-devel] [PATCH 2/2] auhal: fix data race with VolumeSet
Thomas Guillem
thomas at gllm.fr
Thu Apr 22 11:06:30 UTC 2021
VolumeSet (called from any threads) was accessing the au_unit variable,
that is written and setup from the aout stream thread.
This also fixes possible crashes when changing the volume after a
failing Start().
---
modules/audio_output/auhal.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/modules/audio_output/auhal.c b/modules/audio_output/auhal.c
index c1960766241..a0afefd2a5a 100644
--- a/modules/audio_output/auhal.c
+++ b/modules/audio_output/auhal.c
@@ -119,6 +119,13 @@ typedef struct
* thread (start, stop, close) needs no protection. */
vlc_mutex_t selected_device_lock;
+ /* Synchronizes access to au_unit and f_volume. This is needed by the
+ * VolumeSet callback, that can be called from any threads. The au_unit
+ * variable is written in the start and stop callbacks from the aout
+ * thread. Streams callbacks (play, pause, flush...) doesn't need this lock
+ * to access au_unit since they are called from the aout thread. */
+ vlc_mutex_t volume_lock;
+
float f_volume;
bool b_ignore_streams_changed_callback;
@@ -907,10 +914,16 @@ VolumeSet(audio_output_t * p_aout, float volume)
aout_sys_t *p_sys = p_aout->sys;
OSStatus ostatus = 0;
- if (p_sys->b_digital)
- return VLC_EGENERIC;
+ vlc_mutex_lock(&p_sys->volume_lock);
p_sys->f_volume = volume;
+
+ if (p_sys->au_unit == NULL)
+ {
+ vlc_mutex_unlock(&p_sys->volume_lock);
+ return VLC_EGENERIC;
+ }
+
aout_VolumeReport(p_aout, volume);
/* Set volume for output unit */
@@ -921,6 +934,8 @@ VolumeSet(audio_output_t * p_aout, float volume)
volume * volume * volume,
0);
+ vlc_mutex_unlock(&p_sys->volume_lock);
+
if (var_InheritBool(p_aout, "volume-save"))
config_PutInt("auhal-volume", lroundf(volume * AOUT_VOLUME_DEFAULT));
@@ -1403,10 +1418,14 @@ Stop(audio_output_t *p_aout)
if (p_sys->au_unit)
{
+ vlc_mutex_lock(&p_sys->volume_lock);
+
AudioOutputUnitStop(p_sys->au_unit);
au_Uninitialize(p_aout, p_sys->au_unit);
AudioComponentInstanceDispose(p_sys->au_unit);
p_sys->au_unit = NULL;
+
+ vlc_mutex_unlock(&p_sys->volume_lock);
}
else
{
@@ -1602,12 +1621,18 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
}
else
{
+ vlc_mutex_lock(&p_sys->volume_lock);
+
if (StartAnalog(p_aout, fmt) == VLC_SUCCESS)
{
+ vlc_mutex_unlock(&p_sys->volume_lock);
+
msg_Dbg(p_aout, "analog output successfully opened");
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
return VLC_SUCCESS;
}
+
+ vlc_mutex_unlock(&p_sys->volume_lock);
}
msg_Err(p_aout, "opening auhal output failed");
@@ -1687,6 +1712,7 @@ static int Open(vlc_object_t *obj)
vlc_mutex_init(&p_sys->device_list_lock);
vlc_mutex_init(&p_sys->selected_device_lock);
+ vlc_mutex_init(&p_sys->volume_lock);
p_sys->b_digital = false;
p_sys->au_unit = NULL;
p_sys->b_ignore_streams_changed_callback = false;
--
2.30.0
More information about the vlc-devel
mailing list