diff options
author | Tim-Philipp Müller <tim@centricular.net> | 2008-04-02 20:18:58 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2008-04-02 20:18:58 +0000 |
commit | a4246ff3a994d8ab64841f70b698917e39836bd2 (patch) | |
tree | 6b59a6b5aee78ca6d9dfd42133b0f8576b6a5787 /sys/oss4/oss4-mixer-slider.c | |
parent | 3e89814bb10346cabef1a836e8f0dc069f02371c (diff) | |
download | gst-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.c | 296 |
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); + } +} |