diff options
-rw-r--r-- | src/audio_out/audio_pulse_out.c | 145 |
1 files changed, 82 insertions, 63 deletions
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index 214ad9725..5fa945f3d 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.12 2007/03/17 20:57:59 dgp85 Exp $ + * $Id: audio_pulse_out.c,v 1.13 2007/03/31 20:58:51 dgp85 Exp $ * * ao plugin for pulseaudio (rename of polypaudio): * http://0pointer.de/lennart/projects/pulsaudio/ @@ -54,54 +54,40 @@ /* CHECKME: should this be conditional on autotools? */ extern const char *__progname; -typedef struct pulse_driver_s { - - ao_driver_t ao_driver; - - xine_t *xine; - - /** The host to connect to */ - char *host; +typedef struct { + audio_driver_class_t driver_class; + xine_t *xine; - /** The sink to connect to */ - char *sink; + 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; - /** Pulseaudio playback stream object */ - struct pa_stream *stream; +typedef struct pulse_driver_s { + ao_driver_t ao_driver; + xine_t *xine; - /** Pulseaudio connection context */ - struct pa_context *context; + pulse_class_t *pa_class; - /** Main event loop object */ - struct pa_threaded_mainloop *mainloop; + char *host; /*< The host to connect to */ + char *sink; /*< The sink to connect to */ + struct pa_stream *stream; /*< Pulseaudio playback stream object */ - pa_volume_t swvolume; - pa_cvolume cvolume; + pa_volume_t swvolume; + pa_cvolume cvolume; - int capabilities; - int mode; + int capabilities; + int mode; - int32_t sample_rate; - uint32_t num_channels; - uint32_t bits_per_sample; - uint32_t bytes_per_frame; + int32_t sample_rate; + uint32_t num_channels; + uint32_t bits_per_sample; + uint32_t bytes_per_frame; - uint32_t frames_written; + uint32_t frames_written; } pulse_driver_t; -typedef struct { - audio_driver_class_t driver_class; - - xine_t *xine; - - /** Pulseaudio connection context */ - struct pa_context *context; - - /** Main event loop object */ - struct pa_threaded_mainloop *mainloop; -} pulse_class_t; - /** * @brief Callback function called when a stream operation succeed * @param stream Stream which operation has succeeded @@ -117,7 +103,7 @@ static void __xine_pa_stream_success_callback(pa_stream *const stream, const int _x_assert(stream); _x_assert(this); _x_assert(stream == this->stream); - pa_threaded_mainloop_signal(this->mainloop, 0); + pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); } /** @@ -133,9 +119,9 @@ static void __xine_pa_context_success_callback(pa_context *const ctx, const int pulse_driver_t *const this = (pulse_driver_t*)this_gen; _x_assert(ctx); _x_assert(this); - _x_assert(ctx == this->context); + _x_assert(ctx == this->pa_class->context); - pa_threaded_mainloop_signal(this->mainloop, 0); + pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); } /** @@ -156,7 +142,7 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in 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->context))); + pa_strerror(pa_context_errno(this->pa_class->context))); return; } @@ -170,14 +156,14 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in static int wait_for_operation(pulse_driver_t *this, pa_operation *o) { - _x_assert(this && o && this->mainloop); + _x_assert(this && o && this->pa_class->mainloop); - pa_threaded_mainloop_lock(this->mainloop); + pa_threaded_mainloop_lock(this->pa_class->mainloop); while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) - pa_threaded_mainloop_wait(this->mainloop); + pa_threaded_mainloop_wait(this->pa_class->mainloop); - pa_threaded_mainloop_unlock(this->mainloop); + pa_threaded_mainloop_unlock(this->pa_class->mainloop); return 0; } @@ -235,7 +221,7 @@ static int ao_pulse_open(ao_driver_t *this_gen, goto fail; } - this->stream = pa_stream_new(this->context, "audio stream", &ss, NULL); + this->stream = pa_stream_new(this->pa_class->context, "audio stream", &ss, NULL); _x_assert(this->stream); a.maxlength = pa_bytes_per_second(&ss)*1; @@ -256,7 +242,7 @@ static int ao_pulse_open(ao_driver_t *this_gen, 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->context))); + pa_strerror(pa_context_errno(this->pa_class->context))); goto fail; } this->frames_written = 0; @@ -293,7 +279,7 @@ 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->context); + _x_assert(this->stream && this->pa_class->context); if (pa_stream_get_state(this->stream) == PA_STREAM_READY) { @@ -332,7 +318,7 @@ static int ao_pulse_delay (ao_driver_t *this_gen) if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0) break; - if (pa_context_errno(this->context) != PA_ERR_NODATA) { + if (pa_context_errno(this->pa_class->context) != PA_ERR_NODATA) { /* error */ } } @@ -351,11 +337,15 @@ 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; + + pthread_mutex_unlock(&this->pa_class->pa_mutex); } } @@ -377,12 +367,16 @@ 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: - if( this->stream && this->context ) + if( this->stream && this->pa_class->context ) { + pthread_mutex_lock(&this->pa_class->pa_mutex); wait_for_operation(this, - pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream), + pa_context_get_sink_input_info(this->pa_class->context, pa_stream_get_index(this->stream), __xine_pa_sink_info_callback, this)); + pthread_mutex_unlock(&this->pa_class->pa_mutex); + } return (int) (pa_sw_volume_to_linear(this->swvolume)*100); break; + case AO_PROP_MUTE_VOL: break; } @@ -397,11 +391,13 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value case AO_PROP_PCM_VOL: case AO_PROP_MIXER_VOL: this->swvolume = pa_sw_volume_from_linear((double)value/100.0); - if( this->stream && this->context ) { + if( this->stream && this->pa_class->context ) { + pthread_mutex_lock(&this->pa_class->pa_mutex); 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->context, pa_stream_get_index(this->stream), + pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), &this->cvolume, __xine_pa_context_success_callback, this)); + pthread_mutex_unlock(&this->pa_class->pa_mutex); } break; case AO_PROP_MUTE_VOL: @@ -417,13 +413,19 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { switch (cmd) { case AO_CTRL_PLAY_PAUSE: - _x_assert(this->stream && this->context ); + _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->context); + _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); @@ -432,13 +434,20 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { 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->context); + _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; + break; } @@ -510,28 +519,30 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 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->mainloop = class->mainloop; - this->context = class->context; + this->pa_class = class; - if ( pa_context_get_state(this->context) != PA_CONTEXT_READY ){ - pa_context_connect(this->context, this->host, 1, NULL); + 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->context); + 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->context))); + 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); free(this); xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: open_plugin failed.\n"); return NULL; @@ -553,11 +564,14 @@ 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); + 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); } @@ -578,6 +592,9 @@ 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); @@ -586,6 +603,8 @@ static void *init_class (xine_t *xine, void *data) { this->context = pa_context_new(pa_threaded_mainloop_get_api(this->mainloop), __progname); _x_assert(this->context); + pthread_mutex_unlock(&this->pa_mutex); + return this; } |