diff --git a/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c
index 0a3c0af..cec15c6 100644
--- a/sys/oss4/oss4-audio.c
+++ b/sys/oss4/oss4-audio.c
@@ -494,23 +494,6 @@ gst_oss4_audio_get_template_caps (void)
   return caps;
 }
 
-static gint
-gst_oss4_audio_ilog2 (gint x)
-{
-  /* well... hacker's delight explains... */
-  x = x | (x >> 1);
-  x = x | (x >> 2);
-  x = x | (x >> 4);
-  x = x | (x >> 8);
-  x = x | (x >> 16);
-  x = x - ((x >> 1) & 0x55555555);
-  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
-  x = (x + (x >> 4)) & 0x0f0f0f0f;
-  x = x + (x >> 8);
-  x = x + (x >> 16);
-  return (x & 0x0000003f) - 1;
-}
-
 /* called by gst_oss4_sink_prepare() and gst_oss4_source_prepare() */
 gboolean
 gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec)
@@ -555,17 +538,6 @@ gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec)
     goto format_not_what_was_requested;
   }
 
-  /* CHECKME: maybe we should just leave the fragsize alone? (tpm) */
-  fragsize = gst_oss4_audio_ilog2 (spec->segsize);
-  fragsize = ((spec->segtotal & 0x7fff) << 16) | fragsize;
-  GST_DEBUG_OBJECT (obj, "setting segsize: %d, segtotal: %d, value: %08x",
-      spec->segsize, spec->segtotal, fragsize);
-
-  /* we could also use the new SNDCTL_DSP_POLICY if there's something in
-   * particular we're trying to achieve here */
-  if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &fragsize) == -1)
-    goto set_fragsize_failed;
-
   if (GST_IS_OSS4_SOURCE (obj)) {
     if (ioctl (fd, SNDCTL_DSP_GETISPACE, &info) == -1)
       goto get_ispace_failed;
@@ -575,7 +547,13 @@ gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec)
   }
 
   spec->segsize = info.fragsize;
-  spec->segtotal = info.fragstotal;
+  /*
+   * we add some extra fragments -- this helps us account for delays due to
+   * conversion buffer, streams queueing, etc.  Its important that these
+   * be taken into account because otherwise the delay counter can wind up
+   * being too large, and the buffer will wrap.
+   */
+  spec->segtotal = info.fragstotal + 4;
 
   spec->bytes_per_sample = (spec->width / 8) * spec->channels;
 
@@ -615,12 +593,6 @@ set_rate_failed:
         ("DSP_SPEED(%d) failed: %s", rate, g_strerror (errno)));
     return FALSE;
   }
-set_fragsize_failed:
-  {
-    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
-        ("DSP_SETFRAGMENT(%d) failed: %s", fragsize, g_strerror (errno)));
-    return FALSE;
-  }
 get_ospace_failed:
   {
     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
diff --git a/sys/oss4/oss4-mixer-slider.c b/sys/oss4/oss4-mixer-slider.c
index f8e7f66..8e9371f 100644
--- a/sys/oss4/oss4-mixer-slider.c
+++ b/sys/oss4/oss4-mixer-slider.c
@@ -159,8 +159,9 @@ gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes)
   /* 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;
+  if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE))
+	  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);
 
@@ -196,14 +197,22 @@ gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute)
   GstMixerTrack *track = GST_MIXER_TRACK (s);
   gboolean ret;
 
+  /* if the control doesn't support muting, then don't do anything */
+  if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE)) {
+	  return TRUE;
+  }
+
   /* 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) {
+      /* Make sure the current volume values get saved. */
+      gst_oss4_mixer_slider_get_volume (s, s->volumes);
       volume = 0;
     } else {
       volume = gst_oss4_mixer_slider_pack_volume (s, s->volumes);
diff --git a/sys/oss4/oss4-mixer-switch.c b/sys/oss4/oss4-mixer-switch.c
index 403abbc..574efe7 100644
--- a/sys/oss4/oss4-mixer-switch.c
+++ b/sys/oss4/oss4-mixer-switch.c
@@ -49,45 +49,30 @@ gst_oss4_mixer_switch_init (GstOss4MixerSwitch * s)
   /* nothing to do here */
 }
 
-static GstMixerTrackFlags
-gst_oss4_mixer_switch_get_switch_flag (GstMixerTrack * track)
-{
-  if ((track->flags & GST_MIXER_TRACK_INPUT)) {
-    return GST_MIXER_TRACK_RECORD;
-  } else if ((track->flags & GST_MIXER_TRACK_OUTPUT)) {
-    return GST_MIXER_TRACK_MUTE;
-  } else {
-    GST_ERROR_OBJECT (track, "switch neither input nor output track!?");
-  }
-  return 0;
-}
-
 gboolean
-gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean enabled)
+gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean disabled)
 {
-  GstMixerTrackFlags switch_flag;
   GstMixerTrack *track;
   int newval;
 
   track = GST_MIXER_TRACK (s);
-  switch_flag = gst_oss4_mixer_switch_get_switch_flag (track);
 
-  newval = (enabled) ? 1 : 0;
+  newval = disabled ? GST_MIXER_TRACK_MUTE : 0;
 
-  if (!!newval == !!(track->flags & switch_flag)) {
+  if (newval == (track->flags & GST_MIXER_TRACK_MUTE)) {
     GST_LOG_OBJECT (s, "switch is already %d, doing nothing", newval);
     return TRUE;
   }
 
-  if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, newval)) {
-    GST_WARNING_OBJECT (s, "could not set switch to %d", newval);
+  if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, !disabled)) {
+    GST_WARNING_OBJECT (s, "could not set switch to %d", !disabled);
     return FALSE;
   }
 
-  if (newval) {
-    track->flags |= switch_flag;
+  if (disabled) {
+    track->flags |= GST_MIXER_TRACK_MUTE;
   } else {
-    track->flags &= ~switch_flag;
+    track->flags &= ~GST_MIXER_TRACK_MUTE;
   }
 
   GST_LOG_OBJECT (s, "set switch to %d", newval);
@@ -96,31 +81,27 @@ gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean enabled)
 }
 
 gboolean
-gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean * enabled)
+gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean *disabled)
 {
-  GstMixerTrackFlags switch_flag;
   GstMixerTrack *track;
-  int val = -1;
+  int flag;
+  int enabled = -1;
 
   track = GST_MIXER_TRACK (s);
-  switch_flag = gst_oss4_mixer_switch_get_switch_flag (track);
 
-  if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &val) || val < 0) {
+  if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &enabled) || (enabled < 0)) {
     GST_WARNING_OBJECT (s, "could not get switch state");
     return FALSE;
   }
 
-  *enabled = (val != 0);
+  flag = (enabled == 0) ? GST_MIXER_TRACK_MUTE : 0;
 
-  if (!!val != !!(track->flags & switch_flag)) {
-    GST_INFO_OBJECT (s, "updating inconsistent switch state to %d", !!val);
-    if (*enabled) {
-      track->flags |= switch_flag;
-    } else {
-      track->flags &= ~switch_flag;
-    }
+  if (enabled) {
+    track->flags &= ~GST_MIXER_TRACK_MUTE;
+  } else {
+    track->flags |= GST_MIXER_TRACK_MUTE;
   }
-
+  *disabled = (enabled == 0);
 
   return TRUE;
 }
@@ -149,6 +130,12 @@ gst_oss4_mixer_switch_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc)
   if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &cur) || cur < 0)
     return NULL;
 
+  if (cur) {
+    track->flags &= ~GST_MIXER_TRACK_MUTE;
+  } else {
+    track->flags |= GST_MIXER_TRACK_MUTE;
+  }
+
   return track;
 }
 
@@ -161,9 +148,5 @@ gst_oss4_mixer_switch_process_change_unlocked (GstMixerTrack * track)
   if (!s->mc->changed)
     return;
 
-  if ((track->flags & GST_MIXER_TRACK_INPUT)) {
-    gst_mixer_record_toggled (GST_MIXER (s->mixer), track, !!s->mc->last_val);
-  } else {
-    gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, !!s->mc->last_val);
-  }
+  gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, !s->mc->last_val);
 }
diff --git a/sys/oss4/oss4-mixer.c b/sys/oss4/oss4-mixer.c
index 91b14a2..ad4e35b 100644
--- a/sys/oss4/oss4-mixer.c
+++ b/sys/oss4/oss4-mixer.c
@@ -67,7 +67,7 @@
 #include "oss4-property-probe.h"
 #include "oss4-soundcard.h"
 
-#define GST_OSS4_MIXER_WATCH_INTERVAL   500     /* in millisecs, ie. 0.5s */
+#define GST_OSS4_MIXER_WATCH_INTERVAL   150     /* in millisecs, ie. 0.5s */
 
 GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug);
 #define GST_CAT_DEFAULT oss4mixer_debug
@@ -85,7 +85,7 @@ enum
 static void gst_oss4_mixer_init_interfaces (GType type);
 
 GST_BOILERPLATE_FULL (GstOss4Mixer, gst_oss4_mixer, GstElement,
-    GST_TYPE_ELEMENT, gst_oss4_mixer_init_interfaces);
+    GST_TYPE_ELEMENT, gst_oss4_mixer_init_interfaces)
 
 static GstStateChangeReturn gst_oss4_mixer_change_state (GstElement *
     element, GstStateChange transition);
@@ -709,100 +709,117 @@ gst_oss4_mixer_control_get_pretty_name (GstOss4MixerControl * mc)
   return name;
 }
 
-#if 0
-/* FIXME: translations for common option strings */
-static struct
-{
-  const gchar oss_name[32];
-  const gchar *label;
-} option_labels[] = {
-  {
-  "Fast", N_("Fast")}, {
-  "Low", N_("Low")}, {
-  "Medium", N_("Medium")}, {
-  "High", N_("High")}, {
-  "High+", N_("Very high")}, {
-  "Production", N_("Production")}, {
-  "OFF", N_("Off")}, {
-  "ON", N_("On")}, {
-  "Stereo", N_("Stereo")}, {
-  "Multich", N_("Surround sound")}, {
-  "input-mix", N_("Input mix")}, {
-  "front", N_("Front")}, {
-  "rear", N_("Rear")}, {
-  "side", N_("Side")}, {
-  "center/LFE", N_("Center / LFE")}, {
-  "mic", N_("Microphone")}, {
-  "fp-mic", N_("Front panel microphone")}, {
-  "input", N_("Input")}, {
-  "linein", N_("Line-in")}, {
-  "pcm1", N_("PCM 1")}, {
-  "pcm2", N_("PCM 2")}, {
-  "pcm3", N_("PCM 3")}, {
-"pcm4", N_("PCM 4")},};
-#endif
-
-/* these translations are a bit ad-hoc and horribly incomplete; it's not
- * really going to work this way with all the different chipsets and drivers */
+/* These translations are a bit ad-hoc and horribly incomplete; it's not
+ * really going to work this way with all the different chipsets and drivers.
+ * We also use these for translating option values. */
 static struct
 {
   const gchar oss_name[32];
   const gchar *label;
 } labels[] = {
-  /* connectors (e.g. hdaudio) */
-  {
-  "jack.green", N_("Green connector")}, {
-  "jack.fp-green", N_("Green front panel connector")}, {
-  "jack.pink", N_("Pink connector")}, {
-  "jack.fp-pink", N_("Pink front panel connector")}, {
-  "jack.blue", N_("Blue connector")}, {
-  "jack.fp-blue", N_("Blue front panel connector")}, {
-  "jack.orange", N_("Orange connector")}, {
-  "jack.fp-orange", N_("Orange front panel connector")}, {
-  "jack.black", N_("Black connector")}, {
-  "jack.fp-black", N_("Black front panel connector")}, {
-  "jack.gray", N_("Gray connector")}, {
-  "jack.fp-gray", N_("Gray front panel connector")}, {
-  "jack.white", N_("White connector")}, {
-  "jack.fp-white", N_("White front panel connector")}, {
-  "jack.red", N_("Red connector")}, {
-  "jack.fp-red", N_("Red front panel connector")}, {
-  "jack.yellow", N_("Yellow connector")}, {
-  "jack.fp-yellow", N_("Yellow front panel connector")},
-      /* connector functions (e.g. hdaudio) */
   {
-  "jack.green.mode", N_("Green connector function")}, {
-  "jack.fp-green.mode", N_("Green front panel connector function")}, {
-  "jack.pink.mode", N_("Pink connector function")}, {
-  "jack.fp-pink.mode", N_("Pink front panel connector function")}, {
-  "jack.blue.mode", N_("Blue connector function")}, {
-  "jack.fp-blue.mode", N_("Blue front panel connector function")}, {
-  "jack.orange.mode", N_("Orange connector function")}, {
-  "jack.fp-orange.mode", N_("Orange front panel connector function")}, {
-  "jack.black.mode", N_("Black connector function")}, {
-  "jack.fp-black.mode", N_("Black front panel connector function")}, {
-  "jack.gray.mode", N_("Gray connector function")}, {
-  "jack.fp-gray.mode", N_("Gray front panel connector function")}, {
-  "jack.white.mode", N_("White connector function")}, {
-  "jack.fp-white.mode", N_("White front panel connector function")}, {
-  "jack.red.mode", N_("Red connector function")}, {
-  "jack.fp-red.mode", N_("Red front panel connector function")}, {
-  "jack.yellow.mode", N_("Yellow connector function")}, {
-  "jack.fp-yellow.mode", N_("Yellow front panel connector function")},
-      /* other */
-  {
-  "misc.mic", N_("Microphone")}, {
-  "misc.fp-mic", N_("Front panel microphone")}, {
-  "misc.linein", N_("Line-in")}, {
-  "misc.fp-linein", N_("Front panel line-in")}, {
-  "misc.headphone", N_("Headphones")}, {
-  "misc.fp-headphone", N_("Front panel headphones")}, {
-  "misc.front", N_("Front")}, {
-  "misc.rear", N_("Rear")}, {
-  "misc.side", N_("Side")}, {
-  "misc.center/lfe", N_("Center / LFE")}, {
-  "misc.pcm", N_("PCM")}, {
-  "misc.input-mix", N_("Input mix")}
+    "volume", N_("Volume")}, {
+    "master", N_("Master")}, {
+    "front", N_("Front")}, {
+    "rear", N_("Rear")}, {
+    "headphones", N_("Headphones")}, {
+    "center", N_("Center")}, {
+    "lfe", N_("LFE")}, {
+    "surround", N_("Surround")}, {
+    "side", N_("Side")}, {
+    "speaker", N_("Built-in Speaker")}, {
+    "aux1-out", N_("AUX 1 Out")}, {
+    "aux2-out", N_("AUX 2 Out")}, {
+    "aux-out", N_("AUX Out")}, {
+    "bass", N_("Bass")}, {
+    "treble", N_("Treble")}, {
+    "3d-depth", N_("3D Depth")}, {
+    "3d-center", N_("3D Center")}, {
+    "3d-enhance", N_("3D Enhance")}, {
+    "phone", N_("Telephone")}, {
+    "mic", N_("Microphone")}, {
+    "line-out", N_("Line Out")}, {
+    "line-in", N_("Line In")}, {
+    "linein", N_("Line In")}, {
+    "cd", N_("Internal CD")}, {
+    "video", N_("Video In")}, {
+    "aux1-in", N_("AUX 1 In")}, {
+    "aux2-in", N_("AUX 2 In")}, {
+    "aux-in", N_("AUX In")}, {
+    "pcm", N_("PCM")}, {
+    "record-gain", N_("Record Gain")}, {
+    "igain", N_("Record Gain")}, {
+    "ogain", N_("Output Gain")}, {
+    "micboost", N_("Microphone Boost")}, {
+    "loopback", N_("Loopback")}, {
+    "diag", N_("Diagnostic")}, {
+    "loudness", N_("Bass Boost")}, {
+    "outputs", N_("Playback Ports")}, {
+    "input", N_("Input")}, {
+    "inputs", N_("Record Source")}, {
+    "record-source", N_("Record Source")}, {
+    "monitor-source", N_("Monitor Source")}, {
+    "beep", N_("Keyboard Beep")}, {
+    "monitor-gain", N_("Monitor")}, {
+    "stereo-simulate", N_("Simulate Stereo")}, {
+    "stereo", N_("Stereo")}, {
+    "multich", N_("Surround Sound")}, {
+    "mic-gain", N_("Microphone Gain")}, {
+    "speaker-source", N_("Speaker Source")}, {
+    "mic-source", N_("Microphone Source")}, {
+    "jack", N_("Jack")}, {
+    "center/lfe", N_("Center / LFE")}, {
+    "stereo-mix", N_("Stereo Mix")}, {
+    "mono-mix", N_("Mono Mix")}, {
+    "input-mix", N_("Input Mix")}, {
+    "spdif-in", N_("SPDIF In")}, {
+    "spdif-out", N_("SPDIF Out")}, {
+    "mic1", N_("Microphone 1")}, {
+    "mic2", N_("Microphone 2")}, {
+    "digital-out", N_("Digital Out")}, {
+    "digital-in", N_("Digital In")}, {
+    "hdmi", N_("HDMI")}, {
+    "modem", N_("Modem")}, {
+    "handset", N_("Handset")}, {
+    "other", N_("Other")}, {
+    "stereo", N_("Stereo")}, {
+    "none", N_("None")}, {
+    "on", N_("On")}, {
+    "off", N_("Off")}, {
+    "mute", N_("Mute")}, {
+    "fast", N_("Fast")}, {
+    "very-low", N_("Very Low")}, {
+    "low", N_("Low")}, {
+    "medium", N_("Medium")}, {
+    "high", N_("High")}, {
+    "very-high", N_("Very High")}, {
+    "high+", N_("Very High")}, {
+    "production", N_("Production")}, {
+    "fp-mic", N_("Front Panel Microphone")}, {
+    "fp-linein", N_("Front Panel Line In")}, {
+    "fp-headphones", N_("Front Panel Headphones")}, {
+    "fp-lineout", N_("Front Panel Line Out")}, {
+    "green", N_("Green Connector")}, {
+    "pink", N_("Pink Connector")}, {
+    "blue", N_("Blue Connector")}, {
+    "white", N_("White Connector")}, {
+    "black", N_("Black Connector")}, {
+    "gray", N_("Gray Connector")}, {
+    "orange", N_("Orange Connector")}, {
+    "red", N_("Red Connector")}, {
+    "yellow", N_("Yellow Connector")}, {
+    "fp-green", N_("Green Front Panel Connector")}, {
+    "fp-pink", N_("Pink Front Panel Connector")}, {
+    "fp-blue", N_("Blue Front Panel Connector")}, {
+    "fp-white", N_("White Front Panel Connector")}, {
+    "fp-black", N_("Black Front Panel Connector")}, {
+    "fp-gray", N_("Gray Front Panel Connector")}, {
+    "fp-orange", N_("Orange Front Panel Connector")}, {
+    "fp-red", N_("Red Front Panel Connector")}, {
+    "fp-yellow", N_("Yellow Front Panel Connector")}, {
+    "spread", N_("Spread Output")}, {
+    "downmix", N_("Downmix")},
+
   /* FIXME translate Audigy NX USB labels) */
 /*
   { "rec.src", N_("Record Source") },
@@ -836,42 +853,88 @@ static struct
 const gchar *
 gst_oss4_mixer_control_get_translated_name (GstOss4MixerControl * mc)
 {
-  gchar name[33] = { 0, };
-  char vmix_str[32] = { '\0', };
+  gchar name[128] = { 0, };
+  gchar scratch[128] = { 0, };
+  gchar fmtbuf[128] = { 0, };
+  gchar vmix_str[32] = { '\0', };
+  gchar *ptr;
   int dummy, i;
+  int num;
+
+  g_strlcpy (fmtbuf, "%s", sizeof (fmtbuf));
 
   /* main virtual mixer controls (we hide the stream volumes) */
   if (sscanf (mc->mixext.extname, "vmix%d-%32c", &dummy, vmix_str) == 2) {
     if (strcmp (vmix_str, "src") == 0)
-      return _("Virtual mixer input");
+      return _("Virtual Mixer Input");
     else if (strcmp (vmix_str, "vol") == 0)
-      return _("Virtual mixer output");
+      return _("Virtual Mixer Output");
     else if (strcmp (vmix_str, "channels") == 0)
-      return _("Virtual mixer channel configuration");
+      return _("Virtual Mixer Channels");
   }
 
-  /* munge connector.foo => jack.foo (change from 4.0 -> 4.1) */
-  if (g_str_has_prefix (mc->mixext.extname, "connector.")) {
-    g_snprintf (name, sizeof (name), "jack.%s", mc->mixext.extname + 10);
-  } else {
-    g_strlcpy (name, mc->mixext.extname, sizeof (name));
-  }
+  g_strlcpy (name, mc->mixext.extname, sizeof (name));
 
-  /* munge foo.function => foo.mode (change from 4.0 -> 4.1) */
-  if (g_str_has_suffix (name, ".function"))
-    memcpy (name + strlen (name) - strlen (".function"), ".mode", 5 + 1);
+  /* we deal with either "connector." or "jack." */
+  if ((g_str_has_prefix (name, "connector.")) ||
+      (g_str_has_prefix (name, "jack."))) {
+    ptr = strchr (mc->mixext.extname, '.');
+    ptr++;
+    g_strlcpy (scratch, ptr, sizeof (scratch));
+    g_strlcpy (name, scratch, sizeof (name));
+  }
 
-  /* chop off trailing numbers */
-  while (strlen (name) > 0 && g_ascii_isdigit (name[strlen (name) - 1]))
-    name[strlen (name) - 1] = '\0';
+  /* special handling for jack retasking suffixes */
+  if (g_str_has_suffix (name, ".function") || g_str_has_suffix (name, ".mode")) {
+    g_strlcpy (fmtbuf, _("%s Function"), sizeof (fmtbuf));
+    ptr = strrchr (name, '.');
+    *ptr = 0; 
+  }
 
-  for (i = 0; i < G_N_ELEMENTS (labels); ++i) {
-    if (strcmp (name, labels[i].oss_name) == 0)
-      return _(labels[i].label);
+  /* parse off trailing numbers */
+  i = strlen (name);
+  while ((i > 0) && (g_ascii_isdigit(name[i - 1]))) {
+    i--;
   }
+  /* the check catches the case where the control name is just a number */
+  if ((i > 0) && (name[i] != '\0')) {
+    num = atoi(name + i);
+    name[i] = '\0';
+    /* format appends a number to the base, but preserves any surrounding format */
+    g_snprintf(scratch, sizeof (scratch), fmtbuf, _("%s %d"));
+    g_strlcpy(fmtbuf, scratch, sizeof (fmtbuf));
+  }
+
+  /* look for a match, progressively skipping '.' delimited prefixes as we go */
+  ptr = name;
+  do {
+    if (*ptr == '.')
+      ptr++;
+    for (i = 0; i < G_N_ELEMENTS (labels); ++i) {
+      if (g_strcasecmp (ptr, labels[i].oss_name) == 0) {
+	g_snprintf(name, sizeof (name), fmtbuf, _(labels[i].label), num);
+	return g_quark_to_string (g_quark_from_string (name));
+      }
+    }
+  } while ((ptr = strchr (ptr, '.')) != NULL);
 
+  /* failing that, just replace periods with spaces */
   g_strdelimit (name, ".", ' ');
-  return g_quark_to_string (g_quark_from_string (name));        /* eek */
+  g_snprintf(scratch, sizeof (scratch), fmtbuf, name);
+  return g_quark_to_string (g_quark_from_string (scratch));        /* eek */
+}
+
+const gchar *
+gst_oss4_mixer_control_get_translated_option (gchar *name)
+{
+  int i;
+  for (i = 0; i < G_N_ELEMENTS (labels); ++i) {
+    if (g_strcasecmp (name, labels[i].oss_name) == 0) {
+      name = _(labels[i].label);
+      return (name);
+    }
+  }
+  return (name);
 }
 
 #ifndef GST_DISABLE_DEBUG
@@ -1063,21 +1126,6 @@ gst_oss4_mixer_get_controls (GstOss4Mixer * mixer)
         mixer_ext_flags_get_string (mix_ext.flags), mix_ext.flags);
     GST_INFO ("  parent : %d", mix_ext.parent);
 
-    /* get tooltip (just for informational purposes for now) */
-    if (MIXEXT_HAS_DESCRIPTION (mix_ext)) {
-      oss_mixer_enuminfo desc = { 0, };
-
-      desc.dev = mix_ext.dev;
-      desc.ctrl = mix_ext.ctrl;
-      if (ioctl (mixer->fd, SNDCTL_MIX_DESCRIPTION, &desc) >= 0) {
-        /* "The string may contain multiple lines. The first line is the
-         *  'tooltip'. Optional subsequent lines may contain more detailed
-         *  help text. Lines are separated by a linefeed character." */
-        g_strdelimit (&desc.strings[desc.strindex[0]], "\n\r", '\0');
-        GST_INFO ("  tooltip: %s", &desc.strings[desc.strindex[0]]);
-      }
-    }
-
     if (!MIXEXT_IS_ROOT (mix_ext)) {
       /* find parent (we assume it comes in the list before the child) */
       for (l = controls; l != NULL; l = l->next) {
@@ -1122,30 +1170,24 @@ static void
 gst_oss4_mixer_controls_guess_master (GstOss4Mixer * mixer,
     const GList * controls)
 {
-  GstOss4MixerControl *firstpcm_mc = NULL;
   GstOss4MixerControl *master_mc = NULL;
   const GList *l;
 
   for (l = controls; l != NULL; l = l->next) {
     GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data;
 
-    if (((mc->mixext.flags & MIXF_MAINVOL)) && master_mc == NULL) {
-      GST_INFO_OBJECT (mixer, "Master control: %s", mc->mixext.extname);
-      master_mc = mc;
-      break;
-    }
     /* do we need to check if it's a slider type here? */
-    if (((mc->mixext.flags & MIXF_PCMVOL)) && firstpcm_mc == NULL) {
+    if ((mc->mixext.flags & MIXF_PCMVOL)) {
       GST_INFO_OBJECT (mixer, "First PCM control: %s", mc->mixext.extname);
-      firstpcm_mc = mc;
+      master_mc = mc;
+      break;
     }
-  }
 
-  /* if no control with MIXF_MAINVOL found, use first one with PCMVOL */
-  if (master_mc == NULL && firstpcm_mc != NULL) {
-    GST_INFO_OBJECT (mixer, "Marking first PCM control as master: %s",
-        firstpcm_mc->mixext.extname);
-    master_mc = firstpcm_mc;
+    if (((mc->mixext.flags & MIXF_MAINVOL)) && master_mc == NULL) {
+      GST_INFO_OBJECT (mixer, "First main volume control: %s",
+	  mc->mixext.extname);
+      master_mc = mc;
+    }
   }
 
   if (master_mc != NULL)
@@ -1308,7 +1350,8 @@ gst_oss4_mixer_enum_control_update_enum_list (GstOss4Mixer * mixer,
     mc->enum_vals = g_new0 (GQuark, mc->mixext.maxvalue + 1);
     for (i = 0; i < mc->mixext.maxvalue; ++i) {
       GST_LOG ("  %s", ei.strings + ei.strindex[i]);
-      mc->enum_vals[i] = g_quark_from_string (ei.strings + ei.strindex[i]);
+      mc->enum_vals[i] = g_quark_from_string (
+	gst_oss4_mixer_control_get_translated_option (ei.strings + ei.strindex[i]));
     }
   }
 
@@ -1461,7 +1504,8 @@ gst_oss4_mixer_create_tracks (GstOss4Mixer * mixer, const GList * controls)
     if (track == NULL)
       continue;
 
-    track->label = gst_oss4_mixer_control_get_pretty_name (mc);
+    /* The mixer API requires this to be g_strdup'd */
+    track->label = g_strdup (gst_oss4_mixer_control_get_translated_name (mc));
     track->flags = 0;
 
     GST_LOG ("translated label: %s [%s] = %s", track->label, mc->mixext.id,
@@ -1471,20 +1515,41 @@ gst_oss4_mixer_create_tracks (GstOss4Mixer * mixer, const GList * controls)
      * esp. if a slider's role can be changed on the fly, like when you change
      * function of a connector. What should we do in that case? Change the flag
      * and make the app rebuild the interface? Ignore it? */
-    if (g_str_has_prefix (mc->mixext.extname, "record.")) {
-      mc->is_output = FALSE;
-      mc->is_input = TRUE;
+    if (mc->mixext.flags & (MIXF_MAINVOL|MIXF_PCMVOL)) {
+      track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST;
+
+    } else if (mc->mixext.flags & MIXF_RECVOL) {
+      /* record gain whitelisted by default */
+      track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD |
+	GST_MIXER_TRACK_WHITELIST;
+
+    } else if (mc->mixext.flags & MIXF_MONVOL) {
+      /* monitor sources not whitelisted by default */
+      track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD;
     }
 
-    /* FIXME: determine is_input and is_output */
-    /* must be either INPUT or OUTPUT (but not both and not neither) for now,
-     * or gnome-volume-control aborts */
-    if (mc->is_input)
-      track->flags |= GST_MIXER_TRACK_INPUT;
-    else if (mc->is_output)
-      track->flags |= GST_MIXER_TRACK_OUTPUT;
-    else
+    /*
+     * The kernel may give us better clues about the scope of a control.
+     * If so, try to honor it.
+     */
+    switch (mc->mixext.desc & MIXEXT_SCOPE_MASK) {
+    case MIXEXT_SCOPE_INPUT:
+    case MIXEXT_SCOPE_RECSWITCH:
+      track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD |
+	GST_MIXER_TRACK_WHITELIST;
+      break;
+    case MIXEXT_SCOPE_MONITOR:
+      /* don't whitelist monitor tracks by default */
+      track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD;
+      break;
+    case MIXEXT_SCOPE_OUTPUT:
+      track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST;
+      break;
+    }
+
+    if (mc->is_master) {
       track->flags |= GST_MIXER_TRACK_OUTPUT;
+    }
 
     if (mc->is_master)
       track->flags |= GST_MIXER_TRACK_MASTER;
@@ -1597,6 +1662,10 @@ gst_oss4_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track,
 
   memset (volumes, 0, track->num_channels * sizeof (gint));
 
+  if (GST_IS_OSS4_MIXER_SWITCH (track)) {
+    gboolean enabled = FALSE;
+    gst_oss4_mixer_switch_get (GST_OSS4_MIXER_SWITCH (track), &enabled);
+  }
   if (GST_IS_OSS4_MIXER_SLIDER (track)) {
     gst_oss4_mixer_slider_get_volume (GST_OSS4_MIXER_SLIDER (track), volumes);
   }
@@ -1649,11 +1718,7 @@ gst_oss4_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
   if (GST_IS_OSS4_MIXER_SLIDER (track)) {
     gst_oss4_mixer_slider_set_mute (GST_OSS4_MIXER_SLIDER (track), mute);
   } else if (GST_IS_OSS4_MIXER_SWITCH (track)) {
-    if ((track->flags & GST_MIXER_TRACK_OUTPUT)) {
-      gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), mute);
-    } else {
-      GST_WARNING_OBJECT (track, "set_mute called on non-OUTPUT track");
-    }
+    gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), mute);
   }
 
   GST_OBJECT_UNLOCK (oss);
@@ -1717,7 +1782,8 @@ gst_oss4_mixer_get_option (GstMixer * mixer, GstMixerOptions * options)
 static GstMixerFlags
 gst_oss4_mixer_get_mixer_flags (GstMixer * mixer)
 {
-  return GST_MIXER_FLAG_AUTO_NOTIFICATIONS;
+  return GST_MIXER_FLAG_AUTO_NOTIFICATIONS | GST_MIXER_FLAG_HAS_WHITELIST |
+    GST_MIXER_FLAG_GROUPING;
 }
 
 static void
diff --git a/sys/oss4/oss4-mixer.h b/sys/oss4/oss4-mixer.h
index 4eaff50..f470d64 100644
--- a/sys/oss4/oss4-mixer.h
+++ b/sys/oss4/oss4-mixer.h
@@ -81,6 +81,7 @@ struct _GstOss4MixerControl {
   GList               *children;       /* GstOss4MixerControls (no ownership)  */
 
   GQuark              *enum_vals;      /* 0-terminated array of values or NULL */
+
   int                  enum_version;   /* 0 = list won't change                */
 
   int                  last_val;       /* last value seen                      */
diff --git a/sys/oss4/oss4-sink.c b/sys/oss4/oss4-sink.c
index 7454af4..752b19a 100644
--- a/sys/oss4/oss4-sink.c
+++ b/sys/oss4/oss4-sink.c
@@ -102,7 +102,7 @@ enum
 };
 
 GST_BOILERPLATE_FULL (GstOss4Sink, gst_oss4_sink, GstAudioSink,
-    GST_TYPE_AUDIO_SINK, gst_oss4_sink_init_interfaces);
+    GST_TYPE_AUDIO_SINK, gst_oss4_sink_init_interfaces)
 
 static void
 gst_oss4_sink_dispose (GObject * object)
@@ -512,6 +512,10 @@ gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length)
   n = write (oss->fd, data, length);
   GST_LOG_OBJECT (asink, "wrote %d/%d samples, %d bytes",
       n / oss->bytes_per_sample, length / oss->bytes_per_sample, n);
+#if 0
+  printf("wrote %d/%d samples, %d bytes\n",
+      n / oss->bytes_per_sample, length / oss->bytes_per_sample, n);
+#endif
 
   if (G_UNLIKELY (n < 0)) {
     switch (errno) {
@@ -542,6 +546,9 @@ gst_oss4_sink_delay (GstAudioSink * asink)
   GstOss4Sink *oss;
   gint delay = -1;
 
+  audio_buf_info info;
+  gint ret;
+
   oss = GST_OSS4_SINK_CAST (asink);
 
   if (ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay) < 0 || delay < 0) {
diff --git a/sys/oss4/oss4-source.c b/sys/oss4/oss4-source.c
index d3b92f7..75141a4 100644
--- a/sys/oss4/oss4-source.c
+++ b/sys/oss4/oss4-source.c
@@ -77,7 +77,7 @@ enum
 static void gst_oss4_source_init_interfaces (GType type);
 
 GST_BOILERPLATE_FULL (GstOss4Source, gst_oss4_source, GstAudioSrc,
-    GST_TYPE_AUDIO_SRC, gst_oss4_source_init_interfaces);
+    GST_TYPE_AUDIO_SRC, gst_oss4_source_init_interfaces)
 
 static void gst_oss4_source_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
@@ -567,7 +567,7 @@ gst_oss4_source_reset (GstAudioSrc * asrc)
  * gnome-sound-recorder does. */
 
 /* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */
-G_DEFINE_TYPE (GstOss4SourceInput, gst_oss4_source_input, GST_TYPE_MIXER_TRACK);
+G_DEFINE_TYPE (GstOss4SourceInput, gst_oss4_source_input, GST_TYPE_MIXER_TRACK)
 
 static void
 gst_oss4_source_input_class_init (GstOss4SourceInputClass * klass)