summaryrefslogtreecommitdiff
path: root/src/audio_out/audio_pulse_out.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_out/audio_pulse_out.c')
-rw-r--r--src/audio_out/audio_pulse_out.c158
1 files changed, 39 insertions, 119 deletions
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index 9e6089730..b4ec0b156 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -15,9 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* 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.17 2007/04/01 00:32:29 dgp85 Exp $
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* ao plugin for pulseaudio (rename of polypaudio):
* http://0pointer.de/lennart/projects/pulsaudio/
@@ -25,7 +23,6 @@
* originally written for polypaudio simple api. Lennart then suggested
* using the async api for better control (such as volume), therefore, a lot
* of this code comes from Lennart's patch to mplayer.
- *
*/
#ifdef HAVE_CONFIG_H
@@ -44,9 +41,9 @@
#include <pulse/pulseaudio.h>
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "audio_out.h"
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/audio_out.h>
#include "bswap.h"
#define GAP_TOLERANCE AO_MAX_GAP
@@ -58,7 +55,6 @@ 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 */
} pulse_class_t;
@@ -73,13 +69,15 @@ typedef struct pulse_driver_s {
char *sink; /*< The sink to connect to */
struct pa_stream *stream; /*< Pulseaudio playback stream object */
+ pthread_mutex_t info_mutex; /**< Mutex for info callback signaling */
+
pa_volume_t swvolume;
pa_cvolume cvolume;
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;
@@ -88,6 +86,7 @@ typedef struct pulse_driver_s {
} pulse_driver_t;
+
/**
* @brief Callback function called when a stream operation succeed
* @param stream Stream which operation has succeeded
@@ -96,14 +95,11 @@ typedef struct pulse_driver_s {
* instance.
*/
static void __xine_pa_stream_success_callback(pa_stream *const stream, const int success,
- void *const this_gen)
+ void *const mutex_gen)
{
- pulse_driver_t *const this = (pulse_driver_t*)this_gen;
-
- _x_assert(stream); _x_assert(this);
- _x_assert(stream == this->stream);
+ pthread_mutex_t *const completion_mutex = (pthread_mutex_t*)mutex_gen;
- pa_threaded_mainloop_signal(this->pa_class->mainloop, 0);
+ pthread_mutex_unlock(completion_mutex);
}
/**
@@ -116,9 +112,6 @@ static void __xine_pa_context_status_callback(pa_context *const ctx, void *const
{
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:
@@ -179,21 +172,7 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in
this->cvolume = info->volume;
- __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;
+ pthread_mutex_unlock(&this->info_mutex);
}
/*
@@ -249,7 +228,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;
@@ -300,8 +278,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)));
@@ -315,7 +291,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;
}
@@ -342,7 +317,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)
@@ -381,12 +356,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;
@@ -395,13 +368,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);
@@ -416,17 +385,19 @@ 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) {
+ pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback);
+ pa_stream_drain(this->stream, __xine_pa_stream_success_callback, &completion_callback);
+
+ pthread_mutex_lock(&completion_callback);
+ pthread_mutex_destroy(&completion_callback);
+ }
- 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);
}
}
@@ -449,17 +420,16 @@ 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:
{
+ pthread_mutex_lock(&this->info_mutex);
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);
+ pthread_mutex_lock(&this->info_mutex); pthread_mutex_unlock(&this->info_mutex);
result = (pa_sw_volume_to_linear(this->swvolume)*100);
}
@@ -470,8 +440,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;
}
@@ -482,16 +450,14 @@ 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:
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);
- wait_for_operation(this,
- 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_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream),
+ &this->cvolume, __xine_pa_context_success_callback, this);
result = value;
break;
@@ -502,16 +468,13 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
else
pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume);
- wait_for_operation(this,
- 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_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream),
+ &this->cvolume, __xine_pa_context_success_callback, this);
result = value;
break;
}
- pthread_mutex_unlock(&this->pa_class->pa_mutex);
-
return result;
}
@@ -522,39 +485,16 @@ 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:
+ 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) {
- 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);
+ pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback);
+ pa_stream_flush(this->stream, __xine_pa_stream_success_callback, &completion_callback);
- o2 = pa_stream_cork(this->stream, 0, __xine_pa_stream_success_callback, this);
- _x_assert(o2); wait_for_operation(this,o2);
+ pthread_mutex_lock(&completion_callback);
+ pthread_mutex_destroy(&completion_callback);
}
- 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;
@@ -620,45 +560,30 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
this->host = strdup(device);
}
+ pthread_mutex_init(&this->info_mutex, NULL);
+
xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n",
this->host ? this->host : "(null)", this->sink ? this->sink : "(null)");
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;
}
/*
* class functions
*/
-static char* get_identifier (audio_driver_class_t *this_gen) {
- return "pulseaudio";
-}
-
-static char* get_description (audio_driver_class_t *this_gen) {
- return _("xine audio output plugin using pulseaudio sound server");
-}
-
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);
}
@@ -673,24 +598,19 @@ static void *init_class (xine_t *xine, void *data) {
return NULL;
this->driver_class.open_plugin = open_plugin;
- this->driver_class.get_identifier = get_identifier;
- this->driver_class.get_description = get_description;
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;
- 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);
-
+
this->context = NULL;
- pthread_mutex_unlock(&this->pa_mutex);
-
return this;
}
@@ -704,7 +624,7 @@ static const ao_info_t ao_info_pulse = {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_AUDIO_OUT, 8, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class },
+ { PLUGIN_AUDIO_OUT, 9, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};