From 7d3921bb88178475021aca9536755a8a1f09c06d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 27 Mar 2009 16:55:17 +0100 Subject: pulse_mixer: protect the struct with a mutex There are numerous race conditions between the libpulse thread (pulse_mixer.c callbacks) and the rest of MPD. Protect the volatile attributes of the pulse_mixer struct with a mutex to fix that. --- src/mixer/pulse_mixer.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'src/mixer') diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c index 1f077e2b..b6ea077f 100644 --- a/src/mixer/pulse_mixer.c +++ b/src/mixer/pulse_mixer.c @@ -36,6 +36,8 @@ struct pulse_mixer { const char *sink; const char *output_name; + GMutex *mutex; + uint32_t index; bool online; @@ -95,9 +97,13 @@ sink_input_cb(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, g_debug("sink input cb %s, index %d ",i->name,i->index); if (strcmp(i->name,pm->output_name) == 0) { + g_mutex_lock(pm->mutex); + pm->index = i->index; pm->online = true; pm->volume = i->volume; + + g_mutex_unlock(pm->mutex); } else g_debug("bad name"); } @@ -120,7 +126,10 @@ sink_input_vol(G_GNUC_UNUSED pa_context *context, const pa_sink_input_info *i, } g_debug("sink input vol %s, index %d ", i->name, i->index); + + g_mutex_lock(pm->mutex); pm->volume = i->volume; + g_mutex_unlock(pm->mutex); pa_threaded_mainloop_signal(pm->mainloop, 0); } @@ -136,6 +145,8 @@ subscribe_cb(pa_context *c, pa_subscription_event_type_t t, switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + g_mutex_lock(pm->mutex); + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE && pm->index == idx) @@ -146,12 +157,15 @@ subscribe_cb(pa_context *c, pa_subscription_event_type_t t, o = pa_context_get_sink_input_info(c, idx, sink_input_cb, pm); if (o == NULL) { + g_mutex_unlock(pm->mutex); g_debug("pa_context_get_sink_input_info() failed"); return; } pa_operation_unref(o); } + + g_mutex_unlock(pm->mutex); break; } } @@ -215,6 +229,8 @@ pulse_mixer_init(const struct config_param *param) pm->sink = config_get_block_string(param, "sink", NULL); pm->output_name = config_get_block_string(param, "name", NULL); + pm->mutex = g_mutex_new(); + return &pm->base; } @@ -223,6 +239,7 @@ pulse_mixer_finish(struct mixer *data) { struct pulse_mixer *pm = (struct pulse_mixer *) data; + g_mutex_free(pm->mutex); g_free(pm); } @@ -314,12 +331,15 @@ pulse_mixer_get_volume(struct mixer *mixer) int ret; pa_operation *o; + g_mutex_lock(pm->mutex); if (!pm->online) { + g_mutex_unlock(pm->mutex); return false; } o = pa_context_get_sink_input_info(pm->context, pm->index, sink_input_vol, pm); + g_mutex_unlock(pm->mutex); if (o == NULL) { g_debug("pa_context_get_sink_input_info() failed"); return false; @@ -328,7 +348,12 @@ pulse_mixer_get_volume(struct mixer *mixer) if (!pulse_wait_for_operation(pm->mainloop, o)) return false; - ret = (int)((100*(pa_cvolume_avg(&pm->volume)+1))/PA_VOLUME_NORM); + g_mutex_lock(pm->mutex); + ret = pm->online + ? (int)((100*(pa_cvolume_avg(&pm->volume)+1))/PA_VOLUME_NORM) + : -1; + g_mutex_unlock(pm->mutex); + return ret; } @@ -339,7 +364,9 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume) struct pa_cvolume cvolume; pa_operation *o; + g_mutex_lock(pm->mutex); if (!pm->online) { + g_mutex_unlock(pm->mutex); return false; } @@ -348,6 +375,7 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume) o = pa_context_set_sink_input_volume(pm->context, pm->index, &cvolume, NULL, NULL); + g_mutex_unlock(pm->mutex); if (o == NULL) { g_debug("pa_context_set_sink_input_volume() failed"); return false; -- cgit v1.2.3