More refactoring osssrc has more features now, like query/convert etc
authorWim Taymans <wim.taymans@gmail.com>
Sat, 7 Dec 2002 20:54:47 +0000 (20:54 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sat, 7 Dec 2002 20:54:47 +0000 (20:54 +0000)
Original commit message from CVS:
More refactoring
osssrc has more features now, like query/convert etc

sys/oss/gstosscommon.c
sys/oss/gstosscommon.h
sys/oss/gstosssink.c
sys/oss/gstosssink.h
sys/oss/gstosssrc.c
sys/oss/gstosssrc.h

index cadf5a2..50128c7 100644 (file)
  */
 
 
-#include "gstosscommon.h"
+#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>
 
-gboolean 
+#include <config.h>
+#include "gstosscommon.h"
+
+static gboolean 
 gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
                   gint *format, gint *bps) 
 {
@@ -89,3 +98,348 @@ gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint de
 
   return TRUE;
 }
+
+void 
+gst_osscommon_init (GstOssCommon *common) 
+{
+  common->device = g_strdup ("/dev/dsp");
+  common->fd = -1;
+
+  common->law = 0;
+  common->endianness = G_BYTE_ORDER;
+  common->sign = TRUE;
+  common->width = 16;
+  common->depth = 16;
+  common->channels = 2;
+  common->rate = 44100;
+  common->fragment = 6;
+  common->bps = 0;
+
+/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
+#ifdef WORDS_BIGENDIAN
+  common->format = AFMT_S16_BE;
+#else
+  common->format = AFMT_S16_LE;
+#endif /* WORDS_BIGENDIAN */  
+}
+
+gboolean 
+gst_osscommon_parse_caps (GstOssCommon *common, GstCaps *caps) 
+{
+  gint bps, format;
+
+  gst_caps_get_int (caps, "width", &common->width);
+  gst_caps_get_int (caps, "depth", &common->depth);
+               
+  if (common->width != common->depth) 
+    return FALSE;
+                 
+  gst_caps_get_int (caps, "law", &common->law); 
+  gst_caps_get_int (caps, "endianness", &common->endianness);
+  gst_caps_get_boolean (caps, "signed", &common->sign);
+                           
+  if (!gst_ossformat_get (common->law, common->endianness, common->sign, 
+                          common->width, common->depth, &format, &bps))
+  { 
+     GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format");
+     return FALSE;
+  }
+
+  gst_caps_get_int (caps, "channels", &common->channels);
+  gst_caps_get_int (caps, "rate", &common->rate);
+                             
+  common->bps = bps * common->channels * common->rate;
+  common->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_osscommon_merge_fixed_caps (GstOssCommon *common, GstCaps *caps) 
+{
+  gint bps, format;
+
+  /* peel off fixed stuff from the caps */
+  GET_FIXED_INT         (caps, "law",        &common->law);
+  GET_FIXED_INT         (caps, "endianness", &common->endianness);
+  GET_FIXED_BOOLEAN     (caps, "signed",     &common->sign);
+  GET_FIXED_INT         (caps, "width",      &common->width);
+  GET_FIXED_INT         (caps, "depth",      &common->depth);
+
+  if (!gst_ossformat_get (common->law, common->endianness, common->sign, 
+                          common->width, common->depth, &format, &bps))
+  { 
+     return FALSE;
+  }
+
+  GET_FIXED_INT         (caps, "rate",       &common->rate);
+  GET_FIXED_INT         (caps, "channels",   &common->channels);
+                             
+  common->bps = bps * common->channels * common->rate;
+  common->format = format;
+                                         
+  return TRUE;
+}
+
+gboolean 
+gst_osscommon_sync_parms (GstOssCommon *common) 
+{
+  audio_buf_info space;
+  int frag;
+  gint target_format;
+  gint target_channels;
+  gint target_rate;
+  gint fragscale, frag_ln;
+
+  if (common->fd == -1)
+    return FALSE;
+  
+  if (common->fragment >> 16)
+    frag = common->fragment;
+  else
+    frag = 0x7FFF0000 | common->fragment;
+  
+  GST_INFO (GST_CAT_PLUGIN_INFO, 
+            "common: setting sound card to %dHz %d format %s (%08x fragment)",
+            common->rate, common->format,
+            (common->channels == 2) ? "stereo" : "mono", frag);
+
+  ioctl (common->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+  ioctl (common->fd, SNDCTL_DSP_RESET, 0);
+
+  target_format   = common->format;
+  target_channels = common->channels;
+  target_rate     = common->rate;
+
+  ioctl (common->fd, SNDCTL_DSP_SETFMT,   &common->format);
+  ioctl (common->fd, SNDCTL_DSP_CHANNELS, &common->channels);
+  ioctl (common->fd, SNDCTL_DSP_SPEED,    &common->rate);
+
+  ioctl (common->fd, SNDCTL_DSP_GETBLKSIZE, &common->fragment_size);
+
+  if (common->mode == GST_OSSCOMMON_WRITE) {
+    ioctl (common->fd, SNDCTL_DSP_GETOSPACE, &space);
+  }
+  else {
+    ioctl (common->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++;
+  }
+  common->fragment = space.fragstotal << 16 | frag_ln;
+         
+  GST_INFO (GST_CAT_PLUGIN_INFO, 
+            "common: set sound card to %dHz, %d format, %s "
+           "(%d bytes buffer, %08x fragment)",
+            common->rate, common->format,
+            (common->channels == 2) ? "stereo" : "mono", 
+           space.bytes, common->fragment);
+
+  common->fragment_time = (GST_SECOND * common->fragment_size) / common->bps;
+  GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n", 
+            common->bps, common->fragment_time);
+
+  if (target_format   != common->format   ||
+      target_channels != common->channels ||
+      target_rate     != common->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;
+}
+
+gboolean
+gst_osscommon_open_audio (GstOssCommon *common, GstOssOpenMode mode, gchar **error)
+{
+  gint caps;
+  g_return_val_if_fail (common->fd == -1, FALSE);
+
+  GST_INFO (GST_CAT_PLUGIN_INFO, "common: attempting to open sound device");
+
+  /* first try to open the sound card */
+  /* FIXME: this code is dubious, why do we need to open and close this ?*/
+  if (mode == GST_OSSCOMMON_WRITE) {
+    common->fd = open (common->device, O_WRONLY | O_NONBLOCK);
+    if (errno == EBUSY) {
+      g_warning ("osscommon: unable to open the sound device (in use ?)\n");
+    }
+
+    if (common->fd >= 0)
+      close (common->fd);
+  
+    /* re-open the sound device in blocking mode */
+    common->fd = open (common->device, O_WRONLY);
+  }
+  else {
+    common->fd = open (common->device, O_RDONLY);
+  }
+
+  if (common->fd < 0) {
+    switch (errno) {
+      case EISDIR:
+       *error = g_strdup_printf ("osscommon: Device %s is a directory",
+                          common->device);
+       break;
+      case EACCES:
+      case ETXTBSY:
+       *error = g_strdup_printf ( "osscommon: Cannot access %s, check permissions",
+                          common->device);
+       break;
+      case ENXIO:
+      case ENODEV:
+      case ENOENT:
+       *error = g_strdup_printf ("osscommon: Cannot access %s, does it exist ?",
+                          common->device);
+       break;
+      case EROFS:
+       *error = g_strdup_printf ("osscommon: Cannot access %s, read-only filesystem ?",
+                          common->device);
+      default:
+       /* FIXME: strerror is not threadsafe */
+       *error = g_strdup_printf ("osscommon: Cannot open %s, generic error: %s",
+                          common->device, strerror (errno));
+       break;
+    }
+    return FALSE;
+  }
+
+  common->mode = mode;
+
+  /* we have it, set the default parameters and go have fun */
+  /* set card state */
+  ioctl (common->fd, SNDCTL_DSP_GETCAPS, &caps);
+
+  GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Capabilities %08x", caps);
+
+  if (caps & DSP_CAP_DUPLEX)   GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Full duplex");
+  if (caps & DSP_CAP_REALTIME)         GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Realtime");
+  if (caps & DSP_CAP_BATCH)            GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Batch");
+  if (caps & DSP_CAP_COPROC)           GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Has coprocessor");
+  if (caps & DSP_CAP_TRIGGER)          GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Trigger");
+  if (caps & DSP_CAP_MMAP)             GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Direct access");
+
+#ifdef DSP_CAP_MULTI
+  if (caps & DSP_CAP_MULTI)            GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Multiple open");
+#endif /* DSP_CAP_MULTI */
+
+#ifdef DSP_CAP_BIND
+  if (caps & DSP_CAP_BIND)             GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   Channel binding");
+#endif /* DSP_CAP_BIND */
+
+  ioctl(common->fd, SNDCTL_DSP_GETFMTS, &caps);
+
+  GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Formats %08x", caps);
+  if (caps & AFMT_MU_LAW)      GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   MU_LAW");
+  if (caps & AFMT_A_LAW)       GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   A_LAW");
+  if (caps & AFMT_IMA_ADPCM)           GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   IMA_ADPCM");
+  if (caps & AFMT_U8)          GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   U8");
+  if (caps & AFMT_S16_LE)      GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   S16_LE");
+  if (caps & AFMT_S16_BE)      GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   S16_BE");
+  if (caps & AFMT_S8)          GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   S8");
+  if (caps & AFMT_U16_LE)       GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   U16_LE");
+  if (caps & AFMT_U16_BE)      GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   U16_BE");
+  if (caps & AFMT_MPEG)        GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   MPEG");
+#ifdef AFMT_AC3
+  if (caps & AFMT_AC3)         GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon:   AC3");
+#endif
+
+  GST_INFO (GST_CAT_PLUGIN_INFO, 
+                  "osscommon: opened audio (%s) with fd=%d", common->device, common->fd);
+
+  common->caps = caps;
+
+  return TRUE;
+}
+
+void
+gst_osscommon_close_audio (GstOssCommon *common)
+{
+  if (common->fd < 0) 
+    return;
+
+  close(common->fd);
+  common->fd = -1;
+}
+
+gboolean
+gst_osscommon_convert (GstOssCommon *common, 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 (common->bps == 0 || common->channels == 0 || common->width == 0)
+    return FALSE;
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *dest_format = GST_FORMAT_TIME;
+        case GST_FORMAT_TIME:
+         *dest_value = src_value * GST_SECOND / common->bps;
+          break;
+        case GST_FORMAT_UNITS:
+         *dest_value = src_value / (common->channels * common->width);
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *dest_format = GST_FORMAT_BYTES;
+        case GST_FORMAT_BYTES:
+         *dest_value = src_value * common->bps / GST_SECOND;
+          break;
+        case GST_FORMAT_UNITS:
+         *dest_value = src_value * common->rate / GST_SECOND;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_UNITS:
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *dest_format = GST_FORMAT_TIME;
+        case GST_FORMAT_TIME:
+         *dest_value = src_value * GST_SECOND / common->rate;
+          break;
+        case GST_FORMAT_BYTES:
+         *dest_value = src_value * common->channels * common->width;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+
+  return res;
+}
+
index 18bdd90..ab5553f 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef __GST_OSSFORMAT_H__
-#define __GST_OSSFORMAT_H__
+#ifndef __GST_OSSCOMMON_H__
+#define __GST_OSSCOMMON_H__
 
 #include <gst/gst.h>
 
-gboolean       gst_ossformat_get       (gint law, gint endianness, gboolean sign, 
-                                        gint width, gint depth, gint *format, gint *bps);
+typedef struct _GstOssCommon   GstOssCommon;
 
-#endif /* __GST_OSSFORMAT_H__ */
+typedef enum {
+  GST_OSSCOMMON_READ,
+  GST_OSSCOMMON_WRITE,
+} GstOssOpenMode;
+
+struct _GstOssCommon
+{
+  gchar                *device;
+  /* 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;
+};
+
+void           gst_osscommon_init              (GstOssCommon *common);
+
+gboolean       gst_osscommon_open_audio        (GstOssCommon *common, 
+                                                GstOssOpenMode mode, gchar **error);
+void           gst_osscommon_close_audio       (GstOssCommon *common);
+
+gboolean       gst_osscommon_parse_caps        (GstOssCommon *common, GstCaps *caps);
+gboolean       gst_osscommon_merge_fixed_caps  (GstOssCommon *common, GstCaps *caps);
+       
+gboolean       gst_osscommon_sync_parms        (GstOssCommon *common);
+
+gboolean       gst_osscommon_convert           (GstOssCommon *common, 
+                                                GstFormat src_format, gint64 src_value,
+                                                GstFormat *dest_format, gint64 *dest_value);
+
+       
+
+#endif /* __GST_OSSCOMMON_H__ */
index 049a3a0..2360302 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-
-#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 <gstosssink.h>
-#include <gstosscommon.h>
 
 /* elementfactory information */
 static GstElementDetails gst_osssink_details = {  
@@ -49,9 +41,6 @@ static void                   gst_osssink_class_init          (GstOssSinkClass *klass);
 static void                    gst_osssink_init                (GstOssSink *osssink);
 static void                    gst_osssink_finalize            (GObject *object);
 
-static gboolean                gst_osssink_open_audio          (GstOssSink *sink);
-static void                    gst_osssink_close_audio         (GstOssSink *sink);
-static gboolean                gst_osssink_sync_parms          (GstOssSink *osssink);
 static GstElementStateReturn   gst_osssink_change_state        (GstElement *element);
 static void                    gst_osssink_set_clock           (GstElement *element, GstClock *clock);
 static GstClock*               gst_osssink_get_clock           (GstElement *element);
@@ -163,7 +152,7 @@ gst_osssink_finalize (GObject *object)
 {
   GstOssSink *osssink = (GstOssSink *) object;
 
-  g_free (osssink->device);
+  g_free (osssink->common.device);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -227,19 +216,9 @@ gst_osssink_init (GstOssSink *osssink)
 
   gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain);
 
-  osssink->device = g_strdup ("/dev/dsp");
-  osssink->fd = -1;
-  osssink->channels = 1;
-  osssink->frequency = 11025;
-  osssink->fragment = 6;
-/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
-#ifdef WORDS_BIGENDIAN
-  osssink->format = AFMT_S16_BE;
-#else
-  osssink->format = AFMT_S16_LE;
-#endif /* WORDS_BIGENDIAN */  
+  gst_osscommon_init (&osssink->common);
+
   osssink->bufsize = 4096;
-  osssink->bps = 0;
   osssink->resync = FALSE;
   osssink->sync = TRUE;
   osssink->sinkpool = NULL;
@@ -254,141 +233,32 @@ gst_osssink_init (GstOssSink *osssink)
 static GstPadConnectReturn 
 gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps) 
 {
-  gint law, endianness, width, depth, bps;
-  gboolean sign;
-  gint format = -1;
   GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
 
   if (!GST_CAPS_IS_FIXED (caps))
     return GST_PAD_CONNECT_DELAYED;
-  
-  gst_caps_get_int (caps, "width", &width);
-  gst_caps_get_int (caps, "depth", &depth);
 
-  if (width != depth) 
+  if (!gst_osscommon_parse_caps (&osssink->common, caps))
     return GST_PAD_CONNECT_REFUSED;
 
-  osssink->width = width;
-
-  /* laws 1 and 2 are 1 bps anyway */
-  osssink->bps = 1;
-
-  gst_caps_get_int (caps, "law", &law);
-  gst_caps_get_int (caps, "endianness", &endianness);
-  gst_caps_get_boolean (caps, "signed", &sign);
-
-  if (!gst_ossformat_get (law, endianness, sign,
-                         width, depth, &format, &bps)) 
-  {
-    GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format");
-    return GST_PAD_CONNECT_REFUSED;
-  }
-
-  osssink->bps = bps;
-  osssink->format = format;
-
-  gst_caps_get_int (caps, "channels", &osssink->channels);
-  gst_caps_get_int (caps, "rate", &osssink->frequency);
-
-  osssink->bps *= osssink->channels;
-  osssink->bps *= osssink->frequency;
-
-  if (!gst_osssink_sync_parms (osssink)) {
+  if (!gst_osscommon_sync_parms (&osssink->common)) {
     return GST_PAD_CONNECT_REFUSED;
   }
 
   return GST_PAD_CONNECT_OK;
 }
 
-static gboolean 
-gst_osssink_sync_parms (GstOssSink *osssink) 
-{
-  audio_buf_info ospace;
-  int frag;
-  gint target_format;
-  gint target_channels;
-  gint target_frequency;
-  GObject *object;
-  gint fragscale, frag_ln;
-
-  g_return_val_if_fail (osssink != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_OSSSINK (osssink), FALSE);
-
-  if (osssink->fd == -1)
-    return FALSE;
-  
-  if (osssink->fragment >> 16)
-    frag = osssink->fragment;
-  else
-    frag = 0x7FFF0000 | osssink->fragment;
-  
-  GST_INFO (GST_CAT_PLUGIN_INFO, 
-            "osssink: setting sound card to %dHz %d format %s (%08x fragment)",
-            osssink->frequency, osssink->format,
-            (osssink->channels == 2) ? "stereo" : "mono", frag);
-
-  ioctl (osssink->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
-
-  ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
-
-  target_format = osssink->format;
-  target_channels = osssink->channels;
-  target_frequency = osssink->frequency;
-
-  ioctl (osssink->fd, SNDCTL_DSP_SETFMT, &osssink->format);
-  ioctl (osssink->fd, SNDCTL_DSP_CHANNELS, &osssink->channels);
-  ioctl (osssink->fd, SNDCTL_DSP_SPEED, &osssink->frequency);
-
-  ioctl (osssink->fd, SNDCTL_DSP_GETBLKSIZE, &osssink->fragment_size);
-  ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
-
-  /* calculate new fragment using a poor man's logarithm function */
-  fragscale = 1;
-  frag_ln = 0;
-  while (fragscale < ospace.fragsize) {
-    fragscale <<= 1;
-    frag_ln++;
-  }
-  osssink->fragment = ospace.fragstotal << 16 | frag_ln;
-         
-  GST_INFO (GST_CAT_PLUGIN_INFO, 
-            "osssink: set sound card to %dHz %d format %s "
-           "(%d bytes buffer, %08x fragment)",
-            osssink->frequency, osssink->format,
-            (osssink->channels == 2) ? "stereo" : "mono", 
-           ospace.bytes, osssink->fragment);
-
-  object = G_OBJECT (osssink);
-  g_object_freeze_notify (object);
-  g_object_notify (object, "fragment");
-  g_object_thaw_notify (object);
-
-  osssink->fragment_time = (GST_SECOND * osssink->fragment_size) / osssink->bps;
-  GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n", 
-            osssink->bps, osssink->fragment_time);
-
-  if (target_format != osssink->format ||
-      target_channels != osssink->channels ||
-      target_frequency != osssink->frequency) 
-  {
-    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 inline gint64 
 gst_osssink_get_delay (GstOssSink *osssink) 
 {
   gint delay = 0;
 
-  if (osssink->fd == -1)
+  if (osssink->common.fd == -1)
     return 0;
 
-  if (ioctl (osssink->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
+  if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
     audio_buf_info info;
-    if (ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+    if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
       delay = 0;
     }
     else {
@@ -405,7 +275,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
   gint delay;
   GstClockTime res;
 
-  if (!osssink->bps)
+  if (!osssink->common.bps)
     return 0;
 
   delay = gst_osssink_get_delay (osssink);
@@ -416,7 +286,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
   if (((guint64)delay) > osssink->handled) {
     delay = osssink->handled;
   }
-  res =  (osssink->handled - delay) * GST_SECOND / osssink->bps;
+  res =  (osssink->handled - delay) * GST_SECOND / osssink->common.bps;
 
   return res;
 }
@@ -455,7 +325,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
 
     switch (GST_EVENT_TYPE (event)) {
       case GST_EVENT_EOS:
-        ioctl (osssink->fd, SNDCTL_DSP_SYNC);
+        ioctl (osssink->common.fd, SNDCTL_DSP_SYNC);
        gst_oss_clock_set_active (osssink->provided_clock, FALSE);
        gst_pad_event_default (pad, event);
         return;
@@ -466,7 +336,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
       {
        gint64 value;
 
-        ioctl (osssink->fd, SNDCTL_DSP_RESET);
+        ioctl (osssink->common.fd, SNDCTL_DSP_RESET);
        if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
           if (!gst_clock_handle_discont (osssink->clock, value))
            gst_oss_clock_set_active (osssink->provided_clock, FALSE);
@@ -483,7 +353,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
     return;
   }
 
-  if (!osssink->bps) {
+  if (!osssink->common.bps) {
     gst_buffer_unref (buf);
     gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
     return;
@@ -491,7 +361,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
 
   buftime = GST_BUFFER_TIMESTAMP (buf);
 
-  if (osssink->fd >= 0) {
+  if (osssink->common.fd >= 0) {
     if (!osssink->mute) {
       guchar *data = GST_BUFFER_DATA (buf);
       gint size = GST_BUFFER_SIZE (buf);
@@ -502,7 +372,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
        GstClockTimeDiff jitter;
     
        delay = gst_osssink_get_delay (osssink);
-       queued = delay * GST_SECOND / osssink->bps;
+       queued = delay * GST_SECOND / osssink->common.bps;
 
        if  (osssink->resync && osssink->sync) {
          gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock, 
@@ -510,14 +380,14 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
 
          if (jitter >= 0) {
             gst_clock_handle_discont (osssink->clock, buftime - queued + jitter);
-           write (osssink->fd, data, size);
+           write (osssink->common.fd, data, size);
            gst_oss_clock_set_active (osssink->provided_clock, TRUE);
            osssink->resync = FALSE;
            osssink->handled += size;
          }
        }
        else {
-         write (osssink->fd, data, size);
+         write (osssink->common.fd, data, size);
          osssink->handled += size;
         }
       }
@@ -525,10 +395,10 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
       else {
         audio_buf_info ospace;
 
-        ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
+        ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace);
 
         if (ospace.bytes >= size) {
-          write (osssink->fd, data, size);
+          write (osssink->common.fd, data, size);
        }
       }
     }
@@ -552,68 +422,12 @@ static gboolean
 gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
                     GstFormat *dest_format, gint64 *dest_value)
 {
-  gboolean res = TRUE;
-             
   GstOssSink *osssink;
 
-  if (src_format == *dest_format) {
-    *dest_value = src_value;
-    return TRUE;
-  }
-
   osssink = GST_OSSSINK (gst_pad_get_parent (pad));
-
-  if (osssink->bps == 0 || osssink->channels == 0 || osssink->width == 0)
-    return FALSE;
-
-  switch (src_format) {
-    case GST_FORMAT_BYTES:
-      switch (*dest_format) {
-        case GST_FORMAT_DEFAULT:
-          *dest_format = GST_FORMAT_TIME;
-        case GST_FORMAT_TIME:
-         *dest_value = src_value * GST_SECOND / osssink->bps;
-          break;
-        case GST_FORMAT_UNITS:
-         *dest_value = src_value / (osssink->channels * osssink->width);
-          break;
-        default:
-          res = FALSE;
-      }
-      break;
-    case GST_FORMAT_TIME:
-      switch (*dest_format) {
-        case GST_FORMAT_DEFAULT:
-          *dest_format = GST_FORMAT_BYTES;
-        case GST_FORMAT_BYTES:
-         *dest_value = src_value * osssink->bps / GST_SECOND;
-          break;
-        case GST_FORMAT_UNITS:
-         *dest_value = src_value * osssink->frequency / GST_SECOND;
-          break;
-        default:
-          res = FALSE;
-      }
-      break;
-    case GST_FORMAT_UNITS:
-      switch (*dest_format) {
-        case GST_FORMAT_DEFAULT:
-          *dest_format = GST_FORMAT_TIME;
-        case GST_FORMAT_TIME:
-         *dest_value = src_value * GST_SECOND / osssink->frequency;
-          break;
-        case GST_FORMAT_BYTES:
-         *dest_value = src_value * osssink->channels * osssink->width;
-          break;
-        default:
-          res = FALSE;
-      }
-      break;
-    default:
-      res = FALSE;
-  }
-
-  return res;
+  
+  return gst_osscommon_convert (&osssink->common, src_format, src_value,
+                               dest_format, dest_value);
 }
 
 static const GstPadQueryType*
@@ -673,9 +487,6 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
 {
   GstOssSink *osssink;
 
-  /* it's not null if we got it, but it might not be ours */
-  g_return_if_fail (GST_IS_OSSSINK (object));
-  
   osssink = GST_OSSSINK (object);
 
   switch (prop_id) {
@@ -684,8 +495,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
          get_property("device") should return the right one */
       if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
       {
-       g_free (osssink->device);
-        osssink->device = g_strdup (g_value_get_string (value));
+       g_free (osssink->common.device);
+        osssink->common.device = g_strdup (g_value_get_string (value));
        g_object_notify (object, "device");
       }
       break;
@@ -694,8 +505,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
       g_object_notify (G_OBJECT (osssink), "mute");
       break;
     case ARG_FRAGMENT:
-      osssink->fragment = g_value_get_int (value);
-      gst_osssink_sync_parms (osssink);
+      osssink->common.fragment = g_value_get_int (value);
+      gst_osscommon_sync_parms (&osssink->common);
       break;
     case ARG_BUFFER_SIZE:
       if (osssink->bufsize == g_value_get_int (value)) break;
@@ -718,20 +529,17 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
 {
   GstOssSink *osssink;
 
-  /* it's not null if we got it, but it might not be ours */
-  g_return_if_fail (GST_IS_OSSSINK (object));
-  
   osssink = GST_OSSSINK (object);
 
   switch (prop_id) {
     case ARG_DEVICE:
-      g_value_set_string (value, osssink->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->fragment);
+      g_value_set_int (value, osssink->common.fragment);
       break;
     case ARG_BUFFER_SIZE:
       g_value_set_int (value, osssink->bufsize);
@@ -745,132 +553,24 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
   }
 }
 
-static gboolean
-gst_osssink_open_audio (GstOssSink *sink)
-{
-  gint caps;
-  g_return_val_if_fail (sink->fd == -1, FALSE);
-
-  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: attempting to open sound device");
-
-  /* first try to open the sound card */
-  /* FIXME: this code is dubious, why do we need to open and close this ?*/
-  sink->fd = open (sink->device, O_WRONLY | O_NONBLOCK);
-  if (errno == EBUSY) {
-    g_warning ("osssink: unable to open the sound device (in use ?)\n");
-  }
-
-  if (sink->fd >= 0)
-    close (sink->fd);
-  
-  /* re-open the sound device in blocking mode */
-  sink->fd = open (sink->device, O_WRONLY);
-
-  if (sink->fd < 0) {
-    switch (errno) {
-      case EISDIR:
-        gst_element_error (GST_ELEMENT (sink),
-                          "osssink: Device %s is a directory",
-                          sink->device);
-       break;
-      case EACCES:
-      case ETXTBSY:
-        gst_element_error (GST_ELEMENT (sink),
-                          "osssink: Cannot access %s, check permissions",
-                          sink->device);
-       break;
-      case ENXIO:
-      case ENODEV:
-      case ENOENT:
-        gst_element_error (GST_ELEMENT (sink),
-                          "osssink: Cannot access %s, does it exist ?",
-                          sink->device);
-       break;
-      case EROFS:
-        gst_element_error (GST_ELEMENT (sink),
-                          "osssink: Cannot access %s, read-only filesystem ?",
-                          sink->device);
-      default:
-       /* FIXME: strerror is not threadsafe */
-       gst_element_error (GST_ELEMENT (sink),
-                          "osssink: Cannot open %s, generic error: %s",
-                          sink->device, strerror (errno));
-       break;
-    }
-    return FALSE;
-  }
-  /* we have it, set the default parameters and go have fun */
-  /* set card state */
-  ioctl (sink->fd, SNDCTL_DSP_GETCAPS, &caps);
-
-  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Capabilities %08x", caps);
-
-  if (caps & DSP_CAP_DUPLEX)   GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Full duplex");
-  if (caps & DSP_CAP_REALTIME)         GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Realtime");
-  if (caps & DSP_CAP_BATCH)            GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Batch");
-  if (caps & DSP_CAP_COPROC)           GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Has coprocessor");
-  if (caps & DSP_CAP_TRIGGER)          GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Trigger");
-  if (caps & DSP_CAP_MMAP)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Direct access");
-
-#ifdef DSP_CAP_MULTI
-  if (caps & DSP_CAP_MULTI)            GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Multiple open");
-#endif /* DSP_CAP_MULTI */
-
-#ifdef DSP_CAP_BIND
-  if (caps & DSP_CAP_BIND)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Channel binding");
-#endif /* DSP_CAP_BIND */
-
-  ioctl(sink->fd, SNDCTL_DSP_GETFMTS, &caps);
-
-  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Formats %08x", caps);
-  if (caps & AFMT_MU_LAW)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   MU_LAW");
-  if (caps & AFMT_A_LAW)               GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   A_LAW");
-  if (caps & AFMT_IMA_ADPCM)           GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   IMA_ADPCM");
-  if (caps & AFMT_U8)                  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U8");
-  if (caps & AFMT_S16_LE)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S16_LE");
-  if (caps & AFMT_S16_BE)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S16_BE");
-  if (caps & AFMT_S8)                  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S8");
-  if (caps & AFMT_U16_LE)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U16_LE");
-  if (caps & AFMT_U16_BE)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U16_BE");
-  if (caps & AFMT_MPEG)                GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   MPEG");
-#ifdef AFMT_AC3
-  if (caps & AFMT_AC3)                 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   AC3");
-#endif
-
-  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: opened audio (%s) with fd=%d", sink->device, sink->fd);
-  GST_FLAG_SET (sink, GST_OSSSINK_OPEN);
-
-  return TRUE;
-}
-
-static void
-gst_osssink_close_audio (GstOssSink *sink)
-{
-  if (sink->fd < 0) return;
-
-  close(sink->fd);
-  sink->fd = -1;
-
-  GST_FLAG_UNSET (sink, GST_OSSSINK_OPEN);
-
-  GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
-}
-
 static GstElementStateReturn 
 gst_osssink_change_state (GstElement *element) 
 {
   GstOssSink *osssink;
 
-  g_return_val_if_fail (GST_IS_OSSSINK (element), FALSE);
-
   osssink = GST_OSSSINK (element);
 
   switch (GST_STATE_TRANSITION (element)) {
     case GST_STATE_NULL_TO_READY:
       if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
-        if (!gst_osssink_open_audio (osssink)) {
+       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:
@@ -881,18 +581,23 @@ gst_osssink_change_state (GstElement *element)
     case GST_STATE_PLAYING_TO_PAUSED:
     {
       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) 
-        ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
+        ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
       gst_oss_clock_set_active (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->fd, SNDCTL_DSP_RESET, 0);
+        ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
+      gst_osscommon_init (&osssink->common);
       break;
     case GST_STATE_READY_TO_NULL:
-      if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
-        gst_osssink_close_audio (osssink);
+      if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
+        gst_osscommon_close_audio (&osssink->common);
+        GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN);
+
+        GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
+      }
       break;
   }
       
index 06a13ea..b61243f 100644 (file)
 #define __GST_OSSSINK_H__
 
 
-#include <config.h>
 #include <gst/gst.h>
 
+#include "gstosscommon.h"
 #include "gstossclock.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
+G_BEGIN_DECLS
 
 #define GST_TYPE_OSSSINK \
   (gst_osssink_get_type())
@@ -67,23 +64,11 @@ struct _GstOssSink {
   gboolean      sync;
   guint64       handled;
 
-  /* device */
-  gchar        *device;
-
-  /* soundcard state */
-  int           fd;
-  int           caps; /* the capabilities */
-  gint                  format;
-  gint                  width;
-  gint                  channels;
-  gint                  frequency;
-  gint                  fragment;
-  gint          fragment_size;
+  GstOssCommon  common;
+
   gboolean      mute;
   guint         bufsize;
-  guint         bps;
 
-  guint64       fragment_time;
 };
 
 struct _GstOssSinkClass {
@@ -97,9 +82,6 @@ GType gst_osssink_get_type(void);
 
 gboolean gst_osssink_factory_init(GstPlugin *plugin);
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
+G_END_DECLS
 
 #endif /* __GST_OSSSINK_H__ */
index 93c048b..b3f5169 100644 (file)
@@ -51,7 +51,8 @@ enum {
 enum {
   ARG_0,
   ARG_DEVICE,
-  ARG_BYTESPERREAD,
+  ARG_BUFFERSIZE,
+  ARG_FRAGMENT,
 };
 
 GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
@@ -85,16 +86,23 @@ static void                         gst_osssrc_class_init   (GstOssSrcClass *klass);
 static void                    gst_osssrc_init         (GstOssSrc *osssrc);
 
 static GstPadConnectReturn     gst_osssrc_srcconnect   (GstPad *pad, GstCaps *caps);
+static const GstFormat*        gst_osssrc_get_formats  (GstPad *pad);
+static gboolean                gst_osssrc_convert      (GstPad *pad, 
+                                                        GstFormat src_format, gint64 src_value,
+                                                        GstFormat *dest_format, gint64 *dest_value);
+
 static void                    gst_osssrc_set_property (GObject *object, guint prop_id, 
                                                         const GValue *value, GParamSpec *pspec);
 static void                    gst_osssrc_get_property (GObject *object, guint prop_id,
                                                         GValue *value, GParamSpec *pspec);
 static GstElementStateReturn   gst_osssrc_change_state (GstElement *element);
 
-static gboolean                 gst_osssrc_send_event (GstElement *element, GstEvent *event);
-static void                    gst_osssrc_close_audio  (GstOssSrc *src);
-static gboolean                gst_osssrc_open_audio   (GstOssSrc *src);
-static gboolean                        gst_osssrc_sync_parms   (GstOssSrc *osssrc);
+static const GstEventMask*     gst_osssrc_get_event_masks (GstPad *pad);
+static gboolean                gst_osssrc_src_event    (GstPad *pad, GstEvent *event);
+static gboolean                 gst_osssrc_send_event  (GstElement *element, GstEvent *event);
+static const GstPadQueryType*  gst_osssrc_get_query_types (GstPad *pad);
+static gboolean                gst_osssrc_src_query    (GstPad *pad, GstPadQueryType type, 
+                                                        GstFormat *format, gint64 *value);
 
 static GstBuffer *             gst_osssrc_get          (GstPad *pad);
 
@@ -134,12 +142,16 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
 
   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
-  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BYTESPERREAD,
-    g_param_spec_ulong("bytes_per_read","bytes_per_read","bytes_per_read",
-                       0,G_MAXULONG,0,G_PARAM_READWRITE)); /* CHECKME */
+  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_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)",
+                      0, G_MAXINT, 6, G_PARAM_READWRITE));
   
   gobject_class->set_property = gst_osssrc_set_property;
   gobject_class->get_property = gst_osssrc_get_property;
@@ -155,25 +167,20 @@ gst_osssrc_init (GstOssSrc *osssrc)
                  GST_PAD_TEMPLATE_GET (osssrc_src_factory), "src");
   gst_pad_set_get_function (osssrc->srcpad, gst_osssrc_get);
   gst_pad_set_connect_function (osssrc->srcpad, gst_osssrc_srcconnect);
+  gst_pad_set_convert_function (osssrc->srcpad, gst_osssrc_convert);
+  gst_pad_set_formats_function (osssrc->srcpad, gst_osssrc_get_formats);
+  gst_pad_set_event_function (osssrc->srcpad, gst_osssrc_src_event);
+  gst_pad_set_event_mask_function (osssrc->srcpad, gst_osssrc_get_event_masks);
+  gst_pad_set_query_function (osssrc->srcpad, gst_osssrc_src_query);
+  gst_pad_set_query_type_function (osssrc->srcpad, gst_osssrc_get_query_types);
+
+
   gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
 
-  osssrc->device = g_strdup ("/dev/dsp");
-  osssrc->fd = -1;
-
-  /* adding some default values */
-  osssrc->law = 0;
-  osssrc->endianness = G_BYTE_ORDER;
-  osssrc->sign = TRUE;
-  osssrc->depth = 16;
-  osssrc->width = 16;
-  osssrc->channels = 2;
-  osssrc->rate = 44100;
-  osssrc->need_eos = FALSE;
-  
-  osssrc->bytes_per_read = 4096;
+  gst_osscommon_init (&osssrc->common);
+
+  osssrc->buffersize = 4096;
   osssrc->curoffset = 0;
-  osssrc->basetime = 0;
-  osssrc->samples_since_basetime = 0;
 }
 
 static GstPadConnectReturn 
@@ -186,29 +193,14 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
   if (!GST_CAPS_IS_FIXED (caps))
     return GST_PAD_CONNECT_DELAYED;
 
-  gst_caps_get_int     (caps, "law",           &src->law);
-  gst_caps_get_int     (caps, "endianness",    &src->endianness);
-  gst_caps_get_boolean         (caps, "signed",        &src->sign);
-  gst_caps_get_int     (caps, "width",         &src->width);
-  gst_caps_get_int     (caps, "depth",         &src->depth);
-  gst_caps_get_int     (caps, "rate",          &src->rate);
-  gst_caps_get_int     (caps, "channels",      &src->channels);
+  if (!gst_osscommon_parse_caps (&src->common, caps))
+    return GST_PAD_CONNECT_REFUSED;
 
-  if (!gst_osssrc_sync_parms (src))
+  if (!gst_osscommon_sync_parms (&src->common))
     return GST_PAD_CONNECT_REFUSED;
 
   return GST_PAD_CONNECT_OK;
 }
-#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
 
 static gboolean
 gst_osssrc_negotiate (GstPad *pad)
@@ -220,16 +212,10 @@ gst_osssrc_negotiate (GstPad *pad)
 
   allowed = gst_pad_get_allowed_caps (pad);
 
-  /* peel off fixed stuff from the allowed caps */
-  GET_FIXED_INT        (allowed, "law",        &src->law);
-  GET_FIXED_INT        (allowed, "endianness", &src->endianness);
-  GET_FIXED_BOOLEAN    (allowed, "signed",     &src->sign);
-  GET_FIXED_INT        (allowed, "width",      &src->width);
-  GET_FIXED_INT        (allowed, "depth",      &src->depth);
-  GET_FIXED_INT        (allowed, "rate",       &src->rate);
-  GET_FIXED_INT        (allowed, "channels",   &src->channels);
+  if (!gst_osscommon_merge_fixed_caps (&src->common, allowed))
+    return FALSE;
 
-  if (!gst_osssrc_sync_parms (src))
+  if (!gst_osscommon_sync_parms (&src->common))
     return FALSE;
     
   /* set caps on src pad */
@@ -238,13 +224,13 @@ gst_osssrc_negotiate (GstPad *pad)
          "oss_src",
          "audio/raw",
             "format",       GST_PROPS_STRING ("int"),
-             "law",        GST_PROPS_INT (src->law),
-             "endianness", GST_PROPS_INT (src->endianness),
-             "signed",     GST_PROPS_BOOLEAN (src->sign),
-             "width",      GST_PROPS_INT (src->width),
-             "depth",      GST_PROPS_INT (src->depth),
-             "rate",       GST_PROPS_INT (src->rate),
-             "channels",   GST_PROPS_INT (src->channels)
+             "law",        GST_PROPS_INT (src->common.law),
+             "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)
         )) <= 0) 
   {
     return FALSE;
@@ -258,7 +244,6 @@ gst_osssrc_get (GstPad *pad)
   GstOssSrc *src;
   GstBuffer *buf;
   glong readbytes;
-  glong readsamples;
 
   src = GST_OSSSRC(gst_pad_get_parent (pad));
 
@@ -269,10 +254,10 @@ gst_osssrc_get (GstPad *pad)
     return GST_BUFFER (gst_event_new (GST_EVENT_EOS));
   }
   
-  buf = gst_buffer_new_and_alloc (src->bytes_per_read);
+  buf = gst_buffer_new_and_alloc (src->buffersize);
   
-  readbytes = read (src->fd,GST_BUFFER_DATA (buf),
-                    src->bytes_per_read);
+  readbytes = read (src->common.fd,GST_BUFFER_DATA (buf),
+                    src->buffersize);
 
   if (readbytes == 0) {
     gst_element_set_eos (GST_ELEMENT (src));
@@ -286,16 +271,16 @@ gst_osssrc_get (GstPad *pad)
       return NULL;
     }
   }
+  if (src->common.bps == 0) {
+    gst_element_error (GST_ELEMENT (src), "no format negotiated");
+    return NULL;
+  }
 
   GST_BUFFER_SIZE (buf) = readbytes;
   GST_BUFFER_OFFSET (buf) = src->curoffset;
-  GST_BUFFER_TIMESTAMP (buf) = src->basetime +
-         src->samples_since_basetime * GST_SECOND / src->rate;
+  GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps;
 
   src->curoffset += readbytes;
-  readsamples = readbytes / src->channels;
-  if (src->width == 16) readsamples /= 2;
-  src->samples_since_basetime += readsamples;
 
   GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushed buffer from soundcard of %ld bytes, timestamp %lld", 
                  readbytes, GST_BUFFER_TIMESTAMP (buf));
@@ -308,19 +293,20 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP
 {
   GstOssSrc *src;
 
-  /* it's not null if we got it, but it might not be ours */
-  g_return_if_fail (GST_IS_OSSSRC (object));
-  
   src = GST_OSSSRC (object);
 
   switch (prop_id) {
-    case ARG_BYTESPERREAD:
-      src->bytes_per_read = g_value_get_ulong (value);
+    case ARG_BUFFERSIZE:
+      src->buffersize = g_value_get_ulong (value);
       break;
     case ARG_DEVICE:
-      g_free(src->device);
-      src->device = g_strdup (g_value_get_string (value));
+      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);
+      break; 
     default:
       break;
   }
@@ -331,17 +317,17 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
 {
   GstOssSrc *src;
 
-  /* it's not null if we got it, but it might not be ours */
-  g_return_if_fail (GST_IS_OSSSRC (object));
-  
   src = GST_OSSSRC (object);
 
   switch (prop_id) {
-    case ARG_BYTESPERREAD:
-      g_value_set_ulong (value, src->bytes_per_read);
+    case ARG_BUFFERSIZE:
+      g_value_set_ulong (value, src->buffersize);
       break;
     case ARG_DEVICE:
-      g_value_set_string (value, src->device);
+      g_value_set_string (value, src->common.device);
+      break;
+    case ARG_FRAGMENT:
+      g_value_set_int (value, src->common.fragment);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -361,8 +347,13 @@ gst_osssrc_change_state (GstElement *element)
       break;
     case GST_STATE_READY_TO_PAUSED:
       if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { 
-        if (!gst_osssrc_open_audio (osssrc))
+       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_PAUSED_TO_PLAYING:
@@ -370,8 +361,11 @@ gst_osssrc_change_state (GstElement *element)
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
-      if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN))
-        gst_osssrc_close_audio (osssrc);
+      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);
       break;
     case GST_STATE_READY_TO_NULL:
       break;
@@ -383,103 +377,117 @@ gst_osssrc_change_state (GstElement *element)
   return GST_STATE_SUCCESS;
 }
 
+static const GstFormat*
+gst_osssrc_get_formats (GstPad *pad)
+{
+  static const GstFormat formats[] = {
+    GST_FORMAT_TIME,
+    GST_FORMAT_UNITS,
+    GST_FORMAT_BYTES,
+    0
+  };
+  return formats;
+}
+
 static gboolean
-gst_osssrc_send_event (GstElement *element,
-                      GstEvent *event)
+gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
+                                    GstFormat *dest_format, gint64 *dest_value)
+{
+  GstOssSrc *osssrc;
+
+  osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
+
+  return gst_osscommon_convert (&osssrc->common, src_format, src_value,
+                                dest_format, dest_value);
+}
+
+static const GstEventMask*
+gst_osssrc_get_event_masks (GstPad *pad)
+{
+  static const GstEventMask gst_osssrc_src_event_masks[] = {
+    { GST_EVENT_EOS, 0 },
+    { GST_EVENT_SIZE, 0 },
+    { 0, } 
+  };
+  return gst_osssrc_src_event_masks;
+} 
+
+static gboolean
+gst_osssrc_src_event (GstPad *pad, GstEvent *event)
 {
-  gboolean retval = FALSE;
   GstOssSrc *osssrc;
+  gboolean retval = FALSE;
 
-  osssrc = GST_OSSSRC (element);
+  osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_EOS:
       osssrc->need_eos = TRUE;
       retval = TRUE;
       break;
+    case GST_EVENT_SIZE:
+    {
+      GstFormat format;
+      gint64 value;
+
+      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)) 
+      {
+        osssrc->buffersize = GST_EVENT_SIZE_VALUE (event);
+        g_object_notify (G_OBJECT (osssrc), "buffersize");
+        retval = TRUE;
+      }
+    }
     default:
       break;
   }
-
   gst_event_unref (event);
   return retval;
 }
 
-static gboolean 
-gst_osssrc_open_audio (GstOssSrc *src) 
+static gboolean
+gst_osssrc_send_event (GstElement *element,
+                      GstEvent *event)
 {
-  g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN), FALSE);
-
-  /* first try to open the sound card */
-  src->fd = open(src->device, O_RDONLY);
-
-  /* if we have it, set the default parameters and go have fun */ 
-  if (src->fd > 0) {
-
-    /* set card state */
-    GST_DEBUG (GST_CAT_PLUGIN_INFO,"opened audio: %s",src->device);
-    
-    GST_FLAG_SET (src, GST_OSSSRC_OPEN);
-    return TRUE;
-  }
+  GstOssSrc *osssrc = GST_OSSSRC (element);
 
-  return FALSE;
+  return gst_osssrc_src_event (osssrc->srcpad, event);
 }
 
-static void 
-gst_osssrc_close_audio (GstOssSrc *src) 
+static const GstPadQueryType*
+gst_osssrc_get_query_types (GstPad *pad)
 {
-  g_return_if_fail (GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN));
+  static const GstPadQueryType query_types[] = {
+    GST_PAD_QUERY_POSITION,
+    0,
+  };
+  return query_types;
+} 
 
-  close(src->fd);
-  src->fd = -1;
-
-  GST_FLAG_UNSET (src, GST_OSSSRC_OPEN);
-}
-
-static gboolean 
-gst_osssrc_sync_parms (GstOssSrc *osssrc) 
+static gboolean
+gst_osssrc_src_query (GstPad *pad, GstPadQueryType type, GstFormat *format, gint64 *value)
 {
-  audio_buf_info ispace;
-  gint frag;
-  /* remember : ioctl on samplerate returns the sample rate the card
-   * is actually set to ! Setting it to 44101 Hz could cause it to
-   * be set to 44101, for example
-   */
-  guint rate;
-  gint format;
-  gint bps;
-
-  g_return_val_if_fail (osssrc->fd > 0, FALSE);
-  /* get rate, we don't modify the original rate as the audio device
-   * might not exactly give us the requested value */
-  rate = osssrc->rate;
-
-  /* transform format parameters to oss format */
-  if (!gst_ossformat_get (osssrc->law, osssrc->endianness, osssrc->sign, 
-                         osssrc->width, osssrc->depth, &format, &bps)) 
-  {
-    return FALSE;
+  gboolean res = FALSE;
+  GstOssSrc *osssrc;
+             
+  osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
+               
+  switch (type) {
+    case GST_PAD_QUERY_POSITION:
+      res = gst_osscommon_convert (&osssrc->common, 
+                                  GST_FORMAT_BYTES, osssrc->curoffset,
+                                   format, value); 
+      break;
+    default:
+      break;
   }
-  
-  frag = 0x7fff0006;
-
-  ioctl(osssrc->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
-  ioctl(osssrc->fd, SNDCTL_DSP_RESET, 0);
-  ioctl(osssrc->fd, SNDCTL_DSP_SETFMT, &format);
-  ioctl(osssrc->fd, SNDCTL_DSP_CHANNELS, &osssrc->channels);
-  ioctl(osssrc->fd, SNDCTL_DSP_SPEED, &rate);
-  ioctl(osssrc->fd, SNDCTL_DSP_GETISPACE, &ispace);
-  ioctl(osssrc->fd, SNDCTL_DSP_GETBLKSIZE, &frag);
-  g_print("setting sound card to %dHz %d bit %s (%d bytes buffer, %d fragment)\n",
-          rate, osssrc->width,
-          (osssrc->channels == 2) ? "stereo" : "mono", ispace.bytes, frag);
-
-  return TRUE;
-}
+  return res;
+} 
 
 gboolean
 gst_osssrc_factory_init (GstPlugin *plugin)
index 0c082a1..29596fb 100644 (file)
@@ -25,8 +25,8 @@
 #define __GST_OSSSRC_H__
 
 
-#include <config.h>
 #include <gst/gst.h>
+#include "gstosscommon.h"
 
 G_BEGIN_DECLS
 
@@ -51,34 +51,18 @@ typedef struct _GstOssSrc GstOssSrc;
 typedef struct _GstOssSrcClass GstOssSrcClass;
 
 struct _GstOssSrc {
-  GstElement element;
+  GstElement    element;
 
   /* pads */
-  GstPad *srcpad;
+  GstPad       *srcpad;
 
-  /* device */
-  gchar *device;
+  GstOssCommon  common;
 
-  /* sound card */
-  gint fd;
-
-  /* audio parameters */
-  gint law;
-  gint endianness;
-  gint sign;
-  gint width;
-  gint depth;
-  gint rate;
-  gint channels;
-
-  gboolean need_eos; /* Do we need to emit an EOS? */
+  gboolean      need_eos; /* Do we need to emit an EOS? */
   
   /* blocking */
-  guint64 basetime;
-  guint64 samples_since_basetime;
-  gulong curoffset;
-  gulong bytes_per_read;
-
+  gulong        curoffset;
+  gulong        buffersize;
 };
 
 struct _GstOssSrcClass {