diff options
-rw-r--r-- | ext/Makefile.am | 11 | ||||
-rw-r--r-- | ext/arts/Makefile.am | 30 | ||||
-rw-r--r-- | ext/arts/gst_arts.c | 243 | ||||
-rw-r--r-- | ext/arts/gst_arts.h | 66 | ||||
-rw-r--r-- | ext/arts/gst_artsio.idl | 21 | ||||
-rw-r--r-- | ext/arts/gst_artsio_impl.cc | 159 | ||||
-rw-r--r-- | ext/arts/gst_artsio_impl.h | 14 | ||||
-rw-r--r-- | ext/artsd/Makefile.am | 9 | ||||
-rw-r--r-- | ext/artsd/REQUIREMENTS | 4 | ||||
-rw-r--r-- | ext/artsd/gstartsdsink.c | 408 | ||||
-rw-r--r-- | ext/artsd/gstartsdsink.h | 78 |
11 files changed, 1040 insertions, 3 deletions
diff --git a/ext/Makefile.am b/ext/Makefile.am index 39cddbf5..bc223d5b 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -82,13 +82,18 @@ else JPEG_DIR= endif - if USE_MAD MAD_DIR=mad else MAD_DIR= endif +if USE_MIKMOD +MIKMOD_DIR=mikmod +else +MIKMOD_DIR= +endif + if USE_MPEG2DEC MPEG2DEC_DIR=mpeg2dec else @@ -128,10 +133,10 @@ endif SUBDIRS=$(A52_DIR) $(AALIB_DIR) $(ALSA_DIR) $(AUDIOFILE_DIR) \ $(AVIFILE_DIR) $(CDPARANOIA_DIR) $(DVDREAD_DIR) $(ESD_DIR) \ $(FESTIVAL_DIR) $(FLAC_DIR) $(GSM_DIR) $(HERMES_DIR) \ - $(JPEG_DIR) $(LAME_DIR) $(MAD_DIR) $(MPEG2DEC_DIR) \ + $(JPEG_DIR) $(LAME_DIR) $(MAD_DIR) $(MIKMOD_DIR) $(MPEG2DEC_DIR) \ $(OPENQUICKTIME_DIR) $(SDL_DIR) $(SHOUT_DIR) $(VORBIS_DIR) \ $(XMMS_DIR) DIST_SUBDIRS=a52 aalib alsa avifile audiofile cdparanoia dvdread esd \ - festival flac gsm hermes jpeg lame mad mpeg2dec \ + festival flac gsm hermes jpeg lame mad mikmod mpeg2dec \ openquicktime sdl shout vorbis xmms diff --git a/ext/arts/Makefile.am b/ext/arts/Makefile.am new file mode 100644 index 00000000..0be9ebb4 --- /dev/null +++ b/ext/arts/Makefile.am @@ -0,0 +1,30 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgst_arts.la + +gst_artsio_impl.lo: gst_artsio.cc + +SUFFIXES = .idl +.idl.cc: + mcopidl -t $< $(ARTS_MCOPFLAGS) + +# mcopidl Extension Expansion Technology clean up +CLEANFILES = gst_artsio.h gst_artsio.cc gst_artsio.mcopclass gst_artsio.mcoptype + +libgst_arts_la_SOURCES = gst_arts.c gst_artsio.cc gst_artsio_impl.cc +noinst_HEADERS = gst_arts.h gst_artsio_impl.h + +# FIXME automake 1.4 hack, 1.5 should let us put the .idl in +# _SOURCES at which point the follow can be removed +EXTRA_DIST = gst_artsio.idl +dist-hook: + rm -f $(distdir)/gst_artsio.cc + +# gst_artsio.cc and gst_artsio.h are generated from the idl, and the tools +# needed to do this should be present on any platform where the rest of arts +# is present: therefore, these don't need to go in the dist. +#EXTRA_DIST = gst_artsio.cc gst_artsio.h + +libgst_arts_la_CFLAGS = $(ARTS_CFLAGS) +libgst_arts_la_CXXFLAGS = $(ARTS_CFLAGS) $(CFLAGS) +libgst_arts_la_LDFLAGS = $(ARTS_LIBS) diff --git a/ext/arts/gst_arts.c b/ext/arts/gst_arts.c new file mode 100644 index 00000000..a513f677 --- /dev/null +++ b/ext/arts/gst_arts.c @@ -0,0 +1,243 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <math.h> +#include <sys/soundcard.h> + +//#define DEBUG_ENABLED +#include "gst_arts.h" +#include "gst_artsio_impl.h" + +/* elementfactory information */ +static GstElementDetails gst_arts_details = { + "aRts plugin", + "Filter/Audio", + "aRts plugin", + VERSION, + "Erik Walthinsen <omega@temple-baptist.com, +Stefan Westerfeld <stefan@space.twc.de>", + "(C) 2000", +}; + + +GST_PADTEMPLATE_FACTORY ( sink_temp, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "arts_sample", + "audio/raw", + "format", GST_PROPS_INT ("int"), + "law", GST_PROPS_INT (0), + "depth", GST_PROPS_INT (16), + "width", GST_PROPS_INT (16), + "signed", GST_PROPS_BOOLEAN (TRUE), + "channels", GST_PROPS_INT (2), + "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN) + ) +) + +GST_PADTEMPLATE_FACTORY ( src_temp, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "arts_sample", + "audio/raw", + "format", GST_PROPS_INT ("int"), + "law", GST_PROPS_INT (0), + "depth", GST_PROPS_INT (16), + "width", GST_PROPS_INT (16), + "signed", GST_PROPS_BOOLEAN (TRUE), + "channels", GST_PROPS_INT (2), + "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN) + ) +) + +static GstPadTemplate* +mad_src_template_factory (void) +{ + static GstPadTemplate *templ = NULL; + + if (!templ) { + templ = gst_padtemplate_new ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + gst_caps_new ( + "mad_src", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT (44100), + "channels", GST_PROPS_INT (2), + NULL)), + NULL); + } + return templ; +} + +enum { + ARG_0, + ARG_LAST, +}; + +static void gst_arts_class_init (GstARTSClass *klass); +static void gst_arts_init (GstARTS *arts); + +static void gst_arts_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_arts_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static GstElementStateReturn gst_arts_change_state (GstElement *element); +static void gst_arts_loop (GstElement *element); + + +static GstElementClass *parent_class = NULL; +//static guint gst_arts_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_arts_get_type (void) +{ + static GType gst_arts_type = 0; + + if (!gst_arts_type) { + static const GTypeInfo gst_arts_info = { + sizeof(GstARTSClass), NULL, + NULL, + (GClassInitFunc)gst_arts_class_init, + NULL, + NULL, + sizeof(GstARTS), + 0, + (GInstanceInitFunc)gst_arts_init, + }; + gst_arts_type = g_type_register_static(GST_TYPE_ELEMENT, "GstArts", &gst_arts_info, 0); + } + return gst_arts_type; +} + +static void +gst_arts_class_init (GstARTSClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + gobject_class->set_property = gst_arts_set_property; + gobject_class->get_property = gst_arts_get_property; + + gstelement_class->change_state = gst_arts_change_state; +} + +static void +gst_arts_init (GstARTS *arts) +{ + arts->sinkpad = gst_pad_new_from_template(GST_PADTEMPLATE_GET(sink_temp),"sink"); + gst_element_add_pad(GST_ELEMENT(arts),arts->sinkpad); + +// arts->srcpad = gst_pad_new_from_template(GST_PADTEMPLATE_GET(src_temp),"src"); + arts->srcpad = gst_pad_new_from_template(mad_src_template_factory (), "src"); + gst_element_add_pad(GST_ELEMENT(arts),arts->srcpad); + + gst_element_set_loop_function (GST_ELEMENT (arts), gst_arts_loop); + + arts->wrapper = gst_arts_wrapper_new(arts->sinkpad,arts->srcpad); +} + +static void +gst_arts_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstARTS *arts = (GstARTS*)object; + GstARTSClass *oclass = (GstARTSClass*)(G_OBJECT_CLASS (object)); + +} + +static void +gst_arts_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstARTS *arts = (GstARTS*)object; + GstARTSClass *oclass = (GstARTSClass*)(G_OBJECT_CLASS (object)); + +} + +static GstElementStateReturn +gst_arts_change_state (GstElement *element) +{ + GstARTS *arts = (GstARTS*)element; + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +static void +gst_arts_loop (GstElement *element) +{ + GstARTS *arts = (GstARTS*)element; + + g_return_if_fail (arts != NULL); + +// do { + + gst_arts_wrapper_do(arts->wrapper); + +// } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *gstarts; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gstarts = gst_elementfactory_new("gstarts",GST_TYPE_ARTS,&gst_arts_details); + g_return_val_if_fail(gstarts != NULL, FALSE); + + gst_elementfactory_add_padtemplate(gstarts, GST_PADTEMPLATE_GET(sink_temp)); +// gst_elementfactory_add_padtemplate(gstarts, GST_PADTEMPLATE_GET(src_temp)); + gst_elementfactory_add_padtemplate(gstarts, mad_src_template_factory ()); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (gstarts)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "gst_arts", + plugin_init +}; diff --git a/ext/arts/gst_arts.h b/ext/arts/gst_arts.h new file mode 100644 index 00000000..9ecdbaef --- /dev/null +++ b/ext/arts/gst_arts.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * gstarts.h: Header for ARTS plugin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_ARTS_H__ +#define __GST_ARTS_H__ + + +#include <config.h> +#include <gst/gst.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_ARTS \ + (gst_arts_get_type()) +#define GST_ARTS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ARTS,GstARTS)) +#define GST_ARTS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ARTS,GstARTS)) +#define GST_IS_ARTS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ARTS)) +#define GST_IS_ARTS_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ARTS)) + +typedef struct _GstARTS GstARTS; +typedef struct _GstARTSClass GstARTSClass; + +struct _GstARTS { + GstElement element; + + GstPad *sinkpad, *srcpad; + void *wrapper; +}; + +struct _GstARTSClass { + GstElementClass parent_class; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_ARTS_H__ */ diff --git a/ext/arts/gst_artsio.idl b/ext/arts/gst_artsio.idl new file mode 100644 index 00000000..b656a0ac --- /dev/null +++ b/ext/arts/gst_artsio.idl @@ -0,0 +1,21 @@ +#include "artsflow.idl" + +module Gst { + +interface ArtsMonoSink : Arts::SynthModule { + default out audio stream output; +}; + +interface ArtsStereoSink : Arts::SynthModule { + default out audio stream outleft,outright; +}; + +interface ArtsMonoSrc : Arts::SynthModule { + default in audio stream input; +}; + +interface ArtsStereoSrc : Arts::SynthModule { + default in audio stream inleft,inright; +}; + +}; diff --git a/ext/arts/gst_artsio_impl.cc b/ext/arts/gst_artsio_impl.cc new file mode 100644 index 00000000..4d7eb3f9 --- /dev/null +++ b/ext/arts/gst_artsio_impl.cc @@ -0,0 +1,159 @@ +#include <math.h> +#include "artsflow.h" +#include "stdsynthmodule.h" +#include "gst_artsio.h" +#include "convert.h" +#include "connect.h" +#include "flowsystem.h" + +#include <gst/gst.h> + +using namespace Arts; + +namespace Gst { + +class ArtsStereoSink_impl : virtual public ArtsStereoSink_skel, + virtual public StdSynthModule +{ + + GstPad *sinkpad; + long remainingsamples; + GstBuffer *inbuf; + unsigned char *dataptr; + +public: + + ArtsStereoSink_impl() + { + remainingsamples = 0; + inbuf = NULL; + dataptr = NULL; + } + + void calculateBlock (unsigned long samples) + { + unsigned long fulfilled = 0; +//gint16 *s; +//fprintf(stderr,"StereoSink: getting %d samples\n",samples); + + while (fulfilled < samples) { + if (remainingsamples == 0) { +//fprintf(stderr,"need to get a buffer\n"); + if (inbuf) { + gst_buffer_unref(inbuf); + inbuf = 0; + } + + // start by pulling a buffer from GStreamer + inbuf = gst_pad_pull (sinkpad); + dataptr = GST_BUFFER_DATA(inbuf); + remainingsamples = GST_BUFFER_SIZE(inbuf) / 4; +//fprintf(stderr,"got a buffer with %d samples\n",remainingsamples); + } + + unsigned long count = MIN(remainingsamples,samples-fulfilled); +//fprintf(stderr,"have %d samples left, can fill %d\n",remainingsamples,count); + convert_stereo_i16le_2float(count,dataptr,outleft,outright); +//s = (gint16 *)dataptr; +//fprintf(stderr,"samples in are %d and %d, out are %f and %f\n",s[0],s[1],outleft[0],outright[0]); + remainingsamples -= count; + dataptr += 4 * count; + fulfilled += count; + } + } + + + void setPad(GstPad *pad) + { + sinkpad = pad; + } +}; + + +class ArtsStereoSrc_impl : virtual public ArtsStereoSrc_skel, + virtual public StdSynthModule +{ + + GstPad *srcpad; + GstBuffer *outbuf; + unsigned char *dataptr; + +public: + + void calculateBlock (unsigned long samples) + { +//gint16 *s; +//fprintf(stderr,"StereoSrc: handed %d samples\n",samples); + outbuf = gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (guchar *)g_malloc(samples*4); + GST_BUFFER_SIZE(outbuf) = samples*4; + memset(GST_BUFFER_DATA(outbuf),0,samples*4); + convert_stereo_2float_i16le(samples,inleft,inright,GST_BUFFER_DATA(outbuf)); +//s = (gint16 *)GST_BUFFER_DATA(outbuf); +//fprintf(stderr,"samples in are %f and %f, out are %d and %d\n",inleft[0],inright[0],s[0],s[1]); + gst_pad_push(srcpad,outbuf); + outbuf = NULL; + } + + + void setPad(GstPad *pad) + { + srcpad = pad; + } +}; + +class GstArtsWrapper { + Dispatcher *dispatcher; + ArtsStereoSink sink; + ArtsStereoSrc source; + StereoVolumeControl effect; + +public: + GstArtsWrapper(GstPad *sinkpad, GstPad *sourcepad) { + dispatcher = new Arts::Dispatcher(); + ArtsStereoSink_impl *sink_impl = new ArtsStereoSink_impl(); + ArtsStereoSrc_impl *source_impl = new ArtsStereoSrc_impl(); + sink_impl->setPad(sinkpad); + source_impl->setPad(sourcepad); + sink = ArtsStereoSink::_from_base(sink_impl); + source = ArtsStereoSrc::_from_base(source_impl); + sink.start(); + effect.start(); + source.start(); + effect.scaleFactor(0.5); + connect(sink, effect); + connect(effect, source); +// connect(sink,source); + } + void iterate() + { + source._node()->requireFlow(); + } +}; + + +}; + + +extern "C" { + +void *gst_arts_wrapper_new(GstPad *sinkpad, GstPad *sourcepad) +{ + return new Gst::GstArtsWrapper(sinkpad, sourcepad); +} + +void gst_arts_wrapper_free(void *wrapper) +{ + Gst::GstArtsWrapper *w = (Gst::GstArtsWrapper *)wrapper; + delete w; +} + +void gst_arts_wrapper_do(void *wrapper) +{ + Gst::GstArtsWrapper *w = (Gst::GstArtsWrapper *)wrapper; + w->iterate(); +} + +} + +// vim:sts=2:sw=2 diff --git a/ext/arts/gst_artsio_impl.h b/ext/arts/gst_artsio_impl.h new file mode 100644 index 00000000..8ffb29b6 --- /dev/null +++ b/ext/arts/gst_artsio_impl.h @@ -0,0 +1,14 @@ +#include <gst/gst.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void *gst_arts_wrapper_new(GstPad *sinkpad, GstPad *sourcepad); +void gst_arts_wrapper_free(void *wrapper); +void gst_arts_wrapper_do(void *wrapper); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + diff --git a/ext/artsd/Makefile.am b/ext/artsd/Makefile.am new file mode 100644 index 00000000..f41f73d6 --- /dev/null +++ b/ext/artsd/Makefile.am @@ -0,0 +1,9 @@ +plugindir = $(libdir)/gst + +plugin_LTLIBRARIES = libartsdsink.la + +libartsdsink_la_SOURCES = gstartsdsink.c +noinst_HEADERS = gstartsdsink.h + +libartsdsink_la_CFLAGS = $(ARTSC_CFLAGS) $(GST_CFLAGS) +libartsdsink_la_LIBADD = $(ARTSC_LIBS) diff --git a/ext/artsd/REQUIREMENTS b/ext/artsd/REQUIREMENTS new file mode 100644 index 00000000..babc3865 --- /dev/null +++ b/ext/artsd/REQUIREMENTS @@ -0,0 +1,4 @@ + + +To compile: artsc.h (On debian: libarts-dev) +To use: libartsc (On debian: libarts) diff --git a/ext/artsd/gstartsdsink.c b/ext/artsd/gstartsdsink.c new file mode 100644 index 00000000..a49a2261 --- /dev/null +++ b/ext/artsd/gstartsdsink.c @@ -0,0 +1,408 @@ +/* Gnome-Streamer + * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org> + * + * Based on example.c: + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstartsdsink.h" + +/* elementfactory information */ +static GstElementDetails artsdsink_details = { + "aRtsd audio sink", + "Sink/Artsdsink", + "Plays audio to an aRts server", + VERSION, + "Richard Boulton <richard-gst@tartarus.org>", + "(C) 2001", +}; + +/* Signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_MUTE, + ARG_DEPTH, + ARG_CHANNELS, + ARG_RATE, + ARG_NAME, +}; + +GST_PADTEMPLATE_FACTORY (sink_factory, + "sink", /* the name of the pads */ + GST_PAD_SINK, /* type of the pad */ + GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */ + GST_CAPS_NEW ( + "artsdsink_sink", /* the name of the caps */ + "audio/raw", /* the mime type of the caps */ + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (FALSE), + "width", GST_PROPS_INT (8), + "depth", GST_PROPS_INT (8), + "rate", GST_PROPS_INT_RANGE (8000, 96000), + "channels", GST_PROPS_LIST (GST_PROPS_INT (1), GST_PROPS_INT (2)) + ), + GST_CAPS_NEW ( + "artsdsink_sink", /* the name of the caps */ + "audio/raw", /* the mime type of the caps */ + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT_RANGE (8000, 96000), + "channels", GST_PROPS_LIST (GST_PROPS_INT (1), GST_PROPS_INT (2)) + ) +); + +static void gst_artsdsink_class_init (GstArtsdsinkClass *klass); +static void gst_artsdsink_init (GstArtsdsink *artsdsink); + +static gboolean gst_artsdsink_open_audio (GstArtsdsink *sink); +static void gst_artsdsink_close_audio (GstArtsdsink *sink); +static GstElementStateReturn gst_artsdsink_change_state (GstElement *element); +static gboolean gst_artsdsink_sync_parms (GstArtsdsink *artsdsink); + +static void gst_artsdsink_chain (GstPad *pad, GstBuffer *buf); + +static void gst_artsdsink_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_artsdsink_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +#define GST_TYPE_ARTSDSINK_DEPTHS (gst_artsdsink_depths_get_type()) +static GType +gst_artsdsink_depths_get_type (void) +{ + static GType artsdsink_depths_type = 0; + static GEnumValue artsdsink_depths[] = { + {8, "8", "8 Bits"}, + {16, "16", "16 Bits"}, + {0, NULL, NULL}, + }; + if (!artsdsink_depths_type) { + artsdsink_depths_type = g_enum_register_static("GstArtsdsinkDepths", artsdsink_depths); + } + return artsdsink_depths_type; +} + +#define GST_TYPE_ARTSDSINK_CHANNELS (gst_artsdsink_channels_get_type()) +static GType +gst_artsdsink_channels_get_type (void) +{ + static GType artsdsink_channels_type = 0; + static GEnumValue artsdsink_channels[] = { + {1, "1", "Mono"}, + {2, "2", "Stereo"}, + {0, NULL, NULL}, + }; + if (!artsdsink_channels_type) { + artsdsink_channels_type = g_enum_register_static("GstArtsdsinkChannels", artsdsink_channels); + } + return artsdsink_channels_type; +} + + +static GstElementClass *parent_class = NULL; +//static guint gst_artsdsink_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_artsdsink_get_type (void) +{ + static GType artsdsink_type = 0; + + if (!artsdsink_type) { + static const GTypeInfo artsdsink_info = { + sizeof(GstArtsdsinkClass), NULL, + NULL, + (GClassInitFunc)gst_artsdsink_class_init, + NULL, + NULL, + sizeof(GstArtsdsink), + 0, + (GInstanceInitFunc)gst_artsdsink_init, + }; + artsdsink_type = g_type_register_static(GST_TYPE_ELEMENT, "GstArtsdsink", &artsdsink_info, 0); + } + return artsdsink_type; +} + +static void +gst_artsdsink_class_init (GstArtsdsinkClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE, + g_param_spec_boolean("mute","mute","mute", + TRUE,G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEPTH, + g_param_spec_enum("depth","depth","depth", + GST_TYPE_ARTSDSINK_DEPTHS,0,G_PARAM_READWRITE)); // CHECKME! + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNELS, + g_param_spec_enum("channels","channels","channels", + GST_TYPE_ARTSDSINK_CHANNELS,0,G_PARAM_READWRITE)); // CHECKME! + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_RATE, + g_param_spec_int("frequency","frequency","frequency", + G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NAME, + g_param_spec_string("name","name","name", + NULL, G_PARAM_READWRITE)); // CHECKME + + gobject_class->set_property = gst_artsdsink_set_property; + gobject_class->get_property = gst_artsdsink_get_property; + + gstelement_class->change_state = gst_artsdsink_change_state; +} + +static void +gst_artsdsink_init(GstArtsdsink *artsdsink) +{ + artsdsink->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (sink_factory), "sink"); + gst_element_add_pad(GST_ELEMENT(artsdsink), artsdsink->sinkpad); + gst_pad_set_chain_function(artsdsink->sinkpad, gst_artsdsink_chain); + + artsdsink->connected = FALSE; + artsdsink->mute = FALSE; + + // FIXME: get default from somewhere better than just putting them inline. + artsdsink->signd = TRUE; + artsdsink->depth = 16; + artsdsink->channels = 2; + artsdsink->frequency = 44100; + artsdsink->connect_name = NULL; +} + +static gboolean +gst_artsdsink_sync_parms (GstArtsdsink *artsdsink) +{ + g_return_val_if_fail (artsdsink != NULL, FALSE); + g_return_val_if_fail (GST_IS_ARTSDSINK (artsdsink), FALSE); + + if (!artsdsink->connected) return TRUE; + + // Need to set stream to use new parameters: only way to do this is to reopen. + gst_artsdsink_close_audio (artsdsink); + return gst_artsdsink_open_audio (artsdsink); +} + + +static void +gst_artsdsink_chain (GstPad *pad, GstBuffer *buf) +{ + GstArtsdsink *artsdsink; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + artsdsink = GST_ARTSDSINK (gst_pad_get_parent (pad)); + + if (GST_BUFFER_DATA (buf) != NULL) { + gst_trace_add_entry(NULL, 0, buf, "artsdsink: writing to server"); + if (!artsdsink->mute && artsdsink->connected) { + int bytes; + void * bufptr = GST_BUFFER_DATA (buf); + int bufsize = GST_BUFFER_SIZE (buf); + GST_DEBUG (0, "artsdsink: stream=%p data=%p size=%d\n", + artsdsink->stream, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + + do { + bytes = arts_write (artsdsink->stream, bufptr, bufsize); + if(bytes < 0) { + fprintf(stderr,"arts_write error: %s\n", arts_error_text(bytes)); + gst_buffer_unref (buf); + return; + } + bufptr += bytes; + bufsize -= bytes; + } while (bufsize > 0); + } + } + gst_buffer_unref (buf); +} + +static void +gst_artsdsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstArtsdsink *artsdsink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ARTSDSINK(object)); + artsdsink = GST_ARTSDSINK(object); + + switch (prop_id) { + case ARG_MUTE: + artsdsink->mute = g_value_get_boolean (value); + break; + case ARG_DEPTH: + artsdsink->depth = g_value_get_enum (value); + gst_artsdsink_sync_parms (artsdsink); + break; + case ARG_CHANNELS: + artsdsink->channels = g_value_get_enum (value); + gst_artsdsink_sync_parms (artsdsink); + break; + case ARG_RATE: + artsdsink->frequency = g_value_get_int (value); + gst_artsdsink_sync_parms (artsdsink); + break; + case ARG_NAME: + if (artsdsink->connect_name != NULL) g_free(artsdsink->connect_name); + if (g_value_get_string (value) == NULL) + artsdsink->connect_name = NULL; + else + artsdsink->connect_name = g_strdup (g_value_get_string (value)); + break; + default: + break; + } +} + +static void +gst_artsdsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstArtsdsink *artsdsink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ARTSDSINK(object)); + artsdsink = GST_ARTSDSINK(object); + + switch (prop_id) { + case ARG_MUTE: + g_value_set_boolean (value, artsdsink->mute); + break; + case ARG_DEPTH: + g_value_set_enum (value, artsdsink->depth); + break; + case ARG_CHANNELS: + g_value_set_enum (value, artsdsink->channels); + break; + case ARG_RATE: + g_value_set_int (value, artsdsink->frequency); + break; + case ARG_NAME: + g_value_set_string (value, artsdsink->connect_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_elementfactory_new("artsdsink", GST_TYPE_ARTSDSINK, + &artsdsink_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate(factory, GST_PADTEMPLATE_GET (sink_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "artsdsink", + plugin_init +}; + +static gboolean +gst_artsdsink_open_audio (GstArtsdsink *sink) +{ + const char * connname = "gstreamer"; + int errcode; + + // Name used by aRtsd for this connection. + if (sink->connect_name != NULL) connname = sink->connect_name; + + // FIXME: this should only ever happen once per process. + // Really, artsc needs to be made thread safe to fix this (and other related + // problems). + errcode = arts_init(); + if(errcode < 0) { + fprintf(stderr,"arts_init error: %s\n", arts_error_text(errcode)); + return FALSE; + } + + GST_DEBUG (0, "artsdsink: attempting to open connection to aRtsd server\n"); + sink->stream = arts_play_stream(sink->frequency, sink->depth, + sink->channels, connname); + // FIXME: check connection + // GST_DEBUG (0, "artsdsink: can't open connection to aRtsd server\n"); + + GST_FLAG_SET (sink, GST_ARTSDSINK_OPEN); + sink->connected = TRUE; + + return TRUE; +} + +static void +gst_artsdsink_close_audio (GstArtsdsink *sink) +{ + if (!sink->connected) return; + + arts_close_stream(sink->stream); + arts_free(); + GST_FLAG_UNSET (sink, GST_ARTSDSINK_OPEN); + sink->connected = FALSE; + + g_print("artsdsink: closed connection\n"); +} + +static GstElementStateReturn +gst_artsdsink_change_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ARTSDSINK (element), FALSE); + + /* if going down into NULL state, close the stream if it's open */ + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (GST_FLAG_IS_SET (element, GST_ARTSDSINK_OPEN)) + gst_artsdsink_close_audio (GST_ARTSDSINK (element)); + /* otherwise (READY or higher) we need to open the stream */ + } else { + if (!GST_FLAG_IS_SET (element, GST_ARTSDSINK_OPEN)) { + if (!gst_artsdsink_open_audio (GST_ARTSDSINK (element))) + return GST_STATE_FAILURE; + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + return GST_STATE_SUCCESS; +} + diff --git a/ext/artsd/gstartsdsink.h b/ext/artsd/gstartsdsink.h new file mode 100644 index 00000000..64b190d4 --- /dev/null +++ b/ext/artsd/gstartsdsink.h @@ -0,0 +1,78 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_ARTSDSINK_H__ +#define __GST_ARTSDSINK_H__ + +#include <gst/gst.h> +#include <artsc.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_ARTSDSINK \ + (gst_artsdsink_get_type()) +#define GST_ARTSDSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ARTSDSINK,GstArtsdsink)) +#define GST_ARTSDSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ARTSDSINK,GstArtsdsink)) +#define GST_IS_ARTSDSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ARTSDSINK)) +#define GST_IS_ARTSDSINK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ARTSDSINK)) + +typedef enum { + GST_ARTSDSINK_OPEN = GST_ELEMENT_FLAG_LAST, + GST_ARTSDSINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST+2, +} GstArtsdSinkFlags; + +typedef struct _GstArtsdsink GstArtsdsink; +typedef struct _GstArtsdsinkClass GstArtsdsinkClass; + +struct _GstArtsdsink { + GstElement element; + + GstPad *sinkpad; + + gboolean connected; + arts_stream_t stream; + gboolean mute; + gboolean signd; + gint depth; + gint channels; + gint frequency; + gchar* connect_name; +}; + +struct _GstArtsdsinkClass { + GstElementClass parent_class; +}; + +GType gst_artsdsink_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_ARTSDSINK_H__ */ |