diff options
Diffstat (limited to 'src/audio_out/audio_pulse_out.c')
-rw-r--r-- | src/audio_out/audio_pulse_out.c | 158 |
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 } }; |