Commit dcb42685 authored by Thomas Guillem's avatar Thomas Guillem Committed by Jean-Baptiste Kempf
Browse files

auhal: fix data race with VolumeSet

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().
parent 42937c98
......@@ -118,6 +118,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;
......@@ -896,15 +903,16 @@ SwitchAudioDevice(audio_output_t *p_aout, const char *name)
}
static int
VolumeSet(audio_output_t * p_aout, float volume)
VolumeSetLocked(audio_output_t * p_aout, float volume)
{
aout_sys_t *p_sys = p_aout->sys;
OSStatus err;
if (p_sys->b_digital)
p_sys->f_volume = volume;
if (p_sys->au_unit == NULL)
return VLC_EGENERIC;
p_sys->f_volume = volume;
aout_VolumeReport(p_aout, volume);
/* Set volume for output unit */
......@@ -921,6 +929,17 @@ VolumeSet(audio_output_t * p_aout, float volume)
return (err == noErr) ? VLC_SUCCESS : VLC_EGENERIC;
}
static int
VolumeSet(audio_output_t * p_aout, float volume)
{
aout_sys_t *p_sys = p_aout->sys;
vlc_mutex_lock(&p_sys->volume_lock);
int ret = VolumeSetLocked(p_aout, volume);
vlc_mutex_unlock(&p_sys->volume_lock);
return ret;
}
static int
MuteSet(audio_output_t * p_aout, bool mute)
{
......@@ -1102,7 +1121,7 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
}
/* Set volume for output unit */
VolumeSet(p_aout, p_sys->f_volume);
VolumeSetLocked(p_aout, p_sys->f_volume);
free(layout);
......@@ -1396,10 +1415,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
{
......@@ -1595,7 +1618,11 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
}
else
{
if (StartAnalog(p_aout, fmt) == VLC_SUCCESS)
vlc_mutex_lock(&p_sys->volume_lock);
int ret = StartAnalog(p_aout, fmt);
vlc_mutex_unlock(&p_sys->volume_lock);
if (ret == VLC_SUCCESS)
{
msg_Dbg(p_aout, "analog output successfully opened");
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
......@@ -1680,6 +1707,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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment