diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | docs/plugins/gst-plugins-bad-plugins-docs.sgml | 1 | ||||
-rw-r--r-- | docs/plugins/inspect/plugin-alsaspdif.xml | 28 | ||||
-rw-r--r-- | ext/Makefile.am | 8 | ||||
-rw-r--r-- | ext/alsaspdif/Makefile.am | 15 | ||||
-rw-r--r-- | ext/alsaspdif/alsaspdifsink.c | 846 | ||||
-rw-r--r-- | ext/alsaspdif/alsaspdifsink.h | 86 | ||||
-rw-r--r-- | gst-plugins-bad.spec.in | 1 | ||||
-rw-r--r-- | m4/Makefile.am | 1 | ||||
-rw-r--r-- | m4/gst-alsa.m4 | 150 |
11 files changed, 3 insertions, 1151 deletions
diff --git a/Makefile.am b/Makefile.am index 7b2b45688..ff0249420 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,11 +43,12 @@ include $(top_srcdir)/common/coverage/lcov.mak CRUFT_FILES = \ $(top_builddir)/common/shave \ $(top_builddir)/common/shave-libtool \ + $(top_builddir)/ext/alsaspdif/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/ext/ivorbis/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/aacparse/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/amrparse/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/flacparse/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/shapewipe/.libs/*.{so,dll,DLL,dylib} \ - $(top_builddir)/ext/ivorbis/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/imagefreeze/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/sys/oss4/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/tests/check/elements/capssetter \ @@ -62,6 +63,7 @@ CRUFT_DIRS = \ $(top_srcdir)/gst/imagefreeze \ $(top_srcdir)/gst/shapewipe \ $(top_srcdir)/tests/examples/shapewipe + $(top_srcdir)/ext/alsaspdif \ $(top_srcdir)/ext/ivorbis \ $(top_srcdir)/ext/metadata diff --git a/configure.ac b/configure.ac index 3397fbcf2..33ca0ba99 100644 --- a/configure.ac +++ b/configure.ac @@ -499,18 +499,6 @@ dnl keep this list sorted alphabetically ! if test "x$BUILD_EXTERNAL" = "xyes"; then -dnl *** alsa *** -translit(dnm, m, l) AM_CONDITIONAL(USE_ALSA, true) -AG_GST_CHECK_FEATURE(ALSA, [alsa plug-ins], gstalsa, [ - PKG_CHECK_MODULES(ALSA, alsa >= 0.9.1, [ - HAVE_ALSA="yes" - AC_SUBST(ALSA_CFLAGS) - AC_SUBST(ALSA_LIBS) - ], [ - AM_PATH_ALSA(0.9.1, HAVE_ALSA="yes", HAVE_ALSA="no") - ]) -]) - dnl *** assrender *** translit(dnm, m, l) AM_CONDITIONAL(USE_ASSRENDER, true) AG_GST_CHECK_FEATURE(ASSRENDER, [ASS/SSA renderer], assrender, [ @@ -1555,7 +1543,6 @@ 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_ASSRENDER, false) AM_CONDITIONAL(USE_AMRWB, false) AM_CONDITIONAL(USE_APEXSINK, false) @@ -1777,7 +1764,6 @@ tests/examples/scaletempo/Makefile tests/examples/switch/Makefile tests/examples/jack/Makefile tests/icles/Makefile -ext/alsaspdif/Makefile ext/amrwbenc/Makefile ext/assrender/Makefile ext/apexsink/Makefile diff --git a/docs/plugins/gst-plugins-bad-plugins-docs.sgml b/docs/plugins/gst-plugins-bad-plugins-docs.sgml index 387ba5d79..8a9b04eed 100644 --- a/docs/plugins/gst-plugins-bad-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-bad-plugins-docs.sgml @@ -138,7 +138,6 @@ <xi:include href="xml/plugin-audioparsersbad.xml" /> <xi:include href="xml/plugin-autoconvert.xml" /> <xi:include href="xml/plugin-legacyresample.xml" /> - <xi:include href="xml/plugin-alsaspdif.xml" /> <xi:include href="xml/plugin-amrwbenc.xml" /> <xi:include href="xml/plugin-assrender.xml" /> <xi:include href="xml/plugin-bayer.xml" /> diff --git a/docs/plugins/inspect/plugin-alsaspdif.xml b/docs/plugins/inspect/plugin-alsaspdif.xml deleted file mode 100644 index 92ae01a21..000000000 --- a/docs/plugins/inspect/plugin-alsaspdif.xml +++ /dev/null @@ -1,28 +0,0 @@ -<plugin> - <name>alsaspdif</name> - <description>Alsa plugin for S/PDIF output</description> - <filename>../../ext/alsaspdif/.libs/libgstalsaspdif.so</filename> - <basename>libgstalsaspdif.so</basename> - <version>0.10.20.1</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins git</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>alsaspdifsink</name> - <longname>S/PDIF ALSA audiosink</longname> - <class>Sink/Audio</class> - <description>Feeds audio to S/PDIF interfaces through the ALSA sound driver</description> - <author>Martin Soto <martinsoto@users.sourceforge.net>, Michael Smith <msmith@fluendo.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>audio/x-iec958</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/ext/Makefile.am b/ext/Makefile.am index 3893c6274..a9a7c8b5f 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -1,9 +1,3 @@ -if USE_ALSA -ALSASPDIF_DIR = alsaspdif -else -ALSASPDIF_DIR = -endif - if USE_ASSRENDER ASSRENDER_DIR = assrender else @@ -380,7 +374,6 @@ endif SUBDIRS=\ - $(ALSASPDIF_DIR) \ $(ASSRENDER_DIR) \ $(AMRWB_DIR) \ $(APEXSINK_DIR) \ @@ -444,7 +437,6 @@ SUBDIRS=\ $(RTMP_DIR) DIST_SUBDIRS = \ - alsaspdif \ amrwbenc \ assrender \ apexsink \ diff --git a/ext/alsaspdif/Makefile.am b/ext/alsaspdif/Makefile.am deleted file mode 100644 index b67470710..000000000 --- a/ext/alsaspdif/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -plugin_LTLIBRARIES = libgstalsaspdif.la - -# sources used to compile this plugin -libgstalsaspdif_la_SOURCES = alsaspdifsink.c - -# flags used to compile this plugin -# we use the GST_LIBS flags because we might be using plug-in libs -libgstalsaspdif_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(ALSA_CFLAGS) -libgstalsaspdif_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(GST_LIBS) $(ALSA_LIBS) -libgstalsaspdif_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstalsaspdif_la_LIBTOOLFLAGS = --tag=disable-static - -# headers we need but don't want installed -noinst_HEADERS = alsaspdifsink.h - diff --git a/ext/alsaspdif/alsaspdifsink.c b/ext/alsaspdif/alsaspdifsink.c deleted file mode 100644 index c0f5533c2..000000000 --- a/ext/alsaspdif/alsaspdifsink.c +++ /dev/null @@ -1,846 +0,0 @@ -/* Based on a plugin from Martin Soto's Seamless DVD Player. - * Copyright (C) 2003, 2004 Martin Soto <martinsoto@users.sourceforge.net> - * 2005-6 Michael Smith <msmith@fluendo.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <string.h> -#include <unistd.h> - -#include <gst/gst.h> -#include <gst/audio/gstaudioclock.h> -#include <gst/base/gstbasesink.h> - -#include "alsaspdifsink.h" - -GST_DEBUG_CATEGORY_STATIC (alsaspdifsink_debug); -#define GST_CAT_DEFAULT (alsaspdifsink_debug) - -/* The magic audio-type we pretend to be for AC3 output */ -#define AC3_CHANNELS 2 -#define AC3_BITS 16 - -/* Define AC3 FORMAT as big endian. Fall back to swapping - * on sound devices that don't support it */ -#define AC3_FORMAT_BE SND_PCM_FORMAT_S16_BE -#define AC3_FORMAT_LE SND_PCM_FORMAT_S16_LE - -/* The size in bytes of an IEC958 frame. */ -#define IEC958_FRAME_SIZE 6144 - -/* Size in bytes of an ALSA PCM frame (4, for this case). */ -#define ALSASPDIFSINK_BYTES_PER_FRAME ((AC3_BITS / 8) * AC3_CHANNELS) - -#define IEC958_SAMPLES_PER_FRAME (IEC958_FRAME_SIZE / ALSASPDIFSINK_BYTES_PER_FRAME) - -#if 0 -/* The duration of a single IEC958 frame. */ -#define IEC958_FRAME_DURATION (32 * GST_MSECOND) - -/* Maximal synchronization difference. Measures will be taken if - block timestamps differ from actual playing time in more than this - value. */ -#define MAX_SYNC_DIFF (IEC958_FRAME_DURATION * 0.8) - -/* Playing time for the given number of ALSA PCM frames. */ -#define ALSASPDIFSINK_TIME_PER_FRAMES(sink, frames) \ - (((GstClockTime) (frames) * GST_SECOND) / AC3_RATE) - -/* Number of ALSA PCM frames for the given playing time. */ -#define ALSASPDIFSINK_FRAMES_PER_TIME(sink, time) \ - (((GstClockTime) AC3_RATE * (time)) / GST_SECOND) -#endif - -/* AlsaSPDIFSink signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_CARD, - PROP_DEVICE -}; - -static GstStaticPadTemplate alsaspdifsink_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-iec958") - ); - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (alsaspdifsink_debug, "alsaspdifsink", 0, \ - "ALSA S/PDIF audio sink element"); - -GST_BOILERPLATE_FULL (AlsaSPDIFSink, alsaspdifsink, GstBaseSink, - GST_TYPE_BASE_SINK, _do_init); - -static void alsaspdifsink_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void alsaspdifsink_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean alsaspdifsink_event (GstBaseSink * bsink, GstEvent * event); -static GstFlowReturn alsaspdifsink_render (GstBaseSink * bsink, - GstBuffer * buf); -static void alsaspdifsink_get_times (GstBaseSink * bsink, GstBuffer * buffer, - GstClockTime * start, GstClockTime * end); -static gboolean alsaspdifsink_set_caps (GstBaseSink * bsink, GstCaps * caps); - -static gboolean alsaspdifsink_open (AlsaSPDIFSink * sink); -static void alsaspdifsink_close (AlsaSPDIFSink * sink); - -static GstClock *alsaspdifsink_provide_clock (GstElement * elem); -static GstClockTime alsaspdifsink_get_time (GstClock * clock, - gpointer user_data); -static void alsaspdifsink_dispose (GObject * object); -static void alsaspdifsink_finalize (GObject * object); - -static GstStateChangeReturn alsaspdifsink_change_state (GstElement * element, - GstStateChange transition); -static int alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink); -static gboolean alsaspdifsink_set_params (AlsaSPDIFSink * sink); -static snd_pcm_sframes_t alsaspdifsink_delay (AlsaSPDIFSink * sink); - -/* Alsa error handler to suppress messages from within the ALSA library */ -static void ignore_alsa_err (const char *file, int line, const char *function, - int err, const char *fmt, ...); - -static void -alsaspdifsink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, "S/PDIF ALSA audiosink", - "Sink/Audio", - "Feeds audio to S/PDIF interfaces through the ALSA sound driver", - "Martin Soto <martinsoto@users.sourceforge.net>, " - "Michael Smith <msmith@fluendo.com>"); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alsaspdifsink_sink_factory)); -} - -static void -alsaspdifsink_class_init (AlsaSPDIFSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - gobject_class->set_property = alsaspdifsink_set_property; - gobject_class->get_property = alsaspdifsink_get_property; - gobject_class->dispose = alsaspdifsink_dispose; - gobject_class->finalize = alsaspdifsink_finalize; - - gstelement_class->change_state = alsaspdifsink_change_state; - gstelement_class->provide_clock = alsaspdifsink_provide_clock; - - gstbasesink_class->event = alsaspdifsink_event; - gstbasesink_class->render = alsaspdifsink_render; - gstbasesink_class->get_times = alsaspdifsink_get_times; - gstbasesink_class->set_caps = alsaspdifsink_set_caps; - -#if 0 - /* We ignore the device property anyway, so don't install it - * we don't want the user supplying just any device string for us. - * At most we might want a card number and an iec958.%d device name - * to attempt */ - g_object_class_install_property (gobject_class, PROP_DEVICE, - g_param_spec_string ("device", "Device", - "ALSA device, as defined in an asound configuration file", - "default", G_PARAM_READWRITE)); -#endif - g_object_class_install_property (gobject_class, PROP_CARD, - g_param_spec_int ("card", "Card", - "ALSA card number for the SPDIF device to use", - 0, G_MAXINT, 0, G_PARAM_READWRITE)); - - snd_lib_error_set_handler (ignore_alsa_err); -} - -static void -alsaspdifsink_init (AlsaSPDIFSink * sink, AlsaSPDIFSinkClass * g_class) -{ - /* Create the provided clock. */ -#if GST_CHECK_VERSION(0, 10, 31) || (GST_CHECK_VERSION(0, 10, 30) && GST_VERSION_NANO > 0) - sink->clock = - gst_audio_clock_new_full ("clock", alsaspdifsink_get_time, - gst_object_ref (sink), (GDestroyNotify) gst_object_unref); -#else - sink->clock = gst_audio_clock_new ("clock", alsaspdifsink_get_time, sink); -#endif - - sink->card = 0; - sink->device = g_strdup ("default"); -} - -static void -alsaspdifsink_dispose (GObject * object) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (object); - - if (sink->clock) - gst_object_unref (sink->clock); - sink->clock = NULL; - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -alsaspdifsink_finalize (GObject * object) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (object); - - g_free (sink->device); - sink->device = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -alsaspdifsink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - AlsaSPDIFSink *sink; - - sink = ALSASPDIFSINK (object); - - switch (prop_id) { - /* - case PROP_DEVICE: - if(sink->device) - g_free(sink->device); - sink->device = g_strdup(g_value_get_string(value)); - break; - */ - case PROP_CARD: - sink->card = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -alsaspdifsink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - AlsaSPDIFSink *sink; - - sink = ALSASPDIFSINK (object); - - switch (prop_id) { - /* - case PROP_DEVICE: - g_value_set_string(value, sink->device); - break; - */ - case PROP_CARD: - g_value_set_int (value, sink->card); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -alsaspdifsink_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (bsink); - - if (!gst_structure_get_int (gst_caps_get_structure (caps, 0), "rate", - &sink->rate)) - sink->rate = 48000; - - if (!alsaspdifsink_set_params (sink)) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Cannot set ALSA hardware parameters"), GST_ERROR_SYSTEM); - return FALSE; - } - - return TRUE; -} - -static GstClock * -alsaspdifsink_provide_clock (GstElement * elem) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (elem); - - return GST_CLOCK (gst_object_ref (sink->clock)); -} - -static GstClockTime -alsaspdifsink_get_time (GstClock * clock, gpointer user_data) -{ - GstClockTime result; - snd_pcm_sframes_t raw, delay, samples; - AlsaSPDIFSink *sink = ALSASPDIFSINK (user_data); - - raw = samples = sink->frames * IEC958_SAMPLES_PER_FRAME; - delay = alsaspdifsink_delay (sink); - - if (samples > delay) - samples -= delay; - else - samples = 0; - - result = gst_util_uint64_scale_int (samples, GST_SECOND, sink->rate); - GST_LOG_OBJECT (sink, "Samples raw: %d, delay: %d, real: %d, " - "Time: %" GST_TIME_FORMAT, (int) raw, (int) delay, (int) samples, - GST_TIME_ARGS (result)); - return result; -} - -static gboolean -alsaspdifsink_open (AlsaSPDIFSink * sink) -{ - char *pcm_name = sink->device; - int err; - char devstr[256]; /* Storage for local 'default' device string */ - - /* - * Try and open our default iec958 device. Fall back to searching on card x - * if this fails, which should only happen on older alsa setups - */ - - /* The string will be one of these: - * SPDIF_CON: Non-audio flag not set: - * spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2} - * SPDIF_CON: Non-audio flag set: - * spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2} - */ - sprintf (devstr, - "iec958:{CARD %d AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}", - sink->card, - IEC958_AES0_NONAUDIO, - IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, - 0, IEC958_AES3_CON_FS_48000); - - GST_DEBUG_OBJECT (sink, "Generated device string \"%s\"", devstr); - pcm_name = devstr; - - err = snd_pcm_open (&(sink->pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0); - if (err < 0) { - GST_DEBUG_OBJECT (sink, - "Open failed for %s - searching for IEC958 manually\n", pcm_name); - - err = alsaspdifsink_find_pcm_device (sink); - if (err == 0 && sink->pcm == NULL) - goto open_failed; - } - if (err < 0) - goto failed; - - return TRUE; - - /* ERRORS */ -open_failed: - { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Could not open IEC958/SPDIF output device"), GST_ERROR_SYSTEM); - return FALSE; - } -failed: - { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("snd_pcm_open: %s", snd_strerror (err)), GST_ERROR_SYSTEM); - return FALSE; - } -} - -static gboolean -alsaspdifsink_set_params (AlsaSPDIFSink * sink) -{ - snd_pcm_hw_params_t *params; - unsigned int rate; - int err; - - snd_pcm_hw_params_malloc (¶ms); - - err = snd_pcm_hw_params_any (sink->pcm, params); - if (err < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Broken configuration for this PCM: " - "no configurations available"), GST_ERROR_SYSTEM); - goto __error; - } - - /* Set interleaved access. */ - err = snd_pcm_hw_params_set_access (sink->pcm, params, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Access type not available"), GST_ERROR_SYSTEM); - goto __error; - } - - err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_BE); - if (err < 0) { - /* Try LE output and swap data */ - GST_DEBUG_OBJECT (sink, "PCM format S16_BE not supported, trying S16_LE"); - err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_LE); - sink->need_swap = TRUE; - } else - sink->need_swap = FALSE; - - if (err < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Sample format not available"), GST_ERROR_SYSTEM); - goto __error; - } - - err = snd_pcm_hw_params_set_channels (sink->pcm, params, AC3_CHANNELS); - if (err < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Channels count not available"), GST_ERROR_SYSTEM); - goto __error; - } - - rate = sink->rate; - GST_DEBUG_OBJECT (sink, "Setting S/PDIF sample rate: %d", rate); - err = snd_pcm_hw_params_set_rate_near (sink->pcm, params, &rate, 0); - if (err != 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("Rate not available"), GST_ERROR_SYSTEM); - goto __error; - } - - err = snd_pcm_hw_params (sink->pcm, params); - if (err < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("PCM hw_params failed: %s", snd_strerror (err)), GST_ERROR_SYSTEM); - goto __error; - } - - snd_pcm_hw_params_free (params); - - return TRUE; - - /* ERRORS */ -__error: - { - snd_pcm_hw_params_free (params); - return FALSE; - } -} - -static void -alsaspdifsink_close (AlsaSPDIFSink * sink) -{ - if (sink->pcm) { - snd_pcm_close (sink->pcm); - sink->pcm = NULL; - } -} - -/* Try and find an IEC958 PCM device and mixer on card 0 and open it - * This function is only used on older ALSA installs that don't have the - * correct iec958 alias stuff set up, and relies on there being only - * one IEC958 PCM device (relies IEC958 in the device name) and one IEC958 - * mixer control for doing the settings. - */ -static int -alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink) -{ - int err = -1, dev, idx, count; - const gchar *ctl_name = "hw:0"; - const gchar *spdif_name = SND_CTL_NAME_IEC958 ("", PLAYBACK, NONE); - int card = sink->card; - gchar pcm_name[24]; - snd_pcm_t *pcm = NULL; - snd_ctl_t *ctl = NULL; - snd_ctl_card_info_t *info = NULL; - snd_ctl_elem_list_t *clist = NULL; - snd_ctl_elem_id_t *cid = NULL; - snd_pcm_info_t *pinfo = NULL; - - GST_WARNING ("Opening IEC958 named device failed. Trying to autodetect"); - - if ((err = snd_ctl_open (&ctl, ctl_name, card)) < 0) - return err; - - snd_ctl_card_info_malloc (&info); - snd_pcm_info_malloc (&pinfo); - - /* Find a mixer for IEC958 settings */ - snd_ctl_elem_list_malloc (&clist); - if ((err = snd_ctl_elem_list (ctl, clist)) < 0) - goto beach; - - if ((err = - snd_ctl_elem_list_alloc_space (clist, - snd_ctl_elem_list_get_count (clist))) < 0) - goto beach; - if ((err = snd_ctl_elem_list (ctl, clist)) < 0) - goto beach; - - count = snd_ctl_elem_list_get_used (clist); - for (idx = 0; idx < count; idx++) { - if (strstr (snd_ctl_elem_list_get_name (clist, idx), spdif_name) != NULL) - break; - } - if (idx == count) { - /* No SPDIF mixer availble */ - err = 0; - goto beach; - } - snd_ctl_elem_id_malloc (&cid); - snd_ctl_elem_list_get_id (clist, idx, cid); - - /* Now find a PCM device for IEC 958 */ - if ((err = snd_ctl_card_info (ctl, info)) < 0) - goto beach; - dev = -1; - do { - if (snd_ctl_pcm_next_device (ctl, &dev) < 0) - goto beach; - if (dev < 0) - break; /* No more devices */ - - /* Filter for playback devices */ - snd_pcm_info_set_device (pinfo, dev); - snd_pcm_info_set_subdevice (pinfo, 0); - snd_pcm_info_set_stream (pinfo, SND_PCM_STREAM_PLAYBACK); - if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) { - if (err != -ENOENT) - goto beach; /* Genuine error */ - - /* Device has no playback streams */ - continue; - } - if (strstr (snd_pcm_info_get_name (pinfo), "IEC958") == NULL) - continue; /* Not the device we are looking for */ - - count = snd_pcm_info_get_subdevices_count (pinfo); - GST_LOG_OBJECT (sink, "Device %d has %d subdevices\n", dev, - snd_pcm_info_get_subdevices_count (pinfo)); - for (idx = 0; idx < count; idx++) { - snd_pcm_info_set_subdevice (pinfo, idx); - - if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) - goto beach; - - g_assert (snd_pcm_info_get_stream (pinfo) == SND_PCM_STREAM_PLAYBACK); - - GST_LOG_OBJECT (sink, "Found playback stream on dev %d sub-d %d\n", dev, - idx); - - /* Found a suitable PCM device, let's open it */ - g_snprintf (pcm_name, 24, "hw:%d,%d", card, dev); - if ((err = - snd_pcm_open (&(pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) - goto beach; - - break; - } - } while (pcm == NULL); - - if (pcm != NULL) { - snd_ctl_elem_value_t *cval; - snd_aes_iec958_t iec958; - - /* Have a PCM device and a mixer, set things up */ - snd_ctl_elem_value_malloc (&cval); - snd_ctl_elem_value_set_id (cval, cid); - snd_ctl_elem_value_get_iec958 (cval, &iec958); - iec958.status[0] = IEC958_AES0_NONAUDIO; - iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER; - iec958.status[2] = 0; - iec958.status[3] = IEC958_AES3_CON_FS_48000; - snd_ctl_elem_value_set_iec958 (cval, &iec958); - snd_ctl_elem_value_free (cval); - - sink->pcm = pcm; - pcm = NULL; - err = 0; - } - -beach: - if (pcm) - snd_pcm_close (pcm); - if (clist) - snd_ctl_elem_list_clear (clist); - if (ctl) - snd_ctl_close (ctl); - if (clist) - snd_ctl_elem_list_free (clist); - if (cid) - snd_ctl_elem_id_free (cid); - if (info) - snd_ctl_card_info_free (info); - if (pinfo) - snd_pcm_info_free (pinfo); - return err; -} - -static void -alsaspdifsink_write_frame (AlsaSPDIFSink * sink, guchar * buf) -{ - snd_pcm_sframes_t res; - int num_frames = IEC958_FRAME_SIZE / ALSASPDIFSINK_BYTES_PER_FRAME; - - /* If we couldn't output big endian when we opened the devic, then - * we need to swap here */ - if (sink->need_swap) { - int i; - guchar tmp; - - for (i = 0; i < IEC958_FRAME_SIZE; i += 2) { - tmp = buf[i]; - buf[i] = buf[i + 1]; - buf[i + 1] = tmp; - } - } - - res = 0; - do { - if (res == -EPIPE) { - /* Underrun. */ - GST_INFO_OBJECT (sink, "buffer underrun"); - res = snd_pcm_prepare (sink->pcm); - } else if (res == -ESTRPIPE) { - /* Suspend. */ - while ((res = snd_pcm_resume (sink->pcm)) == -EAGAIN) { - GST_DEBUG_OBJECT (sink, "sleeping for suspend"); - g_usleep (100000); - } - - if (res < 0) { - res = snd_pcm_prepare (sink->pcm); - } - } - - if (res >= 0) { - res = snd_pcm_writei (sink->pcm, (void *) buf, num_frames); - } - - if (res > 0) { - num_frames -= res; - } - - } while (res == -EPIPE || num_frames > 0); - - sink->frames++; - - if (res < 0) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - ("writei returned error: %s", snd_strerror (res)), GST_ERROR_SYSTEM); - return; - } -} - -static gboolean -alsaspdifsink_event (GstBaseSink * bsink, GstEvent * event) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (bsink); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - snd_pcm_drop (sink->pcm); - break; - case GST_EVENT_FLUSH_STOP: - snd_pcm_start (sink->pcm); - break; - default: - break; - } - - return TRUE; -} - -static void -alsaspdifsink_get_times (GstBaseSink * bsink, GstBuffer * buffer, - GstClockTime * start, GstClockTime * end) -{ - /* Like GstBaseAudioSink, we set these to NONE */ - *start = GST_CLOCK_TIME_NONE; - *end = GST_CLOCK_TIME_NONE; -} - -static snd_pcm_sframes_t -alsaspdifsink_delay (AlsaSPDIFSink * sink) -{ - snd_pcm_sframes_t delay; - int err; - - err = snd_pcm_delay (sink->pcm, &delay); - if (err < 0 || delay < 0) { - return 0; - } - - return delay; -} - -#if 0 -static void -generate_iec958_zero_frame (guchar * buffer) -{ - /* 2 sync words, 16 bits each */ - buffer[0] = 0xF8; - buffer[1] = 0x72; - buffer[2] = 0x4E; - buffer[3] = 0x1F; - - /* 16-bit burst-info. Contains data type (zero here, for 'null data'), - stream number (we output '0' for this always), and a few other bits. - As it happens, all-zero is the correct value. - */ - buffer[4] = 0; - buffer[5] = 0; - - /* 16-bit frame size. Also zero */ - buffer[6] = 0; - buffer[7] = 0; - - memset (buffer + 8, 0, IEC958_FRAME_SIZE - 8); -} -#endif - -static GstFlowReturn -alsaspdifsink_render (GstBaseSink * bsink, GstBuffer * buf) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (bsink); - -#if 0 - GstClockTime next_write; - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - sink->cur_ts = GST_BUFFER_TIMESTAMP (buf); - - next_write = gst_element_get_time (GST_ELEMENT (sink)) + - alsaspdifsink_current_delay (sink); - - /* - fprintf (stderr, "Drift: % 0.6fs, delay: % 0.6fs\r", - GST_TIME_ARGS (GST_CLOCK_DIFF (sink->cur_ts, next_write)), - GST_TIME_ARGS (alsaspdifsink_current_delay (sink))); - */ - - /* If we're too far behind, send empty IEC958 frames. */ - if (sink->cur_ts > next_write + MAX_SYNC_DIFF) { - int frames = (int) ( - ((double) (sink->cur_ts - next_write)) / - (double) IEC958_FRAME_DURATION + 0.5); - int i; - - for (i = 0; i < frames; i++) { - static guchar frame[IEC958_FRAME_SIZE]; - - generate_iec958_zero_frame (frame); - - alsaspdifsink_write_frame (sink, frame); - } - } - /* If we're too far ahead, just drop this buffer */ - else if (sink->cur_ts + MAX_SYNC_DIFF < next_write) { - goto end; - } -#endif - - GST_LOG_OBJECT (sink, "Writing %d bytes to spdif out", GST_BUFFER_SIZE (buf)); - if (GST_BUFFER_SIZE (buf) == IEC958_FRAME_SIZE) - alsaspdifsink_write_frame (sink, GST_BUFFER_DATA (buf)); - else - GST_WARNING_OBJECT (sink, "Ignoring buffer of incorrect size"); - -#if 0 -end: - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf))) - sink->cur_ts = GST_BUFFER_DURATION (buf); -#endif - - return GST_FLOW_OK; -} - -/* Drop error output from within alsalib on the floor */ -static void -ignore_alsa_err (const char *file, int line, const char *function, - int err, const char *fmt, ...) -{ -} - -static GstStateChangeReturn -alsaspdifsink_change_state (GstElement * element, GstStateChange transition) -{ - AlsaSPDIFSink *sink = ALSASPDIFSINK (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - sink->frames = 0; - gst_audio_clock_reset (GST_AUDIO_CLOCK (sink->clock), 0); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - if (!alsaspdifsink_open (sink)) { - GST_WARNING_OBJECT (sink, "Failed to open alsa device"); - return GST_STATE_CHANGE_FAILURE; - } - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - GST_INFO_OBJECT (sink, "Parent change_state returned %d", ret); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - alsaspdifsink_close (sink); - break; - default: - break; - } - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - /* no rank so it doesn't get autoplugged by autoaudiosink */ - if (!gst_element_register (plugin, "alsaspdifsink", GST_RANK_NONE, - GST_TYPE_ALSASPDIFSINK)) { - return FALSE; - } - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "alsaspdif", - "Alsa plugin for S/PDIF output", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/ext/alsaspdif/alsaspdifsink.h b/ext/alsaspdif/alsaspdifsink.h deleted file mode 100644 index 925b1f778..000000000 --- a/ext/alsaspdif/alsaspdifsink.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Based on a plugin from Martin Soto's Seamless DVD Player. - * Copyright (C) 2003, 2004 Martin Soto <martinsoto@users.sourceforge.net> - * 2005-6 Michael Smith <msmith@fluendo.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __ALSASPDIFSINK_H__ -#define __ALSASPDIFSINK_H__ - -#include <gst/gst.h> - -#define ALSA_PCM_NEW_HW_PARAMS_API -#define ALSA_PCM_NEW_SW_PARAMS_API -#include <alsa/asoundlib.h> - -G_BEGIN_DECLS - -#define GST_TYPE_ALSASPDIFSINK \ - (alsaspdifsink_get_type()) -#define ALSASPDIFSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSASPDIFSINK,AlsaSPDIFSink)) -#define ALSASPDIFSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSASPDIFSINK,AlsaSPDIFSinkClass)) -#define GST_IS_ALSASPDIFSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSASPDIFSINK)) -#define GST_IS_ALSASPDIFSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSASPDIFSINK)) -#define GST_TYPE_ALSASPDIFSINK (alsaspdifsink_get_type()) - -typedef struct _AlsaSPDIFSink AlsaSPDIFSink; -typedef struct _AlsaSPDIFSinkClass AlsaSPDIFSinkClass; - -typedef enum { - ALSASPDIFSINK_OPEN = GST_ELEMENT_FLAG_LAST, - ALSASPDIFSINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2, -} AlsaSPDIFSinkFlags; - -/* ALSA spdif types. */ -enum { - SPDIF_NONE = 0, - SPDIF_CON, - SPDIF_PRO, - SPDIF_PCM -}; - -struct _AlsaSPDIFSink { - GstBaseSink basesink; - - GstClockTime cur_ts; /* Current time stamp. */ - - snd_pcm_t *pcm; /* ALSA output device. */ - - gint card; /* ALSA card number to use */ - char *device; /* ALSA device name */ - - GstClock *clock; /* The clock for this element. */ - - guint64 frames; /* Number of complete frames written */ - gboolean need_swap; /* Whether to byte swap outgoing data */ - - gint rate; /* Sampling rate of data */ -}; - -struct _AlsaSPDIFSinkClass { - GstBaseSinkClass parent_class; -}; - -extern GType alsaspdifsink_get_type (void); - -G_END_DECLS - -#endif /* __DXR3AUDIOINK_H__ */ diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in index 24043da41..8da39aae5 100644 --- a/gst-plugins-bad.spec.in +++ b/gst-plugins-bad.spec.in @@ -159,7 +159,6 @@ rm -rf $RPM_BUILD_ROOT @USE_XVID_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstxvid.so @USE_BZ2_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstbz2.so @USE_NEON_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstneonhttpsrc.so -@USE_ALSA_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstalsaspdif.so @USE_MUSEPACK_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstmusepack.so @USE_GSM_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstgsm.so @USE_DTS_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstdtsdec.so diff --git a/m4/Makefile.am b/m4/Makefile.am index 094c3fdb8..e03a94a61 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -13,7 +13,6 @@ EXTRA_DIST = \ gettext.m4 \ glibc21.m4 \ glib.m4 \ - gst-alsa.m4 \ gst-artsc.m4 \ gst-fionread.m4 \ gst-matroska.m4 \ diff --git a/m4/gst-alsa.m4 b/m4/gst-alsa.m4 deleted file mode 100644 index 4141d0664..000000000 --- a/m4/gst-alsa.m4 +++ /dev/null @@ -1,150 +0,0 @@ -dnl Configure Paths for Alsa -dnl Some modifications by Richard Boulton <richard-alsa@tartarus.org> -dnl Christopher Lansdown <lansdoct@cs.alfred.edu> -dnl Jaroslav Kysela <perex@suse.cz> -dnl Last modification: alsa.m4,v 1.23 2004/01/16 18:14:22 tiwai Exp -dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) -dnl Test for libasound, and define ALSA_CFLAGS and ALSA_LIBS as appropriate. -dnl enables arguments --with-alsa-prefix= -dnl --with-alsa-enc-prefix= -dnl --disable-alsatest -dnl -dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified, -dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result. -dnl -AC_DEFUN([AM_PATH_ALSA], -[dnl Save the original CFLAGS, LDFLAGS, and LIBS -alsa_save_CFLAGS="$CFLAGS" -alsa_save_LDFLAGS="$LDFLAGS" -alsa_save_LIBS="$LIBS" -alsa_found=yes - -dnl -dnl Get the cflags and libraries for alsa -dnl -AC_ARG_WITH(alsa-prefix, - AC_HELP_STRING([--with-alsa-prefix=PFX], - [prefix where Alsa library is installed(optional)]), - [alsa_prefix="$withval"], [alsa_prefix=""]) - -AC_ARG_WITH(alsa-inc-prefix, - AC_HELP_STRING([--with-alsa-inc-prefix=PFX], - [prefix where include libraries are (optional)]), - [alsa_inc_prefix="$withval"], [alsa_inc_prefix=""]) - -dnl FIXME: this is not yet implemented -dnl AC_ARG_ENABLE(alsatest, -dnl AC_HELP_STRING([--disable-alsatest], -dnl [do not try to compile and run a test Alsa program], -dnl [enable_alsatest=no], [enable_alsatest=yes]) - -dnl Add any special include directories -AC_MSG_CHECKING(for ALSA CFLAGS) -if test "$alsa_inc_prefix" != "" ; then - ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix" - CFLAGS="$CFLAGS -I$alsa_inc_prefix" -fi -AC_MSG_RESULT($ALSA_CFLAGS) - -dnl add any special lib dirs -AC_MSG_CHECKING(for ALSA LDFLAGS) -if test "$alsa_prefix" != "" ; then - ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix" - LDFLAGS="$LDFLAGS $ALSA_LIBS" -fi - -dnl add the alsa library -ALSA_LIBS="$ALSA_LIBS -lasound -lm -ldl -lpthread" -LIBS=`echo $LIBS | sed 's/-lm//'` -LIBS=`echo $LIBS | sed 's/-ldl//'` -LIBS=`echo $LIBS | sed 's/-lpthread//'` -LIBS=`echo $LIBS | sed 's/ //'` -LIBS="$ALSA_LIBS $LIBS" -AC_MSG_RESULT($ALSA_LIBS) - -dnl Check for a working version of libasound that is of the right version. -min_alsa_version=ifelse([$1], ,0.1.1,$1) -AC_MSG_CHECKING(for libasound headers version >= $min_alsa_version) -no_alsa="" - alsa_min_major_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - alsa_min_minor_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - alsa_min_micro_version=`echo $min_alsa_version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - -AC_LANG_SAVE -AC_LANG_C -AC_TRY_COMPILE([ -#include <alsa/asoundlib.h> -], [ -void main(void) -{ -/* ensure backward compatibility */ -#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR) -#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR -#endif -#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR) -#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR -#endif -#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR) -#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR -#endif - -# if(SND_LIB_MAJOR > $alsa_min_major_version) - exit(0); -# else -# if(SND_LIB_MAJOR < $alsa_min_major_version) -# error not present -# endif - -# if(SND_LIB_MINOR > $alsa_min_minor_version) - exit(0); -# else -# if(SND_LIB_MINOR < $alsa_min_minor_version) -# error not present -# endif - -# if(SND_LIB_SUBMINOR < $alsa_min_micro_version) -# error not present -# endif -# endif -# endif -exit(0); -} -], - [AC_MSG_RESULT(found.)], - [AC_MSG_RESULT(not present.) - ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)]) - alsa_found=no] -) -AC_LANG_RESTORE - -dnl Now that we know that we have the right version, let's see if we have the library and not just the headers. -if test "x$enable_alsatest" = "xyes"; then -AC_CHECK_LIB([asound], [snd_ctl_open],, - [ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)]) - alsa_found=no] -) -fi - -if test "x$alsa_found" = "xyes" ; then - ifelse([$2], , :, [$2]) - LIBS=`echo $LIBS | sed 's/-lasound//g'` - LIBS=`echo $LIBS | sed 's/ //'` - LIBS="-lasound $LIBS" -fi -if test "x$alsa_found" = "xno" ; then - ifelse([$3], , :, [$3]) - CFLAGS="$alsa_save_CFLAGS" - LDFLAGS="$alsa_save_LDFLAGS" - LIBS="$alsa_save_LIBS" - ALSA_CFLAGS="" - ALSA_LIBS="" -fi - -dnl That should be it. Now just export out symbols: -AC_SUBST(ALSA_CFLAGS) -AC_SUBST(ALSA_LIBS) -]) - |