summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_out/audio_pulse_out.c165
1 files changed, 113 insertions, 52 deletions
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index dbfc4b9f0..9e6089730 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_pulse_out.c,v 1.16 2007/03/31 22:06:54 dgp85 Exp $
+ * $Id: audio_pulse_out.c,v 1.17 2007/04/01 00:32:29 dgp85 Exp $
*
* ao plugin for pulseaudio (rename of polypaudio):
* http://0pointer.de/lennart/projects/pulsaudio/
@@ -107,6 +107,34 @@ static void __xine_pa_stream_success_callback(pa_stream *const stream, const int
}
/**
+ * @brief Callback function called when the state of the context is changed
+ * @param ctx Context which operation has succeeded
+ * @param this_gen pulse_driver_t pointer for the PulseAudio output
+ * instance.
+ */
+static void __xine_pa_context_status_callback(pa_context *const ctx, void *const this_gen)
+{
+ pulse_driver_t *const this = (pulse_driver_t*)this_gen;
+
+ _x_assert(ctx); _x_assert(this);
+ _x_assert(ctx == this->pa_class->context);
+
+ switch (pa_context_get_state(ctx)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ break;
+
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+/**
* @brief Callback function called when a context operation succeed
* @param ctx Context which operation has succeeded
* @param success The success value for the operation (ignored)
@@ -221,6 +249,39 @@ static int ao_pulse_open(ao_driver_t *this_gen,
goto fail;
}
+ pthread_mutex_lock(&this->pa_class->pa_mutex);
+ if ( this->pa_class->context && pa_context_get_state(this->pa_class->context) > PA_CONTEXT_READY ) {
+ pa_context_unref(this->pa_class->context);
+ this->pa_class->context = NULL;
+ }
+
+ if ( this->pa_class->context == NULL ) {
+ this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop),
+ __progname);
+ }
+
+ pa_context_ref(this->pa_class->context);
+
+ if ( pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED ) {
+ int ret;
+
+ pa_threaded_mainloop_lock(this->pa_class->mainloop);
+ ret = pa_context_connect(this->pa_class->context, this->host, 1, NULL);
+ if ( ret < 0 )
+ goto fail;
+
+ pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this);
+
+ pa_threaded_mainloop_wait(this->pa_class->mainloop);
+ pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ }
+
+ if (pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to connect to server: %s\n",
+ pa_strerror(pa_context_errno(this->pa_class->context)));
+ goto fail;
+ }
+
this->stream = pa_stream_new(this->pa_class->context, "audio stream", &ss, NULL);
_x_assert(this->stream);
@@ -229,8 +290,6 @@ static int ao_pulse_open(ao_driver_t *this_gen,
a.prebuf = a.tlength/2;
a.minreq = a.tlength/10;
- pthread_mutex_lock(&this->pa_class->pa_mutex);
-
pa_stream_connect_playback(this->stream, this->sink, &a,
PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE,
NULL, NULL);
@@ -255,6 +314,8 @@ static int ao_pulse_open(ao_driver_t *this_gen,
return this->sample_rate;
fail:
+ pa_threaded_mainloop_unlock(this->pa_class->mainloop);
+ pthread_mutex_unlock(&this->pa_class->pa_mutex);
this_gen->close(this_gen);
return 0;
}
@@ -284,10 +345,11 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
int size = num_frames * this->bytes_per_frame;
int ret = 0;
- _x_assert(this->stream && this->pa_class->context);
-
- if (pa_stream_get_state(this->stream) == PA_STREAM_READY) {
+ if ( !this->stream || !this->pa_class->context)
+ return -1;
+ switch( pa_stream_get_state(this->stream) ) {
+ case PA_STREAM_READY:
while (size > 0) {
size_t l;
@@ -307,6 +369,8 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
if (pa_stream_get_state(this->stream) == PA_STREAM_READY)
ret = 1;
+
+ break;
}
return ret;
@@ -319,15 +383,25 @@ static int ao_pulse_delay (ao_driver_t *this_gen)
pa_usec_t latency = 0;
int delay_frames;
- for (;;) {
- if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0)
- break;
+ if ( ! this->stream ) return this->frames_written;
- if (pa_context_errno(this->pa_class->context) != PA_ERR_NODATA) {
- /* error */
- }
+ pthread_mutex_lock(&this->pa_class->pa_mutex);
+
+ if (pa_stream_get_latency(this->stream, &latency, NULL) < 0) {
+ pa_context_unref(this->pa_class->context);
+ this->pa_class->context = NULL;
+
+ pa_stream_disconnect(this->stream);
+ pa_stream_unref(this->stream);
+ this->stream = NULL;
+
+ pthread_mutex_unlock(&this->pa_class->pa_mutex);
+
+ return 0;
}
+ pthread_mutex_unlock(&this->pa_class->pa_mutex);
+
/* convert latency (us) to frame units. */
delay_frames = (int)(latency * this->sample_rate / 1000000);
@@ -350,6 +424,8 @@ static void ao_pulse_close(ao_driver_t *this_gen)
pa_stream_unref(this->stream);
this->stream = NULL;
+ pa_context_unref(this->pa_class->context);
+
pthread_mutex_unlock(&this->pa_class->pa_mutex);
}
}
@@ -378,10 +454,15 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
switch(property) {
case AO_PROP_PCM_VOL:
case AO_PROP_MIXER_VOL:
- wait_for_operation(this,
- pa_context_get_sink_input_info(this->pa_class->context, pa_stream_get_index(this->stream),
- __xine_pa_sink_info_callback, this));
- result = (pa_sw_volume_to_linear(this->swvolume)*100);
+ {
+ pa_operation *o = pa_context_get_sink_input_info(this->pa_class->context,
+ pa_stream_get_index(this->stream),
+ __xine_pa_sink_info_callback, this);
+ if ( ! o ) return 0;
+ wait_for_operation(this, o);
+
+ result = (pa_sw_volume_to_linear(this->swvolume)*100);
+ }
break;
case AO_PROP_MUTE_VOL:
@@ -437,6 +518,8 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) {
pulse_driver_t *this = (pulse_driver_t *) this_gen;
+ if ( ! this->stream ) return 0;
+
switch (cmd) {
case AO_CTRL_PLAY_PAUSE:
@@ -484,9 +567,7 @@ 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 hn[128];
char *device;
- pa_context_state_t ctxstate;
lprintf ("audio_pulse_out: open_plugin called\n");
@@ -505,6 +586,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
AO_CAP_16BITS | AO_CAP_FLOAT32;
this->sample_rate = 0;
+ this->host = NULL;
+ this->sink = NULL;
this->ao_driver.get_capabilities = ao_pulse_get_capabilities;
this->ao_driver.get_property = ao_pulse_get_property;
@@ -528,18 +611,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
10, NULL,
NULL);
- if (device && strlen(device)) {
- int i = strcspn(device, ":");
- if (i >= sizeof(hn))
- i = sizeof(hn)-1;
-
- if (i > 0) {
- strncpy(this->host = hn, device, i);
- hn[i] = 0;
- }
-
- if (device[i] == ':')
- this->sink = device+i+1;
+ if (device && *device) {
+ char *sep = strchr(device, ':');
+ if ( sep ) {
+ this->host = strndup(device, sep-device);
+ this->sink = strdup(&sep[1]);
+ } else
+ this->host = strdup(device);
}
xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n",
@@ -547,28 +625,10 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
this->pa_class = class;
- pthread_mutex_lock(&this->pa_class->pa_mutex);
- if ( pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY ){
- pa_context_connect(this->pa_class->context, this->host, 1, NULL);
-
- do {
- xine_usec_sleep (100);
-
- ctxstate = pa_context_get_state(this->pa_class->context);
- } while (ctxstate < PA_CONTEXT_READY);
-
- if (ctxstate != PA_CONTEXT_READY) {
- xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to connect to server: %s\n",
- pa_strerror(pa_context_errno(this->pa_class->context)));
- goto fail;
- }
- }
-
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
return &this->ao_driver;
fail:
- pthread_mutex_lock(&this->pa_class->pa_mutex);
+ pthread_mutex_unlock(&this->pa_class->pa_mutex);
free(this);
xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: open_plugin failed.\n");
return NULL;
@@ -592,7 +652,8 @@ static void dispose_class (audio_driver_class_t *this_gen) {
pthread_mutex_lock(&this->pa_mutex);
- pa_context_unref(this->context);
+ if ( this->context )
+ pa_context_unref(this->context);
pa_threaded_mainloop_stop(this->mainloop);
pa_threaded_mainloop_free(this->mainloop);
@@ -626,8 +687,7 @@ static void *init_class (xine_t *xine, void *data) {
pa_threaded_mainloop_start(this->mainloop);
- this->context = pa_context_new(pa_threaded_mainloop_get_api(this->mainloop), __progname);
- _x_assert(this->context);
+ this->context = NULL;
pthread_mutex_unlock(&this->pa_mutex);
@@ -648,3 +708,4 @@ const plugin_info_t xine_plugin_info[] EXPORTED = {
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
+