1190 lines
35 KiB
Diff
1190 lines
35 KiB
Diff
|
Source: OpenBSD ports
|
||
|
Upstream: No
|
||
|
Reason: sndio support
|
||
|
|
||
|
|
||
|
diff --git configure.ac configure.ac
|
||
|
index 1287583a6..5cb12c7db 100644
|
||
|
--- configure.ac
|
||
|
+++ configure.ac
|
||
|
@@ -634,6 +634,20 @@ AG_GST_CHECK_FEATURE(ALSA, [ALSA], alsa, [
|
||
|
])
|
||
|
])
|
||
|
|
||
|
+dnl *** sndio ***
|
||
|
+AG_GST_CHECK_FEATURE(SNDIO, [sndio audio], sndio, [
|
||
|
+ AC_CHECK_HEADER(sndio.h, HAVE_SNDIO="yes", HAVE_SNDIO="no")
|
||
|
+ if test $HAVE_SNDIO = yes
|
||
|
+ then
|
||
|
+ AC_CHECK_LIB(sndio, sio_open, HAVE_SNDIO="yes", HAVE_SNDIO="no", [])
|
||
|
+ if test $HAVE_SNDIO = yes
|
||
|
+ then
|
||
|
+ SNDIO_LIBS=-lsndio
|
||
|
+ AC_SUBST(SNDIO_LIBS)
|
||
|
+ fi
|
||
|
+ fi
|
||
|
+])
|
||
|
+
|
||
|
dnl *** CDParanoia ***
|
||
|
dnl Note: upstream has a pkg-config file only in post-10.2 SVN so far
|
||
|
translit(dnm, m, l) AM_CONDITIONAL(USE_CDPARANOIA, true)
|
||
|
@@ -789,6 +803,7 @@ else
|
||
|
dnl not building plugins with external dependencies,
|
||
|
dnl but we still need to set the conditionals
|
||
|
AM_CONDITIONAL(USE_ALSA, false)
|
||
|
+AM_CONDITIONAL(USE_SNDIO, false)
|
||
|
AM_CONDITIONAL(USE_CDPARANOIA, false)
|
||
|
AM_CONDITIONAL(USE_GL, false)
|
||
|
AM_CONDITIONAL(USE_IVORBIS, false)
|
||
|
@@ -930,6 +945,7 @@ sys/ximage/Makefile
|
||
|
sys/xvimage/Makefile
|
||
|
ext/Makefile
|
||
|
ext/alsa/Makefile
|
||
|
+ext/sndio/Makefile
|
||
|
ext/cdparanoia/Makefile
|
||
|
ext/gl/Makefile
|
||
|
ext/libvisual/Makefile
|
||
|
diff --git ext/Makefile.am ext/Makefile.am
|
||
|
index c70b212d6..c28b8a3ea 100644
|
||
|
--- ext/Makefile.am
|
||
|
+++ ext/Makefile.am
|
||
|
@@ -4,6 +4,12 @@ else
|
||
|
ALSA_DIR=
|
||
|
endif
|
||
|
|
||
|
+if USE_SNDIO
|
||
|
+SNDIO_DIR=sndio
|
||
|
+else
|
||
|
+SNDIO_DIR=
|
||
|
+endif
|
||
|
+
|
||
|
if USE_CDPARANOIA
|
||
|
CDPARANOIA_DIR=cdparanoia
|
||
|
else
|
||
|
@@ -62,6 +68,7 @@ endif
|
||
|
|
||
|
SUBDIRS = \
|
||
|
$(ALSA_DIR) \
|
||
|
+ $(SNDIO_DIR) \
|
||
|
$(CDPARANOIA_DIR) \
|
||
|
$(GL_DIR) \
|
||
|
$(LIBVISUAL_DIR) \
|
||
|
@@ -73,6 +80,7 @@ SUBDIRS = \
|
||
|
|
||
|
DIST_SUBDIRS = \
|
||
|
alsa \
|
||
|
+ sndio \
|
||
|
cdparanoia \
|
||
|
gl \
|
||
|
libvisual \
|
||
|
diff --git ext/sndio/Makefile.am ext/sndio/Makefile.am
|
||
|
new file mode 100644
|
||
|
index 000000000..7b782de8a
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/Makefile.am
|
||
|
@@ -0,0 +1,24 @@
|
||
|
+plugin_LTLIBRARIES = libgstsndio.la
|
||
|
+
|
||
|
+libgstsndio_la_SOURCES = \
|
||
|
+ gstsndio.c \
|
||
|
+ sndiosink.c \
|
||
|
+ sndiosrc.c
|
||
|
+
|
||
|
+libgstsndio_la_CFLAGS = \
|
||
|
+ $(GST_PLUGINS_BASE_CFLAGS) \
|
||
|
+ $(GST_BASE_CFLAGS) \
|
||
|
+ $(GST_CFLAGS)
|
||
|
+ $(SNDIO_CFLAGS)
|
||
|
+libgstsndio_la_LIBADD = \
|
||
|
+ $(top_builddir)/gst-libs/gst/audio/libgstaudio-$(GST_API_VERSION).la \
|
||
|
+ $(GST_BASE_LIBS) \
|
||
|
+ $(SNDIO_LIBS)
|
||
|
+
|
||
|
+libgstsndio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||
|
+libgstsndio_la_LIBTOOLFLAGS = --tag=disable-static
|
||
|
+
|
||
|
+noinst_HEADERS = \
|
||
|
+ gstsndio.h \
|
||
|
+ sndiosink.h \
|
||
|
+ sndiosrc.h
|
||
|
diff --git ext/sndio/gstsndio.c ext/sndio/gstsndio.c
|
||
|
new file mode 100644
|
||
|
index 000000000..2321dc208
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/gstsndio.c
|
||
|
@@ -0,0 +1,401 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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 <stdio.h>
|
||
|
+#include "gstsndio.h"
|
||
|
+
|
||
|
+GST_DEBUG_CATEGORY (gst_sndio_debug);
|
||
|
+#define GST_CAT_DEFAULT gst_sndio_debug
|
||
|
+
|
||
|
+GType gst_sndiosink_get_type (void);
|
||
|
+GType gst_sndiosrc_get_type (void);
|
||
|
+
|
||
|
+static gboolean
|
||
|
+plugin_init (GstPlugin * plugin)
|
||
|
+{
|
||
|
+ GST_DEBUG_CATEGORY_INIT (gst_sndio_debug, "sndio", 0, "sndio plugins");
|
||
|
+
|
||
|
+ /* prefer sndiosrc over pulsesrc (GST_RANK_PRIMARY + 10) */
|
||
|
+ if (!gst_element_register (plugin, "sndiosrc", GST_RANK_PRIMARY + 20,
|
||
|
+ gst_sndiosrc_get_type()))
|
||
|
+ return FALSE;
|
||
|
+ /* prefer sndiosink over pulsesink (GST_RANK_PRIMARY + 10) */
|
||
|
+ if (!gst_element_register (plugin, "sndiosink", GST_RANK_PRIMARY + 20,
|
||
|
+ gst_sndiosink_get_type()))
|
||
|
+ return FALSE;
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||
|
+ GST_VERSION_MINOR,
|
||
|
+ sndio,
|
||
|
+ "sndio plugin library",
|
||
|
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
||
|
+
|
||
|
+/*
|
||
|
+ * common code to src and sink
|
||
|
+ */
|
||
|
+
|
||
|
+void
|
||
|
+gst_sndio_init (struct gstsndio *sio, GObject *obj)
|
||
|
+{
|
||
|
+ sio->obj = obj;
|
||
|
+ sio->hdl = NULL;
|
||
|
+ sio->device = g_strdup (SIO_DEVANY);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gst_sndio_finalize (struct gstsndio *sio)
|
||
|
+{
|
||
|
+ gst_caps_replace (&sio->cur_caps, NULL);
|
||
|
+ g_free (sio->device);
|
||
|
+}
|
||
|
+
|
||
|
+GstCaps *
|
||
|
+gst_sndio_getcaps (struct gstsndio *sio, GstCaps * filter)
|
||
|
+{
|
||
|
+ if (sio->cur_caps == NULL) {
|
||
|
+ /* XXX */
|
||
|
+ GST_LOG_OBJECT (sio->obj, "getcaps called, returning template caps");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (sio->obj, "returning %" GST_PTR_FORMAT, sio->cur_caps);
|
||
|
+
|
||
|
+ if (filter) {
|
||
|
+ return gst_caps_intersect_full (filter,
|
||
|
+ sio->cur_caps, GST_CAPS_INTERSECT_FIRST);
|
||
|
+ } else {
|
||
|
+ return gst_caps_ref (sio->cur_caps);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndio_onvol (void *arg, unsigned int vol)
|
||
|
+{
|
||
|
+ struct gstsndio *sio = arg;
|
||
|
+ sio->volume = vol;
|
||
|
+ g_object_notify (G_OBJECT (sio->obj), "mute");
|
||
|
+ g_object_notify (G_OBJECT (sio->obj), "volume");
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+gst_sndio_open (struct gstsndio *sio, gint mode)
|
||
|
+{
|
||
|
+ GValue list = G_VALUE_INIT, item = G_VALUE_INIT;
|
||
|
+ GstStructure *s;
|
||
|
+ GstCaps *caps;
|
||
|
+ struct sio_enc *enc;
|
||
|
+ struct sio_cap cap;
|
||
|
+ char fmt[16];
|
||
|
+ int i, chan;
|
||
|
+
|
||
|
+ GST_DEBUG_OBJECT (sio->obj, "open");
|
||
|
+
|
||
|
+ sio->hdl = sio_open (sio->device, mode, 0);
|
||
|
+ if (sio->hdl == NULL) {
|
||
|
+ GST_ELEMENT_ERROR (sio->obj, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Couldn't open sndio device"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ sio->mode = mode;
|
||
|
+
|
||
|
+ if (!sio_getcap(sio->hdl, &cap)) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_WRITE,
|
||
|
+ ("Couldn't get device capabilities"), (NULL));
|
||
|
+ sio_close(sio->hdl);
|
||
|
+ sio->hdl = NULL;
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ if (cap.nconf == 0) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_WRITE,
|
||
|
+ ("Device has empty capabilities"), (NULL));
|
||
|
+ sio_close(sio->hdl);
|
||
|
+ sio->hdl = NULL;
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ sio_onvol (sio->hdl, gst_sndio_onvol, sio);
|
||
|
+
|
||
|
+ caps = gst_caps_new_empty ();
|
||
|
+ s = gst_structure_new ("audio/x-raw", (char *)NULL, (void *)NULL);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * scan supported rates
|
||
|
+ */
|
||
|
+ g_value_init (&list, GST_TYPE_LIST);
|
||
|
+ g_value_init (&item, G_TYPE_INT);
|
||
|
+ for (i = 0; i < SIO_NRATE; i++) {
|
||
|
+ if ((cap.confs[0].rate & (1 << i)) == 0)
|
||
|
+ continue;
|
||
|
+ g_value_set_int(&item, cap.rate[i]);
|
||
|
+ gst_value_list_append_value (&list, &item);
|
||
|
+ }
|
||
|
+ gst_structure_set_value (s, "rate", &list);
|
||
|
+ g_value_unset (&item);
|
||
|
+ g_value_unset (&list);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * scan supported channels
|
||
|
+ */
|
||
|
+ g_value_init (&list, GST_TYPE_LIST);
|
||
|
+ g_value_init (&item, G_TYPE_INT);
|
||
|
+ chan = (mode == SIO_PLAY) ? cap.confs[0].pchan : cap.confs[0].rchan;
|
||
|
+ for (i = 0; i < SIO_NCHAN; i++) {
|
||
|
+ if ((chan & (1 << i)) == 0)
|
||
|
+ continue;
|
||
|
+ g_value_set_int(&item, (mode == SIO_PLAY) ? cap.pchan[i] : cap.rchan[i]);
|
||
|
+ gst_value_list_append_value (&list, &item);
|
||
|
+ }
|
||
|
+ gst_structure_set_value (s, "channels", &list);
|
||
|
+ g_value_unset (&item);
|
||
|
+ g_value_unset (&list);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * scan supported encodings
|
||
|
+ */
|
||
|
+ g_value_init (&list, GST_TYPE_LIST);
|
||
|
+ g_value_init (&item, G_TYPE_STRING);
|
||
|
+ for (i = 0; i < SIO_NENC; i++) {
|
||
|
+ if ((cap.confs[0].enc & (1 << i)) == 0)
|
||
|
+ continue;
|
||
|
+ enc = cap.enc + i;
|
||
|
+ if (enc->bits % 8 != 0)
|
||
|
+ continue;
|
||
|
+ if (enc->bits < enc->bps * 8 && enc->msb)
|
||
|
+ continue;
|
||
|
+ if (enc->bits == enc->bps * 8) {
|
||
|
+ snprintf(fmt, sizeof(fmt), "%s%u%s",
|
||
|
+ enc->sig ? "S" : "U",
|
||
|
+ enc->bits,
|
||
|
+ enc->bps > 1 ? (enc->le ? "LE" : "BE") : "");
|
||
|
+ } else {
|
||
|
+ snprintf(fmt, sizeof(fmt), "%s%u_%u%s",
|
||
|
+ enc->sig ? "S" : "U",
|
||
|
+ enc->bits,
|
||
|
+ enc->bps * 8,
|
||
|
+ enc->bps > 1 ? (enc->le ? "LE" : "BE") : "");
|
||
|
+ }
|
||
|
+ g_value_set_string(&item, fmt);
|
||
|
+ gst_value_list_append_value (&list, &item);
|
||
|
+ }
|
||
|
+ gst_structure_set_value (s, "format", &list);
|
||
|
+ g_value_unset (&item);
|
||
|
+ g_value_unset (&list);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * add the only supported layout: interleaved
|
||
|
+ */
|
||
|
+ g_value_init (&item, G_TYPE_STRING);
|
||
|
+ g_value_set_string(&item, "interleaved");
|
||
|
+ gst_structure_set_value (s, "layout", &item);
|
||
|
+ g_value_unset (&item);
|
||
|
+
|
||
|
+ gst_caps_append_structure (caps, s);
|
||
|
+ sio->cur_caps = caps;
|
||
|
+ GST_DEBUG ("caps are %s", gst_caps_to_string(caps));
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+gst_sndio_close (struct gstsndio *sio)
|
||
|
+{
|
||
|
+ GST_DEBUG_OBJECT (sio->obj, "close");
|
||
|
+
|
||
|
+ gst_caps_replace (&sio->cur_caps, NULL);
|
||
|
+ sio_close (sio->hdl);
|
||
|
+ sio->hdl = NULL;
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndio_cb (void *addr, int delta)
|
||
|
+{
|
||
|
+ struct gstsndio *sio = addr;
|
||
|
+
|
||
|
+ delta *= sio->bpf;
|
||
|
+ if (sio->mode == SIO_PLAY)
|
||
|
+ sio->delay -= delta;
|
||
|
+ else
|
||
|
+ sio->delay += delta;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+gst_sndio_prepare (struct gstsndio *sio, GstAudioRingBufferSpec *spec)
|
||
|
+{
|
||
|
+ struct sio_par par, retpar;
|
||
|
+ unsigned nchannels;
|
||
|
+
|
||
|
+ GST_DEBUG_OBJECT (sio, "prepare");
|
||
|
+
|
||
|
+ if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Only raw buffer format supported by sndio"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ if (!GST_AUDIO_INFO_IS_INTEGER(&spec->info)) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Only integer format supported"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ if (GST_AUDIO_INFO_DEPTH(&spec->info) % 8) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Only depths multiple of 8 are supported"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ sio_initpar (&par);
|
||
|
+ switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
|
||
|
+ case GST_AUDIO_FORMAT_S8:
|
||
|
+ case GST_AUDIO_FORMAT_U8:
|
||
|
+ case GST_AUDIO_FORMAT_S16LE:
|
||
|
+ case GST_AUDIO_FORMAT_S16BE:
|
||
|
+ case GST_AUDIO_FORMAT_U16LE:
|
||
|
+ case GST_AUDIO_FORMAT_U16BE:
|
||
|
+ case GST_AUDIO_FORMAT_S32LE:
|
||
|
+ case GST_AUDIO_FORMAT_S32BE:
|
||
|
+ case GST_AUDIO_FORMAT_U32LE:
|
||
|
+ case GST_AUDIO_FORMAT_U32BE:
|
||
|
+ case GST_AUDIO_FORMAT_S24_32LE:
|
||
|
+ case GST_AUDIO_FORMAT_S24_32BE:
|
||
|
+ case GST_AUDIO_FORMAT_U24_32LE:
|
||
|
+ case GST_AUDIO_FORMAT_U24_32BE:
|
||
|
+ case GST_AUDIO_FORMAT_S24LE:
|
||
|
+ case GST_AUDIO_FORMAT_S24BE:
|
||
|
+ case GST_AUDIO_FORMAT_U24LE:
|
||
|
+ case GST_AUDIO_FORMAT_U24BE:
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Unsupported audio format"),
|
||
|
+ ("format = %d", GST_AUDIO_INFO_FORMAT (&spec->info)));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ par.sig = GST_AUDIO_INFO_IS_SIGNED(&spec->info);
|
||
|
+ par.bits = GST_AUDIO_INFO_WIDTH(&spec->info);
|
||
|
+ par.bps = GST_AUDIO_INFO_DEPTH(&spec->info) / 8;
|
||
|
+ if (par.bps > 1)
|
||
|
+ par.le = GST_AUDIO_INFO_IS_LITTLE_ENDIAN(&spec->info);
|
||
|
+ if (par.bits < par.bps * 8)
|
||
|
+ par.msb = 0;
|
||
|
+ par.rate = GST_AUDIO_INFO_RATE(&spec->info);
|
||
|
+ if (sio->mode == SIO_PLAY)
|
||
|
+ par.pchan = GST_AUDIO_INFO_CHANNELS(&spec->info);
|
||
|
+ else
|
||
|
+ par.rchan = GST_AUDIO_INFO_CHANNELS(&spec->info);
|
||
|
+ par.round = par.rate / 1000000. * spec->latency_time;
|
||
|
+ par.appbufsz = par.rate / 1000000. * spec->buffer_time;
|
||
|
+
|
||
|
+ if (!sio_setpar (sio->hdl, &par)) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_WRITE,
|
||
|
+ ("Unsupported audio encoding"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ if (!sio_getpar (sio->hdl, &retpar)) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_WRITE,
|
||
|
+ ("Couldn't get audio device parameters"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+#if 0
|
||
|
+ GST_DEBUG ("format = %s, "
|
||
|
+ "requested: sig = %d, bits = %d, bps = %d, le = %d, msb = %d, "
|
||
|
+ "rate = %d, pchan = %d, round = %d, appbufsz = %d; "
|
||
|
+ "returned: sig = %d, bits = %d, bps = %d, le = %d, msb = %d, "
|
||
|
+ "rate = %d, pchan = %d, round = %d, appbufsz = %d, bufsz = %d",
|
||
|
+ GST_AUDIO_INFO_NAME(&spec->info),
|
||
|
+ par.sig, par.bits, par.bps, par.le, par.msb,
|
||
|
+ par.rate, par.pchan, par.round, par.appbufsz,
|
||
|
+ retpar.sig, retpar.bits, retpar.bps, retpar.le, retpar.msb,
|
||
|
+ retpar.rate, retpar.pchan, retpar.round, retpar.appbufsz, retpar.bufsz);
|
||
|
+#endif
|
||
|
+ if (par.bits != retpar.bits ||
|
||
|
+ par.bps != retpar.bps ||
|
||
|
+ par.rate != retpar.rate ||
|
||
|
+ (sio->mode == SIO_PLAY && par.pchan != retpar.pchan) ||
|
||
|
+ (sio->mode == SIO_REC && par.rchan != retpar.rchan) ||
|
||
|
+ (par.bps > 1 && par.le != retpar.le) ||
|
||
|
+ (par.bits < par.bps * 8 && par.msb != retpar.msb)) {
|
||
|
+ GST_ELEMENT_ERROR (sio, RESOURCE, OPEN_WRITE,
|
||
|
+ ("Audio device refused requested parameters"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ nchannels = (sio->mode == SIO_PLAY) ? retpar.pchan : retpar.rchan;
|
||
|
+ spec->segsize = retpar.round * retpar.bps * nchannels;
|
||
|
+ spec->segtotal = retpar.bufsz / retpar.round;
|
||
|
+ sio->bpf = retpar.bps * nchannels;
|
||
|
+ sio->delay = 0;
|
||
|
+ sio_onmove (sio->hdl, gst_sndio_cb, sio);
|
||
|
+
|
||
|
+ if (!sio_start (sio->hdl)) {
|
||
|
+ GST_ELEMENT_ERROR (sio->obj, RESOURCE, OPEN_READ_WRITE,
|
||
|
+ ("Could not start sndio"), (NULL));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+gst_sndio_unprepare (struct gstsndio *sio)
|
||
|
+{
|
||
|
+ if (sio->hdl)
|
||
|
+ sio_stop (sio->hdl);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gst_sndio_set_property (struct gstsndio *sio, guint prop_id,
|
||
|
+ const GValue * value, GParamSpec * pspec)
|
||
|
+{
|
||
|
+ switch (prop_id) {
|
||
|
+ case PROP_DEVICE:
|
||
|
+ g_free (sio->device);
|
||
|
+ sio->device = g_value_dup_string (value);
|
||
|
+ break;
|
||
|
+ case PROP_VOLUME:
|
||
|
+ sio_setvol (sio->hdl, g_value_get_double (value) * SIO_MAXVOL);
|
||
|
+ break;
|
||
|
+ case PROP_MUTE:
|
||
|
+ if (g_value_get_boolean (value))
|
||
|
+ sio_setvol (sio->hdl, 0);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gst_sndio_get_property (struct gstsndio *sio, guint prop_id,
|
||
|
+ GValue * value, GParamSpec * pspec)
|
||
|
+{
|
||
|
+ switch (prop_id) {
|
||
|
+ case PROP_DEVICE:
|
||
|
+ g_value_set_string (value, sio->device);
|
||
|
+ break;
|
||
|
+ case PROP_VOLUME:
|
||
|
+ g_value_set_double (value, (gdouble)sio->volume / SIO_MAXVOL);
|
||
|
+ break;
|
||
|
+ case PROP_MUTE:
|
||
|
+ g_value_set_boolean (value, (sio->volume == 0));
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (sio->obj, prop_id, pspec);
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git ext/sndio/gstsndio.h ext/sndio/gstsndio.h
|
||
|
new file mode 100644
|
||
|
index 000000000..77ec4e6f8
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/gstsndio.h
|
||
|
@@ -0,0 +1,78 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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_SNDIO_H__
|
||
|
+#define __GST_SNDIO_H__
|
||
|
+
|
||
|
+#include <sndio.h>
|
||
|
+#include <gst/gst.h>
|
||
|
+#include <gst/audio/gstaudiosink.h>
|
||
|
+#include <gst/audio/gstaudiosrc.h>
|
||
|
+#include <gst/audio/streamvolume.h>
|
||
|
+
|
||
|
+enum
|
||
|
+{
|
||
|
+ PROP_0,
|
||
|
+ PROP_DEVICE,
|
||
|
+ PROP_VOLUME,
|
||
|
+ PROP_MUTE
|
||
|
+};
|
||
|
+
|
||
|
+#define GST_SNDIO_CAPS_STRING \
|
||
|
+ "audio/x-raw, " \
|
||
|
+ "format = (string) { " \
|
||
|
+ "S8, U8, " \
|
||
|
+ "S16LE, S16BE, U16LE, U16BE, " \
|
||
|
+ "S32LE, S32BE, U32LE, U32BE, " \
|
||
|
+ "S24_32LE, S24_32BE, U24_32LE, " \
|
||
|
+ "U24_32BE, S24LE, S24BE, U24LE, U24BE " \
|
||
|
+ "}, " \
|
||
|
+ "layout = (string) interleaved, " \
|
||
|
+ "rate = (int) [ 8000, 192000 ], " \
|
||
|
+ "channels = (int) [1, 16]"
|
||
|
+
|
||
|
+/*
|
||
|
+ * data common to src and sink
|
||
|
+ */
|
||
|
+struct gstsndio {
|
||
|
+ struct sio_hdl *hdl;
|
||
|
+ gchar *device;
|
||
|
+ gint mode;
|
||
|
+ gint bpf; /* bytes per frame */
|
||
|
+ gint delay; /* bytes stored in the audio fifo */
|
||
|
+ guint volume; /* volume level */
|
||
|
+ GstCaps *cur_caps; /* saved capabilities of opened device */
|
||
|
+ GObject *obj; /* for logging */
|
||
|
+};
|
||
|
+
|
||
|
+#define GST_SNDIO_DELAY(s) ((s)->delay / (s)->bpf)
|
||
|
+
|
||
|
+void gst_sndio_init (struct gstsndio *sio, GObject *obj);
|
||
|
+void gst_sndio_finalize (struct gstsndio *sio);
|
||
|
+GstCaps *gst_sndio_getcaps (struct gstsndio *sio, GstCaps * filter);
|
||
|
+gboolean gst_sndio_open (struct gstsndio *sio, gint mode);
|
||
|
+gboolean gst_sndio_close (struct gstsndio *sio);
|
||
|
+gboolean gst_sndio_prepare (struct gstsndio *sio, GstAudioRingBufferSpec *spec);
|
||
|
+gboolean gst_sndio_unprepare (struct gstsndio *sio);
|
||
|
+void gst_sndio_set_property (struct gstsndio *sio, guint prop_id,
|
||
|
+ const GValue * value, GParamSpec * pspec);
|
||
|
+void gst_sndio_get_property (struct gstsndio *sio, guint prop_id,
|
||
|
+ GValue * value, GParamSpec * pspec);
|
||
|
+
|
||
|
+int gst_sndio_setpar(gpointer sio, GstAudioRingBufferSpec * spec,
|
||
|
+ int mode, struct sio_hdl *hdl);
|
||
|
+GstCaps *gst_sndio_caps (gpointer sio, int mode, struct sio_hdl *hdl);
|
||
|
+
|
||
|
+#endif
|
||
|
diff --git ext/sndio/sndiosink.c ext/sndio/sndiosink.c
|
||
|
new file mode 100644
|
||
|
index 000000000..cc68bd29d
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/sndiosink.c
|
||
|
@@ -0,0 +1,226 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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"
|
||
|
+
|
||
|
+GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
|
||
|
+#define GST_CAT_DEFAULT gst_sndio_debug
|
||
|
+
|
||
|
+#define gst_sndiosink_parent_class parent_class
|
||
|
+
|
||
|
+static GstStaticPadTemplate sndiosink_factory =
|
||
|
+ GST_STATIC_PAD_TEMPLATE ("sink",
|
||
|
+ GST_PAD_SINK,
|
||
|
+ GST_PAD_ALWAYS,
|
||
|
+ GST_STATIC_CAPS (GST_SNDIO_CAPS_STRING)
|
||
|
+ );
|
||
|
+
|
||
|
+G_DEFINE_TYPE_WITH_CODE (GstSndioSink, gst_sndiosink, GST_TYPE_AUDIO_SINK,
|
||
|
+ G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
|
||
|
+
|
||
|
+static void gst_sndiosink_finalize (GObject * object);
|
||
|
+static GstCaps *gst_sndiosink_getcaps (GstBaseSink * bsink,
|
||
|
+ GstCaps * filter);
|
||
|
+static gboolean gst_sndiosink_open (GstAudioSink * asink);
|
||
|
+static gboolean gst_sndiosink_close (GstAudioSink * asink);
|
||
|
+static gboolean gst_sndiosink_prepare (GstAudioSink * asink,
|
||
|
+ GstAudioRingBufferSpec * spec);
|
||
|
+static gboolean gst_sndiosink_unprepare (GstAudioSink * asink);
|
||
|
+static gint 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_init (GstSndioSink * sink)
|
||
|
+{
|
||
|
+ gst_sndio_init (&sink->sndio, G_OBJECT(sink));
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosink_finalize (GObject * object)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (object);
|
||
|
+
|
||
|
+ gst_sndio_finalize (&sink->sndio);
|
||
|
+ G_OBJECT_CLASS (parent_class)->finalize (object);
|
||
|
+}
|
||
|
+
|
||
|
+static GstCaps *
|
||
|
+gst_sndiosink_getcaps (GstBaseSink * bsink, GstCaps * filter)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (bsink);
|
||
|
+
|
||
|
+ return gst_sndio_getcaps (&sink->sndio, filter);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosink_open (GstAudioSink * asink)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+
|
||
|
+ return gst_sndio_open (&sink->sndio, SIO_PLAY);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosink_close (GstAudioSink * asink)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+
|
||
|
+ return gst_sndio_close (&sink->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+
|
||
|
+ return gst_sndio_prepare (&sink->sndio, spec);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosink_unprepare (GstAudioSink * asink)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+
|
||
|
+ return gst_sndio_unprepare (&sink->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static gint
|
||
|
+gst_sndiosink_write (GstAudioSink * asink, gpointer data, guint length)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+ guint done;
|
||
|
+
|
||
|
+ if (length == 0)
|
||
|
+ return 0;
|
||
|
+ done = sio_write (sink->sndio.hdl, data, length);
|
||
|
+ if (done == 0) {
|
||
|
+ GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
|
||
|
+ ("Failed to write data to sndio"), (NULL));
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ sink->sndio.delay += done;
|
||
|
+ return done;
|
||
|
+}
|
||
|
+
|
||
|
+static guint
|
||
|
+gst_sndiosink_delay (GstAudioSink * asink)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (asink);
|
||
|
+
|
||
|
+ return GST_SNDIO_DELAY(&sink->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosink_reset (GstAudioSink * asink)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosink_set_property (GObject * object, guint prop_id,
|
||
|
+ const GValue * value, GParamSpec * pspec)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (object);
|
||
|
+
|
||
|
+ gst_sndio_set_property (&sink->sndio, prop_id, value, pspec);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosink_get_property (GObject * object, guint prop_id, GValue * value,
|
||
|
+ GParamSpec * pspec)
|
||
|
+{
|
||
|
+ GstSndioSink *sink = GST_SNDIOSINK (object);
|
||
|
+
|
||
|
+ gst_sndio_get_property (&sink->sndio, prop_id, value, pspec);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosink_class_init (GstSndioSinkClass * klass)
|
||
|
+{
|
||
|
+ GObjectClass *gobject_class;
|
||
|
+ GstElementClass *gstelement_class;
|
||
|
+ GstBaseSinkClass *gstbasesink_class;
|
||
|
+ GstAudioBaseSinkClass *gstbaseaudiosink_class;
|
||
|
+ GstAudioSinkClass *gstaudiosink_class;
|
||
|
+
|
||
|
+ gobject_class = (GObjectClass *) klass;
|
||
|
+ gstelement_class = (GstElementClass *) klass;
|
||
|
+ gstbasesink_class = (GstBaseSinkClass *) klass;
|
||
|
+ gstbaseaudiosink_class = (GstAudioBaseSinkClass *) klass;
|
||
|
+ gstaudiosink_class = (GstAudioSinkClass *) klass;
|
||
|
+
|
||
|
+ parent_class = g_type_class_peek_parent (klass);
|
||
|
+
|
||
|
+ gobject_class->finalize = gst_sndiosink_finalize;
|
||
|
+ gobject_class->get_property = gst_sndiosink_get_property;
|
||
|
+ gobject_class->set_property = gst_sndiosink_set_property;
|
||
|
+
|
||
|
+ gst_element_class_set_static_metadata (gstelement_class,
|
||
|
+ "Audio sink (sndio)", "Sink/Audio",
|
||
|
+ "Output to a sound card via sndio",
|
||
|
+ "Jacob Meuser <jakemsr@sdf.lonestar.org>");
|
||
|
+
|
||
|
+ gst_element_class_add_pad_template (gstelement_class,
|
||
|
+ gst_static_pad_template_get (&sndiosink_factory));
|
||
|
+
|
||
|
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosink_getcaps);
|
||
|
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sndiosink_open);
|
||
|
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosink_prepare);
|
||
|
+ gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_sndiosink_unprepare);
|
||
|
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sndiosink_close);
|
||
|
+ 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);
|
||
|
+
|
||
|
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
|
||
|
+ g_param_spec_string ("device", "Device",
|
||
|
+ "sndio device as defined in sndio(7)",
|
||
|
+ SIO_DEVANY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+ g_object_class_install_property (gobject_class, PROP_VOLUME,
|
||
|
+ g_param_spec_double ("volume", "Volume",
|
||
|
+ "Linear volume of this stream, 1.0=100%", 0.0, 1.0,
|
||
|
+ 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+ g_object_class_install_property (gobject_class, PROP_MUTE,
|
||
|
+ g_param_spec_boolean ("mute", "Mute",
|
||
|
+ "Mute state of this stream", FALSE,
|
||
|
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+}
|
||
|
diff --git ext/sndio/sndiosink.h ext/sndio/sndiosink.h
|
||
|
new file mode 100644
|
||
|
index 000000000..314e62210
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/sndiosink.h
|
||
|
@@ -0,0 +1,57 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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>
|
||
|
+#include "gstsndio.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 gstsndio sndio;
|
||
|
+};
|
||
|
+
|
||
|
+struct _GstSndioSinkClass {
|
||
|
+ GstAudioSinkClass parent_class;
|
||
|
+};
|
||
|
+
|
||
|
+GType gst_sndiosink_get_type (void);
|
||
|
+
|
||
|
+G_END_DECLS
|
||
|
+
|
||
|
+#endif /* __GST_SNDIOSINK_H__ */
|
||
|
diff --git ext/sndio/sndiosrc.c ext/sndio/sndiosrc.c
|
||
|
new file mode 100644
|
||
|
index 000000000..5b6d787c5
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/sndiosrc.c
|
||
|
@@ -0,0 +1,225 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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 "gstsndio.h"
|
||
|
+
|
||
|
+GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
|
||
|
+#define GST_CAT_DEFAULT gst_sndio_debug
|
||
|
+
|
||
|
+#define gst_sndiosrc_parent_class parent_class
|
||
|
+G_DEFINE_TYPE_WITH_CODE (GstSndioSrc, gst_sndiosrc, GST_TYPE_AUDIO_SRC,
|
||
|
+ G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
|
||
|
+
|
||
|
+static void gst_sndiosrc_finalize (GObject * object);
|
||
|
+static GstCaps *gst_sndiosrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
|
||
|
+static gboolean gst_sndiosrc_open (GstAudioSrc * asrc);
|
||
|
+static gboolean gst_sndiosrc_close (GstAudioSrc * asrc);
|
||
|
+static gboolean gst_sndiosrc_prepare (GstAudioSrc * asrc,
|
||
|
+ GstAudioRingBufferSpec * 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 GstStaticPadTemplate sndiosrc_factory =
|
||
|
+ GST_STATIC_PAD_TEMPLATE ("src",
|
||
|
+ GST_PAD_SRC,
|
||
|
+ GST_PAD_ALWAYS,
|
||
|
+ GST_STATIC_CAPS (GST_SNDIO_CAPS_STRING)
|
||
|
+ );
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_init (GstSndioSrc * src)
|
||
|
+{
|
||
|
+ gst_sndio_init (&src->sndio, G_OBJECT(src));
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_finalize (GObject * object)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (object);
|
||
|
+
|
||
|
+ gst_sndio_finalize (&src->sndio);
|
||
|
+ G_OBJECT_CLASS (parent_class)->finalize (object);
|
||
|
+}
|
||
|
+
|
||
|
+static GstCaps *
|
||
|
+gst_sndiosrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (bsrc);
|
||
|
+
|
||
|
+ return gst_sndio_getcaps (&src->sndio, filter);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosrc_open (GstAudioSrc * asrc)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+
|
||
|
+ return gst_sndio_open (&src->sndio, SIO_REC);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosrc_close (GstAudioSrc * asrc)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+
|
||
|
+ return gst_sndio_close (&src->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+
|
||
|
+ return gst_sndio_prepare (&src->sndio, spec);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+gst_sndiosrc_unprepare (GstAudioSrc * asrc)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+
|
||
|
+ return gst_sndio_unprepare (&src->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static guint
|
||
|
+gst_sndiosrc_read (GstAudioSrc * asrc, gpointer data, guint length)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+ guint done;
|
||
|
+
|
||
|
+ if (length == 0)
|
||
|
+ return 0;
|
||
|
+ done = sio_read (src->sndio.hdl, data, length);
|
||
|
+ if (done == 0) {
|
||
|
+ GST_ELEMENT_ERROR (src, RESOURCE, READ,
|
||
|
+ ("Failed to read data from sndio"), (NULL));
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ src->sndio.delay -= done;
|
||
|
+ return done;
|
||
|
+}
|
||
|
+
|
||
|
+static guint
|
||
|
+gst_sndiosrc_delay (GstAudioSrc * asrc)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (asrc);
|
||
|
+
|
||
|
+ return GST_SNDIO_DELAY(&src->sndio);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_reset (GstAudioSrc * asrc)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_set_property (GObject * object, guint prop_id,
|
||
|
+ const GValue * value, GParamSpec * pspec)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (object);
|
||
|
+
|
||
|
+ gst_sndio_set_property (&src->sndio, prop_id, value, pspec);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||
|
+ GParamSpec * pspec)
|
||
|
+{
|
||
|
+ GstSndioSrc *src = GST_SNDIOSRC (object);
|
||
|
+
|
||
|
+ gst_sndio_get_property (&src->sndio, prop_id, value, pspec);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gst_sndiosrc_class_init (GstSndioSrcClass * klass)
|
||
|
+{
|
||
|
+ GObjectClass *gobject_class;
|
||
|
+ GstElementClass *gstelement_class;
|
||
|
+ GstBaseSrcClass *gstbasesrc_class;
|
||
|
+ GstAudioBaseSrcClass *gstbaseaudiosrc_class;
|
||
|
+ GstAudioSrcClass *gstaudiosrc_class;
|
||
|
+ gobject_class = (GObjectClass *) klass;
|
||
|
+ gstelement_class = (GstElementClass *) klass;
|
||
|
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
|
||
|
+ gstbaseaudiosrc_class = (GstAudioBaseSrcClass *) klass;
|
||
|
+ gstaudiosrc_class = (GstAudioSrcClass *) klass;
|
||
|
+
|
||
|
+ parent_class = g_type_class_peek_parent (klass);
|
||
|
+
|
||
|
+ gobject_class->finalize = gst_sndiosrc_finalize;
|
||
|
+ gobject_class->get_property = gst_sndiosrc_get_property;
|
||
|
+ gobject_class->set_property = gst_sndiosrc_set_property;
|
||
|
+
|
||
|
+ gst_element_class_set_static_metadata (gstelement_class,
|
||
|
+ "Audio src (sndio)", "Src/Audio",
|
||
|
+ "Input from a sound card via sndio",
|
||
|
+ "Jacob Meuser <jakemsr@sdf.lonestar.org>");
|
||
|
+
|
||
|
+ gst_element_class_add_pad_template (gstelement_class,
|
||
|
+ gst_static_pad_template_get (&sndiosrc_factory));
|
||
|
+
|
||
|
+ gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosrc_getcaps);
|
||
|
+ gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_sndiosrc_open);
|
||
|
+ gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_prepare);
|
||
|
+ gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_unprepare);
|
||
|
+ gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_sndiosrc_close);
|
||
|
+ 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);
|
||
|
+
|
||
|
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
|
||
|
+ g_param_spec_string ("device", "Device",
|
||
|
+ "sndio device as defined in sndio(7)",
|
||
|
+ SIO_DEVANY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+ g_object_class_install_property (gobject_class, PROP_VOLUME,
|
||
|
+ g_param_spec_double ("volume", "Volume",
|
||
|
+ "Linear volume of this stream, 1.0=100%", 0.0, 1.0,
|
||
|
+ 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+ g_object_class_install_property (gobject_class, PROP_MUTE,
|
||
|
+ g_param_spec_boolean ("mute", "Mute",
|
||
|
+ "Mute state of this stream", FALSE,
|
||
|
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
+}
|
||
|
diff --git ext/sndio/sndiosrc.h ext/sndio/sndiosrc.h
|
||
|
new file mode 100644
|
||
|
index 000000000..83fd29ce4
|
||
|
--- /dev/null
|
||
|
+++ ext/sndio/sndiosrc.h
|
||
|
@@ -0,0 +1,57 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
|
||
|
+ * Copyright (C) 2012 Alexandre Ratchov <alex@caoua.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>
|
||
|
+#include "gstsndio.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 gstsndio sndio;
|
||
|
+};
|
||
|
+
|
||
|
+struct _GstSndioSrcClass {
|
||
|
+ GstAudioSrcClass parent_class;
|
||
|
+};
|
||
|
+
|
||
|
+GType gst_sndiosrc_get_type (void);
|
||
|
+
|
||
|
+G_END_DECLS
|
||
|
+
|
||
|
+#endif /* __GST_SNDIOSRC_H__ */
|