summaryrefslogtreecommitdiffstats
path: root/sys/oss4/oss4-mixer-slider.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-slider.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-slider.c')
-rw-r--r--sys/oss4/oss4-mixer-slider.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/sys/oss4/oss4-mixer-slider.c b/sys/oss4/oss4-mixer-slider.c
new file mode 100644
index 00000000..a56dcae8
--- /dev/null
+++ b/sys/oss4/oss4-mixer-slider.c
@@ -0,0 +1,296 @@
+/* GStreamer OSS4 mixer slider 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.
+ */
+
+/* A 'slider' in gnome-volume-control / GstMixer is represented by a
+ * GstMixerTrack with one or more channels.
+ *
+ * A slider should be either flagged as INPUT or OUTPUT (mostly because of
+ * gnome-volume-control being littered with g_asserts for everything it doesn't
+ * expect).
+ *
+ * From mixertrack.h:
+ * "Input tracks can have 'recording' enabled, which means that any input will
+ * be hearable into the speakers that are attached to the output. Mute is
+ * obvious."
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <gst/gst-i18n-plugin.h>
+
+#define NO_LEGACY_MIXER
+#include "oss4-mixer-slider.h"
+
+GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug);
+#define GST_CAT_DEFAULT oss4mixer_debug
+
+/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */
+G_DEFINE_TYPE (GstOss4MixerSlider, gst_oss4_mixer_slider, GST_TYPE_MIXER_TRACK);
+
+static void
+gst_oss4_mixer_slider_class_init (GstOss4MixerSliderClass * klass)
+{
+ /* nothing to do here */
+}
+
+static void
+gst_oss4_mixer_slider_init (GstOss4MixerSlider * s)
+{
+ /* nothing to do here */
+}
+
+static int
+gst_oss4_mixer_slider_pack_volume (GstOss4MixerSlider * s, const gint * volumes)
+{
+ int val = 0;
+
+ switch (s->mc->mixext.type) {
+ case MIXT_MONOSLIDER:
+ case MIXT_MONOSLIDER16:
+ case MIXT_SLIDER:
+ val = volumes[0];
+ break;
+ case MIXT_STEREOSLIDER:
+ val = ((volumes[1] & 0xff) << 8) | (volumes[0] & 0xff);
+ break;
+ case MIXT_STEREOSLIDER16:
+ val = ((volumes[1] & 0xffff) << 16) | (volumes[0] & 0xffff);
+ break;
+ default:
+ g_return_val_if_reached (0);
+ }
+ return val;
+}
+
+static void
+gst_oss4_mixer_slider_unpack_volume (GstOss4MixerSlider * s, int v,
+ gint * volumes)
+{
+ guint32 val; /* use uint so bitshifting the highest bit works right */
+
+ val = (guint32) v;
+ switch (s->mc->mixext.type) {
+ case MIXT_MONOSLIDER:
+ case MIXT_MONOSLIDER16:
+ case MIXT_SLIDER:
+ volumes[0] = val;
+ break;
+ case MIXT_STEREOSLIDER:
+ volumes[0] = (val & 0x00ff);
+ volumes[1] = (val & 0xff00) >> 8;
+ break;
+ case MIXT_STEREOSLIDER16:
+ volumes[0] = (val & 0x0000ffff);
+ volumes[1] = (val & 0xffff0000) >> 16;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+}
+
+gboolean
+gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes)
+{
+ GstMixerTrack *track = GST_MIXER_TRACK (s);
+ int v = 0;
+
+ /* if we're supposed to be muted, and don't have an actual mute control
+ * (ie. 'simulate' the mute), then just return the volume as saved, not
+ * the actually set volume which is most likely 0 */
+ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) {
+ volumes[0] = s->volumes[0];
+ if (track->num_channels == 2)
+ volumes[1] = s->volumes[1];
+ return TRUE;
+ }
+
+ if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &v))
+ return FALSE;
+
+ gst_oss4_mixer_slider_unpack_volume (s, v, volumes);
+
+ if (track->num_channels > 1) {
+ GST_LOG_OBJECT (s, "volume: left=%d, right=%d", volumes[0], volumes[1]);
+ } else {
+ GST_LOG_OBJECT (s, "volume: mono=%d", volumes[0]);
+ }
+
+ return TRUE;
+}
+
+gboolean
+gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes)
+{
+ GstMixerTrack *track = GST_MIXER_TRACK (s);
+ int val = 0;
+
+ /* if we're supposed to be muted, and are 'simulating' the mute because
+ * we don't have a mute control, don't actually change the volume, just
+ * save it as the new desired volume for later when we get unmuted again */
+ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute)
+ goto done;
+
+ val = gst_oss4_mixer_slider_pack_volume (s, volumes);
+
+ if (track->num_channels > 1) {
+ GST_LOG_OBJECT (s, "left=%d, right=%d", volumes[0], volumes[1]);
+ } else {
+ GST_LOG_OBJECT (s, "mono=%d", volumes[0]);
+ }
+
+ if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, val))
+ return FALSE;
+
+done:
+
+ s->volumes[0] = volumes[0];
+ if (track->num_channels == 2)
+ s->volumes[1] = volumes[1];
+
+ return TRUE;
+}
+
+gboolean
+gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record)
+{
+ /* There doesn't seem to be a way to do this using the OSS4 mixer API, so
+ * just do nothing here for now. */
+ return FALSE;
+}
+
+gboolean
+gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute)
+{
+ GstMixerTrack *track = GST_MIXER_TRACK (s);
+ gboolean ret;
+
+ /* if we don't have a mute control, simulate mute (which is a bit broken,
+ * since we can't differentiate between capture/playback volume etc., so
+ * we just assume that setting the volume to 0 would be the same as muting
+ * this control) */
+ if (s->mc->mute == NULL) {
+ int volume;
+
+ if (mute) {
+ volume = 0;
+ } else {
+ volume = gst_oss4_mixer_slider_pack_volume (s, s->volumes);
+ }
+ ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc, volume);
+ } else {
+ ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, !!mute);
+ }
+
+ if (mute) {
+ track->flags |= GST_MIXER_TRACK_MUTE;
+ } else {
+ track->flags &= ~GST_MIXER_TRACK_MUTE;
+ }
+
+ return FALSE;
+}
+
+GstMixerTrack *
+gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc)
+{
+ GstOss4MixerSlider *s;
+ GstMixerTrack *track;
+ gint volumes[2] = { 0, };
+
+ s = g_object_new (GST_TYPE_OSS4_MIXER_SLIDER, "untranslated-label",
+ mc->mixext.extname, NULL);
+
+ track = GST_MIXER_TRACK (s);
+
+ /* caller will set track->label and track->flags */
+
+ s->mc = mc;
+ s->mixer = mixer;
+
+ /* we don't do value scaling but just present a scale of 0-maxvalue */
+ track->min_volume = 0;
+ track->max_volume = mc->mixext.maxvalue;
+
+ switch (mc->mixext.type) {
+ case MIXT_MONOSLIDER:
+ case MIXT_MONOSLIDER16:
+ case MIXT_SLIDER:
+ track->num_channels = 1;
+ break;
+ case MIXT_STEREOSLIDER:
+ case MIXT_STEREOSLIDER16:
+ track->num_channels = 2;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ GST_LOG_OBJECT (track, "min=%d, max=%d, channels=%d", track->min_volume,
+ track->max_volume, track->num_channels);
+
+ if (!gst_oss4_mixer_slider_get_volume (s, volumes)) {
+ GST_WARNING_OBJECT (track, "failed to read volume, returning NULL");
+ g_object_unref (track);
+ track = NULL;
+ }
+
+ return track;
+}
+
+/* This is called from the watch thread */
+void
+gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track)
+{
+ GstOss4MixerSlider *s = GST_OSS4_MIXER_SLIDER_CAST (track);
+
+ if (s->mc->mute != NULL && s->mc->mute->changed) {
+ gst_mixer_mute_toggled (GST_MIXER (s->mixer), track,
+ !!s->mc->mute->last_val);
+ } else {
+ /* nothing to do here, since we don't/can't easily implement the record
+ * flag */
+ }
+
+ if (s->mc->changed) {
+ gint volumes[2] = { 0, 0 };
+
+ gst_oss4_mixer_slider_unpack_volume (s, s->mc->last_val, volumes);
+
+ /* if we 'simulate' the mute, update flag when the volume changes */
+ if (s->mc->mute == NULL) {
+ if (volumes[0] == 0 && volumes[1] == 0) {
+ track->flags |= GST_MIXER_TRACK_MUTE;
+ } else {
+ track->flags &= ~GST_MIXER_TRACK_MUTE;
+ }
+ }
+
+ gst_mixer_volume_changed (GST_MIXER (s->mixer), track, volumes);
+ }
+}