Interface implementation example: OSS mixer. Also osscommon->osselement so it can...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 13 Sep 2003 01:22:59 +0000 (01:22 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 13 Sep 2003 01:22:59 +0000 (01:22 +0000)
Original commit message from CVS:
Interface implementation example: OSS mixer. Also osscommon->osselement so it can be loaded without being a source/sink (for a stand-alone mixer)

sys/oss/Makefile.am
sys/oss/gstossaudio.c
sys/oss/gstosselement.c [new file with mode: 0644]
sys/oss/gstosselement.h [new file with mode: 0644]
sys/oss/gstossmixer.c [new file with mode: 0644]
sys/oss/gstossmixer.h [new file with mode: 0644]
sys/oss/gstosssink.c
sys/oss/gstosssink.h
sys/oss/gstosssrc.c
sys/oss/gstosssrc.h

index 37b0f8f..21d957b 100644 (file)
@@ -3,11 +3,12 @@ plugin_LTLIBRARIES = libgstossaudio.la
 
 EXTRA_LTLIBRARIES = libgstosshelper.la
 
-libgstossaudio_la_SOURCES = gstosssink.c       \
+libgstossaudio_la_SOURCES = gstossaudio.c      \
+                           gstosselement.c     \
+                           gstossmixer.c       \
+                           gstosssink.c        \
                            gstosssrc.c         \
-                           gstossaudio.c       \
-                           gstossgst.c         \
-                           gstosscommon.c
+                           gstossgst.c
 
 libgstossaudio_la_CFLAGS = $(GST_CFLAGS)
 libgstossaudio_la_LIBADD =
@@ -16,4 +17,9 @@ libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstosshelper_la_SOURCES = gstosshelper.c
 libgstosshelper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
-noinst_HEADERS = gstosssink.h gstosssrc.h gstossgst.h gstosshelper.h gstosscommon.h
+noinst_HEADERS = gstosssink.h   \
+                gstosssrc.h     \
+                gstossgst.h     \
+                gstosshelper.h  \
+                gstosselement.h \
+                gstossmixer.c
index e1d54c3..8c9421a 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
+#include "gstosselement.h"
 #include "gstosssink.h"
 #include "gstosssrc.h"
 #include "gstossgst.h"
 static gboolean
 plugin_init (GModule *module, GstPlugin *plugin)
 {
-  gboolean ret;
-
   if (!gst_library_load ("gstaudio"))
     return FALSE;
 
-  ret = gst_osssink_factory_init (plugin);
-  g_return_val_if_fail (ret == TRUE, FALSE);
-
-  ret = gst_osssrc_factory_init (plugin);
-  g_return_val_if_fail (ret == TRUE, FALSE);
-
-  ret = gst_ossgst_factory_init (plugin);
-  g_return_val_if_fail (ret == TRUE, FALSE);
+  if (!gst_osselement_factory_init (plugin) ||
+      !gst_osssrc_factory_init (plugin) ||
+      !gst_osssink_factory_init (plugin) ||
+      !gst_ossgst_factory_init (plugin)) {
+    g_warning ("Failed to register OSS elements!");
+    return FALSE;
+  }
 
   return TRUE;
 }
diff --git a/sys/oss/gstosselement.c b/sys/oss/gstosselement.c
new file mode 100644 (file)
index 0000000..f437998
--- /dev/null
@@ -0,0 +1,681 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstosssink.c: 
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gstosselement.h"
+#include "gstossmixer.h"
+
+enum {
+  ARG_0,
+  ARG_DEVICE,
+  ARG_MIXERDEV,
+};
+
+/* elementfactory information */
+static GstElementDetails gst_osselement_details = {
+  "Audio Element (OSS)",
+  "Generic/Audio",
+  "LGPL",
+  "Generic OSS element",
+  VERSION,
+  "Erik Walthinsen <omega@cse.ogi.edu>",
+  "(C) 1999",
+};
+
+static void                    gst_osselement_class_init       (GstOssElementClass *klass);
+static void                    gst_osselement_init             (GstOssElement *oss);
+static void                    gst_osselement_dispose          (GObject *object);
+
+static void                    gst_osselement_set_property     (GObject *object,
+                                                                guint prop_id, 
+                                                                const GValue *value,
+                                                                GParamSpec *pspec);
+static void                    gst_osselement_get_property     (GObject *object,
+                                                                guint prop_id,
+                                                                GValue *value,
+                                                                GParamSpec *pspec);
+static GstElementStateReturn   gst_osselement_change_state     (GstElement *element);
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_osssrc_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_osselement_get_type (void) 
+{
+  static GType osselement_type = 0;
+
+  if (!osselement_type) {
+    static const GTypeInfo osselement_info = {
+      sizeof(GstOssElementClass),
+      NULL,
+      NULL,
+      (GClassInitFunc)gst_osselement_class_init,
+      NULL,
+      NULL,
+      sizeof(GstOssElement),
+      0,
+      (GInstanceInitFunc)gst_osselement_init,
+    };
+    static const GInterfaceInfo ossiface_info = {
+      (GInterfaceInitFunc) gst_oss_interface_init,
+      NULL,
+      NULL,
+    };
+    static const GInterfaceInfo ossmixer_info = {
+      (GInterfaceInitFunc) gst_ossmixer_interface_init,
+      NULL,
+      NULL,
+    };
+
+    osselement_type = g_type_register_static (GST_TYPE_ELEMENT,
+                                             "GstOssElement",
+                                             &osselement_info, 0);
+    g_type_add_interface_static (osselement_type,
+                                GST_TYPE_INTERFACE,
+                                &ossiface_info);
+    g_type_add_interface_static (osselement_type,
+                                GST_TYPE_MIXER,
+                                &ossmixer_info);
+  }
+
+  return osselement_type;
+}
+
+static void
+gst_osselement_class_init (GstOssElementClass *klass) 
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
+    g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)",
+                         "default", G_PARAM_READWRITE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MIXERDEV,
+    g_param_spec_string ("mixerdev", "mixer device",
+                        "oss mixer device (/dev/mixerN usually)",
+                         "default", G_PARAM_READWRITE));
+  
+  gobject_class->set_property = gst_osselement_set_property;
+  gobject_class->get_property = gst_osselement_get_property;
+  gobject_class->dispose      = gst_osselement_dispose;
+
+  gstelement_class->change_state = gst_osselement_change_state;
+}
+
+static void 
+gst_osselement_init (GstOssElement *oss) 
+{
+  oss->device = g_strdup ("/dev/dsp");
+  oss->mixer_dev = g_strdup ("/dev/mixer");
+  oss->fd = -1;
+  oss->mixer_fd = -1;
+  oss->channellist = NULL;
+
+  gst_osselement_reset (oss);
+}
+
+static void
+gst_osselement_dispose (GObject *object)
+{
+  GstOssElement *oss = (GstOssElement *) object;
+
+  g_free (oss->device);
+  g_free (oss->mixer_dev);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+void 
+gst_osselement_reset (GstOssElement *oss) 
+{
+  oss->law = 0;
+  oss->endianness = G_BYTE_ORDER;
+  oss->sign = TRUE;
+  oss->width = 16;
+  oss->depth = 16;
+  oss->channels = 2;
+  oss->rate = 44100;
+  oss->fragment = 6;
+  oss->bps = 0;
+
+/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
+#ifdef WORDS_BIGENDIAN
+  oss->format = AFMT_S16_BE;
+#else
+  oss->format = AFMT_S16_LE;
+#endif /* WORDS_BIGENDIAN */  
+}
+
+static gboolean 
+gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
+                  gint *format, gint *bps) 
+{
+  if (width != depth) 
+    return FALSE;
+
+  *bps = 1;
+
+  if (law == 0) {
+    if (width == 16) {
+      if (sign == TRUE) {
+        if (endianness == G_LITTLE_ENDIAN) {
+         *format = AFMT_S16_LE;
+         GST_DEBUG (
+                    "16 bit signed LE, no law (%d)", *format);
+       }
+        else if (endianness == G_BIG_ENDIAN) {
+         *format = AFMT_S16_BE;
+         GST_DEBUG (
+                    "16 bit signed BE, no law (%d)", *format);
+       }
+      }
+      else {
+        if (endianness == G_LITTLE_ENDIAN) {
+         *format = AFMT_U16_LE;
+         GST_DEBUG (
+                    "16 bit unsigned LE, no law (%d)", *format);
+       }
+        else if (endianness == G_BIG_ENDIAN) {
+         *format = AFMT_U16_BE;
+         GST_DEBUG (
+                    "16 bit unsigned BE, no law (%d)", *format);
+       }
+      }
+      *bps = 2;
+    }
+    else if (width == 8) {
+      if (sign == TRUE) {
+       *format = AFMT_S8;
+       GST_DEBUG (
+                  "8 bit signed, no law (%d)", *format);
+      }
+      else {
+        *format = AFMT_U8;
+       GST_DEBUG (
+                  "8 bit unsigned, no law (%d)", *format);
+      }
+      *bps = 1;
+    }
+  } else if (law == 1) {
+    *format = AFMT_MU_LAW;
+    GST_DEBUG (
+              "mu law (%d)", *format);
+  } else if (law == 2) {
+    *format = AFMT_A_LAW;
+    GST_DEBUG (
+              "a law (%d)", *format);
+  } else {
+    g_critical ("unknown law");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+gboolean 
+gst_osselement_parse_caps (GstOssElement *oss, GstCaps *caps) 
+{
+  gint bps, format;
+
+  gst_caps_get_int (caps, "width", &oss->width);
+  gst_caps_get_int (caps, "depth", &oss->depth);
+               
+  if (oss->width != oss->depth) 
+    return FALSE;
+                 
+  gst_caps_get_int (caps, "law", &oss->law); 
+  gst_caps_get_int (caps, "endianness", &oss->endianness);
+  gst_caps_get_boolean (caps, "signed", &oss->sign);
+                           
+  if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, 
+                          oss->width, oss->depth, &format, &bps))
+  { 
+     GST_DEBUG ("could not get format");
+     return FALSE;
+  }
+
+  gst_caps_get_int (caps, "channels", &oss->channels);
+  gst_caps_get_int (caps, "rate", &oss->rate);
+                             
+  oss->bps = bps * oss->channels * oss->rate;
+  oss->format = format;
+
+  return TRUE;
+}
+
+#define GET_FIXED_INT(caps, name, dest)         \
+G_STMT_START {                                  \
+  if (gst_caps_has_fixed_property (caps, name)) \
+    gst_caps_get_int (caps, name, dest);        \
+} G_STMT_END
+#define GET_FIXED_BOOLEAN(caps, name, dest)     \
+G_STMT_START {                                  \
+  if (gst_caps_has_fixed_property (caps, name)) \
+    gst_caps_get_boolean (caps, name, dest);    \
+} G_STMT_END
+
+gboolean 
+gst_osselement_merge_fixed_caps (GstOssElement *oss, GstCaps *caps) 
+{
+  gint bps, format;
+
+  /* peel off fixed stuff from the caps */
+  GET_FIXED_INT         (caps, "law",        &oss->law);
+  GET_FIXED_INT         (caps, "endianness", &oss->endianness);
+  GET_FIXED_BOOLEAN     (caps, "signed",     &oss->sign);
+  GET_FIXED_INT         (caps, "width",      &oss->width);
+  GET_FIXED_INT         (caps, "depth",      &oss->depth);
+
+  if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, 
+                          oss->width, oss->depth, &format, &bps))
+  { 
+     return FALSE;
+  }
+
+  GET_FIXED_INT         (caps, "rate",       &oss->rate);
+  GET_FIXED_INT         (caps, "channels",   &oss->channels);
+                             
+  oss->bps = bps * oss->channels * oss->rate;
+  oss->format = format;
+                                         
+  return TRUE;
+}
+
+gboolean 
+gst_osselement_sync_parms (GstOssElement *oss) 
+{
+  audio_buf_info space;
+  int frag;
+  gint target_format;
+  gint target_channels;
+  gint target_rate;
+  gint fragscale, frag_ln;
+
+  if (oss->fd == -1)
+    return FALSE;
+  
+  if (oss->fragment >> 16)
+    frag = oss->fragment;
+  else
+    frag = 0x7FFF0000 | oss->fragment;
+  
+  GST_INFO ("osselement: setting sound card to %dHz %d format %s (%08x fragment)",
+            oss->rate, oss->format,
+            (oss->channels == 2) ? "stereo" : "mono", frag);
+
+  ioctl (oss->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+  ioctl (oss->fd, SNDCTL_DSP_RESET, 0);
+
+  target_format   = oss->format;
+  target_channels = oss->channels;
+  target_rate     = oss->rate;
+
+  ioctl (oss->fd, SNDCTL_DSP_SETFMT,   &oss->format);
+  ioctl (oss->fd, SNDCTL_DSP_CHANNELS, &oss->channels);
+  ioctl (oss->fd, SNDCTL_DSP_SPEED,    &oss->rate);
+
+  ioctl (oss->fd, SNDCTL_DSP_GETBLKSIZE, &oss->fragment_size);
+
+  if (oss->mode == GST_OSSELEMENT_WRITE) {
+    ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space);
+  }
+  else {
+    ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &space);
+  }
+
+  /* calculate new fragment using a poor man's logarithm function */
+  fragscale = 1;
+  frag_ln = 0;
+  while (fragscale < space.fragsize) {
+    fragscale <<= 1;
+    frag_ln++;
+  }
+  oss->fragment = space.fragstotal << 16 | frag_ln;
+         
+  GST_INFO ("osselement: set sound card to %dHz, %d format, %s "
+           "(%d bytes buffer, %08x fragment)",
+            oss->rate, oss->format,
+            (oss->channels == 2) ? "stereo" : "mono", 
+           space.bytes, oss->fragment);
+
+  oss->fragment_time = (GST_SECOND * oss->fragment_size) / oss->bps;
+  GST_INFO ("fragment time %u %" G_GUINT64_FORMAT "\n", 
+            oss->bps, oss->fragment_time);
+
+  if (target_format   != oss->format   ||
+      target_channels != oss->channels ||
+      target_rate     != oss->rate) 
+  {
+    g_warning ("couldn't set requested OSS parameters, enjoy the noise :)");
+    /* we could eventually return FALSE here, or just do some additional tests
+     * to see that the frequencies don't differ too much etc.. */
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_osselement_open_audio (GstOssElement *oss)
+{
+  gint caps;
+  GstOssOpenMode mode = GST_OSSELEMENT_READ;
+  const GList *padlist;
+
+  g_return_val_if_fail (oss->fd == -1, FALSE);
+  GST_INFO ("osselement: attempting to open sound device");
+
+  /* Ok, so how do we open the device? We assume that we have (max.) one
+   * pad, and if this is a sinkpad, we're osssink (w). else, we're osssrc (r) */
+  padlist = gst_element_get_pad_list (GST_ELEMENT (oss));
+  if (padlist != NULL) {
+    GstPad *firstpad = padlist->data;
+    if (GST_PAD_IS_SINK (firstpad)) {
+      mode = GST_OSSELEMENT_WRITE;
+    }
+  }
+
+  /* first try to open the sound card */
+  if (mode == GST_OSSELEMENT_WRITE) {
+    /* open non blocking first so that it returns immediatly with an error
+     * when we cannot get to the device */
+    oss->fd = open (oss->device, O_WRONLY | O_NONBLOCK);
+
+    if (oss->fd >= 0) {
+      close (oss->fd);
+                         
+      /* re-open the sound device in blocking mode */
+      oss->fd = open (oss->device, O_WRONLY);
+    }
+  }
+  else {
+    oss->fd = open (oss->device, O_RDONLY);
+  }
+
+  if (oss->fd < 0) {
+    switch (errno) {
+      case EBUSY:
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Unable to open %s (in use ?)",
+                          oss->device);
+       break;
+      case EISDIR:
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Device %s is a directory",
+                          oss->device);
+       break;
+      case EACCES:
+      case ETXTBSY:
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Cannot access %s, check permissions",
+                          oss->device);
+       break;
+      case ENXIO:
+      case ENODEV:
+      case ENOENT:
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Cannot access %s, does it exist ?",
+                          oss->device);
+       break;
+      case EROFS:
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Cannot access %s, read-only filesystem ?",
+                          oss->device);
+      default:
+       /* FIXME: strerror is not threadsafe */
+       gst_element_error (GST_ELEMENT (oss),
+                          "osselement: Cannot open %s, generic error: %s",
+                          oss->device, strerror (errno));
+       break;
+    }
+    return FALSE;
+  }
+
+  oss->mode = mode;
+
+  /* we have it, set the default parameters and go have fun */
+  /* set card state */
+  ioctl (oss->fd, SNDCTL_DSP_GETCAPS, &caps);
+
+  GST_INFO ("osselement: Capabilities %08x", caps);
+
+  if (caps & DSP_CAP_DUPLEX)   GST_INFO ( "osselement:   Full duplex");
+  if (caps & DSP_CAP_REALTIME)         GST_INFO ( "osselement:   Realtime");
+  if (caps & DSP_CAP_BATCH)            GST_INFO ( "osselement:   Batch");
+  if (caps & DSP_CAP_COPROC)           GST_INFO ( "osselement:   Has coprocessor");
+  if (caps & DSP_CAP_TRIGGER)          GST_INFO ( "osselement:   Trigger");
+  if (caps & DSP_CAP_MMAP)             GST_INFO ( "osselement:   Direct access");
+
+#ifdef DSP_CAP_MULTI
+  if (caps & DSP_CAP_MULTI)            GST_INFO ( "osselement:   Multiple open");
+#endif /* DSP_CAP_MULTI */
+
+#ifdef DSP_CAP_BIND
+  if (caps & DSP_CAP_BIND)             GST_INFO ( "osselement:   Channel binding");
+#endif /* DSP_CAP_BIND */
+
+  ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &caps);
+
+  GST_INFO ( "osselement: Formats %08x", caps);
+  if (caps & AFMT_MU_LAW)      GST_INFO ( "osselement:   MU_LAW");
+  if (caps & AFMT_A_LAW)       GST_INFO ( "osselement:   A_LAW");
+  if (caps & AFMT_IMA_ADPCM)           GST_INFO ( "osselement:   IMA_ADPCM");
+  if (caps & AFMT_U8)          GST_INFO ( "osselement:   U8");
+  if (caps & AFMT_S16_LE)      GST_INFO ( "osselement:   S16_LE");
+  if (caps & AFMT_S16_BE)      GST_INFO ( "osselement:   S16_BE");
+  if (caps & AFMT_S8)          GST_INFO ( "osselement:   S8");
+  if (caps & AFMT_U16_LE)       GST_INFO ( "osselement:   U16_LE");
+  if (caps & AFMT_U16_BE)      GST_INFO ( "osselement:   U16_BE");
+  if (caps & AFMT_MPEG)        GST_INFO ( "osselement:   MPEG");
+#ifdef AFMT_AC3
+  if (caps & AFMT_AC3)         GST_INFO ( "osselement:   AC3");
+#endif
+
+  GST_INFO ("osselement: opened audio (%s) with fd=%d",
+           oss->device, oss->fd);
+
+  oss->caps = caps;
+
+  gst_ossmixer_build_list (oss);
+
+  return TRUE;
+}
+
+static void
+gst_osselement_close_audio (GstOssElement *oss)
+{
+  if (oss->fd < 0) 
+    return;
+
+  gst_ossmixer_free_list (oss);
+  close(oss->fd);
+  oss->fd = -1;
+}
+
+gboolean
+gst_osselement_convert (GstOssElement *oss,
+                       GstFormat      src_format,
+                       gint64         src_value,
+                       GstFormat     *dest_format,
+                       gint64        *dest_value)
+{
+  gboolean res = TRUE;
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  if (oss->bps == 0 || oss->channels == 0 || oss->width == 0)
+    return FALSE;
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+         *dest_value = src_value * GST_SECOND / oss->bps;
+          break;
+        case GST_FORMAT_DEFAULT:
+         *dest_value = src_value / (oss->channels * oss->width);
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+         *dest_value = src_value * oss->bps / GST_SECOND;
+          break;
+        case GST_FORMAT_DEFAULT:
+         *dest_value = src_value * oss->rate / GST_SECOND;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+         *dest_value = src_value * GST_SECOND / oss->rate;
+          break;
+        case GST_FORMAT_BYTES:
+         *dest_value = src_value * oss->channels * oss->width;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+
+  return res;
+}
+
+static void 
+gst_osselement_set_property (GObject *object,
+                            guint prop_id,
+                            const GValue *value,
+                            GParamSpec *pspec) 
+{
+  GstOssElement *oss = GST_OSSELEMENT (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      /* disallow changing the device while it is opened
+         get_property("device") should return the right one */
+      if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) {
+        g_free (oss->device);
+        oss->device = g_strdup (g_value_get_string (value));
+      }
+      break;
+    case ARG_MIXERDEV:
+      /* disallow changing the device while it is opened
+         get_property("mixerdev") should return the right one */
+      if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) {
+        g_free (oss->mixer_dev);
+        oss->mixer_dev = g_strdup (g_value_get_string (value));
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+static void 
+gst_osselement_get_property (GObject *object,
+                            guint prop_id,
+                            GValue *value,
+                            GParamSpec *pspec) 
+{
+  GstOssElement *oss = GST_OSSELEMENT (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      g_value_set_string (value, oss->device);
+      break;
+    case ARG_MIXERDEV:
+      g_value_set_string (value, oss->mixer_dev);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstElementStateReturn 
+gst_osselement_change_state (GstElement *element) 
+{
+  GstOssElement *oss = GST_OSSELEMENT (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_NULL_TO_READY:
+      if (!gst_osselement_open_audio (oss)) {
+        return GST_STATE_FAILURE;
+      }
+      GST_INFO ("osselement: opened sound device");
+      break;
+    case GST_STATE_READY_TO_NULL:
+      gst_osselement_close_audio (oss);
+      gst_osselement_reset (oss);
+      GST_INFO ("osselement: closed sound device");
+      break;
+    default:
+      break;
+  }
+      
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
+
+gboolean 
+gst_osselement_factory_init (GstPlugin *plugin) 
+{ 
+  GstElementFactory *factory;
+
+  factory = gst_element_factory_new ("osselement",
+                                    GST_TYPE_OSSELEMENT,
+                                    &gst_osselement_details);
+  g_return_val_if_fail (factory != NULL, FALSE);
+
+  gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+  return TRUE;
+}
diff --git a/sys/oss/gstosselement.h b/sys/oss/gstosselement.h
new file mode 100644 (file)
index 0000000..eeae84b
--- /dev/null
@@ -0,0 +1,113 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstosselement.h: 
+ *
+ * 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 __GST_OSS_ELEMENT_H__
+#define __GST_OSS_ELEMENT_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSSELEMENT \
+  (gst_osselement_get_type())
+#define GST_OSSELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSELEMENT,GstOssElement))
+#define GST_OSSELEMENT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSELEMENT,GstOssElementClass))
+#define GST_IS_OSSELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSELEMENT))
+#define GST_IS_OSSELEMENT_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSELEMENT))
+
+typedef struct _GstOssElement GstOssElement;
+typedef struct _GstOssElementClass GstOssElementClass;
+
+typedef enum {
+  GST_OSSELEMENT_READ,
+  GST_OSSELEMENT_WRITE,
+} GstOssOpenMode;
+
+struct _GstOssElement
+{
+  /* yes, we're a gstelement too */
+  GstElement     parent;
+
+  gchar                *device,
+               *mixer_dev;
+
+  /* device state */
+  int           fd;
+  int           caps; /* the capabilities */
+  gint          format;
+  gint          fragment;
+  guint64       fragment_time;
+  gint          fragment_size;
+  GstOssOpenMode mode;
+
+  /* stats */
+  guint                 bps;
+
+  /* parameters */
+  gint                  law;
+  gint                  endianness;
+  gboolean      sign;
+  gint          width;
+  gint          depth;
+  gint          channels;
+  gint          rate;
+
+  /* mixer stuff */
+  GList                *channellist;
+  guint32       stereomask,
+                recdevs,
+                recmask,
+                mixcaps;
+  gint          mixer_fd;
+};
+
+struct _GstOssElementClass {
+  GstElementClass klass;
+};
+
+GType          gst_osselement_get_type         (void);
+
+/* factory register function */
+gboolean       gst_osselement_factory_init     (GstPlugin *plugin);
+
+/* some useful functions */
+gboolean       gst_osselement_parse_caps       (GstOssElement *oss,
+                                                GstCaps       *caps);
+gboolean       gst_osselement_merge_fixed_caps (GstOssElement *oss,
+                                                GstCaps       *caps);
+       
+gboolean       gst_osselement_sync_parms       (GstOssElement *oss);
+void           gst_osselement_reset            (GstOssElement *oss);
+
+gboolean       gst_osselement_convert          (GstOssElement *oss, 
+                                                GstFormat      src_format,
+                                                gint64         src_value,
+                                                GstFormat     *dest_format,
+                                                gint64        *dest_value);
+
+G_END_DECLS
+
+#endif /* __GST_OSS_ELEMENT_H__ */
diff --git a/sys/oss/gstossmixer.c b/sys/oss/gstossmixer.c
new file mode 100644 (file)
index 0000000..50efc2f
--- /dev/null
@@ -0,0 +1,323 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstossmixer.h: mixer interface implementation for OSS
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+#include "gstossmixer.h"
+
+#define MASK_BIT_IS_SET(mask, bit) \
+  (mask & (1 << bit))
+
+static gboolean                gst_ossmixer_supported     (GstInterface     *iface);
+
+static const GList *   gst_ossmixer_list_channels (GstMixer         *ossmixer);
+
+static void            gst_ossmixer_set_volume    (GstMixer         *ossmixer,
+                                                   GstMixerChannel  *channel,
+                                                   gint             *volumes);
+static void            gst_ossmixer_get_volume    (GstMixer         *ossmixer,
+                                                   GstMixerChannel  *channel,
+                                                   gint             *volumes);
+
+static void            gst_ossmixer_set_record    (GstMixer         *ossmixer,
+                                                   GstMixerChannel  *channel,
+                                                   gboolean          record);
+static void            gst_ossmixer_set_mute      (GstMixer         *ossmixer,
+                                                   GstMixerChannel  *channel,
+                                                   gboolean          mute);
+
+static const gchar *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
+
+GstMixerChannel *
+gst_ossmixer_channel_new (GstOssElement *oss,
+                         gint channel_num,
+                         gint max_chans,
+                         gint flags)
+{
+  GstMixerChannel *channel = (GstMixerChannel *) g_new (GstOssMixerChannel, 1);
+  gint volumes[2];
+
+  channel->label = g_strdup (labels[channel_num]);
+  channel->num_channels = max_chans;
+  channel->flags = flags;
+  channel->min_volume = 0;
+  channel->max_volume = 100;
+  ((GstOssMixerChannel *) channel)->channel_num = channel_num;
+
+  /* volume */
+  gst_ossmixer_get_volume (GST_MIXER (oss),
+                          channel, volumes);
+  if (max_chans == 1) {
+    volumes[1] = 0;
+  }
+  ((GstOssMixerChannel *) channel)->lvol = volumes[0];
+  ((GstOssMixerChannel *) channel)->rvol = volumes[1];
+
+  return channel;
+}
+
+void
+gst_ossmixer_channel_free (GstMixerChannel *channel)
+{
+  g_free (channel->label);
+  g_free (channel);
+}
+
+void
+gst_oss_interface_init (GstInterfaceClass *klass)
+{
+  /* default virtual functions */
+  klass->supported = gst_ossmixer_supported;
+}
+
+void
+gst_ossmixer_interface_init (GstMixerClass *klass)
+{
+  /* default virtual functions */
+  klass->list_channels = gst_ossmixer_list_channels;
+  klass->set_volume = gst_ossmixer_set_volume;
+  klass->get_volume = gst_ossmixer_get_volume;
+  klass->set_mute = gst_ossmixer_set_mute;
+  klass->set_record = gst_ossmixer_set_record;
+}
+
+static gboolean
+gst_ossmixer_supported (GstInterface *iface)
+{
+  return (GST_OSSELEMENT (iface)->mixer_fd != -1);
+}
+
+static const GList *
+gst_ossmixer_list_channels (GstMixer *mixer)
+{
+  GstOssElement *oss = GST_OSSELEMENT (mixer);
+
+  g_return_val_if_fail (oss->mixer_fd != -1, NULL);
+
+  return (const GList *) GST_OSSELEMENT (mixer)->channellist;
+}
+
+static void
+gst_ossmixer_get_volume (GstMixer        *mixer,
+                        GstMixerChannel *channel,
+                        gint            *volumes)
+{
+  gint volume;
+  GstOssElement *oss = GST_OSSELEMENT (mixer);
+  GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
+
+  g_return_if_fail (oss->mixer_fd != -1);
+
+  if (channel->flags & GST_MIXER_CHANNEL_MUTE) {
+    volumes[0] = osschannel->lvol;
+    if (channel->num_channels == 2) {
+      volumes[1] = osschannel->rvol;
+    }
+  } else {
+    /* get */
+    if (ioctl(oss->mixer_fd, MIXER_READ (osschannel->channel_num), &volume) < 0) {
+      g_warning("Error getting recording device (%d) volume (0x%x): %s\n",
+               osschannel->channel_num, volume, strerror(errno));
+      volume = 0;
+    }
+
+    osschannel->lvol = volumes[0] = (volume & 0xff);
+    if (channel->num_channels == 2) {
+      osschannel->rvol = volumes[1] = ((volume >> 8) & 0xff);
+    }
+  }
+}
+
+static void
+gst_ossmixer_set_volume (GstMixer        *mixer,
+                        GstMixerChannel *channel,
+                        gint            *volumes)
+{
+  gint volume;
+  GstOssElement *oss = GST_OSSELEMENT (mixer);
+  GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
+
+  g_return_if_fail (oss->mixer_fd != -1);
+
+  /* prepare the value for ioctl() */
+  if (!(channel->flags & GST_MIXER_CHANNEL_MUTE)) {
+    volume = (volumes[0] & 0xff);
+    if (channel->num_channels == 2) {
+      volume |= ((volumes[1] & 0xff) << 8);
+    }
+
+    /* set */
+    if (ioctl(oss->mixer_fd, MIXER_WRITE (osschannel->channel_num), &volume) < 0) {
+      g_warning("Error setting recording device (%d) volume (0x%x): %s\n",
+               osschannel->channel_num, volume, strerror(errno));
+      return;
+    }
+  }
+
+  osschannel->lvol = volumes[0];
+  if (channel->num_channels == 2) {
+    osschannel->rvol = volumes[1];
+  }
+}
+
+static void
+gst_ossmixer_set_mute (GstMixer        *mixer,
+                      GstMixerChannel *channel,
+                      gboolean         mute)
+{
+  int volume;
+  GstOssElement *oss = GST_OSSELEMENT (mixer);
+  GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
+
+  g_return_if_fail (oss->mixer_fd != -1);
+
+  if (mute) {
+    volume = 0;
+  } else {
+    volume = (osschannel->lvol & 0xff);
+    if (MASK_BIT_IS_SET (oss->stereomask, osschannel->channel_num)) {
+      volume |= ((osschannel->rvol & 0xff) << 8);
+    }
+  }
+
+  if (ioctl(oss->mixer_fd, MIXER_WRITE(osschannel->channel_num), &volume) < 0) {
+    g_warning("Error setting mixer recording device volume (0x%x): %s",
+             volume, strerror(errno));
+    return;
+  }
+
+  if (mute) {
+    channel->flags |= GST_MIXER_CHANNEL_MUTE;
+  } else {
+    channel->flags &= ~GST_MIXER_CHANNEL_MUTE;
+  }
+}
+
+static void
+gst_ossmixer_set_record (GstMixer        *mixer,
+                        GstMixerChannel *channel,
+                        gboolean         record)
+{
+  GstOssElement *oss = GST_OSSELEMENT (mixer);
+  GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
+
+  g_return_if_fail (oss->mixer_fd != -1);
+
+  /* if we're exclusive, then we need to unset the current one(s) */
+  if (oss->mixcaps & SOUND_CAP_EXCL_INPUT) {
+    GList *channel;
+    for (channel = oss->channellist; channel != NULL; channel = channel->next) {
+      GstMixerChannel *turn = (GstMixerChannel *) channel->data;
+      turn->flags &= ~GST_MIXER_CHANNEL_RECORD;
+    }
+    oss->recdevs = 0;
+  }
+
+  /* set new record bit, if needed */
+  if (record) {
+    oss->recdevs |= (1 << osschannel->channel_num);
+  } else {
+    oss->recdevs &= ~(1 << osschannel->channel_num);
+  }
+
+  /* set it to the device */
+  if (ioctl(oss->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &oss->recdevs) < 0) {
+    g_warning("Error setting mixer recording devices (0x%x): %s",
+             oss->recdevs, strerror(errno));
+    return;
+  }
+
+  if (record) {
+    channel->flags |= GST_MIXER_CHANNEL_RECORD;
+  } else {
+    channel->flags &= ~GST_MIXER_CHANNEL_RECORD;
+  }
+}
+
+void
+gst_ossmixer_build_list (GstOssElement *oss)
+{
+  gint i, devmask;
+
+  g_return_if_fail (oss->mixer_fd == -1);
+
+  oss->mixer_fd = open (oss->mixer_dev, O_RDWR);
+  if (oss->mixer_fd == -1) {
+    g_warning ("Failed to open mixer device %s, mixing disabled: %s",
+              oss->mixer_dev, strerror (errno));
+    return;
+  }
+
+  /* get masks */
+  ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECMASK, &oss->recmask);
+  ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECSRC, &oss->recdevs);
+  ioctl (oss->mixer_fd, SOUND_MIXER_READ_STEREODEVS, &oss->stereomask);
+  ioctl (oss->mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask);
+  ioctl (oss->mixer_fd, SOUND_MIXER_READ_CAPS, &oss->mixcaps);
+
+  /* build channel list */
+  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+    if (devmask & (1 << i)) {
+      GstMixerChannel *channel;
+      gboolean input = FALSE, stereo = FALSE, record = FALSE;
+
+      /* channel exists, make up capabilities */
+      if (MASK_BIT_IS_SET (oss->stereomask, i))
+        stereo = TRUE;
+      if (MASK_BIT_IS_SET (oss->recmask, i))
+        input = TRUE;
+      if (MASK_BIT_IS_SET (oss->recdevs, i))
+        record = TRUE;
+
+      /* add channel to list */
+      channel = gst_ossmixer_channel_new (oss, i, stereo ? 2 : 1,
+                                         (record ? GST_MIXER_CHANNEL_RECORD : 0) |
+                                         (input ? GST_MIXER_CHANNEL_INPUT :
+                                                  GST_MIXER_CHANNEL_OUTPUT));
+      oss->channellist = g_list_append (oss->channellist, channel);
+    }
+  }
+}
+
+void
+gst_ossmixer_free_list (GstOssElement *oss)
+{
+  g_return_if_fail (oss->mixer_fd != -1);
+
+  g_list_foreach (oss->channellist, (GFunc) gst_ossmixer_channel_free, NULL);
+  g_list_free (oss->channellist);
+  oss->channellist = NULL;
+
+  close (oss->mixer_fd);
+  oss->mixer_fd = -1;
+}
diff --git a/sys/oss/gstossmixer.h b/sys/oss/gstossmixer.h
new file mode 100644 (file)
index 0000000..eddb40a
--- /dev/null
@@ -0,0 +1,45 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstossmixer.h: mixer interface implementation for OSS
+ *
+ * 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 __GST_OSS_MIXER_H__
+#define __GST_OSS_MIXER_H__
+
+#include <gst/gst.h>
+#include <gst/mixer/mixer.h>
+#include "gstosselement.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstOssMixerChannel {
+  GstMixerChannel parent;
+  gint            lvol, rvol;
+  gint            channel_num;
+} GstOssMixerChannel;
+
+void           gst_ossmixer_interface_init     (GstMixerClass *klass);
+void           gst_oss_interface_init          (GstInterfaceClass *klass);
+void           gst_ossmixer_build_list         (GstOssElement *oss);
+void           gst_ossmixer_free_list          (GstOssElement *oss);
+
+G_END_DECLS
+
+#endif /* __GST_OSS_MIXER_H__ */
index 05a0419..067f69c 100644 (file)
@@ -45,7 +45,6 @@ static GstElementDetails gst_osssink_details = {
 static void                    gst_osssink_class_init          (GstOssSinkClass *klass);
 static void                    gst_osssink_init                (GstOssSink *osssink);
 static void                    gst_osssink_dispose             (GObject *object);
-static void                    gst_osssink_finalize            (GObject *object);
 
 static GstElementStateReturn   gst_osssink_change_state        (GstElement *element);
 static void                    gst_osssink_set_clock           (GstElement *element, GstClock *clock);
@@ -78,7 +77,6 @@ enum {
 
 enum {
   ARG_0,
-  ARG_DEVICE,
   ARG_MUTE,
   ARG_FRAGMENT,
   ARG_BUFFER_SIZE,
@@ -132,7 +130,7 @@ gst_osssink_get_type (void)
       0,
       (GInstanceInitFunc)gst_osssink_init,
     };
-    osssink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSink", &osssink_info, 0);
+    osssink_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSink", &osssink_info, 0);
   }
 
   return osssink_type;
@@ -163,16 +161,6 @@ gst_osssink_dispose (GObject *object)
 }
 
 static void
-gst_osssink_finalize (GObject *object)
-{
-  GstOssSink *osssink = (GstOssSink *) object;
-
-  g_free (osssink->common.device);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
 gst_osssink_class_init (GstOssSinkClass *klass) 
 {
   GObjectClass *gobject_class;
@@ -181,11 +169,8 @@ gst_osssink_class_init (GstOssSinkClass *klass)
   gobject_class = (GObjectClass*)klass;
   gstelement_class = (GstElementClass*)klass;
 
-  parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+  parent_class = g_type_class_ref(GST_TYPE_OSSELEMENT);
 
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
-    g_param_spec_string ("device", "Device", "The device to use for output",
-                         "/dev/dsp", G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE,
     g_param_spec_boolean ("mute", "Mute", "Mute the audio",
                           FALSE, G_PARAM_READWRITE)); 
@@ -211,7 +196,6 @@ gst_osssink_class_init (GstOssSinkClass *klass)
   gobject_class->set_property = gst_osssink_set_property;
   gobject_class->get_property = gst_osssink_get_property;
   gobject_class->dispose      = gst_osssink_dispose;
-  gobject_class->finalize     = gst_osssink_finalize;
   
   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state);
   gstelement_class->query       = GST_DEBUG_FUNCPTR (gst_osssink_query);
@@ -235,8 +219,6 @@ gst_osssink_init (GstOssSink *osssink)
 
   gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain);
 
-  gst_osscommon_init (&osssink->common);
-
   osssink->bufsize = 4096;
   osssink->chunk_size = 4096;
   osssink->resync = FALSE;
@@ -260,10 +242,10 @@ gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
   if (!GST_CAPS_IS_FIXED (caps))
     return GST_PAD_LINK_DELAYED;
 
-  if (!gst_osscommon_parse_caps (&osssink->common, caps))
+  if (!gst_osselement_parse_caps (GST_OSSELEMENT (osssink), caps))
     return GST_PAD_LINK_REFUSED;
 
-  if (!gst_osscommon_sync_parms (&osssink->common)) {
+  if (!gst_osselement_sync_parms (GST_OSSELEMENT (osssink))) {
     return GST_PAD_LINK_REFUSED;
   }
 
@@ -275,12 +257,12 @@ gst_osssink_get_delay (GstOssSink *osssink)
 {
   gint delay = 0;
 
-  if (osssink->common.fd == -1)
+  if (GST_OSSELEMENT (osssink)->fd == -1)
     return 0;
 
-  if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
+  if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
     audio_buf_info info;
-    if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+    if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
       delay = 0;
     }
     else {
@@ -297,7 +279,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
   gint delay;
   GstClockTime res;
 
-  if (!osssink->common.bps)
+  if (!GST_OSSELEMENT (osssink)->bps)
     return 0;
 
   delay = gst_osssink_get_delay (osssink);
@@ -308,7 +290,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
   if (((guint64)delay) > osssink->handled) {
     delay = osssink->handled;
   }
-  res =  (osssink->handled - delay) * GST_SECOND / osssink->common.bps;
+  res =  (osssink->handled - delay) * GST_SECOND / GST_OSSELEMENT (osssink)->bps;
 
   return res;
 }
@@ -347,7 +329,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
 
     switch (GST_EVENT_TYPE (event)) {
       case GST_EVENT_EOS:
-        ioctl (osssink->common.fd, SNDCTL_DSP_SYNC);
+        ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_SYNC);
        gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
        gst_pad_event_default (pad, event);
         return;
@@ -355,7 +337,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
       {
        gint64 value;
 
-        ioctl (osssink->common.fd, SNDCTL_DSP_RESET);
+        ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET);
        if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
           if (!gst_clock_handle_discont (osssink->clock, value))
            gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
@@ -372,7 +354,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
     return;
   }
 
-  if (!osssink->common.bps) {
+  if (!GST_OSSELEMENT (osssink)->bps) {
     gst_buffer_unref (buf);
     gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
     return;
@@ -380,7 +362,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
 
   buftime = GST_BUFFER_TIMESTAMP (buf);
 
-  if (osssink->common.fd >= 0) {
+  if (GST_OSSELEMENT (osssink)->fd >= 0) {
     if (!osssink->mute) {
       guchar *data = GST_BUFFER_DATA (buf);
       gint size = GST_BUFFER_SIZE (buf);
@@ -392,7 +374,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
        GstClockTimeDiff jitter;
     
        delay = gst_osssink_get_delay (osssink);
-       queued = delay * GST_SECOND / osssink->common.bps;
+       queued = delay * GST_SECOND / GST_OSSELEMENT (osssink)->bps;
 
        if  (osssink->resync && osssink->sync) {
           GstClockID id = gst_clock_new_single_shot_id (osssink->clock, buftime - queued);
@@ -415,7 +397,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
       else {
         audio_buf_info ospace;
 
-        ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace);
+        ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &ospace);
 
         if (ospace.bytes >= size) {
          to_write = size;
@@ -423,7 +405,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
       }
 
       while (to_write > 0) {
-        gint done = write (osssink->common.fd, data, 
+        gint done = write (GST_OSSELEMENT (osssink)->fd, data, 
                            MIN (to_write, osssink->chunk_size));
 
         if (done == -1) {
@@ -464,8 +446,9 @@ gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
 
   osssink = GST_OSSSINK (gst_pad_get_parent (pad));
   
-  return gst_osscommon_convert (&osssink->common, src_format, src_value,
-                               dest_format, dest_value);
+  return gst_osselement_convert (GST_OSSELEMENT (osssink),
+                                src_format, src_value,
+                                dest_format, dest_value);
 }
 
 static const GstQueryType*
@@ -528,23 +511,13 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
   osssink = GST_OSSSINK (object);
 
   switch (prop_id) {
-    case ARG_DEVICE:
-      /* disallow changing the device while it is opened
-         get_property("device") should return the right one */
-      if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
-      {
-       g_free (osssink->common.device);
-        osssink->common.device = g_strdup (g_value_get_string (value));
-       g_object_notify (object, "device");
-      }
-      break;
     case ARG_MUTE:
       osssink->mute = g_value_get_boolean (value);
       g_object_notify (G_OBJECT (osssink), "mute");
       break;
     case ARG_FRAGMENT:
-      osssink->common.fragment = g_value_get_int (value);
-      gst_osscommon_sync_parms (&osssink->common);
+      GST_OSSELEMENT (osssink)->fragment = g_value_get_int (value);
+      gst_osselement_sync_parms (GST_OSSELEMENT (osssink));
       break;
     case ARG_BUFFER_SIZE:
       osssink->bufsize = g_value_get_uint (value);
@@ -572,14 +545,11 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
   osssink = GST_OSSSINK (object);
 
   switch (prop_id) {
-    case ARG_DEVICE:
-      g_value_set_string (value, osssink->common.device);
-      break;
     case ARG_MUTE:
       g_value_set_boolean (value, osssink->mute);
       break;
     case ARG_FRAGMENT:
-      g_value_set_int (value, osssink->common.fragment);
+      g_value_set_int (value, GST_OSSELEMENT (osssink)->fragment);
       break;
     case ARG_BUFFER_SIZE:
       g_value_set_uint (value, osssink->bufsize);
@@ -604,43 +574,23 @@ gst_osssink_change_state (GstElement *element)
   osssink = GST_OSSSINK (element);
 
   switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-      if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
-       gchar *error;
-
-        if (!gst_osscommon_open_audio (&osssink->common, GST_OSSCOMMON_WRITE, &error)) {
-         gst_element_error (GST_ELEMENT (osssink), error);
-         g_free (error);
-          return GST_STATE_FAILURE;
-        }
-       GST_FLAG_SET (element, GST_OSSSINK_OPEN);
-      }
-      break;
     case GST_STATE_READY_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       osssink->resync = TRUE;
       break;
     case GST_STATE_PLAYING_TO_PAUSED:
-    {
       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) 
-        ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
+        ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0);
       gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
       osssink->resync = TRUE;
       break;
-    }
     case GST_STATE_PAUSED_TO_READY:
       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
-        ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
-      gst_osscommon_reset (&osssink->common);
+        ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0);
+      gst_osselement_reset (GST_OSSELEMENT (osssink));
       break;
-    case GST_STATE_READY_TO_NULL:
-      if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
-        gst_osscommon_close_audio (&osssink->common);
-        GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN);
-
-        GST_INFO ( "osssink: closed sound device");
-      }
+    default:
       break;
   }
       
index 7427769..590ce7f 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <gst/gst.h>
 
-#include "gstosscommon.h"
+#include "gstosselement.h"
 #include <gst/audio/audioclock.h>
 
 G_BEGIN_DECLS
@@ -53,7 +53,7 @@ typedef struct _GstOssSink GstOssSink;
 typedef struct _GstOssSinkClass GstOssSinkClass;
 
 struct _GstOssSink {
-  GstElement    element;
+  GstOssElement         element;
 
   GstPad       *sinkpad;
   GstBufferPool *sinkpool;
@@ -64,12 +64,9 @@ struct _GstOssSink {
   gboolean      sync;
   guint64       handled;
 
-  GstOssCommon  common;
-
   gboolean      mute;
   guint         bufsize;
   guint         chunk_size;
-
 };
 
 struct _GstOssSinkClass {
index 0e41d24..c2ff002 100644 (file)
@@ -33,7 +33,7 @@
 #include <string.h>
 
 #include <gstosssrc.h>
-#include <gstosscommon.h>
+#include <gstosselement.h>
 #include <gst/audio/audioclock.h>
 
 /* elementfactory information */
@@ -56,7 +56,6 @@ enum {
 
 enum {
   ARG_0,
-  ARG_DEVICE,
   ARG_BUFFERSIZE,
   ARG_FRAGMENT,
 };
@@ -89,7 +88,6 @@ GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
 static void                    gst_osssrc_class_init   (GstOssSrcClass *klass);
 static void                    gst_osssrc_init         (GstOssSrc *osssrc);
 static void                    gst_osssrc_dispose      (GObject *object);
-static void                    gst_osssrc_finalize     (GObject *object);
 
 static GstPadLinkReturn        gst_osssrc_srcconnect   (GstPad *pad, GstCaps *caps);
 static const GstFormat*        gst_osssrc_get_formats  (GstPad *pad);
@@ -136,7 +134,7 @@ gst_osssrc_get_type (void)
       0,
       (GInstanceInitFunc)gst_osssrc_init,
     };
-    osssrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSrc", &osssrc_info, 0);
+    osssrc_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSrc", &osssrc_info, 0);
   }
   return osssrc_type;
 }
@@ -150,14 +148,11 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
   gobject_class = (GObjectClass*)klass;
   gstelement_class = (GstElementClass*)klass;
 
-  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+  parent_class = g_type_class_ref (GST_TYPE_OSSELEMENT);
 
   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE,
     g_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples",
                         0, G_MAXULONG, 0, G_PARAM_READWRITE));
-  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
-    g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)",
-                         "default", G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAGMENT,
     g_param_spec_int ("fragment", "Fragment",
                       "The fragment as 0xMMMMSSSS (MMMM = total fragments, 2^SSSS = fragment size)",
@@ -166,7 +161,6 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
   gobject_class->set_property = gst_osssrc_set_property;
   gobject_class->get_property = gst_osssrc_get_property;
   gobject_class->dispose      = gst_osssrc_dispose;
-  gobject_class->finalize     = gst_osssrc_finalize;
 
   gstelement_class->change_state = gst_osssrc_change_state;
   gstelement_class->send_event = gst_osssrc_send_event;
@@ -192,8 +186,6 @@ gst_osssrc_init (GstOssSrc *osssrc)
 
   gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
 
-  gst_osscommon_init (&osssrc->common);
-
   osssrc->buffersize = 4096;
   osssrc->curoffset = 0;
 
@@ -202,6 +194,7 @@ gst_osssrc_init (GstOssSrc *osssrc)
   
   osssrc->clock = NULL;
 }
+
 static void
 gst_osssrc_dispose (GObject *object)
 {
@@ -211,16 +204,6 @@ gst_osssrc_dispose (GObject *object)
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
-static void
-gst_osssrc_finalize (GObject *object)
-{
-  GstOssSrc *osssrc = (GstOssSrc *) object;
-
-  g_free (osssrc->common.device);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 
 static GstPadLinkReturn 
 gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
@@ -232,10 +215,10 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
   if (!GST_CAPS_IS_FIXED (caps))
     return GST_PAD_LINK_DELAYED;
 
-  if (!gst_osscommon_parse_caps (&src->common, caps))
+  if (!gst_osselement_parse_caps (GST_OSSELEMENT (src), caps))
     return GST_PAD_LINK_REFUSED;
 
-  if (!gst_osscommon_sync_parms (&src->common))
+  if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
     return GST_PAD_LINK_REFUSED;
 
   return GST_PAD_LINK_OK;
@@ -251,10 +234,10 @@ gst_osssrc_negotiate (GstPad *pad)
 
   allowed = gst_pad_get_allowed_caps (pad);
 
-  if (!gst_osscommon_merge_fixed_caps (&src->common, allowed))
+  if (!gst_osselement_merge_fixed_caps (GST_OSSELEMENT (src), allowed))
     return FALSE;
 
-  if (!gst_osscommon_sync_parms (&src->common))
+  if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
     return FALSE;
     
   /* set caps on src pad */
@@ -262,12 +245,12 @@ gst_osssrc_negotiate (GstPad *pad)
        GST_CAPS_NEW (
          "oss_src",
          "audio/x-raw-int",
-           "endianness", GST_PROPS_INT (src->common.endianness),
-           "signed",     GST_PROPS_BOOLEAN (src->common.sign),
-           "width",      GST_PROPS_INT (src->common.width),
-           "depth",      GST_PROPS_INT (src->common.depth),
-           "rate",       GST_PROPS_INT (src->common.rate),
-           "channels",   GST_PROPS_INT (src->common.channels)
+           "endianness", GST_PROPS_INT (GST_OSSELEMENT (src)->endianness),
+           "signed",     GST_PROPS_BOOLEAN (GST_OSSELEMENT (src)->sign),
+           "width",      GST_PROPS_INT (GST_OSSELEMENT (src)->width),
+           "depth",      GST_PROPS_INT (GST_OSSELEMENT (src)->depth),
+           "rate",       GST_PROPS_INT (GST_OSSELEMENT (src)->rate),
+           "channels",   GST_PROPS_INT (GST_OSSELEMENT (src)->channels)
         )) <= 0) 
   {
     return FALSE;
@@ -281,13 +264,13 @@ gst_osssrc_get_time (GstClock *clock, gpointer data)
   GstOssSrc *osssrc = GST_OSSSRC (data);
   audio_buf_info info;
 
-  if (!osssrc->common.bps)
+  if (!GST_OSSELEMENT (osssrc)->bps)
     return 0;
 
-  if (ioctl(osssrc->common.fd, SNDCTL_DSP_GETISPACE, &info) < 0)
+  if (ioctl(GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_GETISPACE, &info) < 0)
     return 0;
 
-  return (osssrc->curoffset + info.bytes) * GST_SECOND / osssrc->common.bps;
+  return (osssrc->curoffset + info.bytes) * GST_SECOND / GST_OSSELEMENT (osssrc)->bps;
 }
 
 static GstClock*
@@ -336,13 +319,13 @@ gst_osssrc_get (GstPad *pad)
       return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT));
     }
   }
-  if (src->common.bps == 0) {
+  if (GST_OSSELEMENT (src)->bps == 0) {
     gst_buffer_unref (buf);
     gst_element_error (GST_ELEMENT (src), "no format negotiated");
     return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT));
   }
 
-  readbytes = read (src->common.fd,GST_BUFFER_DATA (buf),
+  readbytes = read (GST_OSSELEMENT (src)->fd,GST_BUFFER_DATA (buf),
                     src->buffersize);
   if (readbytes < 0) {
     gst_buffer_unref (buf);
@@ -361,7 +344,9 @@ gst_osssrc_get (GstPad *pad)
   GST_BUFFER_OFFSET (buf) = src->curoffset;
 
   /* FIXME: we are falsely assuming that we are the master clock here */
-  GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps;
+  GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / GST_OSSELEMENT (src)->bps;
+  GST_BUFFER_DURATION (buf) = (GST_SECOND * GST_BUFFER_SIZE (buf)) /
+                              (GST_OSSELEMENT (src)->bps * GST_OSSELEMENT (src)->rate);
 
   src->curoffset += readbytes;
 
@@ -382,13 +367,9 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP
     case ARG_BUFFERSIZE:
       src->buffersize = g_value_get_ulong (value);
       break;
-    case ARG_DEVICE:
-      g_free(src->common.device);
-      src->common.device = g_strdup (g_value_get_string (value));
-      break;
     case ARG_FRAGMENT:
-      src->common.fragment = g_value_get_int (value);
-      gst_osscommon_sync_parms (&src->common);
+      GST_OSSELEMENT (src)->fragment = g_value_get_int (value);
+      gst_osselement_sync_parms (GST_OSSELEMENT (src));
       break; 
     default:
       break;
@@ -406,11 +387,8 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
     case ARG_BUFFERSIZE:
       g_value_set_ulong (value, src->buffersize);
       break;
-    case ARG_DEVICE:
-      g_value_set_string (value, src->common.device);
-      break;
     case ARG_FRAGMENT:
-      g_value_set_int (value, src->common.fragment);
+      g_value_set_int (value, GST_OSSELEMENT (src)->fragment);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -426,17 +404,6 @@ gst_osssrc_change_state (GstElement *element)
   GST_DEBUG ("osssrc: state change");
 
   switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-      if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { 
-       gchar *error;
-        if (!gst_osscommon_open_audio (&osssrc->common, GST_OSSCOMMON_READ, &error)) {
-         gst_element_error (GST_ELEMENT (osssrc), error);
-         g_free (error);
-          return GST_STATE_FAILURE;
-       }
-        GST_FLAG_SET (osssrc, GST_OSSSRC_OPEN);
-      }
-      break;
     case GST_STATE_READY_TO_PAUSED:
       osssrc->curoffset = 0;
       break;
@@ -448,14 +415,9 @@ gst_osssrc_change_state (GstElement *element)
       break;
     case GST_STATE_PAUSED_TO_READY:
       if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN))
-        ioctl (osssrc->common.fd, SNDCTL_DSP_RESET, 0);
+        ioctl (GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_RESET, 0);
       break;
-    case GST_STATE_READY_TO_NULL:
-      if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) {
-        gst_osscommon_close_audio (&osssrc->common);
-        GST_FLAG_UNSET (osssrc, GST_OSSSRC_OPEN);
-      }
-      gst_osscommon_init (&osssrc->common);
+    default:
       break;
   }
 
@@ -485,7 +447,7 @@ gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
 
   osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
 
-  return gst_osscommon_convert (&osssrc->common, src_format, src_value,
+  return gst_osselement_convert (GST_OSSELEMENT (osssrc), src_format, src_value,
                                 dest_format, dest_value);
 }
 
@@ -521,10 +483,10 @@ gst_osssrc_src_event (GstPad *pad, GstEvent *event)
       format = GST_FORMAT_BYTES;
       
       /* convert to bytes */
-      if (gst_osscommon_convert (&osssrc->common
-                                GST_EVENT_SIZE_FORMAT (event), 
-                                GST_EVENT_SIZE_VALUE (event),
-                                 &format, &value)) 
+      if (gst_osselement_convert (GST_OSSELEMENT (osssrc)
+                                 GST_EVENT_SIZE_FORMAT (event), 
+                                 GST_EVENT_SIZE_VALUE (event),
+                                  &format, &value)) 
       {
         osssrc->buffersize = GST_EVENT_SIZE_VALUE (event);
         g_object_notify (G_OBJECT (osssrc), "buffersize");
@@ -567,9 +529,9 @@ gst_osssrc_src_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64
                
   switch (type) {
     case GST_QUERY_POSITION:
-      res = gst_osscommon_convert (&osssrc->common
-                                  GST_FORMAT_BYTES, osssrc->curoffset,
-                                   format, value); 
+      res = gst_osselement_convert (GST_OSSELEMENT (osssrc)
+                                   GST_FORMAT_BYTES, osssrc->curoffset,
+                                    format, value); 
       break;
     default:
       break;
index befbaf9..dff5aef 100644 (file)
@@ -26,7 +26,7 @@
 
 
 #include <gst/gst.h>
-#include "gstosscommon.h"
+#include "gstosselement.h"
 
 G_BEGIN_DECLS
 
@@ -51,13 +51,11 @@ typedef struct _GstOssSrc GstOssSrc;
 typedef struct _GstOssSrcClass GstOssSrcClass;
 
 struct _GstOssSrc {
-  GstElement    element;
+  GstOssElement  element;
 
   /* pads */
   GstPad       *srcpad;
 
-  GstOssCommon  common;
-
   gboolean      need_eos; /* Do we need to emit an EOS? */
   
   /* blocking */