summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego 'Flameeyes' Pettenò <flameeyes@gmail.com>2007-12-10 18:03:41 +0100
committerDiego 'Flameeyes' Pettenò <flameeyes@gmail.com>2007-12-10 18:03:41 +0100
commit900eb2090ded113a6d84f43bb521b8e8da1916c9 (patch)
tree0a9326efd3871570f0b223363a27e6cca5efc4b6
parentc1cdfb8e314fb6441d26775e120dd922acf9729c (diff)
downloadxine-lib-900eb2090ded113a6d84f43bb521b8e8da1916c9.tar.gz
xine-lib-900eb2090ded113a6d84f43bb521b8e8da1916c9.tar.bz2
Backport the PulseAudio plugin from 1.2 branch.
-rw-r--r--src/audio_out/audio_pulse_out.c174
1 files changed, 92 insertions, 82 deletions
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index dfd825047..e341aec3b 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -51,13 +51,24 @@
/* CHECKME: should this be conditional on autotools? */
extern const char *__progname;
+typedef struct operation_waiter {
+ struct pa_operation *operation; /**< Operation waiting */
+ pthread_cond_t condition; /**< Condition to signal */
+
+ struct operation_waiter *prev;
+ struct operation_waiter *next;
+} operation_waiter_t;
+
typedef struct {
audio_driver_class_t driver_class;
xine_t *xine;
- pthread_mutex_t pa_mutex; /*< Mutex controlling PulseAudio access. */
struct pa_context *context; /*< Pulseaudio connection context */
struct pa_threaded_mainloop *mainloop; /*< Main event loop object */
+ operation_waiter_t *op_list; /**< List of operations awaited */
+ pthread_mutex_t op_mutex; /**< Mutex controlling op_list access. */
+ pthread_t op_thread; /**< The operation_waiting_thread() thread. */
+ pthread_cond_t op_list_newentries; /**< condition signalled when new entries are added to the list */
} pulse_class_t;
typedef struct pulse_driver_s {
@@ -76,7 +87,7 @@ typedef struct pulse_driver_s {
int capabilities;
int mode;
- int32_t sample_rate;
+ uint32_t sample_rate;
uint32_t num_channels;
uint32_t bits_per_sample;
uint32_t bytes_per_frame;
@@ -85,6 +96,78 @@ typedef struct pulse_driver_s {
} pulse_driver_t;
+
+static void *operation_waiting_thread(void *class_gen) {
+ pulse_class_t *class = class_gen;
+ operation_waiter_t *curr_op;
+
+ pthread_mutex_t condmutex = PTHREAD_MUTEX_INITIALIZER;
+
+ while(1) {
+ if ( class->op_list == NULL ) {
+ pthread_mutex_lock(&condmutex);
+ pthread_cond_wait(&class->op_list_newentries, &condmutex);
+ }
+
+ pa_threaded_mainloop_lock(class->mainloop);
+ pa_threaded_mainloop_wait(class->mainloop);
+
+ pthread_mutex_lock(&class->op_mutex);
+
+ curr_op = class->op_list;
+ while(curr_op) {
+ if ( pa_operation_get_state(curr_op->operation) != PA_OPERATION_RUNNING ) {
+ /* Unlink the current operation from the list. */
+ if ( curr_op->prev )
+ curr_op->prev->next = curr_op->next;
+ if ( class->op_list == curr_op )
+ class->op_list = curr_op->next;
+
+ pthread_cond_signal(&curr_op->condition);
+ }
+ curr_op = curr_op->next;
+ }
+
+ pthread_mutex_unlock(&class->op_mutex);
+
+ pa_threaded_mainloop_unlock(class->mainloop);
+
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+static void wait_for_operation(pulse_driver_t *this, struct pa_operation *operation) {
+ operation_waiter_t *op = xine_xmalloc(sizeof(operation_waiter_t));
+ int signal_new_entries = 0; /* Signal that new entries are available */
+ pthread_mutex_t condmutex = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_lock(&condmutex);
+
+ op->operation = operation;
+ pthread_cond_init(&op->condition, NULL);
+
+ pthread_mutex_lock(&this->pa_class->op_mutex);
+
+ if ( this->pa_class->op_list )
+ op->next = this->pa_class->op_list;
+ else
+ signal_new_entries = 1;
+ this->pa_class->op_list = op;
+
+ if ( signal_new_entries )
+ pthread_cond_signal(&this->pa_class->op_list_newentries);
+
+ pthread_mutex_unlock(&this->pa_class->op_mutex);
+
+ pthread_cond_wait(&op->condition, &condmutex);
+
+ /* Assuming that the waiting thread already unlinked it from the list */
+ pthread_mutex_lock(&this->pa_class->op_mutex);
+ free(op);
+ pthread_mutex_unlock(&this->pa_class->op_mutex);
+}
+
/**
* @brief Callback function called when a stream operation succeed
* @param stream Stream which operation has succeeded
@@ -179,20 +262,6 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in
__xine_pa_context_success_callback(ctx, 0, this);
}
-static int wait_for_operation(pulse_driver_t *this, pa_operation *o)
-{
- _x_assert(this && o && this->pa_class->mainloop);
-
- pa_threaded_mainloop_lock(this->pa_class->mainloop);
-
- while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(this->pa_class->mainloop);
-
- pa_threaded_mainloop_unlock(this->pa_class->mainloop);
-
- return 0;
-}
-
/*
* open the audio device for writing to
*/
@@ -246,7 +315,6 @@ 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;
@@ -297,8 +365,6 @@ static int ao_pulse_open(ao_driver_t *this_gen,
streamstate = pa_stream_get_state(this->stream);
} while (streamstate < PA_STREAM_READY);
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
if (streamstate != PA_STREAM_READY) {
xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_pulse_out: Failed to connect to server: %s\n",
pa_strerror(pa_context_errno(this->pa_class->context)));
@@ -312,7 +378,6 @@ static int ao_pulse_open(ao_driver_t *this_gen,
fail:
pa_threaded_mainloop_unlock(this->pa_class->mainloop);
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
this_gen->close(this_gen);
return 0;
}
@@ -339,7 +404,7 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data,
uint32_t num_frames)
{
pulse_driver_t *this = (pulse_driver_t *) this_gen;
- int size = num_frames * this->bytes_per_frame;
+ size_t size = num_frames * this->bytes_per_frame;
int ret = 0;
if ( !this->stream || !this->pa_class->context)
@@ -378,12 +443,10 @@ static int ao_pulse_delay (ao_driver_t *this_gen)
{
pulse_driver_t *this = (pulse_driver_t *) this_gen;
pa_usec_t latency = 0;
- int delay_frames;
+ unsigned int delay_frames;
if ( ! this->stream ) return this->frames_written;
- 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;
@@ -392,13 +455,9 @@ static int ao_pulse_delay (ao_driver_t *this_gen)
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);
@@ -413,17 +472,14 @@ static void ao_pulse_close(ao_driver_t *this_gen)
pulse_driver_t *this = (pulse_driver_t *) this_gen;
if (this->stream) {
- pthread_mutex_lock(&this->pa_class->pa_mutex);
-
if (pa_stream_get_state(this->stream) == PA_STREAM_READY)
wait_for_operation(this, pa_stream_drain(this->stream, __xine_pa_stream_success_callback, this));
+
pa_stream_disconnect(this->stream);
pa_stream_unref(this->stream);
this->stream = NULL;
pa_context_unref(this->pa_class->context);
-
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
}
}
@@ -446,8 +502,6 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
if ( ! this->stream || ! this->pa_class->context )
return 0;
- pthread_mutex_lock(&this->pa_class->pa_mutex);
-
switch(property) {
case AO_PROP_PCM_VOL:
case AO_PROP_MIXER_VOL:
@@ -467,8 +521,6 @@ static int ao_pulse_get_property (ao_driver_t *this_gen, int property) {
break;
}
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
return result;
}
@@ -479,8 +531,6 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
if ( ! this->stream || ! this->pa_class->context )
return result;
- pthread_mutex_lock(&this->pa_class->pa_mutex);
-
switch(property) {
case AO_PROP_PCM_VOL:
case AO_PROP_MIXER_VOL:
@@ -507,8 +557,6 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
break;
}
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
return result;
}
@@ -519,39 +567,11 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) {
switch (cmd) {
- case AO_CTRL_PLAY_PAUSE:
- _x_assert(this->stream && this->pa_class->context );
-
- pthread_mutex_lock(&this->pa_class->pa_mutex);
- if(pa_stream_get_state(this->stream) == PA_STREAM_READY)
- wait_for_operation(this,pa_stream_cork(this->stream, 1, __xine_pa_stream_success_callback, this));
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
- break;
-
- case AO_CTRL_PLAY_RESUME:
- _x_assert(this->stream && this->pa_class->context);
-
- pthread_mutex_lock(&this->pa_class->pa_mutex);
- if(pa_stream_get_state(this->stream) == PA_STREAM_READY) {
- struct pa_operation *o2, *o1;
- o1 = pa_stream_prebuf(this->stream, __xine_pa_stream_success_callback, this);
- _x_assert(o1); wait_for_operation(this, o1);
-
- o2 = pa_stream_cork(this->stream, 0, __xine_pa_stream_success_callback, this);
- _x_assert(o2); wait_for_operation(this,o2);
- }
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
- break;
-
case AO_CTRL_FLUSH_BUFFERS:
_x_assert(this->stream && this->pa_class->context);
- pthread_mutex_lock(&this->pa_class->pa_mutex);
if(pa_stream_get_state(this->stream) == PA_STREAM_READY)
wait_for_operation(this,pa_stream_flush(this->stream, __xine_pa_stream_success_callback, this));
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
this->frames_written = 0;
@@ -623,12 +643,6 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
this->pa_class = class;
return &this->ao_driver;
-
- fail:
- 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;
}
/*
@@ -647,15 +661,12 @@ static void dispose_class (audio_driver_class_t *this_gen) {
pulse_class_t *this = (pulse_class_t *) this_gen;
- pthread_mutex_lock(&this->pa_mutex);
-
if ( this->context )
pa_context_unref(this->context);
pa_threaded_mainloop_stop(this->mainloop);
pa_threaded_mainloop_free(this->mainloop);
- pthread_mutex_destroy(&this->pa_mutex);
free (this);
}
@@ -676,18 +687,17 @@ static void *init_class (xine_t *xine, void *data) {
this->xine = xine;
- pthread_mutex_init(&this->pa_mutex, NULL);
- pthread_mutex_lock(&this->pa_mutex);
-
this->mainloop = pa_threaded_mainloop_new();
_x_assert(this->mainloop);
pa_threaded_mainloop_start(this->mainloop);
+
+ pthread_mutex_init(&this->op_mutex, NULL);
+ pthread_cond_init(&this->op_list_newentries, NULL);
+ pthread_create(&this->op_thread, NULL, &operation_waiting_thread, this);
this->context = NULL;
- pthread_mutex_unlock(&this->pa_mutex);
-
return this;
}