summaryrefslogtreecommitdiffstats
path: root/sys/oss4/oss4-mixer-enum.c
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2008-04-02 20:18:58 +0000
committerTim-Philipp Müller <tim@centricular.net>2008-04-02 20:18:58 +0000
commita4246ff3a994d8ab64841f70b698917e39836bd2 (patch)
tree6b59a6b5aee78ca6d9dfd42133b0f8576b6a5787 /sys/oss4/oss4-mixer-enum.c
parent3e89814bb10346cabef1a836e8f0dc069f02371c (diff)
downloadgst-plugins-bad-a4246ff3a994d8ab64841f70b698917e39836bd2.tar.gz
gst-plugins-bad-a4246ff3a994d8ab64841f70b698917e39836bd2.tar.bz2
gst-plugins-bad-a4246ff3a994d8ab64841f70b698917e39836bd2.zip
Add initial support for OSSv4. Mixer still needs a bit more love, but even magic has its limits.
Original commit message from CVS: * configure.ac: * sys/Makefile.am: * sys/oss4/Makefile.am: * sys/oss4/oss4-audio.c: * sys/oss4/oss4-audio.h: * sys/oss4/oss4-mixer-enum.c: * sys/oss4/oss4-mixer-enum.h: * sys/oss4/oss4-mixer-slider.c: * sys/oss4/oss4-mixer-slider.h: * sys/oss4/oss4-mixer-switch.c: * sys/oss4/oss4-mixer-switch.h: * sys/oss4/oss4-mixer.c: * sys/oss4/oss4-mixer.h: * sys/oss4/oss4-property-probe.c: * sys/oss4/oss4-property-probe.h: * sys/oss4/oss4-sink.c: * sys/oss4/oss4-sink.h: * sys/oss4/oss4-soundcard.h: * sys/oss4/oss4-source.c: * sys/oss4/oss4-source.h: Add initial support for OSSv4. Mixer still needs a bit more love, but even magic has its limits.
Diffstat (limited to 'sys/oss4/oss4-mixer-enum.c')
-rw-r--r--sys/oss4/oss4-mixer-enum.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/sys/oss4/oss4-mixer-enum.c b/sys/oss4/oss4-mixer-enum.c
new file mode 100644
index 00000000..edd0d7bb
--- /dev/null
+++ b/sys/oss4/oss4-mixer-enum.c
@@ -0,0 +1,269 @@
+/* GStreamer OSS4 mixer enumeration control
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * 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.
+ */
+
+/* An 'enum' in gnome-volume-control / GstMixer is represented by a
+ * GstMixerOptions object
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#define NO_LEGACY_MIXER
+#include "oss4-mixer.h"
+#include "oss4-mixer-enum.h"
+#include "oss4-soundcard.h"
+
+GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug);
+#define GST_CAT_DEFAULT oss4mixer_debug
+
+static GList *gst_oss4_mixer_enum_get_values (GstMixerOptions * options);
+
+/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */
+G_DEFINE_TYPE (GstOss4MixerEnum, gst_oss4_mixer_enum, GST_TYPE_MIXER_OPTIONS);
+
+static void
+gst_oss4_mixer_enum_init (GstOss4MixerEnum * e)
+{
+ e->need_update = TRUE;
+}
+
+static void
+gst_oss4_mixer_enum_dispose (GObject * obj)
+{
+ GstMixerOptions *options = GST_MIXER_OPTIONS (obj);
+
+ /* our list is a flat list with constant strings, but the GstMixerOptions
+ * dispose will try to g_free the contained strings, so clean up the list
+ * before chaining up to GstMixerOptions */
+ g_list_free (options->values);
+ options->values = NULL;
+
+ G_OBJECT_CLASS (gst_oss4_mixer_enum_parent_class)->dispose (obj);
+}
+
+static void
+gst_oss4_mixer_enum_class_init (GstOss4MixerEnumClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstMixerOptionsClass *mixeroptions_class = (GstMixerOptionsClass *) klass;
+
+ gobject_class->dispose = gst_oss4_mixer_enum_dispose;
+ mixeroptions_class->get_values = gst_oss4_mixer_enum_get_values;
+}
+
+static GList *
+gst_oss4_mixer_enum_get_values_locked (GstMixerOptions * options)
+{
+ GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (options);
+ GList *oldlist, *list = NULL;
+ int i;
+
+ /* if current list of values is empty, update/re-check in any case */
+ if (!e->need_update && options->values != NULL)
+ return options->values;
+
+ GST_LOG_OBJECT (e, "updating available values for %s", e->mc->mixext.extname);
+
+ for (i = 0; i < e->mc->mixext.maxvalue; ++i) {
+ if (MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) {
+ const gchar *s;
+
+ s = g_quark_to_string (e->mc->enum_vals[i]);
+ GST_LOG_OBJECT (e, "option '%s' is available", s);
+ list = g_list_prepend (list, (gpointer) s);
+ } else {
+ GST_LOG_OBJECT (e, "option '%s' is currently not available");
+ }
+ }
+
+ list = g_list_reverse (list);
+
+ /* this is not thread-safe, but then the entire GstMixer API isn't really,
+ * since we return foo->list and not a copy and don't take any locks, so
+ * not much we can do here but pray; we're usually either called from _new()
+ * or from within _get_values() though, so it should be okay. We could use
+ * atomic ops here, but I'm not sure how much more that really buys us.*/
+ oldlist = options->values; /* keep window small */
+ options->values = list;
+ g_list_free (oldlist);
+
+ e->need_update = FALSE;
+
+ return options->values;
+}
+
+static GList *
+gst_oss4_mixer_enum_get_values (GstMixerOptions * options)
+{
+ GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM (options);
+ GList *list;
+
+ /* we take the lock here mostly to serialise ioctls with the watch thread */
+ GST_OBJECT_LOCK (e->mixer);
+
+ list = gst_oss4_mixer_enum_get_values_locked (options);
+
+ GST_OBJECT_UNLOCK (e->mixer);
+
+ return list;
+}
+
+static const gchar *
+gst_oss4_mixer_enum_get_current_value (GstOss4MixerEnum * e)
+{
+ const gchar *cur_val = NULL;
+
+ if (e->mc->enum_vals != NULL && e->mc->last_val < e->mc->mixext.maxvalue) {
+ cur_val = g_quark_to_string (e->mc->enum_vals[e->mc->last_val]);
+ }
+
+ return cur_val;
+}
+
+static gboolean
+gst_oss4_mixer_enum_update_current (GstOss4MixerEnum * e)
+{
+ int cur = -1;
+
+ if (!gst_oss4_mixer_get_control_val (e->mixer, e->mc, &cur))
+ return FALSE;
+
+ if (cur < 0 || cur >= e->mc->mixext.maxvalue) {
+ GST_WARNING_OBJECT (e, "read value %d out of bounds [0-%d]", cur,
+ e->mc->mixext.maxvalue - 1);
+ e->mc->last_val = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value)
+{
+ GQuark q;
+ int i;
+
+ q = g_quark_try_string (value);
+ if (q == 0) {
+ GST_WARNING_OBJECT (e, "unknown option '%s'", value);
+ return FALSE;
+ }
+
+ for (i = 0; i < e->mc->mixext.maxvalue; ++i) {
+ if (q == e->mc->enum_vals[i])
+ break;
+ }
+
+ if (i >= e->mc->mixext.maxvalue) {
+ GST_WARNING_OBJECT (e, "option '%s' is not valid for this control", value);
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (e, "option '%s' = %d", value, i);
+
+ if (!MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) {
+ GST_WARNING_OBJECT (e, "option '%s' is not selectable currently", value);
+ return FALSE;
+ }
+
+ if (!gst_oss4_mixer_set_control_val (e->mixer, e->mc, i)) {
+ GST_WARNING_OBJECT (e, "could not set option '%s' (%d)", value, i);
+ return FALSE;
+ }
+
+ /* and re-read current value with sanity checks (or could just assign here) */
+ gst_oss4_mixer_enum_update_current (e);
+
+ return TRUE;
+}
+
+const gchar *
+gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e)
+{
+ const gchar *cur_str = NULL;
+
+ if (!gst_oss4_mixer_enum_update_current (e)) {
+ GST_WARNING_OBJECT (e, "failed to read current value");
+ return NULL;
+ }
+
+ cur_str = gst_oss4_mixer_enum_get_current_value (e);
+ GST_LOG_OBJECT (e, "%s (%d)", GST_STR_NULL (cur_str), e->mc->last_val);
+ return cur_str;
+}
+
+GstMixerTrack *
+gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc)
+{
+ GstOss4MixerEnum *e;
+ GstMixerTrack *track;
+
+ e = g_object_new (GST_TYPE_OSS4_MIXER_ENUM, "untranslated-label",
+ mc->mixext.extname, NULL);
+ e->mixer = mixer;
+ e->mc = mc;
+
+ track = GST_MIXER_TRACK (e);
+
+ /* caller will set track->label and track->flags */
+
+ track->num_channels = 0;
+ track->min_volume = 0;
+ track->max_volume = 0;
+
+ (void) gst_oss4_mixer_enum_get_values_locked (GST_MIXER_OPTIONS (track));
+
+ if (!gst_oss4_mixer_enum_update_current (e)) {
+ GST_WARNING_OBJECT (track, "failed to read current value, returning NULL");
+ g_object_unref (track);
+ track = NULL;
+ }
+
+ GST_LOG_OBJECT (e, "current value: %d (%s)", e->mc->last_val,
+ gst_oss4_mixer_enum_get_current_value (e));
+
+ return track;
+}
+
+/* This is called from the watch thread */
+void
+gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track)
+{
+ GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (track);
+
+ gchar *cur;
+
+ if (!e->mc->changed && !e->mc->list_changed)
+ return;
+
+ if (e->mc->list_changed) {
+ gst_mixer_options_list_changed (GST_MIXER (e->mixer),
+ GST_MIXER_OPTIONS (e));
+ }
+
+ GST_OBJECT_LOCK (e->mixer);
+ cur = (gchar *) gst_oss4_mixer_enum_get_current_value (e);
+ GST_OBJECT_UNLOCK (e->mixer);
+
+ gst_mixer_option_changed (GST_MIXER (e->mixer), GST_MIXER_OPTIONS (e), cur);
+}