summaryrefslogtreecommitdiff
path: root/src/audio_out
diff options
context:
space:
mode:
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.am7
-rw-r--r--src/audio_out/audio_alsa_out.c23
-rw-r--r--src/audio_out/audio_coreaudio_out.c2
-rw-r--r--src/audio_out/audio_fusionsound_out.c6
-rw-r--r--src/audio_out/audio_oss_out.c50
-rw-r--r--src/audio_out/audio_pulse_out.c481
-rw-r--r--src/audio_out/audio_sun_out.c42
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