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.
This commit is contained in:
Arun Raghavan 2014-09-29 22:48:16 +05:30
parent 0ed08ac3fd
commit 2a3adec2f7
2 changed files with 29 additions and 2 deletions

View file

@ -107,6 +107,30 @@ typedef struct _GstPulseRingBufferClass GstPulseRingBufferClass;
typedef struct _GstPulseContext GstPulseContext; 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 /* Store the PA contexts in a hash table to allow easy sharing among
* multiple instances of the sink. Keys are $context_name@$server_name * multiple instances of the sink. Keys are $context_name@$server_name
* (strings) and values should be GstPulseContext pointers. * (strings) and values should be GstPulseContext pointers.
@ -1161,7 +1185,7 @@ gst_pulseringbuffer_clear (GstAudioRingBuffer * buf)
pa_threaded_mainloop_unlock (mainloop); pa_threaded_mainloop_unlock (mainloop);
} }
/* called from pulse with the mainloop lock */ /* called from pulse thread with the mainloop lock */
static void static void
mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata) mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
{ {
@ -1248,7 +1272,7 @@ gst_pulseringbuffer_pause (GstAudioRingBuffer * buf)
return res; return res;
} }
/* called from pulse with the mainloop lock */ /* called from pulse thread with the mainloop lock */
static void static void
mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata) mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
{ {

View file

@ -60,6 +60,9 @@ GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
#define DEFAULT_MUTE FALSE #define DEFAULT_MUTE FALSE
#define MAX_VOLUME 10.0 #define MAX_VOLUME 10.0
/* See the pulsesink code for notes on how we interact with the PA mainloop
* thread. */
enum enum
{ {
PROP_0, PROP_0,