diff options
Diffstat (limited to 'src/audio_out')
-rw-r--r-- | src/audio_out/.hgignore (renamed from src/audio_out/.cvsignore) | 0 | ||||
-rw-r--r-- | src/audio_out/Makefile.am | 7 | ||||
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 23 | ||||
-rw-r--r-- | src/audio_out/audio_coreaudio_out.c | 2 | ||||
-rw-r--r-- | src/audio_out/audio_fusionsound_out.c | 6 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 50 | ||||
-rw-r--r-- | src/audio_out/audio_pulse_out.c | 481 | ||||
-rw-r--r-- | src/audio_out/audio_sun_out.c | 42 |
8 files changed, 396 insertions, 215 deletions
diff --git a/src/audio_out/.cvsignore b/src/audio_out/.hgignore index 7d926a554..7d926a554 100644 --- a/src/audio_out/.cvsignore +++ b/src/audio_out/.hgignore diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am index 445622765..d52f700f3 100644 --- a/src/audio_out/Makefile.am +++ b/src/audio_out/Makefile.am @@ -94,7 +94,7 @@ xineplug_ao_out_oss_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_oss_la_LDFLAGS = -avoid-version -module xineplug_ao_out_alsa_la_SOURCES = audio_alsa_out.c -xineplug_ao_out_alsa_la_LIBADD = $(ALSA_LIBS) $(XINE_LIB) +xineplug_ao_out_alsa_la_LIBADD = $(ALSA_LIBS) $(XINE_LIB) $(PTHREAD_LIBS) xineplug_ao_out_alsa_la_CFLAGS = $(VISIBILITY_FLAG) $(ALSA_CFLAGS) xineplug_ao_out_alsa_la_LDFLAGS = -avoid-version -module @@ -104,6 +104,7 @@ xineplug_ao_out_esd_la_CFLAGS = $(VISIBILITY_FLAG) $(ESD_CFLAGS) xineplug_ao_out_esd_la_LDFLAGS = -avoid-version -module xineplug_ao_out_sun_la_SOURCES = audio_sun_out.c +xineplug_ao_out_sun_la_LIBADD = $(XINE_LIB) xineplug_ao_out_sun_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_sun_la_LDFLAGS = -avoid-version -module @@ -113,7 +114,7 @@ xineplug_ao_out_sun_la_LDFLAGS = -avoid-version -module #xineplug_ao_out_irixal_la_LDFLAGS = -avoid-version -module xineplug_ao_out_arts_la_SOURCES = audio_arts_out.c -xineplug_ao_out_arts_la_LIBADD = $(ARTS_LIBS) +xineplug_ao_out_arts_la_LIBADD = $(ARTS_LIBS) $(XINE_LIB) xineplug_ao_out_arts_la_CFLAGS = $(VISIBILITY_FLAG) $(ARTS_CFLAGS) xineplug_ao_out_arts_la_LDFLAGS = -avoid-version -module @@ -140,7 +141,7 @@ xineplug_ao_out_pulseaudio_la_LDFLAGS = -avoid-version -module xineplug_ao_out_directx2_la_SOURCES = audio_directx2_out.c xineplug_ao_out_directx2_la_CPPFLAGS = $(DIRECTX_CPPFLAGS) -xineplug_ao_out_directx2_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) $(THREAD_LIBS) +xineplug_ao_out_directx2_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) $(PTHREAD_LIBS) xineplug_ao_out_directx2_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_directx2_la_LDFLAGS = -avoid-version -module diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index da8b87fc5..3651d21da 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -26,7 +26,7 @@ * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.165 2006/09/08 20:40:34 miguelfreitas Exp $ + * $Id: audio_alsa_out.c,v 1.168 2007/02/25 22:33:25 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -162,7 +162,6 @@ static int my_snd_mixer_wait(snd_mixer_t *mixer, int timeout) { static void *ao_alsa_handle_event_thread(void *data) { alsa_driver_t *this = (alsa_driver_t *) data; - this->mixer.running = 1; do { if(my_snd_mixer_wait(this->mixer.handle, 333) > 0) { @@ -665,6 +664,15 @@ static int ao_alsa_delay (ao_driver_t *this_gen) { printf("audio_alsa_out:delay:ENTERED\n"); #endif err=snd_pcm_delay( this->audio_fd, &delay ); + + int state = snd_pcm_state(this->audio_fd); + + /* check for idle states, which need to be handled as delay=0 */ + if(state == SND_PCM_STATE_PREPARED || state == SND_PCM_STATE_PAUSED || + state == SND_PCM_STATE_OPEN || SND_PCM_STATE_XRUN) { + return 0; + } + #ifdef LOG_DEBUG printf("audio_alsa_out:delay:delay all=%ld err=%d\n",delay, err); gettimeofday(&now, 0); @@ -1292,6 +1300,8 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { if (send_events && found) { pthread_attr_t pth_attrs; struct sched_param pth_params; + + this->mixer.running = 1; pthread_attr_init(&pth_attrs); @@ -1321,7 +1331,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da char *pcm_device; snd_pcm_hw_params_t *params; /* for usability reasons, keep this in sync with audio_oss_out.c */ - static char *speaker_arrangement[] = {"Mono 1.0", "Stereo 2.0", "Headphones 2.0", "Stereo 2.1", + static const char *speaker_arrangement[] = {"Mono 1.0", "Stereo 2.0", "Headphones 2.0", "Stereo 2.1", "Surround 3.0", "Surround 4.0", "Surround 4.1", "Surround 5.0", "Surround 5.1", "Surround 6.0", "Surround 6.1", "Surround 7.1", "Pass Through", NULL}; #define MONO 0 @@ -1504,6 +1514,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->capabilities |= AO_CAP_FLOAT32; xprintf(class->xine, XINE_VERBOSITY_LOG, _("32bit ")); } + if (0 == (this->capabilities & (AO_CAP_FLOAT32 | AO_CAP_24BITS | AO_CAP_16BITS | AO_CAP_8BITS))) { + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + "\naudio_alsa_out: no supported PCM format found\n"); + snd_pcm_close(this->audio_fd); + free(this); + return NULL; + } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 1))) { this->capabilities |= AO_CAP_MODE_MONO; xprintf(class->xine, XINE_VERBOSITY_LOG, _("mono ")); diff --git a/src/audio_out/audio_coreaudio_out.c b/src/audio_out/audio_coreaudio_out.c index 80cab6d71..22f53c0ef 100644 --- a/src/audio_out/audio_coreaudio_out.c +++ b/src/audio_out/audio_coreaudio_out.c @@ -265,7 +265,9 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate format.mSampleRate = rate; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger +#ifdef WORDS_BIGENDIAN | kLinearPCMFormatFlagIsBigEndian +#endif | kLinearPCMFormatFlagIsPacked; format.mBitsPerChannel = this->bits_per_sample; format.mChannelsPerFrame = this->num_channels; diff --git a/src/audio_out/audio_fusionsound_out.c b/src/audio_out/audio_fusionsound_out.c index 1a6f44972..71a17f6e6 100644 --- a/src/audio_out/audio_fusionsound_out.c +++ b/src/audio_out/audio_fusionsound_out.c @@ -262,6 +262,12 @@ static uint32_t ao_fusionsound_get_capabilities(ao_driver_t *ao_driver) { static void ao_fusionsound_exit(ao_driver_t *ao_driver) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + if (this->playback) + this->playback->Release (this->playback); + + if (this->stream) + this->stream->Release (this->stream); + if (this->sound) this->sound->Release (this->sound); diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 366fa250c..793b47650 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_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_oss_out.c,v 1.117 2006/07/16 16:18:09 dsalt Exp $ + * $Id: audio_oss_out.c,v 1.120 2007/03/17 06:59:31 dgp85 Exp $ * * 20-8-2001 First implementation of Audio sync and Audio driver separation. * Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk @@ -48,20 +48,19 @@ #include <fcntl.h> #include <math.h> #include <unistd.h> -#if defined(__OpenBSD__) -# include <soundcard.h> -#elif defined (__FreeBSD__) -# if __FreeBSD__ < 4 -# include <machine/soundcard.h> -# else -# include <sys/soundcard.h> -# endif -#else -# include <sys/soundcard.h> -#endif #include <sys/ioctl.h> #include <inttypes.h> +#ifdef HAVE_SYS_SOUNDCARD_H +# include <sys/soundcard.h> +#endif +#ifdef HAVE_MACHINE_SOUNDCARD_H +# include <sys/soundcard.h> +#endif +#ifdef HAVE_SOUNDCARD_H +# include <soundcard.h> +#endif + #define LOG_MODULE "audio_oss_out" #define LOG_VERBOSE /* @@ -75,9 +74,18 @@ #include <sys/time.h> +#ifndef SNDCTL_DSP_SETFMT +/* Deprecated OSS API */ +#define SNDCTL_DSP_SETFMT SOUND_PCM_SETFMT +#endif + +#ifndef SNDCTL_DSP_SPEED +/* Deprecated OSS API */ +#define SNDCTL_DSP_SPEED SOUND_PCM_WRITE_RATE +#endif + #ifndef AFMT_S16_NE -# if defined(sparc) || defined(__sparc__) || defined(PPC) -/* Big endian machines */ +# ifdef WORDS_BIGENDIAN # define AFMT_S16_NE AFMT_S16_BE # else # define AFMT_S16_NE AFMT_S16_LE @@ -515,7 +523,7 @@ static int ao_oss_get_property (ao_driver_t *this_gen, int property) { if(!this->mixer.mute) { if(this->mixer.fd != -1) { - int cmd = 0; + IOCTL_REQUEST_TYPE cmd = 0; int v; ioctl(this->mixer.fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); @@ -554,7 +562,7 @@ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) if(!this->mixer.mute) { if(this->mixer.fd != -1) { - int cmd = 0; + IOCTL_REQUEST_TYPE cmd = 0; int v; ioctl(this->mixer.fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); @@ -583,7 +591,7 @@ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) if(this->mixer.mute) { if(this->mixer.fd != -1) { - int cmd = 0; + IOCTL_REQUEST_TYPE cmd = 0; int v = 0; ioctl(this->mixer.fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); @@ -789,9 +797,9 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da */ arg = AFMT_S16_NE; - status = ioctl(audio_fd, SOUND_PCM_SETFMT, &arg); + status = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg); arg = 44100; - status = ioctl(audio_fd, SOUND_PCM_WRITE_RATE, &arg); + status = ioctl(audio_fd, SNDCTL_DSP_SPEED, &arg); /* * find out which sync method to use @@ -903,12 +911,12 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->capabilities = 0; arg = AFMT_U8; - if( ioctl(audio_fd, SOUND_PCM_SETFMT, &arg) != -1 && arg == AFMT_U8) + if( ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg) != -1 && arg == AFMT_U8) this->capabilities |= AO_CAP_8BITS; /* switch back to 16bits, because some soundcards otherwise do not report all their capabilities */ arg = AFMT_S16_NE; - if (ioctl(audio_fd, SOUND_PCM_SETFMT, &arg) == -1 || arg != AFMT_S16_NE) { + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg) == -1 || arg != AFMT_S16_NE) { xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: switching the soundcard to 16 bits mode failed\n"); free(this); close(audio_fd); diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index 2cef1992d..9e6089730 100644 --- a/src/audio_out/audio_pulse_out.c +++ b/src/audio_out/audio_pulse_out.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2006 the xine project + * Copyright (C) 2000-2007 the xine project * * This file is part of xine, a free video player. * @@ -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.5 2006/11/10 12:10:54 dgp85 Exp $ + * $Id: audio_pulse_out.c,v 1.17 2007/04/01 00:32:29 dgp85 Exp $ * * ao plugin for pulseaudio (rename of polypaudio): * http://0pointer.de/lennart/projects/pulsaudio/ @@ -40,12 +40,9 @@ #include <math.h> #include <unistd.h> #include <inttypes.h> -#include <assert.h> #include <pthread.h> #include <pulse/pulseaudio.h> -#include <pulse/error.h> -#include <pulse/mainloop.h> #include "xine_internal.h" #include "xineutils.h" @@ -57,78 +54,146 @@ /* CHECKME: should this be conditional on autotools? */ extern const char *__progname; -typedef struct pulse_driver_s { +typedef struct { + audio_driver_class_t driver_class; + xine_t *xine; - ao_driver_t ao_driver; + 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; - xine_t *xine; +typedef struct pulse_driver_s { + ao_driver_t ao_driver; + xine_t *xine; - /** The host to connect to */ - char *host; + pulse_class_t *pa_class; - /** The sink to connect to */ - char *sink; + char *host; /*< The host to connect to */ + char *sink; /*< The sink to connect to */ + struct pa_stream *stream; /*< Pulseaudio playback stream object */ - /** Pulseaudio playback stream object */ - struct pa_stream *stream; + pa_volume_t swvolume; + pa_cvolume cvolume; - /** Pulseaudio connection context */ - struct pa_context *context; + int capabilities; + int mode; - /** Main event loop object */ - struct pa_mainloop *mainloop; + int32_t sample_rate; + uint32_t num_channels; + uint32_t bits_per_sample; + uint32_t bytes_per_frame; - pa_volume_t swvolume; - pa_cvolume cvolume; + uint32_t frames_written; - int capabilities; - int mode; +} pulse_driver_t; - int32_t sample_rate; - uint32_t num_channels; - uint32_t bits_per_sample; - uint32_t bytes_per_frame; +/** + * @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. + */ +static void __xine_pa_stream_success_callback(pa_stream *const stream, const int success, + void *const this_gen) +{ + pulse_driver_t *const this = (pulse_driver_t*)this_gen; - uint32_t frames_written; + _x_assert(stream); _x_assert(this); + _x_assert(stream == this->stream); - pthread_mutex_t lock; + pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); +} -} pulse_driver_t; +/** + * @brief Callback function called when the state of the context is changed + * @param ctx Context which operation has succeeded + * @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) +{ + pulse_driver_t *const this = (pulse_driver_t*)this_gen; -typedef struct { - audio_driver_class_t driver_class; + _x_assert(ctx); _x_assert(this); + _x_assert(ctx == this->pa_class->context); - xine_t *xine; -} pulse_class_t; + 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; + } +} + +/** + * @brief Callback function called when a context operation succeed + * @param ctx Context 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. + */ +static void __xine_pa_context_success_callback(pa_context *const ctx, const int success, + void *const this_gen) +{ + pulse_driver_t *const this = (pulse_driver_t*)this_gen; -/** Make sure that the connection context doesn't starve to death */ -static void keep_alive(pulse_driver_t *this) { - assert(this->context && this->mainloop); + _x_assert(ctx); _x_assert(this); + _x_assert(ctx == this->pa_class->context); - while (pa_mainloop_iterate(this->mainloop, 0, NULL) > 0); + pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); } -/** Wait until no further actions are pending on the connection context */ -static void wait_for_completion(pulse_driver_t *this) { - assert(this->context && this->mainloop); +/** + * @brief Callback function called when the information on the + * context's sink is retrieved. + * @param ctx Context which operation has succeeded + * @param info Structure containing the sink's information + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + * + * 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) { + + pulse_driver_t *const this = (pulse_driver_t *) userdata; - while (pa_context_is_pending(this->context)) { - int r = pa_mainloop_iterate(this->mainloop, 1, NULL); - assert(r >= 0); + 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->pa_class->context))); + return; } + + if (!info) + return; + + this->cvolume = info->volume; + + __xine_pa_context_success_callback(ctx, 0, this); } -/** Wait until the specified operation completes */ -static void wait_for_operation(pulse_driver_t *this, struct pa_operation *o) { - assert(o && this->context && this->mainloop); +static int wait_for_operation(pulse_driver_t *this, pa_operation *o) +{ + _x_assert(this && o && this->pa_class->mainloop); - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - int r = pa_mainloop_iterate(this->mainloop, 1, NULL); - assert(r >= 0); - } + 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); - pa_operation_unref(o); + return 0; } /* @@ -140,6 +205,7 @@ static int ao_pulse_open(ao_driver_t *this_gen, pulse_driver_t *this = (pulse_driver_t *) this_gen; struct pa_sample_spec ss; struct pa_buffer_attr a; + pa_stream_state_t streamstate; xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); @@ -171,68 +237,85 @@ static int ao_pulse_open(ao_driver_t *this_gen, ss.format = PA_SAMPLE_U8; break; case 16: -#ifdef WORDS_BIGENDIAN - ss.format = PA_SAMPLE_S16BE; -#else - ss.format = PA_SAMPLE_S16LE; -#endif + ss.format = PA_SAMPLE_S16NE; break; case 32: - ss.format = PA_SAMPLE_FLOAT32; + ss.format = PA_SAMPLE_FLOAT32NE; break; } - pthread_mutex_lock(&this->lock); - if (!pa_sample_spec_valid(&ss)) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Invalid sample spec\n"); goto fail; } - this->mainloop = pa_mainloop_new(); - assert(this->mainloop); + 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; + } + + if ( this->pa_class->context == NULL ) { + this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop), + __progname); + } + + pa_context_ref(this->pa_class->context); + + if ( pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED ) { + int ret; - this->context = pa_context_new(pa_mainloop_get_api(this->mainloop), __progname); - assert(this->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; - pa_context_connect(this->context, this->host, 1, NULL); + pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this); - wait_for_completion(this); + pa_threaded_mainloop_wait(this->pa_class->mainloop); + pa_threaded_mainloop_unlock(this->pa_class->mainloop); + } - if (pa_context_get_state(this->context) != PA_CONTEXT_READY) { + 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->context))); + pa_strerror(pa_context_errno(this->pa_class->context))); goto fail; } - this->stream = pa_stream_new(this->context, "audio stream", &ss, NULL); - assert(this->stream); + 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; a.tlength = a.maxlength*9/10; a.prebuf = a.tlength/2; a.minreq = a.tlength/10; - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); pa_stream_connect_playback(this->stream, this->sink, &a, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, - &this->cvolume, NULL); + NULL, NULL); - wait_for_completion(this); + do { + xine_usec_sleep (100); - if (pa_stream_get_state(this->stream) != PA_STREAM_READY) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to connect to server: %s\n", - pa_strerror(pa_context_errno(this->context))); + 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))); goto fail; } - pthread_mutex_unlock(&this->lock); - this->frames_written = 0; + this->ao_driver.set_property(this, AO_PROP_PCM_VOL, 100); + return this->sample_rate; fail: - pthread_mutex_unlock(&this->lock); + pa_threaded_mainloop_unlock(this->pa_class->mainloop); + pthread_mutex_unlock(&this->pa_class->pa_mutex); this_gen->close(this_gen); return 0; } @@ -262,22 +345,16 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data, int size = num_frames * this->bytes_per_frame; int ret = 0; - assert(this->stream && this->context); - - pthread_mutex_lock(&this->lock); - - if (pa_stream_get_state(this->stream) == PA_STREAM_READY) { + 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; - keep_alive(this); - while (!(l = pa_stream_writable_size(this->stream))) { - pthread_mutex_unlock(&this->lock); xine_usec_sleep (10000); - pthread_mutex_lock(&this->lock); - keep_alive(this); } if (l > size) @@ -286,16 +363,15 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data, pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); data = (int16_t *) ((uint8_t*) data + l); size -= l; - - wait_for_completion(this); } this->frames_written += num_frames; if (pa_stream_get_state(this->stream) == PA_STREAM_READY) ret = 1; + + break; } - pthread_mutex_unlock(&this->lock); return ret; } @@ -307,20 +383,25 @@ static int ao_pulse_delay (ao_driver_t *this_gen) pa_usec_t latency = 0; int delay_frames; - pthread_mutex_lock(&this->lock); + if ( ! this->stream ) return this->frames_written; - for (;;) { - if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0) - break; + pthread_mutex_lock(&this->pa_class->pa_mutex); - if (pa_context_errno(this->context) != PA_ERR_NODATA) { - /* error */ - } - keep_alive(this); - } + if (pa_stream_get_latency(this->stream, &latency, NULL) < 0) { + pa_context_unref(this->pa_class->context); + this->pa_class->context = NULL; - pthread_mutex_unlock(&this->lock); + pa_stream_disconnect(this->stream); + 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); @@ -334,26 +415,19 @@ static void ao_pulse_close(ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - pthread_mutex_lock(&this->lock); 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, NULL, NULL)); + 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; - } - if (this->context) { - pa_context_disconnect(this->context); - pa_context_unref(this->context); - this->context = NULL; - } + pa_context_unref(this->pa_class->context); - if (this->mainloop) { - pa_mainloop_free(this->mainloop); - this->mainloop = NULL; + pthread_mutex_unlock(&this->pa_class->pa_mutex); } - pthread_mutex_unlock(&this->lock); } static uint32_t ao_pulse_get_capabilities (ao_driver_t *this_gen) { @@ -368,101 +442,124 @@ static void ao_pulse_exit(ao_driver_t *this_gen) free (this); } -/** A callback function that is called when the - * pa_context_get_sink_input_info() operation completes. Saves the - * volume field of the specified structure to the global variable volume. */ -static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { - - pulse_driver_t *this = (pulse_driver_t *) userdata; - 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))); - return; - } - - if (!i) - return; - - this->cvolume = i->volume; -} - - 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; + + 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->lock); - if( this->stream && this->context ) - wait_for_operation(this, - pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream), info_func, this)); - pthread_mutex_unlock(&this->lock); - return (int) (pa_sw_volume_to_linear(this->swvolume)*100); + { + 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); + + result = (pa_sw_volume_to_linear(this->swvolume)*100); + } break; + case AO_PROP_MUTE_VOL: + result = pa_cvolume_is_muted(&this->cvolume); break; } - return 0; + pthread_mutex_unlock(&this->pa_class->pa_mutex); + + 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; + + 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: - pthread_mutex_lock(&this->lock); this->swvolume = pa_sw_volume_from_linear((double)value/100.0); - if( this->stream && this->context ) { - 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), - &this->cvolume, NULL, NULL)); - } - pthread_mutex_unlock(&this->lock); + 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)); + + result = value; break; + 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); + + 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)); + + result = value; break; } - return 0; + pthread_mutex_unlock(&this->pa_class->pa_mutex); + + return result; } static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - pthread_mutex_lock(&this->lock); + if ( ! this->stream ) return 0; + switch (cmd) { case AO_CTRL_PLAY_PAUSE: - 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, NULL, NULL)); + 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: - 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, NULL, NULL); - o2 = pa_stream_cork(this->stream, 0, NULL, NULL); - assert(o1 && o2); - wait_for_operation(this,o1); - wait_for_operation(this,o2); - wait_for_completion(this); + o1 = pa_stream_prebuf(this->stream, __xine_pa_stream_success_callback, this); + _x_assert(o1); wait_for_operation(this, o1); + + 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: - 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, NULL, NULL)); + 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; } - pthread_mutex_unlock(&this->lock); return 0; } @@ -470,7 +567,6 @@ static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { pulse_class_t *class = (pulse_class_t *) class_gen; pulse_driver_t *this; - char hn[128]; char *device; lprintf ("audio_pulse_out: open_plugin called\n"); @@ -490,7 +586,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da AO_CAP_16BITS | AO_CAP_FLOAT32; this->sample_rate = 0; - this->swvolume = PA_VOLUME_NORM; + this->host = NULL; + this->sink = NULL; this->ao_driver.get_capabilities = ao_pulse_get_capabilities; this->ao_driver.get_property = ao_pulse_get_property; @@ -514,35 +611,27 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 10, NULL, NULL); - if (device && strlen(device)) { - int i = strcspn(device, ":"); - if (i >= sizeof(hn)) - i = sizeof(hn)-1; - - if (i > 0) { - strncpy(this->host = hn, device, i); - hn[i] = 0; - } - - if (device[i] == ':') - this->sink = device+i+1; + 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); } xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n", this->host ? this->host : "(null)", this->sink ? this->sink : "(null)"); - pthread_mutex_init (&this->lock, NULL); - - /* test pulseaudio connection */ - if( this->ao_driver.open(&this->ao_driver, 16, 44100, AO_CAP_MODE_STEREO) != 0 ) { - this->ao_driver.close(&this->ao_driver); - } else { - free(this); - xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: open_plugin failed.\n"); - return 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; } /* @@ -561,6 +650,15 @@ 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); } @@ -581,6 +679,18 @@ 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); + + pa_threaded_mainloop_start(this->mainloop); + + this->context = NULL; + + pthread_mutex_unlock(&this->pa_mutex); + return this; } @@ -598,3 +708,4 @@ const plugin_info_t xine_plugin_info[] EXPORTED = { { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; + diff --git a/src/audio_out/audio_sun_out.c b/src/audio_out/audio_sun_out.c index 95e38d811..93361d2f3 100644 --- a/src/audio_out/audio_sun_out.c +++ b/src/audio_out/audio_sun_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_sun_out.c,v 1.45 2006/07/16 16:18:09 dsalt Exp $ + * $Id: audio_sun_out.c,v 1.47 2007/03/10 00:55:14 dgp85 Exp $ */ #ifdef HAVE_CONFIG_H @@ -41,13 +41,20 @@ #ifdef __svr4__ #include <stropts.h> #endif +#include <sys/param.h> + +#if (defined(BSD) && BSD >= 199306) +typedef unsigned uint_t; +#endif #include "xine_internal.h" #include "xineutils.h" #include "audio_out.h" +#ifdef __svr4__ #define CS4231_WORKAROUND 1 /* enable workaround for audiocs play.samples bug */ #define SW_SAMPLE_COUNT 1 +#endif #ifndef AUDIO_CHANNELS_MONO @@ -89,7 +96,9 @@ typedef struct sun_driver_s { uint32_t num_channels; int bytes_per_frame; +#ifdef __svr4__ uint32_t frames_in_buffer; /* number of frames writen to audio hardware */ +#endif enum { RTSC_UNKNOWN = 0, @@ -114,12 +123,14 @@ typedef struct sun_driver_s { unsigned buf_len; #endif +#ifdef __svr4__ #if SW_SAMPLE_COUNT struct timeval tv0; uint_t sample0; #endif uint_t last_samplecnt; +#endif } sun_driver_t; @@ -129,6 +140,7 @@ typedef struct sun_driver_s { */ static int realtime_samplecounter_available(xine_t *xine, char *dev) { +#ifdef __svr4__ int fd = -1; audio_info_t info; int rtsc_ok = RTSC_DISABLED; @@ -247,6 +259,9 @@ error: } return rtsc_ok; +#else + return RTSC_ENABLED; +#endif } @@ -430,7 +445,9 @@ static int ao_sun_open(ao_driver_t *this_gen, this->mode = mode; this->input_sample_rate = rate; +#ifdef __svr4__ this->frames_in_buffer = 0; +#endif /* * open audio device @@ -462,6 +479,9 @@ static int ao_sun_open(ao_driver_t *this_gen, info.play.sample_rate = this->input_sample_rate; info.play.eof = 0; info.play.samples = 0; +#ifndef __svr4__ + info.blocksize = 1024; +#endif this->convert_u8_s8 = 0; @@ -523,7 +543,9 @@ static int ao_sun_open(ao_driver_t *this_gen, return 0; } +#ifdef __svr4__ this->last_samplecnt = 0; +#endif this->output_sample_rate = info.play.sample_rate; this->num_channels = info.play.channels; @@ -564,6 +586,7 @@ static int ao_sun_delay(ao_driver_t *this_gen) sun_driver_t *this = (sun_driver_t *) this_gen; audio_info_t info; +#ifdef __svr4__ if (ioctl(this->audio_fd, AUDIO_GETINFO, &info) == 0 && (this->frames_in_buffer == 0 || info.play.samples > 0)) { @@ -610,6 +633,10 @@ static int ao_sun_delay(ao_driver_t *this_gen) } #endif } +#else + if (ioctl(this->audio_fd, AUDIO_GETINFO, &info) == 0) + return info.play.seek / this->bytes_per_frame; +#endif return NOT_REAL_TIME; } @@ -718,7 +745,9 @@ static int ao_sun_write(ao_driver_t *this_gen, if (num_written > 0) { int buffered_samples; +#ifdef __svr4__ this->frames_in_buffer += num_written / this->bytes_per_frame; +#endif /* * Avoid storing too much data in the sound driver's buffers. @@ -862,6 +891,9 @@ static int ao_sun_ctrl(ao_driver_t *this_gen, int cmd, ...) { this->frames_in_buffer = 0; this->last_samplecnt = 0; #endif +#ifdef __NetBSD__ + ioctl(this->audio_fd, AUDIO_FLUSH); +#endif break; } @@ -888,9 +920,10 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v audiodev = getenv("AUDIODEV"); /* This config entry is security critical, is it really necessary? */ - devname = config->register_string(config, + devname = config->register_filename(config, "audio.device.sun_audio_device", audiodev && *audiodev ? audiodev : "/dev/audio", + XINE_CONFIG_STRING_IS_DEVICE_NAME, _("Sun audio device name"), _("Specifies the file name for the Sun audio device " "to be used.\nThis setting is security critical, " @@ -945,7 +978,10 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v */ this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_8BITS - | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL; + | AO_CAP_16BITS | AO_CAP_PCM_VOL; +#ifdef __svr4__ + this->capabilities |= AO_CAP_MUTE_VOL; +#endif /* * get initial mixer volume |