sndio: add sndio plugin for OpenBSD
authorJacob Meuser <jakemsr@sdf.lonestar.org>
Thu, 12 Apr 2012 01:05:26 +0000 (21:05 -0400)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 25 Apr 2012 08:26:48 +0000 (10:26 +0200)
configure.ac
ext/Makefile.am
ext/sndio/Makefile.am [new file with mode: 0644]
ext/sndio/gstsndio.c [new file with mode: 0644]
ext/sndio/sndiosink.c [new file with mode: 0644]
ext/sndio/sndiosink.h [new file with mode: 0644]
ext/sndio/sndiosrc.c [new file with mode: 0644]
ext/sndio/sndiosrc.h [new file with mode: 0644]

index e6e7368..4da2865 100644 (file)
@@ -1839,6 +1839,19 @@ AG_GST_CHECK_FEATURE(GSETTINGS, [GSettings plugin], gsettings, [
   fi
 ])
 
+dnl *** sndio ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_SNDIO, true)
+AG_GST_CHECK_FEATURE(SNDIO, [sndio audio], sndio, [
+  AC_CHECK_HEADER(sndio.h, HAVE_SNDIO="yes", HAVE_SNDIO="no")
+  if test "x$HAVE_SNDIO" = "xyes"; then
+    AC_CHECK_LIB(sndio, sio_open, HAVE_SNDIO="yes", HAVE_SNDIO="no")
+    if test "x$HAVE_SNDIO" = "xyes"; then
+      SNDIO_LIBS=-lsndio
+      AC_SUBST(SNDIO_LIBS)
+    fi
+  fi
+])
+
 else
 
 dnl not building plugins with external dependencies,
@@ -1910,6 +1923,7 @@ AM_CONDITIONAL(USE_ZBAR, false)
 AM_CONDITIONAL(USE_VP8, false)
 AM_CONDITIONAL(USE_RTMP, false)
 AM_CONDITIONAL(USE_TELETEXTDEC, false)
+AM_CONDITIONAL(USE_SNDIO, false)
 
 fi dnl of EXT plugins
 
@@ -2147,6 +2161,7 @@ ext/sdl/Makefile
 ext/sndfile/Makefile
 ext/soundtouch/Makefile
 ext/spandsp/Makefile
+ext/sndio/Makefile
 ext/teletextdec/Makefile
 ext/gme/Makefile
 ext/gsettings/Makefile
index 0d57dc3..6bd7044 100644 (file)
@@ -330,6 +330,12 @@ else
 SNDFILE_DIR=
 endif
 
+if USE_SNDIO
+SNDIO_DIR = sndio
+else
+SNDIO_DIR =
+endif
+
 if USE_SOUNDTOUCH
 SOUNDTOUCH_DIR=soundtouch
 else
@@ -452,6 +458,7 @@ SUBDIRS=\
        $(SHOUT_DIR) \
        $(SMOOTHWAVE_DIR) \
        $(SNDFILE_DIR) \
+       $(SNDIO_DIR) \
        $(SOUNDTOUCH_DIR) \
        $(SPANDSP_DIR) \
        $(GME_DIR) \
@@ -507,6 +514,7 @@ DIST_SUBDIRS = \
        schroedinger \
        sdl \
        sndfile \
+       sndio \
        soundtouch \
        spandsp \
        spc \
diff --git a/ext/sndio/Makefile.am b/ext/sndio/Makefile.am
new file mode 100644 (file)
index 0000000..03a42b1
--- /dev/null
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = libgstsndio.la
+
+libgstsndio_la_SOURCES = gstsndio.c sndiosink.c sndiosrc.c 
+libgstsndio_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstsndio_la_LIBADD = \
+       $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+       $(SNDIO_LIBS)
+libgstsndio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = sndiosink.h sndiosrc.h
+EXTRA_DIST =
diff --git a/ext/sndio/gstsndio.c b/ext/sndio/gstsndio.c
new file mode 100644 (file)
index 0000000..d52a424
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sndiosink.h"
+#include "sndiosrc.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY (gst_sndio_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "sndiosrc", GST_RANK_PRIMARY,
+          GST_TYPE_SNDIOSRC) ||
+      !gst_element_register (plugin, "sndiosink", GST_RANK_PRIMARY,
+          GST_TYPE_SNDIOSINK)) {
+    return FALSE;
+  }
+
+  GST_DEBUG_CATEGORY_INIT (gst_sndio_debug, "sndio", 0, "sndio elements");
+
+#ifdef ENABLE_NLS
+  setlocale (LC_ALL, "");
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif /* ENABLE_NLS */
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "sndio",
+    "sndio support for GStreamer",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/sndio/sndiosink.c b/ext/sndio/sndiosink.c
new file mode 100644 (file)
index 0000000..e91ecd4
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * SECTION:element-sndiosink
+ * @see_also: #GstAutoAudioSink
+ *
+ * <refsect2>
+ * <para>
+ * This element outputs sound to a sound card using sndio.
+ * </para>
+ * <para>
+ * Simple example pipeline that plays an Ogg/Vorbis file via sndio:
+ * <programlisting>
+ * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! audioresample ! sndiosink
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sndiosink.h"
+#include <unistd.h>
+#include <errno.h>
+
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
+#define GST_CAT_DEFAULT gst_sndio_debug
+
+enum
+{
+  PROP_0,
+  PROP_HOST
+};
+
+static GstStaticPadTemplate sndio_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw-int, "
+        "endianness = (int) { 1234, 4321 }, "
+        "signed = (boolean) { TRUE, FALSE }, "
+        "width = (int) { 8, 16, 24, 32 }, "
+        "depth = (int) { 8, 16, 24, 32 }, "
+        "rate = (int) [ 8000, 192000 ], "
+        "channels = (int) [ 1, 16 ] ")
+    );
+
+static void gst_sndiosink_finalize (GObject * object);
+
+static GstCaps *gst_sndiosink_getcaps (GstBaseSink * bsink);
+
+static gboolean gst_sndiosink_open (GstAudioSink * asink);
+static gboolean gst_sndiosink_close (GstAudioSink * asink);
+static gboolean gst_sndiosink_prepare (GstAudioSink * asink,
+    GstRingBufferSpec * spec);
+static gboolean gst_sndiosink_unprepare (GstAudioSink * asink);
+static guint gst_sndiosink_write (GstAudioSink * asink, gpointer data,
+    guint length);
+static guint gst_sndiosink_delay (GstAudioSink * asink);
+static void gst_sndiosink_reset (GstAudioSink * asink);
+
+static void gst_sndiosink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_sndiosink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_sndiosink_cb (void *addr, int delta);
+
+GST_BOILERPLATE (GstSndioSink, gst_sndiosink, GstAudioSink,
+    GST_TYPE_AUDIO_SINK);
+
+static void
+gst_sndiosink_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_set_details_simple (element_class,
+      "Sndio audio sink",
+      "Sink/Audio",
+      "Plays audio through sndio",
+      "Jacob Meuser <jakemsr@sdf.lonestar.org>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sndio_sink_factory));
+}
+
+static void
+gst_sndiosink_class_init (GstSndioSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstBaseAudioSinkClass *gstbaseaudiosink_class;
+  GstAudioSinkClass *gstaudiosink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
+  gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_sndiosink_finalize;
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosink_getcaps);
+
+  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sndiosink_open);
+  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sndiosink_close);
+  gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosink_prepare);
+  gstaudiosink_class->unprepare =
+      GST_DEBUG_FUNCPTR (gst_sndiosink_unprepare);
+  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sndiosink_write);
+  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sndiosink_delay);
+  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sndiosink_reset);
+
+  gobject_class->set_property = gst_sndiosink_set_property;
+  gobject_class->get_property = gst_sndiosink_get_property;
+
+  /* default value is filled in the _init method */
+  g_object_class_install_property (gobject_class, PROP_HOST,
+      g_param_spec_string ("host", "Host",
+          "Device or socket sndio will access", NULL, G_PARAM_READWRITE));
+}
+
+static void
+gst_sndiosink_init (GstSndioSink * sndiosink,
+    GstSndioSinkClass * klass)
+{
+  sndiosink->hdl = NULL;
+  sndiosink->host = g_strdup (g_getenv ("AUDIODEVICE"));
+}
+
+static void
+gst_sndiosink_finalize (GObject * object)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (object);
+
+  gst_caps_replace (&sndiosink->cur_caps, NULL);
+  g_free (sndiosink->host);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_sndiosink_getcaps (GstBaseSink * bsink)
+{
+  GstSndioSink *sndiosink;
+
+  sndiosink = GST_SNDIOSINK (bsink);
+
+  /* no hdl, we're done with the template caps */
+  if (sndiosink->cur_caps == NULL) {
+    GST_LOG_OBJECT (sndiosink, "getcaps called, returning template caps");
+    return NULL;
+  }
+
+  GST_LOG_OBJECT (sndiosink, "returning %" GST_PTR_FORMAT,
+      sndiosink->cur_caps);
+
+  return gst_caps_ref (sndiosink->cur_caps);
+}
+
+static gboolean
+gst_sndiosink_open (GstAudioSink * asink)
+{
+  GstPadTemplate *pad_template;
+  GstSndioSink *sndiosink;
+  struct sio_par par;
+  struct sio_cap cap;
+  GArray *rates, *chans;
+  GValue rates_v = { 0 };
+  GValue chans_v = { 0 };
+  GValue value = { 0 };
+  struct sio_enc enc;
+  struct sio_conf conf;
+  int confs[SIO_NCONF];
+  int rate, chan;
+  int i, j, k;
+  int nconfs;
+
+  sndiosink = GST_SNDIOSINK (asink);
+
+  GST_DEBUG_OBJECT (sndiosink, "open");
+
+  /* conect */
+  sndiosink->hdl = sio_open (sndiosink->host, SIO_PLAY, 0);
+
+  if (sndiosink->hdl == NULL)
+    goto couldnt_connect;
+
+  /* Use sndio defaults as the only encodings, but get the supported
+   * sample rates and number of channels.
+   */
+
+  if (!sio_getpar (sndiosink->hdl, &par))
+    goto no_server_info;
+
+  if (!sio_getcap (sndiosink->hdl, &cap))
+    goto no_server_info;
+
+  rates = g_array_new (FALSE, FALSE, sizeof (int));
+  chans = g_array_new (FALSE, FALSE, sizeof (int));
+
+  /* find confs that have the default encoding */
+  nconfs = 0;
+  for (i = 0; i < cap.nconf; i++) {
+    for (j = 0; j < SIO_NENC; j++) {
+      if (cap.confs[i].enc & (1 << j)) {
+        enc = cap.enc[j];
+        if (enc.bits == par.bits && enc.sig == par.sig && enc.le == par.le) {
+          confs[nconfs] = i;
+          nconfs++;
+          break;
+        }
+      }
+    }
+  }
+
+  /* find the rates and channels of the confs that have the default encoding */
+  for (i = 0; i < nconfs; i++) {
+    conf = cap.confs[confs[i]];
+    /* rates */
+    for (j = 0; j < SIO_NRATE; j++) {
+      if (conf.rate & (1 << j)) {
+        rate = cap.rate[j];
+        for (k = 0; k < rates->len && rate; k++) {
+          if (rate == g_array_index (rates, int, k))
+              rate = 0;
+        }
+        /* add in ascending order */
+        if (rate) {
+          for (k = 0; k < rates->len; k++) {
+            if (rate < g_array_index (rates, int, k))
+            {
+              g_array_insert_val (rates, k, rate);
+              break;
+            }
+          }
+          if (k == rates->len)
+            g_array_append_val (rates, rate);
+        }
+      }
+    }
+    /* channels */
+    for (j = 0; j < SIO_NCHAN; j++) {
+      if (conf.pchan & (1 << j)) {
+        chan = cap.pchan[j];
+        for (k = 0; k < chans->len && chan; k++) {
+          if (chan == g_array_index (chans, int, k))
+              chan = 0;
+        }
+        /* add in ascending order */
+        if (chan) {
+          for (k = 0; k < chans->len; k++) {
+            if (chan < g_array_index (chans, int, k))
+            {
+              g_array_insert_val (chans, k, chan);
+              break;
+            }
+          }
+          if (k == chans->len)
+            g_array_append_val (chans, chan);
+        }
+      }
+    }
+  }
+  /* not sure how this can happen, but it might */
+  if (cap.nconf == 0) {
+    g_array_append_val (rates, par.rate);
+    g_array_append_val (chans, par.pchan);
+  }
+
+  g_value_init (&rates_v, GST_TYPE_LIST);
+  g_value_init (&chans_v, GST_TYPE_LIST);
+  g_value_init (&value, G_TYPE_INT);
+
+  for (i = 0; i < rates->len; i++) {
+    g_value_set_int (&value, g_array_index (rates, int, i));
+    gst_value_list_append_value (&rates_v, &value);
+  }
+  for (i = 0; i < chans->len; i++) {
+    g_value_set_int (&value, g_array_index (chans, int, i));
+    gst_value_list_append_value (&chans_v, &value);
+  }
+
+  g_array_free (rates, TRUE);
+  g_array_free (chans, TRUE);
+
+  pad_template = gst_static_pad_template_get (&sndio_sink_factory);
+  sndiosink->cur_caps =
+      gst_caps_copy (gst_pad_template_get_caps (pad_template));
+  gst_object_unref (pad_template);
+
+  for (i = 0; i < sndiosink->cur_caps->structs->len; i++) {
+    GstStructure *s;
+
+    s = gst_caps_get_structure (sndiosink->cur_caps, i);
+    gst_structure_set (s, "endianness", G_TYPE_INT, par.le ? 1234 : 4321, NULL);
+    gst_structure_set (s, "signed", G_TYPE_BOOLEAN, par.sig ? TRUE : FALSE,
+        NULL);
+    gst_structure_set (s, "width", G_TYPE_INT, par.bits, NULL);
+    // gst_structure_set (s, "depth", G_TYPE_INT, par.bps * 8, NULL); /* XXX */
+    gst_structure_set_value (s, "rate", &rates_v);
+    gst_structure_set_value (s, "channels", &chans_v);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+couldnt_connect:
+  {
+    GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
+        (_("Could not establish connection to sndio")),
+        ("can't open connection to sndio"));
+    return FALSE;
+  }
+no_server_info:
+  {
+    GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
+        (_("Failed to query sndio capabilities")),
+        ("couldn't get sndio info!"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_sndiosink_close (GstAudioSink * asink)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
+
+  GST_DEBUG_OBJECT (sndiosink, "close");
+
+  gst_caps_replace (&sndiosink->cur_caps, NULL);
+  sio_close (sndiosink->hdl);
+  sndiosink->hdl = NULL;
+
+  return TRUE;
+}
+
+static void
+gst_sndiosink_cb (void *addr, int delta)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK ((GstAudioSink *) addr);
+
+  sndiosink->realpos += delta;
+
+  if (sndiosink->realpos >= sndiosink->playpos)
+    sndiosink->latency = 0;
+  else
+    sndiosink->latency = sndiosink->playpos - sndiosink->realpos;
+}
+
+static gboolean
+gst_sndiosink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
+  struct sio_par par;
+  int spec_bpf;
+
+  GST_DEBUG_OBJECT (sndiosink, "prepare");
+
+  sndiosink->playpos = sndiosink->realpos = sndiosink->latency = 0;
+
+  sio_initpar (&par);
+  par.sig = spec->sign;
+  par.le = !spec->bigend;
+  par.bits = spec->width;
+  // par.bps = spec->depth / 8;  /* XXX */
+  par.rate = spec->rate;
+  par.pchan = spec->channels;
+
+  spec_bpf = ((spec->width / 8) * spec->channels);
+
+  par.appbufsz = (spec->segsize * spec->segtotal) / spec_bpf;
+
+  if (!sio_setpar (sndiosink->hdl, &par))
+    goto cannot_configure;
+
+  sio_getpar (sndiosink->hdl, &par);
+
+  spec->sign = par.sig;
+  spec->bigend = !par.le;
+  spec->width = par.bits;
+  // spec->depth = par.bps * 8;  /* XXX */
+  spec->rate = par.rate;
+  spec->channels = par.pchan;
+
+  sndiosink->bpf = par.bps * par.pchan;
+
+  spec->segsize = par.round * par.pchan * par.bps;
+  spec->segtotal = par.bufsz / par.round;
+
+  /* FIXME: this is wrong for signed ints (and the
+   * audioringbuffers should do it for us anyway) */
+  spec->silence_sample[0] = 0;
+  spec->silence_sample[1] = 0;
+  spec->silence_sample[2] = 0;
+  spec->silence_sample[3] = 0;
+
+  sio_onmove (sndiosink->hdl, gst_sndiosink_cb, sndiosink);
+
+  if (!sio_start (sndiosink->hdl))
+    goto cannot_start;
+
+  GST_INFO_OBJECT (sndiosink, "successfully opened connection to sndio");
+
+  return TRUE;
+
+  /* ERRORS */
+cannot_configure:
+  {
+    GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
+        (_("Could not configure sndio")), ("can't configure sndio"));
+    return FALSE;
+  }
+cannot_start:
+  {
+    GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
+        (_("Could not start sndio")), ("can't start sndio"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_sndiosink_unprepare (GstAudioSink * asink)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
+
+  if (sndiosink->hdl == NULL)
+    return TRUE;
+
+  sio_stop (sndiosink->hdl);
+
+  return TRUE;
+}
+
+static guint
+gst_sndiosink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
+  guint done;
+
+  done = sio_write (sndiosink->hdl, data, length);
+
+  if (done == 0)
+    goto write_error;
+
+  sndiosink->playpos += (done / sndiosink->bpf);
+
+  data = (char *) data + done;
+
+  return done;
+
+  /* ERRORS */
+write_error:
+  {
+    GST_ELEMENT_ERROR (sndiosink, RESOURCE, WRITE,
+        ("Failed to write data to sndio"), GST_ERROR_SYSTEM);
+    return 0;
+  }
+}
+
+static guint
+gst_sndiosink_delay (GstAudioSink * asink)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
+
+  if (sndiosink->latency == (guint) - 1) {
+    GST_WARNING_OBJECT (asink, "couldn't get latency");
+    return 0;
+  }
+
+  GST_DEBUG_OBJECT (asink, "got latency: %u", sndiosink->latency);
+
+  return sndiosink->latency;
+}
+
+static void
+gst_sndiosink_reset (GstAudioSink * asink)
+{
+  /* no way to flush the buffers with sndio ? */
+
+  GST_DEBUG_OBJECT (asink, "reset called");
+}
+
+static void
+gst_sndiosink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (object);
+
+  switch (prop_id) {
+    case PROP_HOST:
+      g_free (sndiosink->host);
+      sndiosink->host = g_value_dup_string (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_sndiosink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstSndioSink *sndiosink = GST_SNDIOSINK (object);
+
+  switch (prop_id) {
+    case PROP_HOST:
+      g_value_set_string (value, sndiosink->host);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/sndio/sndiosink.h b/ext/sndio/sndiosink.h
new file mode 100644 (file)
index 0000000..25bb879
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef __GST_SNDIOSINK_H__
+#define __GST_SNDIOSINK_H__
+
+#include <sndio.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SNDIOSINK \
+  (gst_sndiosink_get_type())
+#define GST_SNDIOSINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SNDIOSINK,GstSndioSink))
+#define GST_SNDIOSINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SNDIOSINK,GstSndioSinkClass))
+#define GST_IS_SNDIOSINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SNDIOSINK))
+#define GST_IS_SNDIOSINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SNDIOSINK))
+
+typedef struct _GstSndioSink GstSndioSink;
+typedef struct _GstSndioSinkClass GstSndioSinkClass;
+
+struct _GstSndioSink {
+  GstAudioSink   sink;
+
+  struct sio_hdl *hdl;
+  gchar    *host;
+
+  /* bytes per frame */
+  int bpf;
+
+  /* frames counts */
+  volatile long long realpos;
+  volatile long long playpos;
+  volatile guint latency;
+
+  GstCaps  *cur_caps;
+};
+
+struct _GstSndioSinkClass {
+  GstAudioSinkClass parent_class;
+};
+
+GType gst_sndiosink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SNDIOSINK_H__ */
diff --git a/ext/sndio/sndiosrc.c b/ext/sndio/sndiosrc.c
new file mode 100644 (file)
index 0000000..43cf35a
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * SECTION:element-sndiosrc
+ * @see_also: #GstAutoAudioSrc
+ *
+ * <refsect2>
+ * <para>
+ * This element retrieves samples from a sound card using sndio.
+ * </para>
+ * <para>
+ * Simple example pipeline that records an Ogg/Vorbis file via sndio:
+ * <programlisting>
+ * gst-launch -v sndiosrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=foo.ogg 
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sndiosrc.h"
+#include <unistd.h>
+#include <errno.h>
+
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
+#define GST_CAT_DEFAULT gst_sndio_debug
+
+enum
+{
+  PROP_0,
+  PROP_HOST
+};
+
+static GstStaticPadTemplate sndio_src_factory =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw-int, "
+        "endianness = (int) { 1234, 4321 }, "
+        "signed = (boolean) { TRUE, FALSE }, "
+        "width = (int) { 8, 16, 24, 32 }, "
+        "depth = (int) { 8, 16, 24, 32 }, "
+        "rate = (int) [ 8000, 192000 ], "
+        "channels = (int) [ 1, 16 ] ")
+    );
+
+static void gst_sndiosrc_finalize (GObject * object);
+
+static GstCaps *gst_sndiosrc_getcaps (GstBaseSrc * bsrc);
+
+static gboolean gst_sndiosrc_open (GstAudioSrc * asrc);
+static gboolean gst_sndiosrc_close (GstAudioSrc * asrc);
+static gboolean gst_sndiosrc_prepare (GstAudioSrc * asrc,
+    GstRingBufferSpec * spec);
+static gboolean gst_sndiosrc_unprepare (GstAudioSrc * asrc);
+static guint gst_sndiosrc_read (GstAudioSrc * asrc, gpointer data,
+    guint length);
+static guint gst_sndiosrc_delay (GstAudioSrc * asrc);
+static void gst_sndiosrc_reset (GstAudioSrc * asrc);
+
+static void gst_sndiosrc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_sndiosrc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_sndiosrc_cb (void *addr, int delta);
+
+GST_BOILERPLATE (GstSndioSrc, gst_sndiosrc, GstAudioSrc,
+    GST_TYPE_AUDIO_SRC);
+
+static void
+gst_sndiosrc_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_set_details_simple (element_class,
+      "Sndio audio source",
+      "Source/Audio",
+      "Records audio through sndio",
+      "Jacob Meuser <jakemsr@sdf.lonestar.org>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sndio_src_factory));
+}
+
+static void
+gst_sndiosrc_class_init (GstSndioSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstBaseAudioSrcClass *gstbaseaudiosrc_class;
+  GstAudioSrcClass *gstaudiosrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
+  gstaudiosrc_class = (GstAudioSrcClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_sndiosrc_finalize;
+
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosrc_getcaps);
+
+  gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_sndiosrc_open);
+  gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_sndiosrc_close);
+  gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_prepare);
+  gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_unprepare);
+  gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_sndiosrc_read);
+  gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_sndiosrc_delay);
+  gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_sndiosrc_reset);
+
+  gobject_class->set_property = gst_sndiosrc_set_property;
+  gobject_class->get_property = gst_sndiosrc_get_property;
+
+  /* default value is filled in the _init method */
+  g_object_class_install_property (gobject_class, PROP_HOST,
+      g_param_spec_string ("host", "Host",
+          "Device or socket sndio will access", NULL, G_PARAM_READWRITE));
+}
+
+static void
+gst_sndiosrc_init (GstSndioSrc * sndiosrc, GstSndioSrcClass * klass)
+{
+  sndiosrc->hdl = NULL;
+  sndiosrc->host = g_strdup (g_getenv ("AUDIODEVICE"));
+}
+
+static void
+gst_sndiosrc_finalize (GObject * object)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
+
+  gst_caps_replace (&sndiosrc->cur_caps, NULL);
+  g_free (sndiosrc->host);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_sndiosrc_getcaps (GstBaseSrc * bsrc)
+{
+  GstSndioSrc *sndiosrc;
+
+  sndiosrc = GST_SNDIOSRC (bsrc);
+
+  /* no hdl, we're done with the template caps */
+  if (sndiosrc->cur_caps == NULL) {
+    GST_LOG_OBJECT (sndiosrc, "getcaps called, returning template caps");
+    return NULL;
+  }
+
+  GST_LOG_OBJECT (sndiosrc, "returning %" GST_PTR_FORMAT,
+      sndiosrc->cur_caps);
+
+  return gst_caps_ref (sndiosrc->cur_caps);
+}
+
+static gboolean
+gst_sndiosrc_open (GstAudioSrc * asrc)
+{
+  GstPadTemplate *pad_template;
+  GstSndioSrc *sndiosrc;
+  struct sio_par par;
+  struct sio_cap cap;
+  GArray *rates, *chans;
+  GValue rates_v = { 0 };
+  GValue chans_v = { 0 };
+  GValue value = { 0 };
+  struct sio_enc enc;
+  struct sio_conf conf;
+  int confs[SIO_NCONF];
+  int rate, chan;
+  int i, j, k;
+  int nconfs;
+
+  sndiosrc = GST_SNDIOSRC (asrc);
+
+  GST_DEBUG_OBJECT (sndiosrc, "open");
+
+  /* connect */
+  sndiosrc->hdl = sio_open (sndiosrc->host, SIO_REC, 0);
+
+  if (sndiosrc->hdl == NULL)
+    goto couldnt_connect;
+
+  /* Use sndio defaults as the only encodings, but get the supported
+   * sample rates and number of channels.
+   */
+
+  if (!sio_getpar (sndiosrc->hdl, &par))
+    goto no_server_info;
+
+  if (!sio_getcap (sndiosrc->hdl, &cap))
+    goto no_server_info;
+
+  rates = g_array_new (FALSE, FALSE, sizeof (int));
+  chans = g_array_new (FALSE, FALSE, sizeof (int));
+
+  /* find confs that have the default encoding */
+  nconfs = 0;
+  for (i = 0; i < cap.nconf; i++) {
+    for (j = 0; j < SIO_NENC; j++) {
+      if (cap.confs[i].enc & (1 << j)) {
+        enc = cap.enc[j];
+        if (enc.bits == par.bits && enc.sig == par.sig && enc.le == par.le) {
+          confs[nconfs] = i;
+          nconfs++;
+          break;
+        }
+      }
+    }
+  }
+
+  /* find the rates and channels of the confs that have the default encoding */
+  for (i = 0; i < nconfs; i++) {
+    conf = cap.confs[confs[i]];
+    /* rates */
+    for (j = 0; j < SIO_NRATE; j++) {
+      if (conf.rate & (1 << j)) {
+        rate = cap.rate[j];
+        for (k = 0; k < rates->len && rate; k++) {
+          if (rate == g_array_index (rates, int, k))
+              rate = 0;
+        }
+        /* add in ascending order */
+        if (rate) {
+          for (k = 0; k < rates->len; k++) {
+            if (rate < g_array_index (rates, int, k))
+            {
+              g_array_insert_val (rates, k, rate);
+              break;
+            }
+          }
+          if (k == rates->len)
+            g_array_append_val (rates, rate);
+        }
+      }
+    }
+    /* channels */
+    for (j = 0; j < SIO_NCHAN; j++) {
+      if (conf.rchan & (1 << j)) {
+        chan = cap.rchan[j];
+        for (k = 0; k < chans->len && chan; k++) {
+          if (chan == g_array_index (chans, int, k))
+              chan = 0;
+        }
+        /* add in ascending order */
+        if (chan) {
+          for (k = 0; k < chans->len; k++) {
+            if (chan < g_array_index (chans, int, k))
+            {
+              g_array_insert_val (chans, k, chan);
+              break;
+            }
+          }
+          if (k == chans->len)
+            g_array_append_val (chans, chan);
+        }
+      }
+    }
+  }
+  /* not sure how this can happen, but it might */
+  if (cap.nconf == 0) {
+    g_array_append_val (rates, par.rate);
+    g_array_append_val (chans, par.rchan);
+  }
+
+  g_value_init (&rates_v, GST_TYPE_LIST);
+  g_value_init (&chans_v, GST_TYPE_LIST);
+  g_value_init (&value, G_TYPE_INT);
+
+  for (i = 0; i < rates->len; i++) {
+    g_value_set_int (&value, g_array_index (rates, int, i));
+    gst_value_list_append_value (&rates_v, &value);
+  }
+  for (i = 0; i < chans->len; i++) {
+    g_value_set_int (&value, g_array_index (chans, int, i));
+    gst_value_list_append_value (&chans_v, &value);
+  }
+
+  g_array_free (rates, TRUE);
+  g_array_free (chans, TRUE);
+
+  pad_template = gst_static_pad_template_get (&sndio_src_factory);
+  sndiosrc->cur_caps =
+      gst_caps_copy (gst_pad_template_get_caps (pad_template));
+  gst_object_unref (pad_template);
+
+  for (i = 0; i < sndiosrc->cur_caps->structs->len; i++) {
+    GstStructure *s;
+
+    s = gst_caps_get_structure (sndiosrc->cur_caps, i);
+    gst_structure_set (s, "endianness", G_TYPE_INT, par.le ? 1234 : 4321, NULL);
+    gst_structure_set (s, "signed", G_TYPE_BOOLEAN, par.sig ? TRUE : FALSE,
+        NULL);
+    gst_structure_set (s, "width", G_TYPE_INT, par.bits, NULL);
+    // gst_structure_set (s, "depth", G_TYPE_INT, par.bps * 8, NULL); /* XXX */
+    gst_structure_set_value (s, "rate", &rates_v);
+    gst_structure_set_value (s, "channels", &chans_v);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+couldnt_connect:
+  {
+    GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
+        (_("Could not establish connection to sndio")),
+        ("can't open connection to sndio"));
+    return FALSE;
+  }
+no_server_info:
+  {
+    GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
+        (_("Failed to query sndio capabilities")),
+        ("couldn't get sndio info!"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_sndiosrc_close (GstAudioSrc * asrc)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
+
+  GST_DEBUG_OBJECT (sndiosrc, "close");
+
+  gst_caps_replace (&sndiosrc->cur_caps, NULL);
+  sio_close (sndiosrc->hdl);
+  sndiosrc->hdl = NULL;
+
+  return TRUE;
+}
+
+static void
+gst_sndiosrc_cb (void *addr, int delta)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC ((GstAudioSrc *) addr);
+
+  sndiosrc->realpos += delta;
+
+  if (sndiosrc->readpos >= sndiosrc->realpos)
+    sndiosrc->latency = 0;
+  else
+    sndiosrc->latency = sndiosrc->realpos - sndiosrc->readpos;
+}
+
+static gboolean
+gst_sndiosrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
+  struct sio_par par;
+  int spec_bpf;
+
+  GST_DEBUG_OBJECT (sndiosrc, "prepare");
+
+  sndiosrc->readpos = sndiosrc->realpos = sndiosrc->latency = 0;
+
+  sio_initpar (&par);
+  par.sig = spec->sign;
+  par.le = !spec->bigend;
+  par.bits = spec->width;
+  // par.bps = spec->depth / 8;  /* XXX */
+  par.rate = spec->rate;
+  par.rchan = spec->channels;
+
+  spec_bpf = ((spec->width / 8) * spec->channels);
+
+  par.round = spec->segsize / spec_bpf;
+  par.appbufsz = (spec->segsize * spec->segtotal) / spec_bpf;
+
+  if (!sio_setpar (sndiosrc->hdl, &par))
+    goto cannot_configure;
+
+  sio_getpar (sndiosrc->hdl, &par);
+
+  spec->sign = par.sig;
+  spec->bigend = !par.le;
+  spec->width = par.bits;
+  // spec->depth = par.bps * 8;  /* XXX */
+  spec->rate = par.rate;
+  spec->channels = par.rchan;
+
+  sndiosrc->bpf = par.bps * par.rchan;
+
+  spec->segsize = par.round * par.rchan * par.bps;
+  spec->segtotal = par.bufsz / par.round;
+
+  /* FIXME: this is wrong for signed ints (and the
+   * audioringbuffers should do it for us anyway) */
+  spec->silence_sample[0] = 0;
+  spec->silence_sample[1] = 0;
+  spec->silence_sample[2] = 0;
+  spec->silence_sample[3] = 0;
+
+  sio_onmove (sndiosrc->hdl, gst_sndiosrc_cb, sndiosrc);
+
+  if (!sio_start (sndiosrc->hdl))
+    goto cannot_start;
+
+  GST_INFO_OBJECT (sndiosrc, "successfully opened connection to sndio");
+
+  return TRUE;
+
+  /* ERRORS */
+cannot_configure:
+  {
+    GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
+        (_("Could not configure sndio")), ("can't configure sndio"));
+    return FALSE;
+  }
+cannot_start:
+  {
+    GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
+        (_("Could not start sndio")), ("can't start sndio"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_sndiosrc_unprepare (GstAudioSrc * asrc)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
+
+  if (sndiosrc->hdl == NULL)
+    return TRUE;
+
+  sio_stop (sndiosrc->hdl);
+
+  return TRUE;
+}
+
+static guint
+gst_sndiosrc_read (GstAudioSrc * asrc, gpointer data, guint length)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
+  guint done;
+
+  done = sio_read (sndiosrc->hdl, data, length);
+
+  if (done == 0)
+    goto read_error;
+
+  sndiosrc->readpos += (done / sndiosrc->bpf);
+
+  data = (char *) data + done;
+
+  return done;
+
+  /* ERRORS */
+read_error:
+  {
+    GST_ELEMENT_ERROR (sndiosrc, RESOURCE, READ,
+        ("Failed to read data from sndio"), GST_ERROR_SYSTEM);
+    return 0;
+  }
+}
+
+static guint
+gst_sndiosrc_delay (GstAudioSrc * asrc)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
+
+  if (sndiosrc->latency == (guint) - 1) {
+    GST_WARNING_OBJECT (asrc, "couldn't get latency");
+    return 0;
+  }
+
+  GST_DEBUG_OBJECT (asrc, "got latency: %u", sndiosrc->latency);
+
+  return sndiosrc->latency;
+}
+
+static void
+gst_sndiosrc_reset (GstAudioSrc * asrc)
+{
+  /* no way to flush the buffers with sndio ? */
+
+  GST_DEBUG_OBJECT (asrc, "reset called");
+}
+
+static void
+gst_sndiosrc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
+
+  switch (prop_id) {
+    case PROP_HOST:
+      g_free (sndiosrc->host);
+      sndiosrc->host = g_value_dup_string (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_sndiosrc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
+
+  switch (prop_id) {
+    case PROP_HOST:
+      g_value_set_string (value, sndiosrc->host);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/sndio/sndiosrc.h b/ext/sndio/sndiosrc.h
new file mode 100644 (file)
index 0000000..48e7a26
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef __GST_SNDIOSRC_H__
+#define __GST_SNDIOSRC_H__
+
+#include <sndio.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SNDIOSRC \
+  (gst_sndiosrc_get_type())
+#define GST_SNDIOSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SNDIOSRC,GstSndioSrc))
+#define GST_SNDIOSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SNDIOSRC,GstSndioSrcClass))
+#define GST_IS_SNDIOSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SNDIOSRC))
+#define GST_IS_SNDIOSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SNDIOSRC))
+
+typedef struct _GstSndioSrc GstSndioSrc;
+typedef struct _GstSndioSrcClass GstSndioSrcClass;
+
+struct _GstSndioSrc {
+  GstAudioSrc   src;
+
+  struct sio_hdl *hdl;
+  gchar    *host;
+
+  /* bytes per frame */
+  int bpf;
+
+  /* frames counts */
+  volatile long long realpos;
+  volatile long long readpos;
+  volatile guint latency;
+
+  GstCaps  *cur_caps;
+};
+
+struct _GstSndioSrcClass {
+  GstAudioSrcClass parent_class;
+};
+
+GType gst_sndiosrc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SNDIOSRC_H__ */