summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Raghavan <arun@accosted.net>2014-09-29 22:48:16 +0530
committerArun Raghavan <arun@accosted.net>2014-09-30 06:28:50 +0530
commit2a3adec2f769576fa4c950448756182884dbf10b (patch)
treecd1ee65509a6079d96bd4d76515b105b1ab8739a
parent0ed08ac3fd1a086ada5ce8b70045994c4d25cc80 (diff)
pulse: Add some documentation about threading and synchronisation
This gives a quick introduction to how the pulsesink/pulsesrc code interacts with the pa_threaded_mainloop that we start up to communicate with the server.
-rw-r--r--ext/pulse/pulsesink.c28
-rw-r--r--ext/pulse/pulsesrc.c3
2 files changed, 29 insertions, 2 deletions
diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
index e77ce8d5e..e3cdf05b4 100644
--- a/ext/pulse/pulsesink.c
+++ b/ext/pulse/pulsesink.c
@@ -107,6 +107,30 @@ typedef struct _GstPulseRingBufferClass GstPulseRingBufferClass;
typedef struct _GstPulseContext GstPulseContext;
+/* A note on threading.
+ *
+ * We use a pa_threaded_mainloop to interact with the PulseAudio server. This
+ * starts up a separate thread that runs a mainloop to carry back events,
+ * messages and timing updates from the PulseAudio server.
+ *
+ * In most cases, the PulseAudio API we use communicates with the server and
+ * processes replies asynchronously. Operations on PA objects that result in
+ * such communication are protected with a pa_threaded_mainloop_lock() and
+ * pa_threaded_mainloop_unlock(). These guarantee mutual exclusion with the
+ * mainloop thread -- when an iteration of the mainloop thread begins, it first
+ * tries to acquire this lock, and cannot do so if our code also holds that
+ * lock.
+ *
+ * When we need to complete an operation synchronously, we use
+ * pa_threaded_mainloop_wait() and pa_threaded_mainloop_signal(). These work
+ * much as pthread conditionals do. pa_threaded_mainloop_wait() is called with
+ * the mainloop lock held. It releases the lock (thereby allowing the mainloop
+ * to execute), and waits till one of our callbacks to be executed by the
+ * mainloop thread calls pa_threaded_mainloop_signal(). At the end of the
+ * mainloop iteration, the pa_threaded_mainloop_wait() will reacquire the
+ * mainloop lock and return control to the caller.
+ */
+
/* Store the PA contexts in a hash table to allow easy sharing among
* multiple instances of the sink. Keys are $context_name@$server_name
* (strings) and values should be GstPulseContext pointers.
@@ -1161,7 +1185,7 @@ gst_pulseringbuffer_clear (GstAudioRingBuffer * buf)
pa_threaded_mainloop_unlock (mainloop);
}
-/* called from pulse with the mainloop lock */
+/* called from pulse thread with the mainloop lock */
static void
mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
{
@@ -1248,7 +1272,7 @@ gst_pulseringbuffer_pause (GstAudioRingBuffer * buf)
return res;
}
-/* called from pulse with the mainloop lock */
+/* called from pulse thread with the mainloop lock */
static void
mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
{
diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
index 95eb4b7f0..682b92957 100644
--- a/ext/pulse/pulsesrc.c
+++ b/ext/pulse/pulsesrc.c
@@ -60,6 +60,9 @@ GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
#define DEFAULT_MUTE FALSE
#define MAX_VOLUME 10.0
+/* See the pulsesink code for notes on how we interact with the PA mainloop
+ * thread. */
+
enum
{
PROP_0,