summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_out/audio_pulse_out.c272
1 files changed, 147 insertions, 125 deletions
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index 587d2cab3..9b811aaaf 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -51,9 +51,6 @@
typedef struct {
audio_driver_class_t driver_class;
xine_t *xine;
-
- struct pa_context *context; /*< Pulseaudio connection context */
- struct pa_threaded_mainloop *mainloop; /*< Main event loop object */
} pulse_class_t;
typedef struct pulse_driver_s {
@@ -64,7 +61,10 @@ typedef struct pulse_driver_s {
char *host; /*< The host to connect to */
char *sink; /*< The sink to connect to */
- struct pa_stream *stream; /*< Pulseaudio playback stream object */
+
+ pa_threaded_mainloop *mainloop; /*< Main event loop object */
+ pa_context *context; /*< Pulseaudio connection context */
+ pa_stream *stream; /*< Pulseaudio playback stream object */
pa_volume_t swvolume;
int muted;
@@ -88,7 +88,7 @@ typedef struct pulse_driver_s {
*/
static void __xine_pa_context_state_callback(pa_context *c, void *this_gen)
{
- pulse_class_t * this = (pulse_class_t*) this_gen;
+ pulse_driver_t * this = (pulse_driver_t*) this_gen;
switch (pa_context_get_state(c)) {
@@ -121,7 +121,7 @@ static void __xine_pa_stream_state_callback(pa_stream *s, void *this_gen)
case PA_STREAM_READY:
case PA_STREAM_TERMINATED:
case PA_STREAM_FAILED:
- pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ pa_threaded_mainloop_signal(this->mainloop, 0);
break;
case PA_STREAM_UNCONNECTED:
@@ -141,7 +141,7 @@ static void __xine_pa_stream_request_callback(pa_stream *s, size_t nbytes, void
{
pulse_driver_t * this = (pulse_driver_t*) this_gen;
- pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ pa_threaded_mainloop_signal(this->mainloop, 0);
}
/**
@@ -154,7 +154,7 @@ static void __xine_pa_stream_notify_callback(pa_stream *s, void *this_gen)
{
pulse_driver_t * this = (pulse_driver_t*) this_gen;
- pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ pa_threaded_mainloop_signal(this->mainloop, 0);
}
/**
@@ -169,9 +169,9 @@ static void __xine_pa_stream_success_callback(pa_stream *s, int success, void *t
pulse_driver_t * this = (pulse_driver_t*) this_gen;
if (!success)
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: stream operation failed: %s\n", pa_strerror(pa_context_errno(this->pa_class->context)));
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: stream operation failed: %s\n", pa_strerror(pa_context_errno(this->context)));
- pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ pa_threaded_mainloop_signal(this->mainloop, 0);
}
/**
@@ -183,7 +183,7 @@ static void __xine_pa_stream_success_callback(pa_stream *s, int success, void *t
*/
static void __xine_pa_context_success_callback(pa_context *c, int success, void *this_gen)
{
- pulse_class_t *this = (pulse_class_t*) this_gen;
+ pulse_driver_t *this = (pulse_driver_t*) this_gen;
if (!success)
xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: context operation failed: %s\n", pa_strerror(pa_context_errno(this->context)));
@@ -209,7 +209,7 @@ static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info
if (is_last < 0) {
xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n",
- pa_strerror(pa_context_errno(this->pa_class->context)));
+ pa_strerror(pa_context_errno(this->context)));
return;
}
@@ -221,6 +221,53 @@ static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info
this->muted = info->mute;
}
+static int connect_context(pulse_driver_t *this) {
+
+ if (this->context && (pa_context_get_state(this->context) == PA_CONTEXT_FAILED ||
+ pa_context_get_state(this->context) == PA_CONTEXT_TERMINATED)) {
+ pa_context_unref(this->context);
+ this->context = NULL;
+ }
+
+ if (!this->context) {
+ char fn[PATH_MAX], *p;
+
+ if (pa_get_binary_name(fn, sizeof(fn)))
+ p = pa_path_get_filename(fn);
+ else
+ p = "Xine";
+
+ this->context = pa_context_new(pa_threaded_mainloop_get_api(this->mainloop), p);
+ _x_assert(this->context);
+
+ pa_context_set_state_callback(this->context, __xine_pa_context_state_callback, this);
+ }
+
+ if (pa_context_get_state(this->context) == PA_CONTEXT_UNCONNECTED) {
+
+ if (pa_context_connect(this->context, this->host, 0, NULL) < 0) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object %s\n", pa_strerror(pa_context_errno(this->context)));
+ return -1;
+ }
+ }
+
+ for (;;) {
+ pa_context_state_t state = pa_context_get_state(this->context);
+
+ if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context)));
+ return -1;
+ }
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ pa_threaded_mainloop_wait(this->mainloop);
+ }
+
+ return 0;
+}
+
/*
* open the audio device for writing to
*/
@@ -240,14 +287,14 @@ static int ao_pulse_open(ao_driver_t *this_gen,
return 0;
}
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
if (this->stream) {
if (mode == this->mode && rate == this->sample_rate &&
bits == this->bits_per_sample) {
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return this->sample_rate;
}
@@ -325,50 +372,11 @@ static int ao_pulse_open(ao_driver_t *this_gen,
goto fail;
}
- if ( this->pa_class->context && (pa_context_get_state(this->pa_class->context) == PA_CONTEXT_FAILED ||
- pa_context_get_state(this->pa_class->context) == PA_CONTEXT_TERMINATED)) {
- pa_context_unref(this->pa_class->context);
- this->pa_class->context = NULL;
- }
-
- if (!this->pa_class->context) {
- char fn[PATH_MAX], *p;
-
- if (pa_get_binary_name(fn, sizeof(fn)))
- p = pa_path_get_filename(fn);
- else
- p = "Xine";
-
- this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop), p);
- _x_assert(this->pa_class->context);
-
- pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_state_callback, this->pa_class);
- }
-
- if (pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED) {
-
- if (pa_context_connect(this->pa_class->context, this->host, 0, NULL) < 0) {
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object\n");
- goto fail;
- }
- }
-
- for (;;) {
- pa_context_state_t state = pa_context_get_state(this->pa_class->context);
-
- if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) {
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->pa_class->context)));
- goto fail;
- }
-
- if (state == PA_CONTEXT_READY)
- break;
-
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
- }
+ if (connect_context(this) < 0)
+ goto fail;
_x_assert(!this->stream);
- this->stream = pa_stream_new(this->pa_class->context, "Audio Stream", &ss, &cm);
+ this->stream = pa_stream_new(this->context, "Audio Stream", &ss, &cm);
_x_assert(this->stream);
pa_stream_set_state_callback(this->stream, __xine_pa_stream_state_callback, this);
@@ -380,28 +388,28 @@ static int ao_pulse_open(ao_driver_t *this_gen,
NULL, NULL);
for (;;) {
- pa_context_state_t cstate = pa_context_get_state(this->pa_class->context);
+ pa_context_state_t cstate = pa_context_get_state(this->context);
pa_stream_state_t sstate = pa_stream_get_state(this->stream);
if (cstate == PA_CONTEXT_FAILED || cstate == PA_CONTEXT_TERMINATED ||
sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) {
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->pa_class->context)));
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context)));
goto fail;
}
if (sstate == PA_STREAM_READY)
break;
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
+ pa_threaded_mainloop_wait(this->mainloop);
}
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return this->sample_rate;
fail:
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
this_gen->close(this_gen);
return 0;
}
@@ -432,7 +440,7 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
int ret = -1;
size_t done = 0;
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
while (size > 0) {
size_t l;
@@ -440,8 +448,8 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
for (;;) {
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY)
goto finish;
@@ -451,7 +459,7 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
if (l > 0)
break;
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
+ pa_threaded_mainloop_wait(this->mainloop);
}
if (l > size)
@@ -467,7 +475,7 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
finish:
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
/* fprintf(stderr, "write-out\n"); */
@@ -482,14 +490,14 @@ static int ao_pulse_delay (ao_driver_t *this_gen)
/* fprintf(stderr, "delay-in\n"); */
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
for (;;) {
pa_usec_t latency = 0;
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY)
goto finish;
@@ -498,17 +506,17 @@ static int ao_pulse_delay (ao_driver_t *this_gen)
goto finish;
}
- if (pa_context_errno(this->pa_class->context) != PA_ERR_NODATA) {
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to query latency: %s\n", pa_strerror(pa_context_errno(this->pa_class->context)));
+ if (pa_context_errno(this->context) != PA_ERR_NODATA) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to query latency: %s\n", pa_strerror(pa_context_errno(this->context)));
goto finish;
}
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
+ pa_threaded_mainloop_wait(this->mainloop);
}
finish:
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return ret;
}
@@ -517,7 +525,7 @@ static void ao_pulse_close(ao_driver_t *this_gen)
{
pulse_driver_t *this = (pulse_driver_t *) this_gen;
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
if (this->stream) {
pa_stream_disconnect(this->stream);
@@ -525,7 +533,7 @@ static void ao_pulse_close(ao_driver_t *this_gen)
this->stream = NULL;
}
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
}
static uint32_t ao_pulse_get_capabilities (ao_driver_t *this_gen) {
@@ -539,7 +547,20 @@ static void ao_pulse_exit(ao_driver_t *this_gen) {
ao_pulse_close(this_gen);
- free (this);
+ pa_threaded_mainloop_lock(this->mainloop);
+
+ if (this->context) {
+ pa_context_disconnect(this->context);
+ pa_context_unref(this->context);
+ }
+
+ pa_threaded_mainloop_unlock(this->mainloop);
+
+ pa_threaded_mainloop_free(this->mainloop);
+
+ free(this->host);
+ free(this->sink);
+ free(this);
}
static int wait_for_operation(pulse_driver_t *this, pa_operation *o) {
@@ -547,15 +568,15 @@ static int wait_for_operation(pulse_driver_t *this, pa_operation *o) {
for (;;) {
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY)
return -1;
if (pa_operation_get_state(o) != PA_OPERATION_RUNNING)
return 0;
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
+ pa_threaded_mainloop_wait(this->mainloop);
}
}
@@ -564,13 +585,13 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
int result = 0;
pa_operation *o = NULL;
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY) {
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return 0;
}
@@ -580,7 +601,7 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
case AO_PROP_PCM_VOL:
case AO_PROP_MIXER_VOL:
- o = pa_context_get_sink_input_info(this->pa_class->context, pa_stream_get_index(this->stream),
+ o = pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream),
__xine_pa_sink_info_callback, this);
break;
@@ -603,7 +624,7 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
break;
}
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return result;
}
@@ -613,13 +634,13 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
int result = ~value;
pa_operation *o = NULL;
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY) {
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return 0;
}
@@ -630,8 +651,8 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
this->swvolume = pa_sw_volume_from_linear((double)value/100.0);
pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume);
- o = pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream),
- &this->cvolume, __xine_pa_context_success_callback, this->pa_class);
+ o = pa_context_set_sink_input_volume(this->context, pa_stream_get_index(this->stream),
+ &this->cvolume, __xine_pa_context_success_callback, this);
result = value;
break;
@@ -640,8 +661,8 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
this->muted = value;
- o = pa_context_set_sink_input_mute(this->pa_class->context, pa_stream_get_index(this->stream),
- value, __xine_pa_context_success_callback, this->pa_class);
+ o = pa_context_set_sink_input_mute(this->context, pa_stream_get_index(this->stream),
+ value, __xine_pa_context_success_callback, this);
result = value;
}
@@ -651,7 +672,7 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
pa_operation_unref(o);
}
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return result;
}
@@ -660,13 +681,13 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) {
pulse_driver_t *this = (pulse_driver_t *) this_gen;
pa_operation *o = NULL;
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ pa_threaded_mainloop_lock(this->mainloop);
if (!this->stream ||
- !this->pa_class->context ||
- pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ||
+ !this->context ||
+ pa_context_get_state(this->context) != PA_CONTEXT_READY ||
pa_stream_get_state(this->stream) != PA_STREAM_READY) {
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return 0;
}
@@ -689,7 +710,7 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) {
pa_operation_unref(o);
}
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->mainloop);
return 0;
}
@@ -697,7 +718,8 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) {
static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) {
pulse_class_t *class = (pulse_class_t *) class_gen;
pulse_driver_t *this;
- char *device;
+ const char* device;
+ int r;
lprintf ("audio_pulse_out: open_plugin called\n");
@@ -708,15 +730,17 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
this->xine = class->xine;
this->host = NULL;
this->sink = NULL;
+ this->context = NULL;
+ this->mainloop = NULL;
- device = this->xine->config->register_string(this->xine->config,
- "audio.pulseaudio_device",
- "",
- _("device used for pulseaudio"),
- _("use 'server[:sink]' for setting the "
- "pulseaudio sink device."),
- 10, NULL,
- NULL);
+ device = class->xine->config->register_string(class->xine->config,
+ "audio.pulseaudio_device",
+ "",
+ _("device used for pulseaudio"),
+ _("use 'server[:sink]' for setting the "
+ "pulseaudio sink device."),
+ 10, NULL,
+ NULL);
if (device && *device) {
char *sep = strrchr(device, ':');
@@ -740,6 +764,10 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
}
}
+ this->mainloop = pa_threaded_mainloop_new();
+ _x_assert(this->mainloop);
+ pa_threaded_mainloop_start(this->mainloop);
+
/*
* set capabilities
*/
@@ -769,6 +797,15 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
this->pa_class = class;
+ pa_threaded_mainloop_lock(this->mainloop);
+ r = connect_context(this);
+ pa_threaded_mainloop_unlock(this->mainloop);
+
+ if (r < 0) {
+ ao_pulse_exit((ao_driver_t *) this);
+ return NULL;
+ }
+
return &this->ao_driver;
}
@@ -780,16 +817,7 @@ static void dispose_class (audio_driver_class_t *this_gen) {
pulse_class_t *this = (pulse_class_t *) this_gen;
- pa_threaded_mainloop_stop(this->mainloop);
-
- if (this->context) {
- pa_context_disconnect(this->context);
- pa_context_unref(this->context);
- }
-
- pa_threaded_mainloop_free(this->mainloop);
-
- free (this);
+ free(this);
}
static void *init_class (xine_t *xine, void *data) {
@@ -802,18 +830,12 @@ static void *init_class (xine_t *xine, void *data) {
if (!this)
return NULL;
+ this->xine = xine;
this->driver_class.open_plugin = open_plugin;
this->driver_class.dispose = dispose_class;
this->driver_class.identifier = "pulseaudio";
this->driver_class.description = N_("xine audio output plugin using pulseaudio sound server");
- this->xine = xine;
- this->context = NULL;
-
- this->mainloop = pa_threaded_mainloop_new();
- _x_assert(this->mainloop);
- pa_threaded_mainloop_start(this->mainloop);
-
return this;
}