Commit 7deade85 authored by Max Kellermann's avatar Max Kellermann

mixer: protect the mixer struct with a mutex

In some rare cases, there was a race condition between the output thread and the main thread: when you disable/enable an output device in the main thread, this caused a crash in the output thread. Protect the whole mixer struct with a GMutex to prevent that.
parent 82963ee0
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include "mixer_api.h" #include "mixer_api.h"
#include <glib.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mixer" #define G_LOG_DOMAIN "mixer"
...@@ -28,4 +26,5 @@ void ...@@ -28,4 +26,5 @@ void
mixer_init(struct mixer *mixer, const struct mixer_plugin *plugin) mixer_init(struct mixer *mixer, const struct mixer_plugin *plugin)
{ {
mixer->plugin = plugin; mixer->plugin = plugin;
mixer->mutex = g_mutex_new();
} }
...@@ -23,8 +23,16 @@ ...@@ -23,8 +23,16 @@
#include "mixer_plugin.h" #include "mixer_plugin.h"
#include "mixer_list.h" #include "mixer_list.h"
#include <glib.h>
struct mixer { struct mixer {
const struct mixer_plugin *plugin; const struct mixer_plugin *plugin;
/**
* This mutex protects all of the mixer struct, including its
* implementation, so plugins don't have to deal with that.
*/
GMutex *mutex;
}; };
void void
......
...@@ -62,6 +62,9 @@ mixer_free(struct mixer *mixer) ...@@ -62,6 +62,9 @@ mixer_free(struct mixer *mixer)
return; return;
} }
assert(mixer->plugin != NULL); assert(mixer->plugin != NULL);
assert(mixer->mutex != NULL);
g_mutex_free(mixer->mutex);
mixer->plugin->finish(mixer); mixer->plugin->finish(mixer);
} }
...@@ -69,11 +72,18 @@ mixer_free(struct mixer *mixer) ...@@ -69,11 +72,18 @@ mixer_free(struct mixer *mixer)
bool bool
mixer_open(struct mixer *mixer) mixer_open(struct mixer *mixer)
{ {
bool success;
if (!mixer) { if (!mixer) {
return false; return false;
} }
assert(mixer->plugin != NULL); assert(mixer->plugin != NULL);
return mixer->plugin->open(mixer);
g_mutex_lock(mixer->mutex);
success = mixer->plugin->open(mixer);
g_mutex_unlock(mixer->mutex);
return success;
} }
void void
...@@ -83,17 +93,32 @@ mixer_close(struct mixer *mixer) ...@@ -83,17 +93,32 @@ mixer_close(struct mixer *mixer)
return; return;
} }
assert(mixer->plugin != NULL); assert(mixer->plugin != NULL);
g_mutex_lock(mixer->mutex);
mixer->plugin->close(mixer); mixer->plugin->close(mixer);
g_mutex_unlock(mixer->mutex);
} }
int int
mixer_get_volume(struct mixer *mixer) mixer_get_volume(struct mixer *mixer)
{ {
return mixer->plugin->get_volume(mixer); int volume;
g_mutex_lock(mixer->mutex);
volume = mixer->plugin->get_volume(mixer);
g_mutex_unlock(mixer->mutex);
return volume;
} }
bool bool
mixer_set_volume(struct mixer *mixer, unsigned volume) mixer_set_volume(struct mixer *mixer, unsigned volume)
{ {
return mixer->plugin->set_volume(mixer, volume); bool success;
g_mutex_lock(mixer->mutex);
success = mixer->plugin->set_volume(mixer, volume);
g_mutex_unlock(mixer->mutex);
return success;
} }
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