diff -Nru xine-lib-1.1.11.1/debian/changelog xine-lib-1.1.11.1/debian/changelog --- xine-lib-1.1.11.1/debian/changelog 2008-04-12 17:34:14.000000000 +0200 +++ xine-lib-1.1.11.1/debian/changelog 2008-04-12 17:34:15.000000000 +0200 @@ -1,3 +1,13 @@ +xine-lib (1.1.11.1-1ubuntu3) hardy; urgency=low + + * Add debian/patches/ubuntu_01_fix_pulseaudio.diff to improve pulseaudio + support (LP: #176332) + * Add quilt and cdbs as build-dependencies + * Add quilt cdbs include to debian/rules + * Re-Enable the pulseaudio plugin and add the build-dep on libpulse-dev + + -- Harald Sitter Sat, 12 Apr 2008 14:13:49 +0200 + xine-lib (1.1.11.1-1ubuntu2) hardy; urgency=low [ Darren Salt ] diff -Nru /tmp/RzuU91chF9/xine-lib-1.1.11.1/debian/control /tmp/lMIeCJaDPO/xine-lib-1.1.11.1/debian/control --- xine-lib-1.1.11.1/debian/control 2008-04-12 17:34:14.000000000 +0200 +++ xine-lib-1.1.11.1/debian/control 2008-04-12 17:34:15.000000000 +0200 @@ -4,7 +4,7 @@ Maintainer: Ubuntu Core Developers XSBC-Original-Maintainer: Reinhard Tartler Uploaders: Darren Salt -Build-Depends: debhelper (>= 5.0.1), pkg-config, +Build-Depends: debhelper (>= 5.0.1), cdbs, quilt, pkg-config, libavcodec-dev (>= 0.cvs20070307-3), libavformat-dev (>= 0.cvs20070307-3), libpostproc-dev (>= 0.cvs20070307-3), @@ -16,12 +16,13 @@ libmagick9-dev | libmagick-dev, libpng12-dev, libfreetype6-dev, libogg-dev, libvorbis-dev, libtheora-dev, libesd0-dev, libgnomevfs2-dev, + libpulse-dev, liblircclient-dev, libdirectfb-dev, libgtk2.0-dev, libflac-dev, libsdl1.2-dev, libwavpack-dev, libsmbclient-dev, libspeex-dev, libmng-dev, libmad0-dev, libmpcdec-dev, libcdio-dev (>= 0.76-1), - zlib1g-dev, w3m, transfig, sgmltools-lite, gs-gpl | gs + zlib1g-dev, w3m, transfig, sgmltools-lite, gs-gpl | gs, XS-Vcs-hg: http://hg.debian.org/hg/xine-lib/pkg/xine-lib-deb XS-Vcs-Browser: http://hg.debian.org/hg/xine-lib/pkg/xine-lib-deb XS-DM-Upload-Allowed: yes diff -Nru /tmp/RzuU91chF9/xine-lib-1.1.11.1/debian/libxine1-misc-plugins.install /tmp/lMIeCJaDPO/xine-lib-1.1.11.1/debian/libxine1-misc-plugins.install --- xine-lib-1.1.11.1/debian/libxine1-misc-plugins.install 2008-04-12 17:34:14.000000000 +0200 +++ xine-lib-1.1.11.1/debian/libxine1-misc-plugins.install 2008-04-12 17:34:15.000000000 +0200 @@ -22,7 +22,7 @@ debian/tmp/usr/lib/xine/plugins/*/xineplug_ao_out_file.so debian/tmp/usr/lib/xine/plugins/*/xineplug_ao_out_none.so debian/tmp/usr/lib/xine/plugins/*/xineplug_ao_out_oss.so -#debian/tmp/usr/lib/xine/plugins/*/xineplug_ao_out_pulseaudio.so +debian/tmp/usr/lib/xine/plugins/*/xineplug_ao_out_pulseaudio.so # video output plugins which don't fit in elsewhere debian/tmp/usr/lib/xine/plugins/*/xineplug_vo_out_none.so diff -Nru /tmp/RzuU91chF9/xine-lib-1.1.11.1/debian/patches/series /tmp/lMIeCJaDPO/xine-lib-1.1.11.1/debian/patches/series --- xine-lib-1.1.11.1/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ xine-lib-1.1.11.1/debian/patches/series 2008-04-12 17:34:15.000000000 +0200 @@ -0,0 +1 @@ +ubuntu_01_fix_pulseaudio.diff diff -Nru /tmp/RzuU91chF9/xine-lib-1.1.11.1/debian/patches/ubuntu_01_fix_pulseaudio.diff /tmp/lMIeCJaDPO/xine-lib-1.1.11.1/debian/patches/ubuntu_01_fix_pulseaudio.diff --- xine-lib-1.1.11.1/debian/patches/ubuntu_01_fix_pulseaudio.diff 1970-01-01 01:00:00.000000000 +0100 +++ xine-lib-1.1.11.1/debian/patches/ubuntu_01_fix_pulseaudio.diff 2008-04-12 17:34:15.000000000 +0200 @@ -0,0 +1,968 @@ +Index: xine-lib-1.1.11.1/src/audio_out/audio_pulse_out.c +=================================================================== +--- xine-lib-1.1.11.1.orig/src/audio_out/audio_pulse_out.c 2008-04-12 14:12:49.000000000 +0200 ++++ xine-lib-1.1.11.1/src/audio_out/audio_pulse_out.c 2008-04-12 14:13:17.000000000 +0200 +@@ -1,28 +1,28 @@ +-/* +- * Copyright (C) 2000-2007 the xine project +- * ++/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ ++ ++/* ++ * Copyright (C) 2000-2008 the xine project ++ * + * This file is part of xine, a free video player. +- * ++ * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. +- * ++ * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +- * ++ * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * +- * ao plugin for pulseaudio (rename of polypaudio): ++ * ao plugin for PulseAudio: + * http://0pointer.de/lennart/projects/pulsaudio/ + * +- * 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. ++ * Diego Petteno, Lennart Poettering + */ + + #ifdef HAVE_CONFIG_H +@@ -48,9 +48,6 @@ + + #define GAP_TOLERANCE AO_MAX_GAP + +-/* CHECKME: should this be conditional on autotools? */ +-extern const char *__progname; +- + typedef struct { + audio_driver_class_t driver_class; + xine_t *xine; +@@ -69,9 +66,8 @@ + 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; ++ int muted; + pa_cvolume cvolume; + + int capabilities; +@@ -82,70 +78,120 @@ + uint32_t bits_per_sample; + uint32_t bytes_per_frame; + +- uint32_t frames_written; +- + } pulse_driver_t; + + + /** +- * @brief Callback function called when a stream operation succeed +- * @param stream Stream which operation has succeeded +- * @param success The success value for the operation (ignored) +- * @param this_Gen pulse_driver_t pointer for the PulseAudio output +- * instance. ++ * @brief Callback function called when the state of the context is changed ++ * @param c Context which changed status ++ * @param this_gen pulse_class_t pointer for the PulseAudio output class + */ +-static void __xine_pa_stream_success_callback(pa_stream *const stream, const int success, +- void *const mutex_gen) ++static void __xine_pa_context_state_callback(pa_context *c, void *this_gen) + { +- pthread_mutex_t *const completion_mutex = (pthread_mutex_t*)mutex_gen; ++ pulse_class_t * this = (pulse_class_t*) this_gen; ++ ++ switch (pa_context_get_state(c)) { + +- pthread_mutex_unlock(completion_mutex); ++ case PA_CONTEXT_READY: ++ case PA_CONTEXT_TERMINATED: ++ case PA_CONTEXT_FAILED: ++ pa_threaded_mainloop_signal(this->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 the state of the context is changed +- * @param ctx Context which operation has succeeded ++ * @brief Callback function called when the state of the stream is changed ++ * @param s Stream that changed status + * @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) ++static void __xine_pa_stream_state_callback(pa_stream *s, void *this_gen) + { +- pulse_driver_t *const this = (pulse_driver_t*)this_gen; ++ pulse_driver_t * this = (pulse_driver_t*) this_gen; ++ ++ switch (pa_stream_get_state(s)) { + +- 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; ++ case PA_STREAM_READY: ++ case PA_STREAM_TERMINATED: ++ case PA_STREAM_FAILED: ++ pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); ++ break; ++ ++ case PA_STREAM_UNCONNECTED: ++ case PA_STREAM_CREATING: ++ break; + } + } + + /** +- * @brief Callback function called when a context operation succeed ++ * @brief Callback function called when PA asks for more audio data. ++ * @param s Stream on which data is requested ++ * @param nbytes the number of bytes PA requested ++ * @param this_gen pulse_driver_t pointer for the PulseAudio output ++ * instance. ++ */ ++static void __xine_pa_stream_request_callback(pa_stream *s, size_t nbytes, void *this_gen) ++{ ++ pulse_driver_t * this = (pulse_driver_t*) this_gen; ++ ++ pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); ++} ++ ++/** ++ * @brief Callback function called when PA notifies about something ++ * @param s Stream on which the notification happened ++ * @param this_gen pulse_driver_t pointer for the PulseAudio output ++ * instance. ++ */ ++static void __xine_pa_stream_notify_callback(pa_stream *s, void *this_gen) ++{ ++ pulse_driver_t * this = (pulse_driver_t*) this_gen; ++ ++ pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); ++} ++ ++/** ++ * @brief Callback function called when PA completed an operation + * @param ctx Context which operation has succeeded +- * @param success The success value for the operation (ignored) ++ * @param nbytes the number of bytes PA requested + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +-static void __xine_pa_context_success_callback(pa_context *const ctx, const int success, +- void *const this_gen) ++static void __xine_pa_stream_success_callback(pa_stream *s, int success, void *this_gen) + { +- pulse_driver_t *const this = (pulse_driver_t*)this_gen; ++ pulse_driver_t * this = (pulse_driver_t*) this_gen; + +- _x_assert(ctx); _x_assert(this); +- _x_assert(ctx == this->pa_class->context); ++ if (!success) ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: stream operation failed: %s\n", pa_strerror(pa_context_errno(this->pa_class->context))); + + pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); + } + + /** ++ * @brief Callback function called when PA completed an operation ++ * @param c Context on which operation has succeeded ++ * @param nbytes the number of bytes PA requested ++ * @param this_gen pulse_driver_t pointer for the PulseAudio output ++ * instance. ++ */ ++static void __xine_pa_context_success_callback(pa_context *c, int success, void *this_gen) ++{ ++ pulse_class_t *this = (pulse_class_t*) this_gen; ++ ++ if (!success) ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: context operation failed: %s\n", pa_strerror(pa_context_errno(this->context))); ++ ++ pa_threaded_mainloop_signal(this->mainloop, 0); ++} ++ ++/** + * @brief Callback function called when the information on the + * context's sink is retrieved. + * @param ctx Context which operation has succeeded +@@ -156,8 +202,8 @@ + * This function saves the volume field of the passed structure to the + * @c cvolume variable of the output instance. + */ +-static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_input_info *const info, +- const int is_last, void *const userdata) { ++static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info, ++ int is_last, void *userdata) { + + pulse_driver_t *const this = (pulse_driver_t *) userdata; + +@@ -171,36 +217,43 @@ + return; + + this->cvolume = info->volume; +- +- pthread_mutex_unlock(&this->info_mutex); ++ this->swvolume = pa_sw_volume_to_linear(pa_cvolume_avg(&info->volume)); ++ this->muted = info->mute; + } + + /* + * open the audio device for writing to + */ + static int ao_pulse_open(ao_driver_t *this_gen, +- uint32_t bits, uint32_t rate, int mode) ++ uint32_t bits, uint32_t rate, int mode) + { + pulse_driver_t *this = (pulse_driver_t *) this_gen; +- struct pa_sample_spec ss; +- struct pa_buffer_attr a; +- pa_stream_state_t streamstate; ++ pa_sample_spec ss; ++ pa_channel_map cm; ++ int r; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, +- "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); ++ "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); + + if ( (mode & this->capabilities) == 0 ) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: unsupported mode %08x\n", mode); + return 0; + } + ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); ++ + if (this->stream) { + +- if ( mode == this->mode && rate == this->sample_rate && +- bits == this->bits_per_sample ) ++ if (mode == this->mode && rate == this->sample_rate && ++ bits == this->bits_per_sample) { ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); + return this->sample_rate; ++ } + +- this_gen->close(this_gen); ++ pa_stream_disconnect(this->stream); ++ pa_stream_unref(this->stream); ++ this->stream = NULL; + } + + this->mode = mode; +@@ -221,6 +274,8 @@ + case 32: + ss.format = PA_SAMPLE_FLOAT32NE; + break; ++ default: ++ _x_assert(!"Should not be reached"); + } + + if (!pa_sample_spec_valid(&ss)) { +@@ -228,70 +283,125 @@ + goto fail; + } + +- if ( this->pa_class->context && pa_context_get_state(this->pa_class->context) > PA_CONTEXT_READY ) { ++ cm.channels = ss.channels; ++ ++ switch (mode) { ++ case AO_CAP_MODE_MONO: ++ cm.map[0] = PA_CHANNEL_POSITION_MONO; ++ _x_assert(cm.channels == 1); ++ break; ++ ++ case AO_CAP_MODE_STEREO: ++ cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; ++ cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; ++ _x_assert(cm.channels == 2); ++ break; ++ ++ case AO_CAP_MODE_4CHANNEL: ++ cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; ++ cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; ++ cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; ++ cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; ++ _x_assert(cm.channels == 4); ++ break; ++ ++ case AO_CAP_MODE_4_1CHANNEL: ++ case AO_CAP_MODE_5CHANNEL: ++ case AO_CAP_MODE_5_1CHANNEL: ++ cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; ++ cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; ++ cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; ++ cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; ++ cm.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; ++ cm.map[5] = PA_CHANNEL_POSITION_LFE; ++ cm.channels = 6; ++ break; ++ default: ++ _x_assert(!"Should not be reached"); ++ } ++ ++ if (!pa_channel_map_valid(&cm)) { ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Invalid channel map\n"); ++ goto fail; ++ } ++ ++ if ( this->pa_class->context && (pa_context_get_state(this->pa_class->context) == PA_CONTEXT_FAILED || ++ pa_context_get_state(this->pa_class->context) == PA_CONTEXT_TERMINATED)) { + 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); +- } ++ if (!this->pa_class->context) { ++ char fn[PATH_MAX], *p; + +- pa_context_ref(this->pa_class->context); ++ if (pa_get_binary_name(fn, sizeof(fn))) ++ p = pa_path_get_filename(fn); ++ else ++ p = "Xine"; + +- if ( pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED ) { +- int ret; ++ this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop), p); ++ _x_assert(this->pa_class->context); + +- 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_unlock; ++ pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_state_callback, this->pa_class); ++ } + +- pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this); ++ if (pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED) { + +- pa_threaded_mainloop_wait(this->pa_class->mainloop); +- pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ if (pa_context_connect(this->pa_class->context, this->host, 0, NULL) < 0) { ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object\n"); ++ goto fail; ++ } + } + +- 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; ++ for (;;) { ++ pa_context_state_t state = pa_context_get_state(this->pa_class->context); ++ ++ if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->pa_class->context))); ++ goto fail; ++ } ++ ++ if (state == PA_CONTEXT_READY) ++ break; ++ ++ pa_threaded_mainloop_wait(this->pa_class->mainloop); + } + +- this->stream = pa_stream_new(this->pa_class->context, "audio stream", &ss, NULL); ++ _x_assert(!this->stream); ++ this->stream = pa_stream_new(this->pa_class->context, "Audio Stream", &ss, &cm); + _x_assert(this->stream); + +- a.maxlength = pa_bytes_per_second(&ss)*1; +- a.tlength = a.maxlength*9/10; +- a.prebuf = a.tlength/2; +- a.minreq = a.tlength/10; ++ pa_stream_set_state_callback(this->stream, __xine_pa_stream_state_callback, this); ++ pa_stream_set_write_callback(this->stream, __xine_pa_stream_request_callback, this); ++ pa_stream_set_latency_update_callback(this->stream, __xine_pa_stream_notify_callback, this); + +- pa_stream_connect_playback(this->stream, this->sink, &a, +- PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, ++ r = pa_stream_connect_playback(this->stream, this->sink, NULL, ++ PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, + NULL, NULL); + +- do { +- xine_usec_sleep (100); ++ for (;;) { ++ pa_context_state_t cstate = pa_context_get_state(this->pa_class->context); ++ pa_stream_state_t sstate = pa_stream_get_state(this->stream); ++ ++ if (cstate == PA_CONTEXT_FAILED || cstate == PA_CONTEXT_TERMINATED || ++ sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) { ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->pa_class->context))); ++ goto fail; ++ } + +- streamstate = pa_stream_get_state(this->stream); +- } while (streamstate < PA_STREAM_READY); +- +- 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))); +- goto fail; ++ if (sstate == PA_STREAM_READY) ++ break; ++ ++ pa_threaded_mainloop_wait(this->pa_class->mainloop); + } +- this->frames_written = 0; + +- this->ao_driver.set_property(this, AO_PROP_PCM_VOL, 100); ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); + + return this->sample_rate; + +- fail_unlock: +- pa_threaded_mainloop_unlock(this->pa_class->mainloop); + fail: ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); + this_gen->close(this_gen); + return 0; + } +@@ -319,189 +429,268 @@ + { + pulse_driver_t *this = (pulse_driver_t *) this_gen; + size_t size = num_frames * this->bytes_per_frame; +- int ret = 0; +- +- 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; ++ int ret = -1; ++ size_t done = 0; + +- while (!(l = pa_stream_writable_size(this->stream))) { +- xine_usec_sleep (10000); +- } ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); + +- if (l > size) +- l = size; +- +- pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); +- data = (int16_t *) ((uint8_t*) data + l); +- size -= l; +- } ++ while (size > 0) { ++ size_t l; ++ ++ for (;;) { + +- this->frames_written += num_frames; ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) ++ goto finish; + +- if (pa_stream_get_state(this->stream) == PA_STREAM_READY) +- ret = 1; ++ if ((l = pa_stream_writable_size(this->stream)) == (size_t) -1) ++ goto finish; + +- break; ++ if (l > 0) ++ break; ++ ++ pa_threaded_mainloop_wait(this->pa_class->mainloop); ++ } ++ ++ if (l > size) ++ l = size; ++ ++ pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); ++ data = (int16_t *) ((uint8_t*) data + l); ++ size -= l; ++ done += l; + } + ++ ret = done; ++ ++finish: ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ ++/* fprintf(stderr, "write-out\n"); */ ++ + return ret; +-} + ++} + + static int ao_pulse_delay (ao_driver_t *this_gen) + { + pulse_driver_t *this = (pulse_driver_t *) this_gen; +- pa_usec_t latency = 0; +- unsigned int delay_frames; ++ int ret = 0; + +- if ( ! this->stream ) return this->frames_written; ++/* fprintf(stderr, "delay-in\n"); */ + +- if (pa_stream_get_latency(this->stream, &latency, NULL) < 0) { +- pa_context_unref(this->pa_class->context); +- this->pa_class->context = NULL; ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); + +- pa_stream_disconnect(this->stream); +- pa_stream_unref(this->stream); +- this->stream = NULL; ++ for (;;) { ++ pa_usec_t latency = 0; + +- return 0; ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) ++ goto finish; ++ ++ if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0) { ++ ret = (int) ((latency * this->sample_rate) / 1000000); ++ goto finish; ++ } ++ ++ if (pa_context_errno(this->pa_class->context) != PA_ERR_NODATA) { ++ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to query latency: %s\n", pa_strerror(pa_context_errno(this->pa_class->context))); ++ goto finish; ++ } ++ ++ pa_threaded_mainloop_wait(this->pa_class->mainloop); + } + +- /* convert latency (us) to frame units. */ +- delay_frames = (int)(latency * this->sample_rate / 1000000); ++finish: + +- if( delay_frames > this->frames_written ) +- return this->frames_written; +- else +- return delay_frames; ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ ++ return ret; + } + + static void ao_pulse_close(ao_driver_t *this_gen) + { + pulse_driver_t *this = (pulse_driver_t *) this_gen; +- +- if (this->stream) { +- 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); +- } ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); + ++ if (this->stream) { + pa_stream_disconnect(this->stream); + pa_stream_unref(this->stream); + this->stream = NULL; +- +- pa_context_unref(this->pa_class->context); + } ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); + } + + static uint32_t ao_pulse_get_capabilities (ao_driver_t *this_gen) { + pulse_driver_t *this = (pulse_driver_t *) this_gen; ++ + return this->capabilities; + } + +-static void ao_pulse_exit(ao_driver_t *this_gen) +-{ ++static void ao_pulse_exit(ao_driver_t *this_gen) { + pulse_driver_t *this = (pulse_driver_t *) this_gen; + ++ ao_pulse_close(this_gen); ++ + free (this); + } + ++static int wait_for_operation(pulse_driver_t *this, pa_operation *o) { ++ ++ for (;;) { ++ ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) ++ return -1; ++ ++ if (pa_operation_get_state(o) != PA_OPERATION_RUNNING) ++ return 0; ++ ++ pa_threaded_mainloop_wait(this->pa_class->mainloop); ++ } ++} ++ + static int ao_pulse_get_property (ao_driver_t *this_gen, int property) { + pulse_driver_t *this = (pulse_driver_t *) this_gen; + int result = 0; ++ pa_operation *o = NULL; ++ ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); + +- if ( ! this->stream || ! this->pa_class->context ) ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) { ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); + return 0; ++ } + + 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; +- pthread_mutex_lock(&this->info_mutex); pthread_mutex_unlock(&this->info_mutex); +- +- result = (pa_sw_volume_to_linear(this->swvolume)*100); +- } +- break; + +- case AO_PROP_MUTE_VOL: +- result = pa_cvolume_is_muted(&this->cvolume); +- break; ++ case AO_PROP_MUTE_VOL: ++ case AO_PROP_PCM_VOL: ++ case AO_PROP_MIXER_VOL: ++ ++ o = pa_context_get_sink_input_info(this->pa_class->context, pa_stream_get_index(this->stream), ++ __xine_pa_sink_info_callback, this); ++ ++ break; ++ } ++ ++ if (o) { ++ wait_for_operation(this, o); ++ pa_operation_unref(o); + } +- ++ ++ switch(property) { ++ ++ case AO_PROP_MUTE_VOL: ++ result = this->muted; ++ break; ++ ++ case AO_PROP_PCM_VOL: ++ case AO_PROP_MIXER_VOL: ++ result = (int) (pa_sw_volume_to_linear(this->swvolume)*100); ++ break; ++ } ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ + return result; + } + + static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value) { + pulse_driver_t *this = (pulse_driver_t *) this_gen; + int result = ~value; ++ pa_operation *o = NULL; + +- if ( ! this->stream || ! this->pa_class->context ) +- return result; ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); ++ ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) { ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ return 0; ++ } + + 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); +- +- 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; +- +- case AO_PROP_MUTE_VOL: +- if ( value ) +- pa_cvolume_mute(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels); +- else ++ 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); + +- 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; ++ o = 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_class); ++ ++ result = value; ++ break; ++ ++ case AO_PROP_MUTE_VOL: ++ ++ this->muted = value; ++ ++ o = pa_context_set_sink_input_mute(this->pa_class->context, pa_stream_get_index(this->stream), ++ value, __xine_pa_context_success_callback, this->pa_class); ++ ++ result = value; ++ } ++ ++ if (o) { ++ wait_for_operation(this, o); ++ pa_operation_unref(o); + } +- ++ ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ + return result; + } + + static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { + pulse_driver_t *this = (pulse_driver_t *) this_gen; ++ pa_operation *o = NULL; ++ ++ pa_threaded_mainloop_lock(this->pa_class->mainloop); + +- if ( ! this->stream ) return 0; ++ if (!this->stream || ++ !this->pa_class->context || ++ pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY || ++ pa_stream_get_state(this->stream) != PA_STREAM_READY) { ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ return 0; ++ } + + switch (cmd) { + +- case AO_CTRL_FLUSH_BUFFERS: +- _x_assert(this->stream && this->pa_class->context); ++ case AO_CTRL_FLUSH_BUFFERS: + +- 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_flush(this->stream, __xine_pa_stream_success_callback, &completion_callback); ++ o = pa_stream_flush(this->stream, __xine_pa_stream_success_callback, this); ++ break; + +- pthread_mutex_lock(&completion_callback); +- pthread_mutex_destroy(&completion_callback); +- } ++ case AO_CTRL_PLAY_RESUME: ++ case AO_CTRL_PLAY_PAUSE: + +- this->frames_written = 0; ++ o = pa_stream_cork(this->stream, cmd == AO_CTRL_PLAY_PAUSE, __xine_pa_stream_success_callback, this); ++ break; ++ } + +- break; ++ if (o) { ++ wait_for_operation(this, o); ++ pa_operation_unref(o); + } + ++ pa_threaded_mainloop_unlock(this->pa_class->mainloop); ++ + return 0; + } + +@@ -515,21 +704,53 @@ + this = (pulse_driver_t *) xine_xmalloc (sizeof (pulse_driver_t)); + if (!this) + return NULL; ++ + this->xine = class->xine; ++ this->host = NULL; ++ this->sink = NULL; ++ ++ device = this->xine->config->register_string(this->xine->config, ++ "audio.pulseaudio_device", ++ "", ++ _("device used for pulseaudio"), ++ _("use 'server[:sink]' for setting the " ++ "pulseaudio sink device."), ++ 10, NULL, ++ NULL); ++ ++ if (device && *device) { ++ char *sep = strrchr(device, ':'); ++ if ( sep ) { ++ if (!(this->host = strndup(device, sep-device))) { ++ free(this); ++ return NULL; ++ } ++ ++ if (!(this->sink = strdup(sep+1))) { ++ free(this->host); ++ free(this); ++ return NULL; ++ } ++ } else { ++ ++ if (!(this->host = strdup(device))) { ++ free(this); ++ return NULL; ++ } ++ } ++ } + + /* + * set capabilities + */ +- this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | +- AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | +- AO_CAP_MODE_5_1CHANNEL | AO_CAP_MIXER_VOL | +- AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS | +- AO_CAP_16BITS | AO_CAP_FLOAT32; ++ this->capabilities = ++ AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | ++ AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL | ++ AO_CAP_MIXER_VOL | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | ++ AO_CAP_8BITS | 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; + this->ao_driver.set_property = ao_pulse_set_property; +@@ -541,27 +762,7 @@ + this->ao_driver.close = ao_pulse_close; + this->ao_driver.exit = ao_pulse_exit; + this->ao_driver.get_gap_tolerance = ao_pulse_get_gap_tolerance; +- this->ao_driver.control = ao_pulse_ctrl; +- +- device = this->xine->config->register_string(this->xine->config, +- "audio.pulseaudio_device", +- "", +- _("device used for pulseaudio"), +- _("use 'server[:sink]' for setting the " +- "pulseaudio sink device."), +- 10, NULL, +- NULL); +- +- 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); +- } +- +- pthread_mutex_init(&this->info_mutex, NULL); ++ this->ao_driver.control = ao_pulse_ctrl; + + xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n", + this->host ? this->host : "(null)", this->sink ? this->sink : "(null)"); +@@ -587,10 +788,13 @@ + + pulse_class_t *this = (pulse_class_t *) this_gen; + +- if ( this->context ) ++ pa_threaded_mainloop_stop(this->mainloop); ++ ++ if (this->context) { ++ pa_context_disconnect(this->context); + pa_context_unref(this->context); ++ } + +- pa_threaded_mainloop_stop(this->mainloop); + pa_threaded_mainloop_free(this->mainloop); + + free (this); +@@ -611,20 +815,18 @@ + this->driver_class.get_description = get_description; + this->driver_class.dispose = dispose_class; + +- this->xine = xine; ++ this->xine = xine; ++ this->context = NULL; + + this->mainloop = pa_threaded_mainloop_new(); + _x_assert(this->mainloop); +- + pa_threaded_mainloop_start(this->mainloop); +- +- this->context = NULL; + + return this; + } + + static const ao_info_t ao_info_pulse = { +- 6 ++ 12 + }; + + /* +@@ -636,5 +838,3 @@ + { PLUGIN_AUDIO_OUT, 8, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } + }; +- +- diff -Nru /tmp/RzuU91chF9/xine-lib-1.1.11.1/debian/rules /tmp/lMIeCJaDPO/xine-lib-1.1.11.1/debian/rules --- xine-lib-1.1.11.1/debian/rules 2008-04-12 17:34:14.000000000 +0200 +++ xine-lib-1.1.11.1/debian/rules 2008-04-12 17:34:15.000000000 +0200 @@ -7,6 +7,8 @@ # Uncomment this to turn on verbose mode. # export DH_VERBOSE=1 +include /usr/share/cdbs/1/rules/patchsys-quilt.mk + BINARY_ANY_PACKAGES=$(shell dh_listpackages -a) BINARY_ALL_PACKAGES=$(shell dh_listpackages -i) @@ -53,7 +55,7 @@ --with-external-libmpcdec \ --enable-ipv6 \ --without-jack \ - --without-pulseaudio \ + --with-pulseaudio \ --with-libflac \ --with-wavpack \ --with-freetype \ @@ -75,7 +77,7 @@ $(MAKE) -j $(NJOBS) touch build-stamp -clean: +clean:: dh_testdir dh_testroot dh_clean build-stamp configure-stamp install-stamp po/*.gmo