From 09698f917cf8971e50e574d0aa9f2bcf1be8cfb1 Mon Sep 17 00:00:00 2001 From: "J. Alexander Treuman" Date: Thu, 13 Jul 2006 19:03:49 +0000 Subject: Add PulseAudio support git-svn-id: https://svn.musicpd.org/mpd/trunk@4316 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- configure.ac | 18 +++- doc/mpd.conf.5 | 20 ++-- src/Makefile.am | 1 + src/audio.c | 2 + src/audioOutputs/audioOutput_pulse.c | 193 +++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 8 deletions(-) create mode 100644 src/audioOutputs/audioOutput_pulse.c diff --git a/configure.ac b/configure.ac index 7e84f7fcc..5c2b0cfd5 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,7 @@ AC_ARG_ENABLE(ipv6,[ --disable-ipv6 disable IPv6 support (default: enable)] AC_ARG_ENABLE(sun,[ --disable-sun disable sun support (default: enable)],[enable_sun=$enableval],[enable_sun=yes]) AC_ARG_ENABLE(oss,[ --disable-oss disable OSS support (default: enable)],[enable_oss=$enableval],[enable_oss=yes]) AC_ARG_ENABLE(alsa,[ --disable-alsa disable ALSA support (default: enable)],[enable_alsa=$enableval],[enable_alsa=yes]) +AC_ARG_ENABLE(pulse,[ --disable-pulse disable support for the PulseAudio sound server (default: enable)],[enable_pulse=$enableval],[enable_pulse=yes]) AC_ARG_ENABLE(mvp,[ --enable-mvp enable support for Hauppauge Media MVP (default: disable)],[enable_mvp=$enableval],[enable_mvp=no]) AC_ARG_ENABLE(oggvorbis,[ --disable-oggvorbis disable Ogg Vorbis support (default: enable)],[enable_oggvorbis=$enableval],enable_oggvorbis=yes) AC_ARG_ENABLE(oggflac,[ --disable-oggflac disable OggFLAC support (default: enable)],[enable_oggflac=$enableval],enable_oggflac=yes) @@ -147,6 +148,12 @@ if test x$enable_oss = xyes; then AC_CHECK_HEADER(sys/soundcard.h,[enable_oss=yes;AC_DEFINE(HAVE_OSS,1,[Define to enable OSS])],[AC_MSG_WARN(Soundcard headers not found -- disabling OSS support);enable_oss=no]) fi +if test x$enable_pulse = xyes; then + PKG_CHECK_MODULES([PULSE], [libpulse-simple], + [enable_pulse=yes;AC_DEFINE([HAVE_PULSE], 1, [Define to enable PulseAudio])] MPD_LIBS="$MPD_LIBS $PULSE_LIBS" MPD_CFLAGS="$MPD_CFLAGS $PULSE_CFLAGS", + [enable_pulse=no;AC_MSG_WARN([PulseAudio not found -- disabling])]) +fi + if test x$enable_mvp = xyes; then AC_DEFINE(HAVE_MVP,1,[Define to enable Hauppauge Media MVP support]) fi @@ -636,9 +643,9 @@ else fi if test x$enable_sun = xyes; then - echo " Sun support ...... ............enabled" + echo " Sun support ...................enabled" else - echo " Sun support ...... ............disabled" + echo " Sun support ...................disabled" fi if test x$enable_osx = xyes; then @@ -647,6 +654,12 @@ else echo " OS X support ..................disabled" fi +if test x$enable_pulse = xyes; then + echo " PulseAudio support ............enabled" +else + echo " PulseAudio support ............disabled" +fi + if test x$enable_mvp = xyes; then echo " Media MVP support .............enabled" else @@ -667,6 +680,7 @@ if test x$enable_ao = xno && test x$enable_sun = xno && test x$enable_alsa = xno && test x$enable_osx = xno && + test x$enable_pulse = xno && test x$enable_mvp = xno; then AC_MSG_ERROR("No Audio Output types configured!") fi diff --git a/doc/mpd.conf.5 b/doc/mpd.conf.5 index 6a5336e92..06f675131 100644 --- a/doc/mpd.conf.5 +++ b/doc/mpd.conf.5 @@ -186,14 +186,14 @@ This specifies whether relative or absolute paths for song filenames are used when saving playlists. The default is "no". .SH REQUIRED AUDIO OUTPUT PARAMETERS .TP -.B name -This specifies a unique name for the audio output. -.TP .B type This specifies the audio output type. Depending on what audio output support -mpd was built with possible values could be "alsa", "oss", "osx", "mvp", "ao", -or "shout" (see \fBREQUIRED SHOUT OUTPUT PARAMETERS\fP and \fBOPTIONAL SHOUT -OUTPUT PARAMETERS\fP). +mpd was built with possible values could be "alsa", "oss", "osx", "pulse", +"mvp", "ao", or "shout" (see \fBREQUIRED SHOUT OUTPUT PARAMETERS\fP and +\fBOPTIONAL SHOUT OUTPUT PARAMETERS\fP). +.TP +.B name +This specifies a unique name for the audio output. .SH OPTIONAL AUDIO OUTPUT PARAMETERS .TP .B format @@ -207,6 +207,14 @@ This specifies the device to use for audio output. Used by the alsa and oss output types. The default for oss is "/dev/dsp"; the default for alsa is "hw:0,0". .TP +.B server +A space separated list of servers to try to connect to. Used only by the pulse +audio output. The default is to let PulseAudio choose a server. +.TP +.B sink +The sink to output to. Used only by the pulse audio output. The default is to +let PulseAudio choose a sink. +.TP .B driver This specifies the libao driver to use for audio output. Used only by the ao output type. Possible values depend on what libao drivers are available. See diff --git a/src/Makefile.am b/src/Makefile.am index 9197c3d69..91669ec40 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ mpd_audioOutputs = \ audioOutputs/audioOutput_ao.c \ audioOutputs/audioOutput_oss.c \ audioOutputs/audioOutput_osx.c \ + audioOutputs/audioOutput_pulse.c \ audioOutputs/audioOutput_mvp.c \ audioOutputs/audioOutput_shout.c diff --git a/src/audio.c b/src/audio.c index 3469a6825..308dcc3e9 100644 --- a/src/audio.c +++ b/src/audio.c @@ -75,6 +75,7 @@ extern AudioOutputPlugin alsaPlugin; extern AudioOutputPlugin aoPlugin; extern AudioOutputPlugin ossPlugin; extern AudioOutputPlugin osxPlugin; +extern AudioOutputPlugin pulsePlugin; extern AudioOutputPlugin mvpPlugin; extern AudioOutputPlugin shoutPlugin; @@ -88,6 +89,7 @@ void initAudioDriver() { loadAudioOutputPlugin(&aoPlugin); loadAudioOutputPlugin(&ossPlugin); loadAudioOutputPlugin(&osxPlugin); + loadAudioOutputPlugin(&pulsePlugin); loadAudioOutputPlugin(&mvpPlugin); loadAudioOutputPlugin(&shoutPlugin); diff --git a/src/audioOutputs/audioOutput_pulse.c b/src/audioOutputs/audioOutput_pulse.c new file mode 100644 index 000000000..8dcf09f87 --- /dev/null +++ b/src/audioOutputs/audioOutput_pulse.c @@ -0,0 +1,193 @@ +#include "../audioOutput.h" + +#include + +#ifdef HAVE_PULSE + +#define MPD_PULSE_NAME "mpd" +#define MPD_PULSE_STREAM_NAME "mpd" + +#include "../conf.h" +#include "../log.h" + +#include +#include + +typedef struct _PulseData { + char * server; + char * sink; + pa_simple * s; +} PulseData; + +static PulseData * newPulseData() +{ + PulseData * ret; + + ret = malloc(sizeof(PulseData)); + ret->server = NULL; + ret->sink = NULL; + ret->s = NULL; + return ret; +} + +static void freePulseData(PulseData * ad) +{ + if (ad->server) free(ad->server); + if (ad->sink) free(ad->sink); + free(ad); +} + +static int pulse_initDriver(AudioOutput * audioOutput, ConfigParam * param) +{ + BlockParam * server = NULL; + BlockParam * sink = NULL; + PulseData * ad; + + if (param) { + server = getBlockParam(param, "server"); + sink = getBlockParam(param, "sink"); + } + + ad = newPulseData(); + ad->server = server ? strdup(server->value) : NULL; + ad->sink = sink ? strdup(sink->value) : NULL; + audioOutput->data = ad; + + return 0; +} + +static void pulse_finishDriver(AudioOutput * audioOutput) +{ + freePulseData((PulseData *) audioOutput->data); +} + +static int pulse_testDefault() +{ + pa_simple * s; + pa_sample_spec ss; + int error; + + ss.format = PA_SAMPLE_S16NE; + ss.rate = 44100; + ss.channels = 2; + + s = pa_simple_new(NULL, MPD_PULSE_NAME, PA_STREAM_PLAYBACK, NULL, + MPD_PULSE_STREAM_NAME, &ss, NULL, NULL, &error); + if (!s) { + WARNING("Cannot connect to default PulseAudio server: %s\n", + pa_strerror(error)); + return -1; + } + + pa_simple_free(s); + + return 0; +} + +static int pulse_openDevice(AudioOutput * audioOutput) +{ + PulseData * ad; + AudioFormat * audioFormat; + pa_sample_spec ss; + int error; + + ad = audioOutput->data; + audioFormat = &audioOutput->outAudioFormat; + + if (audioFormat->bits != 16) { + ERROR("PulseAudio doesn't support %i bit audio\n", + audioFormat->bits); + return -1; + } + + ss.format = PA_SAMPLE_S16NE; + ss.rate = audioFormat->sampleRate; + ss.channels = audioFormat->channels; + + ad->s = pa_simple_new(ad->server, MPD_PULSE_NAME, PA_STREAM_PLAYBACK, + ad->sink, MPD_PULSE_STREAM_NAME, &ss, + NULL, NULL, &error); + if (!ad->s) { + ERROR("Cannot connect to server in PulseAudio output " \ + "\"%s\": %s\n", audioOutput->name, pa_strerror(error)); + return -1; + } + + audioOutput->open = 1; + + DEBUG("PulseAudio output \"%s\" connected and playing %i bit, %i " \ + "channel audio at %i Hz\n", audioOutput->name, audioFormat->bits, + audioFormat->channels, audioFormat->sampleRate); + + return 0; +} + +static void pulse_dropBufferedAudio(AudioOutput * audioOutput) +{ + PulseData * ad; + int error; + + ad = audioOutput->data; + if (pa_simple_flush(ad->s, &error) < 0) + WARNING("Flush failed in PulseAudio output \"%s\": %s\n", + audioOutput->name, pa_strerror(error)); +} + +static void pulse_closeDevice(AudioOutput * audioOutput) +{ + PulseData * ad; + + ad = audioOutput->data; + if (ad->s) { + pa_simple_drain(ad->s, NULL); + pa_simple_free(ad->s); + } + + audioOutput->open = 0; +} + +static int pulse_playAudio(AudioOutput * audioOutput, char * playChunk, + int size) +{ + PulseData * ad; + int error; + + ad = audioOutput->data; + + if (pa_simple_write(ad->s, playChunk, size, &error) < 0) { + ERROR("PulseAudio output \"%s\" disconnecting due to write " \ + "error: %s\n", audioOutput->name, pa_strerror(error)); + pulse_closeDevice(audioOutput); + return -1; + } + + return 0; +} + +AudioOutputPlugin pulsePlugin = { + "pulse", + pulse_testDefault, + pulse_initDriver, + pulse_finishDriver, + pulse_openDevice, + pulse_playAudio, + pulse_dropBufferedAudio, + pulse_closeDevice, + NULL, /* sendMetadataFunc */ +}; + +#else /* HAVE_PULSE */ + +AudioOutputPlugin pulsePlugin = +{ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +#endif /* HAVE_PULSE */ -- cgit v1.2.3