summaryrefslogtreecommitdiff
path: root/java/openjfx14/files/gstsndio.c
diff options
context:
space:
mode:
Diffstat (limited to 'java/openjfx14/files/gstsndio.c')
-rw-r--r--java/openjfx14/files/gstsndio.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/java/openjfx14/files/gstsndio.c b/java/openjfx14/files/gstsndio.c
new file mode 100644
index 000000000000..4ef2cf1b5fdc
--- /dev/null
+++ b/java/openjfx14/files/gstsndio.c
@@ -0,0 +1,396 @@
+/*
+ * 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);
+
+gboolean
+plugin_init_alsa (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_sndio_debug, "sndio", 0, "sndio plugins");
+
+ /* prefer sndiosink over pulsesink (GST_RANK_PRIMARY + 10) */
+ if (!gst_element_register (plugin, "bsdaudiosink", 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_alsa, 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);
+ }
+}