diff options
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | src/audio_out/Makefile.am | 15 | ||||
-rw-r--r-- | src/audio_out/audio_fusionsound_out.c | 488 |
3 files changed, 524 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index ccdae89ef..77fadf58d 100644 --- a/configure.ac +++ b/configure.ac @@ -1346,6 +1346,26 @@ AM_CONDITIONAL(HAVE_ARTS, test x"$no_arts" != "xyes") dnl --------------------------------------------- +dnl FusionSound support +dnl --------------------------------------------- + +AC_ARG_ENABLE([fusionsound], + AC_HELP_STRING([--enable-fusionsound], [build with fusionsound support]), + [with_fusionsound=$enableval], [with_fusionsound=no]) + +if test "x$with_fusionsound" = "xyes"; then + PKG_CHECK_MODULES(FUSIONSOUND, fusionsound >= 0.9.23, + AC_DEFINE(HAVE_FUSIONSOUND,1,[Define to 1 if you have FusionSound.]), + AC_MSG_RESULT(*** All of FusionSound dependent parts will be disabled ***)) + AC_SUBST(FUSIONSOUND_CFLAGS) + AC_SUBST(FUSIONSOUND_LIBS) +else + no_fusionsound=yes +fi +AM_CONDITIONAL(HAVE_FUSIONSOUND, test x"$no_fusionsound" != "xyes") + + +dnl --------------------------------------------- dnl gnome-vfs support dnl --------------------------------------------- @@ -2662,6 +2682,9 @@ fi if test x"$no_arts" != "xyes"; then echo " - arts (aRts - KDE soundserver)" fi +if test x"$no_fusionsound" != "xyes"; then + echo " - fusionsound (FusionSound driver)" +fi if test x"$have_sunaudio" = "xyes"; then echo " - sun ()" fi diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am index 745aac962..1bbfa396f 100644 --- a/src/audio_out/Makefile.am +++ b/src/audio_out/Makefile.am @@ -1,7 +1,7 @@ include $(top_srcdir)/misc/Makefile.common AM_CFLAGS = -DXINE_COMPILE $(ALSA_CFLAGS) $(ESD_CFLAGS) $(IRIXAL_CFLAGS) $(ARTS_CFLAGS) \ - $(POLYPAUDIO_CFLAGS) + $(POLYPAUDIO_CFLAGS) $(FUSIONSOUND_CFLAGS) EXTRA_DIST = audio_irixal_out.c @@ -46,6 +46,11 @@ if HAVE_POLYPAUDIO polypaudio_module = xineplug_ao_out_polypaudio.la endif +if HAVE_FUSIONSOUND +fusionsound_module = xineplug_ao_out_fusionsound.la +endif + + ## # IMPORTANT: # --------- @@ -61,7 +66,8 @@ lib_LTLIBRARIES = xineplug_ao_out_none.la xineplug_ao_out_file.la \ $(directx_module) \ $(coreaudio_module) \ $(polypaudio_module) \ - $(directx2_module) + $(directx2_module) \ + $(fusionsound_module) #lib_LTLIBRARIES = \ # $(alsa_module) \ @@ -125,3 +131,8 @@ 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_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + +xineplug_ao_out_fusionsound_la_SOURCES = audio_fusionsound_out.c +xineplug_ao_out_fusionsound_la_LIBADD = $(FUSIONSOUND_LIBS) $(XINE_LIB) +xineplug_ao_out_fusionsound_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + diff --git a/src/audio_out/audio_fusionsound_out.c b/src/audio_out/audio_fusionsound_out.c new file mode 100644 index 000000000..765b1d584 --- /dev/null +++ b/src/audio_out/audio_fusionsound_out.c @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2000-2006 the xine project and Claudio Ciccani + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * FusionSound based audio output plugin by Claudio Ciccani <klan@directfb.org> + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define LOG_MODULE "audio_fusionsound_out" +#define LOG_VERBOSE + +#include "xine.h" +#include "xine_internal.h" +#include "audio_out.h" +#include "xineutils.h" + +#include <directfb.h> + +#include <fusionsound.h> +#include <fusionsound_version.h> + + +#define AO_OUT_FS_IFACE_VERSION 8 + +#define GAP_TOLERANCE 5000 + +typedef struct fusionsound_driver_s { + ao_driver_t ao_driver; + + xine_t *xine; + + IFusionSound *sound; + IFusionSoundStream *stream; + IFusionSoundPlayback *playback; + + FSSampleFormat format; + int channels; + int rate; + int bytes_per_frame; + + float vol; + int vol_mute; + + float amp; + int amp_mute; + + int paused; +} fusionsound_driver_t; + +typedef struct { + audio_driver_class_t ao_class; + xine_t *xine; +} fusionsound_class_t; + + + +static int ao_fusionsound_open(ao_driver_t *ao_driver, + uint32_t bits, uint32_t rate, int mode) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + FSStreamDescription dsc; + DFBResult ret; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: ao_open bits=%d rate=%d, mode=%d\n", + bits, rate, mode); + + dsc.flags = FSSDF_BUFFERSIZE | FSBDF_CHANNELS | + FSSDF_SAMPLEFORMAT | FSSDF_SAMPLERATE; + + switch (mode) { + case AO_CAP_MODE_MONO: + dsc.channels = 1; + break; + case AO_CAP_MODE_STEREO: + dsc.channels = 2; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: mode %#x not supported\n", mode); + return 0; + } + + switch (bits) { + case 8: + dsc.sampleformat = FSSF_U8; + break; + case 16: + dsc.sampleformat = FSSF_S16; + break; + case 24: + dsc.sampleformat = FSSF_S24; + break; + case 32: + dsc.sampleformat = FSSF_S32; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: bits %d not supported\n", bits); + return 0; + } + + dsc.samplerate = rate; + dsc.buffersize = rate / 5; + + if (dsc.sampleformat != this->format || + dsc.channels != this->channels || + dsc.samplerate != this->rate || + this->stream == NULL) + { + if (this->playback) { + this->playback->Release (this->playback); + this->playback = NULL; + } + + if (this->stream) { + this->stream->Release (this->stream); + this->stream = NULL; + } + + ret = this->sound->CreateStream (this->sound, &dsc, &this->stream); + if (ret != DFB_OK) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: IFusionSound::CreateStream() failed [%s]\n", + FusionSoundErrorString (ret)); + return 0; + } + + this->stream->GetDescription (this->stream, &dsc); + + this->format = dsc.sampleformat; + this->channels = dsc.channels; + this->rate = dsc.samplerate; + this->bytes_per_frame = this->channels * FS_BYTES_PER_SAMPLE(this->format); + + ret = this->stream->GetPlayback (this->stream, &this->playback); + if (ret == DFB_OK) { + this->playback->SetVolume (this->playback, + (this->vol_mute ? 0 : this->vol) * + (this->amp_mute ? 0 : this->amp)); + if (this->paused) + this->playback->Stop (this->playback); + } + else { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: " + "IFusionSoundStream::GetPlayback() failed [%s]\n", + FusionSoundErrorString (ret)); + } + } + + return this->rate; +} + +static int ao_fusionsound_num_channels(ao_driver_t *ao_driver) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + return this->channels; +} + +static int ao_fusionsound_bytes_per_frame(ao_driver_t *ao_driver) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + return this->bytes_per_frame; +} + +static int ao_fusionsound_delay(ao_driver_t *ao_driver) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + int delay = 0; + + this->stream->GetPresentationDelay (this->stream, &delay); + + return (delay * this->rate / 1000); +} + +static int ao_fusionsound_get_gap_tolerance(ao_driver_t *ao_driver) { + return GAP_TOLERANCE; +} + +static int ao_fusionsound_write(ao_driver_t *ao_driver, + int16_t *data, uint32_t num_frames) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + DFBResult ret; + + ret = this->stream->Write (this->stream, (void *)data, num_frames); + if (ret != DFB_OK) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: IFusionSoundStream::Write() failed [%s]\n", + FusionSoundErrorString (ret)); + return 0; + } + + return num_frames; +} + +static void ao_fusionsound_close(ao_driver_t *ao_driver){ + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + if (this->playback) { + this->playback->Release (this->playback); + this->playback = NULL; + } + + if (this->stream) { + this->stream->Release (this->stream); + this->stream = NULL; + } +} + +/* + * FusionSound supports amplifier level adjustment; + * probably AO_CAP_AMP should be added to take advantage of this feature. + */ + +static uint32_t ao_fusionsound_get_capabilities(ao_driver_t *ao_driver) { + return (AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | + AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_24BITS); +} + +static void ao_fusionsound_exit(ao_driver_t *ao_driver) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + if (this->sound) + this->sound->Release (this->sound); + + free (this); +} + +static int ao_fusionsound_get_property(ao_driver_t *ao_driver, int property) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + switch (property) { + case AO_PROP_MIXER_VOL: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: volume is %.2f\n", this->vol); + return (int) (this->vol * 100.0); + + case AO_PROP_MUTE_VOL: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: volume mute is %d\n", this->vol_mute); + return this->vol_mute; + + case AO_PROP_AMP: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: amplifier is %.2f\n", this->amp); + return (int) (this->amp * 100.0); + + case AO_PROP_AMP_MUTE: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: amplifier mute is %d\n", this->amp_mute); + return this->amp_mute; + + default: + break; + } + + return 0; +} + +static int ao_fusionsound_set_property(ao_driver_t *ao_driver, + int property, int value ) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + + if (!this->playback) + return 0; + + switch (property) { + case AO_PROP_MIXER_VOL: + this->vol = (float)value / 100.0; + this->playback->SetVolume (this->playback, + (this->vol_mute ? 0 : this->vol) * + (this->amp_mute ? 0 : this->amp)); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: volume set to %.2f\n", this->vol); + break; + + case AO_PROP_MUTE_VOL: + value = value ? 1 : 0; + if (this->vol_mute != value) { + this->vol_mute = value; + this->playback->SetVolume (this->playback, + (this->vol_mute ? 0 : this->vol) * + (this->amp_mute ? 0 : this->amp)); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: volume mute set to %d\n", + this->vol_mute); + } + break; + + case AO_PROP_AMP: + this->amp = (float)value / 100.0; + this->playback->SetVolume (this->playback, + (this->vol_mute ? 0 : this->vol) * + (this->amp_mute ? 0 : this->amp)); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: amplifier set to %.2f\n", this->amp); + break; + + case AO_PROP_AMP_MUTE: + value = value ? 1 : 0; + if (this->amp_mute != value) { + this->amp_mute = value; + this->playback->SetVolume (this->playback, + (this->vol_mute ? 0 : this->vol) * + (this->amp_mute ? 0 : this->amp)); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_fusionsound_out: amplifier mute set to %d\n", + this->amp_mute); + } + break; + + default: + return 0; + } + + return value; +} + +static int ao_fusionsound_control(ao_driver_t *ao_driver, int cmd, ...) { + fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; + DFBResult ret = DFB_UNSUPPORTED; + + switch (cmd) { + case AO_CTRL_PLAY_PAUSE: + if (this->playback) { + lprintf ("Pause()\n"); + ret = this->playback->Stop (this->playback); + this->paused = 1; + } + break; + + case AO_CTRL_PLAY_RESUME: + if (this->playback) { + lprintf ("Resume()\n"); + ret = this->playback->Continue (this->playback); + this->paused = 0; + } + break; + + case AO_CTRL_FLUSH_BUFFERS: + lprintf ("Flush()\n"); + ret = this->stream->Flush (this->stream); + break; + + default: + break; + } + + return (ret == DFB_OK); +} + + +static ao_driver_t* open_plugin(audio_driver_class_t *ao_class, + const void *data ) { + fusionsound_class_t *class = (fusionsound_class_t *) ao_class; + fusionsound_driver_t *this; + DFBResult ret; + + this = (fusionsound_driver_t *) xine_xmalloc (sizeof(fusionsound_driver_t)); + if (!this) { + xprintf (class->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: driver interface allocation failed!\n"); + return NULL; + } + + ret = FusionSoundInit (NULL, NULL); + if (ret != DFB_OK) { + xprintf (class->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: FusionSoundInit() failed [%s]\n", + FusionSoundErrorString (ret)); + free (this); + return NULL; + } + + DirectFBSetOption ("no-sighandler", NULL); + + ret = FusionSoundCreate (&this->sound); + if (ret != DFB_OK) { + xprintf (class->xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: FusionSoundCreate() failed [%s]\n", + FusionSoundErrorString (ret)); + free (this); + return NULL; + } + + this->xine = class->xine; + this->ao_driver.get_capabilities = ao_fusionsound_get_capabilities; + this->ao_driver.get_property = ao_fusionsound_get_property; + this->ao_driver.set_property = ao_fusionsound_set_property; + this->ao_driver.open = ao_fusionsound_open; + this->ao_driver.num_channels = ao_fusionsound_num_channels; + this->ao_driver.bytes_per_frame = ao_fusionsound_bytes_per_frame; + this->ao_driver.delay = ao_fusionsound_delay; + this->ao_driver.write = ao_fusionsound_write; + this->ao_driver.close = ao_fusionsound_close; + this->ao_driver.exit = ao_fusionsound_exit; + this->ao_driver.get_gap_tolerance = ao_fusionsound_get_gap_tolerance; + this->ao_driver.control = ao_fusionsound_control; + + this->vol = this->amp = 1.0; + + return &this->ao_driver; +} + +/* + * class functions + */ + +static char* get_identifier(audio_driver_class_t *ao_class) { + return "FusionSound"; +} + +static char* get_description(audio_driver_class_t *ao_class) { + return "xine FusionSound audio output plugin"; +} + +static void dispose_class(audio_driver_class_t *ao_class) { + free (ao_class); +} + +static void* init_class(xine_t *xine, void *data) { + fusionsound_class_t *class; + const char *error; + + /* check FusionSound version */ + error = FusionSoundCheckVersion( FUSIONSOUND_MAJOR_VERSION, + FUSIONSOUND_MINOR_VERSION, + FUSIONSOUND_MICRO_VERSION ); + if (error) { + xprintf (xine, XINE_VERBOSITY_NONE, + "audio_fusionsound_out: %s!\n", error); + return NULL; + } + + class = (fusionsound_class_t *) xine_xmalloc (sizeof( fusionsound_class_t)); + if (!class) { + xprintf (xine, XINE_VERBOSITY_LOG, + "audio_fusionsound_out: class interface allocation failed!\n"); + return NULL; + } + + class->ao_class.open_plugin = open_plugin; + class->ao_class.get_identifier = get_identifier; + class->ao_class.get_description = get_description; + class->ao_class.dispose = dispose_class; + class->xine = xine; + + return class; +} + +static ao_info_t ao_info_fusionsound = { + 4 +}; + +/* + * exported plugin catalog entry + */ + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, AO_OUT_FS_IFACE_VERSION, "FusionSound", + XINE_VERSION_CODE, &ao_info_fusionsound, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + |