]> git.sesse.net Git - vlc/commitdiff
Revert back to one PulseAudio mainloop per context, kill libvlcpulse
authorRémi Denis-Courmont <remi@remlab.net>
Sat, 8 Oct 2011 13:57:51 +0000 (16:57 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Sat, 8 Oct 2011 14:06:27 +0000 (17:06 +0300)
This fixes deadlocks between input and output.

modules/access/Modules.am
modules/access/pulse.c
modules/audio_output/Modules.am
modules/audio_output/pulse.c
modules/audio_output/vlcpulse.c [moved from src/pulse/mainloop.c with 68% similarity]
modules/audio_output/vlcpulse.h [moved from include/vlc_pulse.h with 77% similarity]
src/Makefile.am

index d42335d92e6b433df8345e8e03b8edb4d6f07721..45b6499d9f3282875d203ca42fe97d5156c6d84c 100644 (file)
@@ -124,10 +124,12 @@ if HAVE_ALSA
 libvlc_LTLIBRARIES += libaccess_alsa_plugin.la
 endif
 
-libpulsesrc_plugin_la_SOURCES = pulse.c
+libpulsesrc_plugin_la_SOURCES = \
+       ../audio_output/vlcpulse.c \
+       ../audio_output/vlcpulse.h \
+       pulse.c
 libpulsesrc_plugin_la_CFLAGS= $(AM_CFLAGS) $(PULSE_CFLAGS)
-libpulsesrc_plugin_la_LIBADD = $(AM_LIBADD) $(PULSE_LIBS) \
-       ../../src/libvlcpulse.la
+libpulsesrc_plugin_la_LIBADD = $(AM_LIBADD) $(PULSE_LIBS)
 libpulsesrc_plugin_la_DEPENDENCIES =
 if HAVE_PULSE
 libvlc_LTLIBRARIES += libpulsesrc_plugin.la
index d75747bd76aadf0f48d71ba78235b9ff81d4f307..240b15613f5d0d0ed84eca6bf20220ea8c015346 100644 (file)
@@ -28,7 +28,7 @@
 #include <vlc_demux.h>
 #include <vlc_plugin.h>
 #include <pulse/pulseaudio.h>
-#include <vlc_pulse.h>
+#include "../audio_output/vlcpulse.h"
 
 static int Open(vlc_object_t *);
 static void Close(vlc_object_t *);
@@ -47,6 +47,7 @@ struct demux_sys_t
 {
     pa_stream *stream; /**< PulseAudio playback stream object */
     pa_context *context; /**< PulseAudio connection context */
+    pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
 
     es_out_id_t *es;
     bool discontinuity; /**< The next block will not follow the last one */
@@ -57,15 +58,16 @@ struct demux_sys_t
 /* Stream helpers */
 static void stream_state_cb(pa_stream *s, void *userdata)
 {
+    pa_threaded_mainloop *mainloop = userdata;
+
     switch (pa_stream_get_state(s)) {
         case PA_STREAM_READY:
         case PA_STREAM_FAILED:
         case PA_STREAM_TERMINATED:
-            vlc_pa_signal(0);
+            pa_threaded_mainloop_signal(mainloop, 0);
         default:
             break;
     }
-    (void) userdata;
 }
 
 static void stream_moved_cb(pa_stream *s, void *userdata)
@@ -109,14 +111,14 @@ static void stream_underflow_cb(pa_stream *s, void *userdata)
     (void) s;
 }
 
-static int stream_wait(pa_stream *stream)
+static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
 {
     pa_stream_state_t state;
 
     while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
         if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
             return -1;
-        vlc_pa_wait();
+        pa_threaded_mainloop_wait(mainloop);
     }
     return 0;
 }
@@ -210,17 +212,17 @@ static int Open(vlc_object_t *obj)
 {
     demux_t *demux = (demux_t *)obj;
 
-    pa_context *ctx = vlc_pa_connect(obj);
-    if (ctx == NULL)
-        return VLC_EGENERIC;
-
     demux_sys_t *sys = malloc(sizeof (*sys));
-    if (unlikely(sys == NULL)) {
-        vlc_pa_disconnect (obj, ctx);
+    if (unlikely(sys == NULL))
         return VLC_ENOMEM;
+
+    sys->context = vlc_pa_connect(obj, &sys->mainloop);
+    if (sys->context == NULL) {
+        free(sys);
+        return VLC_EGENERIC;
     }
+
     sys->stream = NULL;
-    sys->context = ctx;
     sys->es = NULL;
     sys->discontinuity = false;
     sys->caching = INT64_C(1000) * var_InheritInteger(obj, "live-caching");
@@ -254,13 +256,13 @@ static int Open(vlc_object_t *obj)
     /* Create record stream */
     pa_stream *s;
 
-    vlc_pa_lock();
-    s = pa_stream_new(ctx, "audio stream", &ss, &map);
+    pa_threaded_mainloop_lock(sys->mainloop);
+    s = pa_stream_new(sys->context, "audio stream", &ss, &map);
     if (s == NULL)
         goto error;
 
     sys->stream = s;
-    pa_stream_set_state_callback(s, stream_state_cb, NULL);
+    pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
     pa_stream_set_read_callback(s, stream_read_cb, demux);
     pa_stream_set_moved_callback(s, stream_moved_cb, demux);
     pa_stream_set_overflow_callback(s, stream_overflow_cb, demux);
@@ -269,8 +271,8 @@ static int Open(vlc_object_t *obj)
     pa_stream_set_underflow_callback(s, stream_underflow_cb, demux);
 
     if (pa_stream_connect_record(s, NULL, &attr, flags) < 0
-     || stream_wait(s)) {
-        vlc_pa_error(obj, "cannot connect record stream", ctx);
+     || stream_wait(s, sys->mainloop)) {
+        vlc_pa_error(obj, "cannot connect record stream", sys->context);
         goto error;
     }
 
@@ -289,14 +291,14 @@ static int Open(vlc_object_t *obj)
     const struct pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
     msg_Dbg(obj, "using buffer metrics: maxlength=%"PRIu32", fragsize=%"PRIu32,
             pba->maxlength, pba->fragsize);
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 
     demux->pf_demux = NULL;
     demux->pf_control = Control;
     return VLC_SUCCESS;
 
 error:
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
     Close(obj);
     return VLC_EGENERIC;
 }
@@ -305,11 +307,10 @@ static void Close (vlc_object_t *obj)
 {
     demux_t *demux = (demux_t *)obj;
     demux_sys_t *sys = demux->p_sys;
-    pa_context *ctx = sys->context;
     pa_stream *s = sys->stream;
 
     if (likely(s != NULL)) {
-        vlc_pa_lock();
+        pa_threaded_mainloop_lock(sys->mainloop);
         pa_stream_disconnect(s);
         pa_stream_set_state_callback(s, NULL, NULL);
         pa_stream_set_read_callback(s, NULL, NULL);
@@ -319,9 +320,9 @@ static void Close (vlc_object_t *obj)
         pa_stream_set_suspended_callback(s, NULL, NULL);
         pa_stream_set_underflow_callback(s, NULL, NULL);
         pa_stream_unref(s);
-        vlc_pa_unlock();
+        pa_threaded_mainloop_unlock(sys->mainloop);
     }
 
-    vlc_pa_disconnect(obj, ctx);
+    vlc_pa_disconnect(obj, sys->context, sys->mainloop);
     free(sys);
 }
index 1ac2da8dcc1ad06f813d7dbdbff857b7b8d690ab..0cbbbb7facf70e655cbd3b92bf20d90b268413dc 100644 (file)
@@ -38,10 +38,9 @@ if HAVE_ALSA
 libvlc_LTLIBRARIES += libalsa_plugin.la
 endif
 
-libpulse_plugin_la_SOURCES = pulse.c
+libpulse_plugin_la_SOURCES = vlcpulse.c vlcpulse.h pulse.c
 libpulse_plugin_la_CFLAGS = $(AM_CFLAGS) $(PULSE_CFLAGS)
-libpulse_plugin_la_LIBADD = $(AM_LIBADD) $(PULSE_LIBS) \
-       $(LIBM) ../../src/libvlcpulse.la
+libpulse_plugin_la_LIBADD = $(AM_LIBADD) $(PULSE_LIBS) $(LIBM)
 libpulse_plugin_la_DEPENDENCIES =
 if HAVE_PULSE
 libvlc_LTLIBRARIES += libpulse_plugin.la
index cd15f84f57ed53b8540de5fe35013b1e8773d133..5e0268031cd969f14776356deefe4f8693f285a3 100644 (file)
@@ -32,7 +32,7 @@
 #include <vlc_cpu.h>
 
 #include <pulse/pulseaudio.h>
-#include <vlc_pulse.h>
+#include "vlcpulse.h"
 #if !PA_CHECK_VERSION(0,9,22)
 # include <vlc_xlib.h>
 #endif
@@ -60,7 +60,7 @@ vlc_module_end ()
 
 /* NOTE:
  * Be careful what you do when the PulseAudio mainloop is held, which is to say
- * within PulseAudio callbacks, or after vlc_pa_lock().
+ * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
  * In particular, a VLC variable callback cannot be triggered nor deleted with
  * the PulseAudio mainloop lock held, if the callback acquires the lock. */
 
@@ -68,6 +68,7 @@ struct aout_sys_t
 {
     pa_stream *stream; /**< PulseAudio playback stream object */
     pa_context *context; /**< PulseAudio connection context */
+    pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
     pa_time_event *trigger; /**< Deferred stream trigger */
     pa_volume_t base_volume; /**< 0dB reference volume */
     pa_cvolume cvolume; /**< actual sink input volume */
@@ -177,20 +178,6 @@ static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol,
 
 
 /*** Latency management and lip synchronization ***/
-static mtime_t vlc_pa_get_latency(audio_output_t *aout,
-                                  pa_context *ctx, pa_stream *s)
-{
-    pa_usec_t latency;
-    int negative;
-
-    if (pa_stream_get_latency(s, &latency, &negative)) {
-        if (pa_context_errno (ctx) != PA_ERR_NODATA)
-            vlc_pa_error(aout, "unknown latency", ctx);
-        return VLC_TS_INVALID;
-    }
-    return negative ? -latency : +latency;
-}
-
 static void stream_reset_sync(pa_stream *s, audio_output_t *aout)
 {
     aout_sys_t *sys = aout->sys;
@@ -211,7 +198,7 @@ static void stream_start(pa_stream *s, audio_output_t *aout)
     pa_operation *op;
 
     if (sys->trigger != NULL) {
-        vlc_pa_rttime_free(sys->trigger);
+        vlc_pa_rttime_free(sys->mainloop, sys->trigger);
         sys->trigger = NULL;
     }
 
@@ -229,7 +216,7 @@ static void stream_stop(pa_stream *s, audio_output_t *aout)
     pa_operation *op;
 
     if (sys->trigger != NULL) {
-        vlc_pa_rttime_free(sys->trigger);
+        vlc_pa_rttime_free(sys->mainloop, sys->trigger);
         sys->trigger = NULL;
     }
 
@@ -363,15 +350,16 @@ static void stream_latency_cb(pa_stream *s, void *userdata)
 /*** Stream helpers ***/
 static void stream_state_cb(pa_stream *s, void *userdata)
 {
+    pa_threaded_mainloop *mainloop = userdata;
+
     switch (pa_stream_get_state(s)) {
         case PA_STREAM_READY:
         case PA_STREAM_FAILED:
         case PA_STREAM_TERMINATED:
-            vlc_pa_signal(0);
+            pa_threaded_mainloop_signal(mainloop, 0);
         default:
             break;
     }
-    (void) userdata;
 }
 
 static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
@@ -456,14 +444,14 @@ static void stream_underflow_cb(pa_stream *s, void *userdata)
     stream_reset_sync(s, aout);
 }
 
-static int stream_wait(pa_stream *stream)
+static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
 {
     pa_stream_state_t state;
 
     while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
         if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
             return -1;
-        vlc_pa_wait();
+        pa_threaded_mainloop_wait(mainloop);
     }
     return 0;
 }
@@ -533,7 +521,7 @@ static void Play(audio_output_t *aout, block_t *block)
      * output FIFO lock while the PulseAudio threaded main loop lock is held
      * (including from PulseAudio stream callbacks). Otherwise lock inversion
      * will take place, and sooner or later a deadlock. */
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
 
     sys->pts = pts;
     if (pa_stream_is_corked(s) > 0)
@@ -552,7 +540,7 @@ static void Play(audio_output_t *aout, block_t *block)
         block_Release(block);
     }
 
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 }
 
 /**
@@ -563,7 +551,7 @@ static void Pause(audio_output_t *aout, bool paused, mtime_t date)
     aout_sys_t *sys = aout->sys;
     pa_stream *s = sys->stream;
 
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
 
     if (paused) {
         sys->paused = date;
@@ -577,7 +565,7 @@ static void Pause(audio_output_t *aout, bool paused, mtime_t date)
         stream_resync(aout, s);
     }
 
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 }
 
 /**
@@ -589,7 +577,7 @@ static void Flush(audio_output_t *aout, bool wait)
     pa_stream *s = sys->stream;
     pa_operation *op;
 
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
 
     if (wait)
         op = pa_stream_drain(s, NULL, NULL);
@@ -598,7 +586,7 @@ static void Flush(audio_output_t *aout, bool wait)
         op = pa_stream_flush(s, NULL, NULL);
     if (op != NULL)
         pa_operation_unref(op);
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 }
 
 static int VolumeSet(audio_output_t *aout, float vol, bool mute)
@@ -623,14 +611,14 @@ static int VolumeSet(audio_output_t *aout, float vol, bool mute)
 
     assert(pa_cvolume_valid(&cvolume));
 
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
     op = pa_context_set_sink_input_volume(sys->context, idx, &cvolume, NULL, NULL);
     if (likely(op != NULL))
         pa_operation_unref(op);
     op = pa_context_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
     if (likely(op != NULL))
         pa_operation_unref(op);
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 
     return 0;
 }
@@ -647,7 +635,7 @@ static int StreamMove(vlc_object_t *obj, const char *varname, vlc_value_t old,
 
     (void) varname; (void) old;
 
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
     op = pa_context_move_sink_input_by_index(sys->context, idx, sink_idx,
                                              NULL, NULL);
     if (likely(op != NULL)) {
@@ -655,7 +643,7 @@ static int StreamMove(vlc_object_t *obj, const char *varname, vlc_value_t old,
         msg_Dbg(aout, "moving to sink %"PRIu32, sink_idx);
     } else
         vlc_pa_error(obj, "cannot move sink", sys->context);
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 
     return (op != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
 }
@@ -828,7 +816,7 @@ static int Open(vlc_object_t *obj)
     if (unlikely(sys == NULL))
         return VLC_ENOMEM;
 
-    pa_context *ctx = vlc_pa_connect (obj);
+    pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
     if (ctx == NULL)
     {
         free (sys);
@@ -881,13 +869,13 @@ static int Open(vlc_object_t *obj)
     /* Create a playback stream */
     pa_stream *s;
 
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
     s = pa_stream_new_extended(ctx, "audio stream", formatv, formatc, NULL);
 
     for (unsigned i = 0; i < formatc; i++)
         pa_format_info_free(formatv[i]);
 #else
-    vlc_pa_lock();
+    pa_threaded_mainloop_lock(sys->mainloop);
     pa_stream *s = pa_stream_new(ctx, "audio stream", &ss, &map);
 #endif
     if (s == NULL) {
@@ -895,7 +883,7 @@ static int Open(vlc_object_t *obj)
         goto fail;
     }
     sys->stream = s;
-    pa_stream_set_state_callback(s, stream_state_cb, NULL);
+    pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
     pa_stream_set_event_callback(s, stream_event_cb, aout);
     pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
     pa_stream_set_moved_callback(s, stream_moved_cb, aout);
@@ -905,7 +893,7 @@ static int Open(vlc_object_t *obj)
     pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
 
     if (pa_stream_connect_playback(s, NULL, &attr, flags, NULL, NULL) < 0
-     || stream_wait(s)) {
+     || stream_wait(s, sys->mainloop)) {
         vlc_pa_error(obj, "stream connection failure", ctx);
         goto fail;
     }
@@ -940,7 +928,7 @@ static int Open(vlc_object_t *obj)
     if (op != NULL)
         pa_operation_unref(op);
     stream_moved_cb(s, aout);
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
 
     aout->format.i_format = format;
     aout->pf_play = Play;
@@ -950,7 +938,7 @@ static int Open(vlc_object_t *obj)
     return VLC_SUCCESS;
 
 fail:
-    vlc_pa_unlock();
+    pa_threaded_mainloop_unlock(sys->mainloop);
     Close(obj);
     return VLC_EGENERIC;
 }
@@ -970,9 +958,9 @@ static void Close (vlc_object_t *obj)
         var_DelCallback (aout, "audio-device", StreamMove, s);
         var_Destroy (aout, "audio-device");
 
-        vlc_pa_lock ();
+        pa_threaded_mainloop_lock(sys->mainloop);
         if (unlikely(sys->trigger != NULL))
-            vlc_pa_rttime_free(sys->trigger);
+            vlc_pa_rttime_free(sys->mainloop, sys->trigger);
         pa_stream_disconnect(s);
 
         /* Clear all callbacks */
@@ -986,9 +974,9 @@ static void Close (vlc_object_t *obj)
         pa_stream_set_underflow_callback(s, NULL, NULL);
 
         pa_stream_unref(s);
-        vlc_pa_unlock ();
+        pa_threaded_mainloop_unlock(sys->mainloop);
     }
 
-    vlc_pa_disconnect(obj, ctx);
+    vlc_pa_disconnect(obj, ctx, sys->mainloop);
     free(sys);
 }
similarity index 68%
rename from src/pulse/mainloop.c
rename to modules/audio_output/vlcpulse.c
index 34f722b113dd2fe20741a7b190dceead6183eebb..a8b09292dd5c039a46e8ba7ad2248138113c4bcc 100644 (file)
 # include "config.h"
 #endif
 
-#define MODULE_STRING "pulse"
 #include <vlc_common.h>
 #include <pulse/pulseaudio.h>
 
-#include <vlc_pulse.h>
+#include "vlcpulse.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <locale.h>
@@ -40,105 +39,22 @@ void vlc_pa_error (vlc_object_t *obj, const char *msg, pa_context *ctx)
     msg_Err (obj, "%s: %s", msg, pa_strerror (pa_context_errno (ctx)));
 }
 
-static pa_threaded_mainloop *vlc_pa_mainloop;
-static unsigned refs = 0;
-static vlc_mutex_t lock = VLC_STATIC_MUTEX;
-
-/**
- * Creates and references the VLC PulseAudio threaded main loop.
- * @return 0 on success, -1 on failure
- */
-static int vlc_pa_mainloop_init (void)
-{
-    vlc_mutex_lock (&lock);
-    if (refs == 0)
-    {
-        vlc_pa_mainloop = pa_threaded_mainloop_new ();
-        if (unlikely(vlc_pa_mainloop == NULL))
-            goto err;
-
-        if (pa_threaded_mainloop_start (vlc_pa_mainloop) < 0)
-        {
-            pa_threaded_mainloop_free (vlc_pa_mainloop);
-            goto err;
-        }
-    }
-    else
-    {
-        if (unlikely(refs >= UINT_MAX))
-            goto err;
-    }
-    refs++;
-    vlc_mutex_unlock (&lock);
-    return 0;
-err:
-    vlc_mutex_unlock (&lock);
-    return -1;
-}
-
-/**
- * Releases a reference to the VLC PulseAudio main loop.
- */
-static void vlc_pa_mainloop_deinit (void)
-{
-    vlc_mutex_lock (&lock);
-    assert (refs > 0);
-    if (--refs == 0)
-    {
-        pa_threaded_mainloop_stop (vlc_pa_mainloop);
-        pa_threaded_mainloop_free (vlc_pa_mainloop);
-    }
-    vlc_mutex_unlock (&lock);
-}
-
-/**
- * Acquires the main loop lock.
- */
-void vlc_pa_lock (void)
-{
-    pa_threaded_mainloop_lock (vlc_pa_mainloop);
-}
-
-/**
- * Releases the main loop lock.
- */
-void vlc_pa_unlock (void)
-{
-    pa_threaded_mainloop_unlock (vlc_pa_mainloop);
-}
-
-/**
- * Signals the main loop.
- */
-void vlc_pa_signal (int do_wait)
-{
-    pa_threaded_mainloop_signal (vlc_pa_mainloop, do_wait);
-}
-
-/**
- * Waits for the main loop to be signaled.
- */
-void vlc_pa_wait (void)
-{
-    pa_threaded_mainloop_wait (vlc_pa_mainloop);
-}
-
-
 static void context_state_cb (pa_context *ctx, void *userdata)
 {
+    pa_threaded_mainloop *mainloop = userdata;
+
     switch (pa_context_get_state(ctx))
     {
         case PA_CONTEXT_READY:
         case PA_CONTEXT_FAILED:
         case PA_CONTEXT_TERMINATED:
-            vlc_pa_signal (0);
+            pa_threaded_mainloop_signal (mainloop, 0);
         default:
             break;
     }
-    (void) userdata;
 }
 
-static bool context_wait (pa_context *ctx)
+static bool context_wait (pa_context *ctx, pa_threaded_mainloop *mainloop)
 {
     pa_context_state_t state;
 
@@ -146,7 +62,7 @@ static bool context_wait (pa_context *ctx)
     {
         if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
             return -1;
-        vlc_pa_wait ();
+        pa_threaded_mainloop_wait (mainloop);
     }
     return 0;
 }
@@ -155,19 +71,25 @@ static bool context_wait (pa_context *ctx)
  * Initializes the PulseAudio main loop and connects to the PulseAudio server.
  * @return a PulseAudio context on success, or NULL on error
  */
-pa_context *vlc_pa_connect (vlc_object_t *obj)
+pa_context *vlc_pa_connect (vlc_object_t *obj, pa_threaded_mainloop **mlp)
 {
-    if (unlikely(vlc_pa_mainloop_init ()))
-        return NULL;
-
     msg_Dbg (obj, "using library version %s", pa_get_library_version ());
     msg_Dbg (obj, " (compiled with version %s, protocol %u)",
              pa_get_headers_version (), PA_PROTOCOL_VERSION);
 
-    char *ua = var_InheritString (obj, "user-agent");
-    pa_context *ctx;
+    /* Initialize main loop */
+    pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new ();
+    if (unlikely(mainloop == NULL))
+        return NULL;
+
+    if (pa_threaded_mainloop_start (mainloop) < 0)
+    {
+        pa_threaded_mainloop_free (mainloop);
+        return NULL;
+    }
 
     /* Fill in context (client) properties */
+    char *ua = var_InheritString (obj, "user-agent");
     pa_proplist *props = pa_proplist_new ();
     if (likely(props != NULL))
     {
@@ -208,18 +130,21 @@ pa_context *vlc_pa_connect (vlc_object_t *obj)
     }
 
     /* Connect to PulseAudio daemon */
-    vlc_pa_lock ();
+    pa_context *ctx;
+    pa_mainloop_api *api;
 
-    ctx = pa_context_new_with_proplist (pa_threaded_mainloop_get_api (vlc_pa_mainloop), ua, props);
+    pa_threaded_mainloop_lock (mainloop);
+    api = pa_threaded_mainloop_get_api (mainloop);
+    ctx = pa_context_new_with_proplist (api, ua, props);
     free (ua);
     if (props != NULL)
-        pa_proplist_free(props);
+        pa_proplist_free (props);
     if (unlikely(ctx == NULL))
         goto fail;
 
-    pa_context_set_state_callback (ctx, context_state_cb, NULL);
+    pa_context_set_state_callback (ctx, context_state_cb, mainloop);
     if (pa_context_connect (ctx, NULL, 0, NULL) < 0
-     || context_wait (ctx))
+     || context_wait (ctx, mainloop))
     {
         vlc_pa_error (obj, "PulseAudio server connection failure", ctx);
         pa_context_unref (ctx);
@@ -232,27 +157,31 @@ pa_context *vlc_pa_connect (vlc_object_t *obj)
              pa_context_get_protocol_version (ctx),
              pa_context_get_server_protocol_version (ctx));
 
-    vlc_pa_unlock ();
+    pa_threaded_mainloop_unlock (mainloop);
+    *mlp = mainloop;
     return ctx;
 
 fail:
-    vlc_pa_unlock ();
-    vlc_pa_mainloop_deinit ();
+    pa_threaded_mainloop_unlock (mainloop);
+    pa_threaded_mainloop_stop (mainloop);
+    pa_threaded_mainloop_free (mainloop);
     return NULL;
 }
 
 /**
  * Closes a connection to PulseAudio.
  */
-void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx)
+void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx,
+                        pa_threaded_mainloop *mainloop)
 {
-    vlc_pa_lock ();
+    pa_threaded_mainloop_lock (mainloop);
     pa_context_disconnect (ctx);
     pa_context_set_state_callback (ctx, NULL, NULL);
     pa_context_unref (ctx);
-    vlc_pa_unlock ();
+    pa_threaded_mainloop_unlock (mainloop);
 
-    vlc_pa_mainloop_deinit ();
+    pa_threaded_mainloop_stop (mainloop);
+    pa_threaded_mainloop_free (mainloop);
     (void) obj;
 }
 
@@ -262,7 +191,27 @@ void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx)
  * \warning This function must be called from the mainloop,
  * or with the mainloop lock held.
  */
-void vlc_pa_rttime_free(pa_time_event *e)
+void vlc_pa_rttime_free (pa_threaded_mainloop *mainloop, pa_time_event *e)
 {
-    (pa_threaded_mainloop_get_api (vlc_pa_mainloop))->time_free (e);
+    pa_mainloop_api *api = pa_threaded_mainloop_get_api (mainloop);
+
+    api->time_free (e);
+}
+
+#undef vlc_pa_get_latency
+/**
+ * Gets latency of a PulseAudio stream.
+ * \return the latency or VLC_TS_INVALID on error.
+ */
+mtime_t vlc_pa_get_latency(vlc_object_t *obj, pa_context *ctx, pa_stream *s)
+{
+    pa_usec_t latency;
+    int negative;
+
+    if (pa_stream_get_latency(s, &latency, &negative)) {
+        if (pa_context_errno (ctx) != PA_ERR_NODATA)
+            vlc_pa_error(obj, "unknown latency", ctx);
+        return VLC_TS_INVALID;
+    }
+    return negative ? -latency : +latency;
 }
similarity index 77%
rename from include/vlc_pulse.h
rename to modules/audio_output/vlcpulse.h
index e23c840dbe0e0f7d865f0ab8e25f2d6a809df772..b00d8c2b1ae0d0c10922ede60037bf38e68b5e37 100644 (file)
 extern "C" {
 # endif
 
-VLC_API void vlc_pa_lock (void);
-VLC_API void vlc_pa_unlock (void);
-VLC_API void vlc_pa_signal (int);
-VLC_API void vlc_pa_wait (void);
-
-VLC_API pa_context *vlc_pa_connect (vlc_object_t *obj);
-VLC_API void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx);
+VLC_API pa_context *vlc_pa_connect (vlc_object_t *obj,
+                                    pa_threaded_mainloop **);
+VLC_API void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx,
+                                pa_threaded_mainloop *);
 
 VLC_API void vlc_pa_error (vlc_object_t *, const char *msg, pa_context *);
 #define vlc_pa_error(o, m, c) vlc_pa_error(VLC_OBJECT(o), m, c)
 
-VLC_API void vlc_pa_rttime_free (pa_time_event *);
+VLC_API mtime_t vlc_pa_get_latency (vlc_object_t *, pa_context *, pa_stream *);
+#define vlc_pa_get_latency(o, c, s) vlc_pa_get_latency(VLC_OBJECT(o), c, s)
+
+VLC_API void vlc_pa_rttime_free (pa_threaded_mainloop *, pa_time_event *);
 
 # ifdef __cplusplus
 }
index 3210814858e25d948affc0a0b2a3de336b7ba22d..386794b6316677def9afb98f630436eb040eae16 100644 (file)
@@ -466,19 +466,6 @@ SOURCES_libvlc = \
        $(SOURCES_libvlc_common) \
        $(NULL)
 
-###############################################################################
-# libvlc pulse
-###############################################################################
-
-if HAVE_PULSE
-pkglib_LTLIBRARIES = libvlcpulse.la
-endif
-
-libvlcpulse_la_SOURCES = pulse/mainloop.c ../include/vlc_pulse.h
-libvlcpulse_la_CPPFLAGS = $(PULSE_CFLAGS)
-libvlcpulse_la_LIBADD = $(PULSE_LIBS) libvlccore.la
-libvlcpulse_la_LDFLAGS = -export-symbols-regex ^vlc_pa_ -no-undefined
-
 ###############################################################################
 # GIT revision
 ###############################################################################