Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
43731984
Commit
43731984
authored
Oct 08, 2011
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert back to one PulseAudio mainloop per context, kill libvlcpulse
This fixes deadlocks between input and output.
parent
ed17149b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
129 additions
and
203 deletions
+129
-203
modules/access/Modules.am
modules/access/Modules.am
+5
-3
modules/access/pulse.c
modules/access/pulse.c
+24
-23
modules/audio_output/Modules.am
modules/audio_output/Modules.am
+2
-3
modules/audio_output/pulse.c
modules/audio_output/pulse.c
+31
-43
modules/audio_output/vlcpulse.c
modules/audio_output/vlcpulse.c
+59
-110
modules/audio_output/vlcpulse.h
modules/audio_output/vlcpulse.h
+8
-8
src/Makefile.am
src/Makefile.am
+0
-13
No files found.
modules/access/Modules.am
View file @
43731984
...
...
@@ -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
...
...
modules/access/pulse.c
View file @
43731984
...
...
@@ -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
);
}
modules/audio_output/Modules.am
View file @
43731984
...
...
@@ -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
...
...
modules/audio_output/pulse.c
View file @
43731984
...
...
@@ -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
);
}
src/pulse/mainloop
.c
→
modules/audio_output/vlcpulse
.c
View file @
43731984
...
...
@@ -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
;
}
include/vlc_
pulse.h
→
modules/audio_output/vlc
pulse.h
View file @
43731984
...
...
@@ -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
}
...
...
src/Makefile.am
View file @
43731984
...
...
@@ -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
###############################################################################
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment