Commit 43731984 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Revert back to one PulseAudio mainloop per context, kill libvlcpulse

This fixes deadlocks between input and output.
parent ed17149b
......@@ -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
......
......@@ -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);
}
......@@ -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
......
......@@ -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);
}
......@@ -23,11 +23,10 @@
# 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;
}
......@@ -24,18 +24,18 @@
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
}
......
......@@ -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
###############################################################################
......
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