From 3350b8b761d9cd0052d280cf89848a58989c3b1b Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 30 Mar 2008 19:48:58 +0100 Subject: Add video/x-matroska. --- src/demuxers/demux_matroska.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index 7643a2cb4..d081caf61 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -2915,7 +2915,8 @@ static const char *get_extensions (demux_class_t *this_gen) { static const char *get_mimetypes (demux_class_t *this_gen) { - return "video/mkv: mkv: matroska;"; + return "video/mkv: mkv: matroska;" + "video/x-matroska: mkv: matroska;"; } -- cgit v1.2.3 From 7dab7b45bb3ac2e16b4a5eb1c8ed110dcd239246 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Mon, 31 Mar 2008 16:08:23 +0100 Subject: Revert a change which broke Quicktime atom parsing. --- src/demuxers/demux_qt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index e28952b23..851b0aef5 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -896,11 +896,6 @@ static qt_error parse_trak_atom (qt_trak *trak, current_atom_size = _X_BE_32(&trak_atom[i - 4]); current_atom = _X_BE_32(&trak_atom[i]); - if (current_atom_size > trak_atom_size - i) { - last_error = QT_NOT_A_VALID_FILE; - goto free_trak; - } - if (current_atom == TKHD_ATOM) { trak->flags = _X_BE_16(&trak_atom[i + 6]); } else if (current_atom == ELST_ATOM) { -- cgit v1.2.3 From 55c8e3a5c01ff089531ab5f73f43584a12ca9edd Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Mon, 31 Mar 2008 21:13:31 +0100 Subject: Correct the wavpack demuxer's MIME type data. --- src/combined/demux_wavpack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/combined/demux_wavpack.c b/src/combined/demux_wavpack.c index a79f70627..a9b20e5f9 100644 --- a/src/combined/demux_wavpack.c +++ b/src/combined/demux_wavpack.c @@ -391,7 +391,7 @@ static const char *get_extensions (demux_class_t *const this_gen) { } static const char *get_mimetypes (demux_class_t *const this_gen) { - return "audio/x-wavpack"; + return "audio/x-wavpack: wv,wvp: WavPack audio;"; } static void class_dispose (demux_class_t *const this_gen) { -- cgit v1.2.3 From 577d6eca166c0f0dce00d4a0f22eabb7025f61a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Apr 2008 14:05:56 +0200 Subject: Updated PulseAudio driver It's basically a rework of the PulseAudio driver, fixing all the inherent races (and thus stability issues), adding proper surround sound support, support for proper muting and pause/resume. It also gets rid of all usleep() loops to make sure we don't wakeup more often than we need to. Also does a couple of other minor cleanups. This also increases the autoprobe priority to 12, above ALSA, to make sure that the Pulse plugin is preferred over ALSA if both are available. This is because we want to make sure that Xine-on-PA is preferred over Xine-on-ALSA-on-PA. --- src/audio_out/audio_pulse_out.c | 680 ++++++++++++++++++++++++++-------------- 1 file changed, 440 insertions(+), 240 deletions(-) diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index 2811bbdbc..f5ade655f 100644 --- a/src/audio_out/audio_pulse_out.c +++ b/src/audio_out/audio_pulse_out.c @@ -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 @@ 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; + int muted; pa_cvolume cvolume; int capabilities; @@ -82,69 +78,119 @@ typedef struct pulse_driver_s { 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; - - 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; + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + switch (pa_stream_get_state(s)) { + + 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. @@ -156,8 +202,8 @@ static void __xine_pa_context_success_callback(pa_context *const ctx, const int * 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 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in 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 @@ static int ao_pulse_open(ao_driver_t *this_gen, 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 @@ static int ao_pulse_open(ao_driver_t *this_gen, 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); - 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 (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; + } + + 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 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data, { 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; + int ret = -1; + size_t done = 0; - switch( pa_stream_get_state(this->stream) ) { - case PA_STREAM_READY: - while (size > 0) { - size_t l; + pa_threaded_mainloop_lock(this->pa_class->mainloop); - while (!(l = pa_stream_writable_size(this->stream))) { - xine_usec_sleep (10000); - } + while (size > 0) { + size_t l; - 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; - } + 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: + + pa_threaded_mainloop_unlock(this->pa_class->mainloop); - if( delay_frames > this->frames_written ) - return this->frames_written; - else - return delay_frames; + 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; - if ( ! this->stream || ! this->pa_class->context ) + 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: - { - 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); + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: - pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), - &this->cvolume, __xine_pa_context_success_callback, this); + 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); - 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); - case AO_PROP_MUTE_VOL: - if ( value ) - pa_cvolume_mute(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels); - else - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + 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; + } - 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; + 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 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 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 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 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 @@ static void dispose_class (audio_driver_class_t *this_gen) { 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 @@ static void *init_class (xine_t *xine, void *data) { 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 @@ const plugin_info_t xine_plugin_info[] EXPORTED = { { PLUGIN_AUDIO_OUT, 8, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - - -- cgit v1.2.3 From b9625851863a5a0d259fedd9ea8286febc1aa1e4 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Tue, 1 Apr 2008 15:03:57 +0100 Subject: Changelog updates. --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index d756df256..d08f74627 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +xine-lib (1.1.12) 2008-??-?? + * Fixed and improved the PulseAudio driver. + * Fixed a regression in 1.1.11.1 which broke Quicktime container handling. + xine-lib (1.1.11.1) 2008-03-30 * Security fixes: - Integer overflows in FLV, Qt, Real, WC3Movie, Matroska and FILM -- cgit v1.2.3 From 5427b59e6473c95a23edeee331ecef95e7b7a978 Mon Sep 17 00:00:00 2001 From: "Carlos E. R." Date: Wed, 2 Apr 2008 01:56:02 +0200 Subject: Spanish translation update. --- po/es.po | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/po/es.po b/po/es.po index 35ed138a6..4c320e6ef 100644 --- a/po/es.po +++ b/po/es.po @@ -1,17 +1,18 @@ # translation of xine-lib.hg.po to Spanish -# Spanish .po file for xine-lib. +# Spanish es.po file for xine-lib. +# Copyright (C) YEAR Copyright (C) 2000-2006 the xine project # Copyright (C) 2002, 2006, 2007, 2008 Free Software Foundation, Inc. # # Juan Manuel García Molina , 2002. -# Carlos E. Robinson M. , 2006, 2007, 2008. +# Carlos E. R. M. , 2006, 2007, 2008. # Cer: <<== marcas de revision. msgid "" msgstr "" "Project-Id-Version: xine-lib.hg\n" "Report-Msgid-Bugs-To: xine-devel@lists.sourceforge.net\n" -"POT-Creation-Date: 2008-03-19 13:16+0000\n" -"PO-Revision-Date: 2008-01-31 14:32+0100\n" -"Last-Translator: Carlos E. Robinson M. \n" +"POT-Creation-Date: 2008-04-02 01:36+0100\n" +"PO-Revision-Date: 2008-04-02 01:05+0200\n" +"Last-Translator: Carlos E. R. M. \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -811,18 +812,18 @@ msgstr "" "compatibles OSS" # Cer: ¿pulseaudio? -#: src/audio_out/audio_pulse_out.c:549 +#: src/audio_out/audio_pulse_out.c:715 msgid "device used for pulseaudio" msgstr "dispositivo usado para audio a pulsos" # Cer: ¿pulseaudio? Estaba como "polypaudio" pero fuzzy. -#: src/audio_out/audio_pulse_out.c:550 +#: src/audio_out/audio_pulse_out.c:716 msgid "use 'server[:sink]' for setting the pulseaudio sink device." msgstr "" "use 'server[:sink]' para definir el sumidero del dispositivo audio a pulsos." # Cer: ¿pulseaudio? -#: src/audio_out/audio_pulse_out.c:583 +#: src/audio_out/audio_pulse_out.c:784 msgid "xine audio output plugin using pulseaudio sound server" msgstr "" "complemento de xine de salida de audio usando servidor de sonido audio a " @@ -1058,7 +1059,7 @@ msgstr "Flujo de bits del medio revuelto/encriptado" msgid "Restoring index..." msgstr "Restaurando índice..." -#: src/demuxers/demux_avi.c:628 src/demuxers/demux_avi.c:1683 +#: src/demuxers/demux_avi.c:628 src/demuxers/demux_avi.c:1693 #, c-format msgid "demux_avi: invalid avi chunk \"%c%c%c%c\" at pos %\n" msgstr "demux_avi: bloque avi inválido \"%c%c%c%c\" en posición %\n" @@ -1079,7 +1080,7 @@ msgstr "" msgid "invalid FILM chunk size\n" msgstr "tamaño de bloque FILM inválido\n" -#: src/demuxers/demux_film.c:340 +#: src/demuxers/demux_film.c:344 #, c-format msgid "unrecognized FILM chunk\n" msgstr "bloque FILM no reconocido\n" @@ -1225,7 +1226,7 @@ msgid "demux_wc3movie: SHOT chunk referenced invalid palette (%d >= %d)\n" msgstr "" "demux_wc3movie: bloque SHOT referenció una paleta inválida (%d >= %d)\n" -#: src/demuxers/demux_wc3movie.c:404 +#: src/demuxers/demux_wc3movie.c:410 #, c-format msgid "demux_wc3movie: There was a problem while loading palette chunks\n" msgstr "" @@ -4705,20 +4706,21 @@ msgstr "" #: src/video_out/video_out_xcbxv.c:1508 src/video_out/video_out_xv.c:1561 msgid "enable vblank sync" -msgstr "" +msgstr "activar sincronismo de blanqueo vertical (vblank sync)" #: src/video_out/video_out_xcbxv.c:1509 src/video_out/video_out_xv.c:1562 -#, fuzzy msgid "" "This option will synchronize the update of the video image to the repainting " "of the entire screen (\"vertical retrace\"). This eliminates flickering and " "tearing artifacts. On nvidia cards one may also need to run \"nvidia-settings" "\" and choose which display device to sync to under the XVideo Settings tab" msgstr "" -"El doble tamponeado sincronizará la actualización de la imagen de vídeo al " +"Esta opción sincronizará la actualización de la imagen de vídeo al " "redibujado de la pantalla de video entera (\"vertical retrace\", retrazado " -"vertical). Esto elimina el parpadeo y artifactos de rajado, pero usa más " -"memoria gráfica." +"vertical). Esto elimina el parpadeo y artefactos de rajado. En las tarjetas " +"nvidia puede también necesitar que ejecute \"nvidia-settings" +"\" (configuración de nvidia) y escoger que dispositivo de pantalla debe " +"sincronizar bajo la pestaña de configuración de XVideo" #: src/video_out/video_out_xcbxv.c:1547 msgid "video_out_xcbxv: this adaptor supports the yv12 format.\n" -- cgit v1.2.3 From a50219269aa4522530de7b7a26bc4e95a5cda1dd Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Wed, 2 Apr 2008 17:17:03 +0100 Subject: Add wvp to the wavpack demuxer's extensions list. --- src/combined/demux_wavpack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/combined/demux_wavpack.c b/src/combined/demux_wavpack.c index a9b20e5f9..754052199 100644 --- a/src/combined/demux_wavpack.c +++ b/src/combined/demux_wavpack.c @@ -387,7 +387,7 @@ static const char *get_identifier (demux_class_t *const this_gen) { } static const char *get_extensions (demux_class_t *const this_gen) { - return "wv"; + return "wv wvp"; } static const char *get_mimetypes (demux_class_t *const this_gen) { -- cgit v1.2.3