pulse: Add some documentation about threading and synchronisation
authorArun Raghavan <arun@accosted.net>
Mon, 29 Sep 2014 17:18:16 +0000 (22:48 +0530)
committerArun Raghavan <arun@accosted.net>
Tue, 30 Sep 2014 00:58:50 +0000 (06:28 +0530)
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.

ext/pulse/pulsesink.c
ext/pulse/pulsesrc.c

index e77ce8d..e3cdf05 100644 (file)
@@ -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)
 {
index 95eb4b7..682b929 100644 (file)
@@ -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,