sys/directsound/gstdirectsoundsink.*: Remove include of unused headers.
authorSébastien Moutte <sebastien@moutte.net>
Tue, 20 Feb 2007 21:34:00 +0000 (21:34 +0000)
committerSébastien Moutte <sebastien@moutte.net>
Tue, 20 Feb 2007 21:34:00 +0000 (21:34 +0000)
Original commit message from CVS:
* sys/directsound/gstdirectsoundsink.c:
* sys/directsound/gstdirectsoundsink.h:
Remove include of unused headers.
* sys/waveform/gstwaveformplugin.c:
* sys/waveform/gstwaveformsink.c:
* sys/waveform/gstwaveformsink.h:
* win32/vs6/libgstwaveform.dsp:
Add a new waveform plugin which includes an audio sink
element using the WaveForm win32 API.
* win32/MANIFEST:
Add the new project file form waveform plugin.

ChangeLog
sys/directsound/gstdirectsoundsink.c
sys/directsound/gstdirectsoundsink.h
sys/waveform/gstwaveformplugin.c [new file with mode: 0644]
sys/waveform/gstwaveformsink.c [new file with mode: 0644]
sys/waveform/gstwaveformsink.h [new file with mode: 0644]
win32/MANIFEST
win32/vs6/libgstwaveform.dsp [new file with mode: 0644]

index 42608ad..0240749 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2007-02-20  Sébastien Moutte  <sebastien@moutte.net>
+
+       * sys/directsound/gstdirectsoundsink.c:
+       * sys/directsound/gstdirectsoundsink.h:
+         Remove include of unused headers.
+       * sys/waveform/gstwaveformplugin.c:
+       * sys/waveform/gstwaveformsink.c:
+       * sys/waveform/gstwaveformsink.h:
+       * win32/vs6/libgstwaveform.dsp:
+         Add a new waveform plugin which includes an audio sink 
+         element using the WaveForm win32 API.
+       * win32/MANIFEST:
+         Add the new project file form waveform plugin.
+       
 2007-02-18  Sébastien Moutte  <sebastien@moutte.net>
        
        * sys/directdraw/gstdirectdrawplugin.c:
index 46a57e8..94b5579 100644 (file)
@@ -20,7 +20,7 @@
 */
 
 /**
- * SECTION:element-directsound
+ * SECTION:element-directsoundsink
  * @short_description: output sound using Directsound API
  *
  * <refsect2>
 
 #include "gstdirectsoundsink.h"
 
-#include <fcntl.h>
-#include <errno.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <string.h>
-
 GST_DEBUG_CATEGORY_STATIC (directsoundsink_debug);
 
 /* elementfactory information */
@@ -76,7 +69,6 @@ static void gst_directsound_sink_base_init (gpointer g_class);
 static void gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass);
 static void gst_directsound_sink_init (GstDirectSoundSink * dsoundsink,
     GstDirectSoundSinkClass * g_class);
-static void gst_directsound_sink_dispose (GObject * object);
 static void gst_directsound_sink_finalise (GObject * object);
 static void gst_directsound_sink_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
@@ -128,11 +120,6 @@ _do_init (GType directsoundsink_type)
 GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsound_sink, GstAudioSink,
     GST_TYPE_AUDIO_SINK, _do_init);
 
-static void
-gst_directsound_sink_dispose (GObject * object)
-{
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-}
 
 static void
 gst_directsound_sink_finalise (GObject * object)
@@ -171,7 +158,6 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
 
   parent_class = g_type_class_peek_parent (klass);
 
-  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_directsound_sink_dispose);
   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directsound_sink_finalise);
   gobject_class->get_property =
       GST_DEBUG_FUNCPTR (gst_directsound_sink_get_property);
index d1a47aa..dd0a04f 100644 (file)
@@ -19,7 +19,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __GST_DIRECTSOUNDSINK_H__
 #define __GST_DIRECTSOUNDSINK_H__
 
@@ -30,7 +29,6 @@
 #include <dxerr9.h>
 #include <dsound.h>
 
-
 G_BEGIN_DECLS
 #define GST_TYPE_DIRECTSOUND_SINK            (gst_directsound_sink_get_type())
 #define GST_DIRECTSOUND_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSink))
diff --git a/sys/waveform/gstwaveformplugin.c b/sys/waveform/gstwaveformplugin.c
new file mode 100644 (file)
index 0000000..0d7943e
--- /dev/null
@@ -0,0 +1,42 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstwaveformplugin.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 "gstwaveformsink.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "waveformsink", GST_RANK_PRIMARY,
+          GST_TYPE_WAVEFORM_SINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "waveform",
+    "WaveForm win32 API plugin",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/waveform/gstwaveformsink.c b/sys/waveform/gstwaveformsink.c
new file mode 100644 (file)
index 0000000..e709d64
--- /dev/null
@@ -0,0 +1,601 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstwaveformsink.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.
+*/
+
+/**
+ * SECTION:element-waveformsink
+ * @short_description: output sound using WaveForm API
+ *
+ * <refsect2>
+ * <para>
+ * This element lets you output sound using the WaveForm API.
+ * </para>
+ * <para>
+ * Note that you should almost always use generic audio conversion elements
+ * like audioconvert and audioresample in front of an audiosink to make sure
+ * your pipeline works under all circumstances (those conversion elements will
+ * act in passthrough-mode if no conversion is necessary).
+ * </para>
+ * <title>Example pipelines</title>
+ * <para>
+ * <programlisting>
+ * gst-launch-0.10 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! waveformsink
+ * </programlisting>
+ * will output a sine wave (continuous beep sound) to your sound card (with
+ * a very low volume as precaution).
+ * </para>
+ * <para>
+ * <programlisting>
+ * gst-launch-0.10 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! waveformsink
+ * </programlisting>
+ * will play an Ogg/Vorbis audio file and output it.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstwaveformsink.h"
+
+GST_DEBUG_CATEGORY_STATIC (waveformsink_debug);
+
+/* elementfactory information */
+static const GstElementDetails gst_waveform_sink_details =
+GST_ELEMENT_DETAILS ("WaveForm Audio Sink",
+    "Sink/Audio",
+    "Output to a sound card via WaveForm API",
+    "Sebastien Moutte <sebastien@moutte.net>");
+
+static void gst_waveform_sink_base_init (gpointer g_class);
+static void gst_waveform_sink_class_init (GstWaveFormSinkClass * klass);
+static void gst_waveform_sink_init (GstWaveFormSink * wfsink,
+    GstWaveFormSinkClass * g_class);
+static void gst_waveform_sink_finalise (GObject * object);
+static void gst_waveform_sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_waveform_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink);
+
+/************************************************************************/
+/* GstAudioSink functions                                               */
+/************************************************************************/
+static gboolean gst_waveform_sink_prepare (GstAudioSink * asink,
+    GstRingBufferSpec * spec);
+static gboolean gst_waveform_sink_unprepare (GstAudioSink * asink);
+static gboolean gst_waveform_sink_open (GstAudioSink * asink);
+static gboolean gst_waveform_sink_close (GstAudioSink * asink);
+static guint gst_waveform_sink_write (GstAudioSink * asink, gpointer data,
+    guint length);
+static guint gst_waveform_sink_delay (GstAudioSink * asink);
+static void gst_waveform_sink_reset (GstAudioSink * asink);
+
+/************************************************************************/
+/* Utils                                                                */
+/************************************************************************/
+GstCaps *gst_waveform_sink_create_caps (gint rate, gint channels,
+    gint bits_per_sample);
+WAVEHDR *bufferpool_get_buffer (GstWaveFormSink * wfsink, gpointer data,
+    guint length);
+void CALLBACK waveOutProc (HWAVEOUT hwo, UINT uMsg, unsigned long dwInstance,
+    DWORD dwParam1, DWORD dwParam2);
+
+static GstStaticPadTemplate waveformsink_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw-int, "
+        "signed = (boolean) { TRUE, FALSE }, "
+        "width = (int) 16, "
+        "depth = (int) 16, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
+        "audio/x-raw-int, "
+        "signed = (boolean) { TRUE, FALSE }, "
+        "width = (int) 8, "
+        "depth = (int) 8, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
+
+GST_BOILERPLATE (GstWaveFormSink, gst_waveform_sink, GstAudioSink,
+    GST_TYPE_AUDIO_SINK);
+
+static void
+gst_waveform_sink_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_set_details (element_class, &gst_waveform_sink_details);
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&waveformsink_sink_factory));
+}
+
+static void
+gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstBaseAudioSinkClass *gstbaseaudiosink_class;
+  GstAudioSinkClass *gstaudiosink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
+  gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_waveform_sink_finalise);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_waveform_sink_get_property);
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_waveform_sink_set_property);
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_waveform_sink_getcaps);
+
+  gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_waveform_sink_prepare);
+  gstaudiosink_class->unprepare =
+      GST_DEBUG_FUNCPTR (gst_waveform_sink_unprepare);
+  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_waveform_sink_open);
+  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_waveform_sink_close);
+  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_waveform_sink_write);
+  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_waveform_sink_delay);
+  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_waveform_sink_reset);
+
+  GST_DEBUG_CATEGORY_INIT (waveformsink_debug, "waveformsink", 0,
+      "Waveform sink");
+}
+
+static void
+gst_waveform_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_waveform_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_waveform_sink_init (GstWaveFormSink * wfsink,
+    GstWaveFormSinkClass * g_class)
+{
+  /* initialize members */
+  wfsink->hwaveout = NULL;
+  wfsink->cached_caps = NULL;
+  wfsink->wave_buffers = NULL;
+  wfsink->write_buffer = 0;
+  wfsink->buffer_count = BUFFER_COUNT;
+  wfsink->buffer_size = BUFFER_SIZE;
+  wfsink->free_buffers_count = wfsink->buffer_count;
+  wfsink->bytes_in_queue = 0;
+
+  InitializeCriticalSection (&wfsink->critic_wave);
+}
+
+static void
+gst_waveform_sink_finalise (GObject * object)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
+
+  if (wfsink->cached_caps) {
+    gst_caps_unref (wfsink->cached_caps);
+    wfsink->cached_caps = NULL;
+  }
+
+  DeleteCriticalSection (&wfsink->critic_wave);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_waveform_sink_getcaps (GstBaseSink * bsink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink);
+  MMRESULT mmresult;
+  WAVEOUTCAPS wocaps;
+  GstCaps *caps, *caps_temp;
+
+  /* return the cached caps if already defined */
+  if (wfsink->cached_caps) {
+    return gst_caps_ref (wfsink->cached_caps);
+  }
+
+  /* get the default device caps */
+  mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps));
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS,
+        ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s",
+            wfsink->error_string), (NULL));
+    return NULL;
+  }
+
+  caps = gst_caps_new_empty ();
+
+  /* create a caps for all wave formats supported by the device 
+     starting by the best quality format */
+  if (wocaps.dwFormats & WAVE_FORMAT_96S16) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 2, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96S08) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 2, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96M16) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 1, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96M08) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 1, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4S16) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 2, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4S08) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 2, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4M16) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 1, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4M08) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 1, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2S16) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 2, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2S08) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 2, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2M16) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 1, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2M08) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 1, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1S16) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 2, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1S08) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 2, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1M16) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 1, 16);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1M08) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 1, 8);
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+
+  if (gst_caps_is_empty (caps)) {
+    gst_caps_unref (caps);
+    caps = NULL;
+  } else {
+    wfsink->cached_caps = gst_caps_ref (caps);
+  }
+
+  GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "Returning caps %s",
+      gst_caps_to_string (caps));
+
+  return caps;
+}
+
+static gboolean
+gst_waveform_sink_open (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+
+  /* nothing to do here as the device needs to be opened with the format we will use */
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  WAVEFORMATEX wfx;
+  MMRESULT mmresult;
+  guint index;
+
+  /* setup waveformex struture with the input ringbuffer specs */
+  memset (&wfx, 0, sizeof (wfx));
+  wfx.cbSize = 0;
+  wfx.wFormatTag = WAVE_FORMAT_PCM;
+  wfx.nChannels = spec->channels;
+  wfx.nSamplesPerSec = spec->rate;
+  wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels;
+  wfx.nBlockAlign = spec->bytes_per_sample;
+  wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+  /* save bytes per sample to use it in delay */
+  wfsink->bytes_per_sample = spec->bytes_per_sample;
+
+  /* open the default audio device with the given caps */
+  mmresult = waveOutOpen (&wfsink->hwaveout, WAVE_MAPPER,
+      &wfx, (DWORD) waveOutProc, (DWORD) wfsink, CALLBACK_FUNCTION);
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
+        ("gst_waveform_sink_prepare: waveOutOpen failed error=>%s",
+            wfsink->error_string), (NULL));
+    return FALSE;
+  }
+
+  /* evaluate the buffer size and the number of buffers needed */
+  wfsink->free_buffers_count = wfsink->buffer_count;
+
+  /* allocate wave buffers */
+  wfsink->wave_buffers = (WAVEHDR *) g_new0 (WAVEHDR, wfsink->buffer_count);
+  if (!wfsink->wave_buffers) {
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
+        ("gst_waveform_sink_prepare: Failed to allocate wave buffer headers (buffer count=%d)",
+            wfsink->buffer_count), (NULL));
+    return FALSE;
+  }
+  memset (wfsink->wave_buffers, 0, sizeof (WAVEHDR) * wfsink->buffer_count);
+
+  /* setup headers */
+  for (index = 0; index < wfsink->buffer_count; index++) {
+    wfsink->wave_buffers[index].dwBufferLength = wfsink->buffer_size;
+    wfsink->wave_buffers[index].lpData = g_new0 (gchar, wfsink->buffer_size);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_unprepare (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+
+  /* free wave buffers */
+  if (wfsink->wave_buffers) {
+    guint index;
+
+    for (index = 0; index < wfsink->buffer_count; index++) {
+      if (wfsink->wave_buffers[index].dwFlags & WHDR_PREPARED) {
+        MMRESULT mmresult =
+            waveOutUnprepareHeader (wfsink->hwaveout,
+            &wfsink->wave_buffers[index], sizeof (WAVEHDR));
+        if (mmresult != MMSYSERR_NOERROR) {
+          waveOutGetErrorText (mmresult, wfsink->error_string,
+              ERROR_LENGTH - 1);
+          GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+              "gst_waveform_sink_unprepare: Error unpreparing buffer => %s",
+              wfsink->error_string);
+        }
+      }
+      g_free (wfsink->wave_buffers[index].lpData);
+    }
+    g_free (wfsink->wave_buffers);
+    wfsink->wave_buffers = NULL;
+  }
+
+  /* close waveform-audio output device */
+  if (wfsink->hwaveout) {
+    waveOutClose (wfsink->hwaveout);
+    wfsink->hwaveout = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_close (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+
+  return TRUE;
+}
+
+static guint
+gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  WAVEHDR *waveheader;
+  MMRESULT mmresult;
+  guint bytes_to_write = length;
+  guint remaining_length = length;
+
+  wfsink->bytes_in_queue += length;
+
+  while (remaining_length > 0) {
+    if (wfsink->free_buffers_count == 0) {
+      /* no free buffer available, wait for one */
+      Sleep (10);
+      continue;
+    }
+
+    /* get the current write buffer header */
+    waveheader = &wfsink->wave_buffers[wfsink->write_buffer];
+
+    /* unprepare the header if needed */
+    if (waveheader->dwFlags & WHDR_PREPARED) {
+      mmresult =
+          waveOutUnprepareHeader (wfsink->hwaveout, waveheader,
+          sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "Error unpreparing buffer => %s", wfsink->error_string);
+      }
+    }
+
+    if (wfsink->buffer_size - waveheader->dwUser >= remaining_length)
+      bytes_to_write = remaining_length;
+    else
+      bytes_to_write = wfsink->buffer_size - waveheader->dwUser;
+
+    memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write);
+    waveheader->dwUser += bytes_to_write;
+    remaining_length -= bytes_to_write;
+    data = (byte *) data + bytes_to_write;
+
+    if (waveheader->dwUser == wfsink->buffer_size) {
+      /* we have filled a buffer, let's prepare it and next write it to the device */
+      mmresult =
+          waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "gst_waveform_sink_write: Error preparing header => %s",
+            wfsink->error_string);
+      }
+      mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "gst_waveform_sink_write: Error writting buffer to the device => %s",
+            wfsink->error_string);
+      }
+
+      EnterCriticalSection (&wfsink->critic_wave);
+      wfsink->free_buffers_count--;
+      LeaveCriticalSection (&wfsink->critic_wave);
+
+      wfsink->write_buffer++;
+      wfsink->write_buffer %= wfsink->buffer_count;
+      waveheader->dwUser = 0;
+      wfsink->bytes_in_queue = 0;
+      GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink,
+          "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)",
+          wfsink->free_buffers_count, wfsink->write_buffer);
+    }
+  }
+
+  return length;
+}
+
+static guint
+gst_waveform_sink_delay (GstAudioSink * asink)
+{
+  /* return the number of samples in queue (device+internal queue) */
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  guint bytes_in_device =
+      (wfsink->buffer_count - wfsink->free_buffers_count) * wfsink->buffer_size;
+  guint delay =
+      (bytes_in_device + wfsink->bytes_in_queue) / wfsink->bytes_per_sample;
+  return delay;
+}
+
+static void
+gst_waveform_sink_reset (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  MMRESULT mmresult = waveOutReset (wfsink->hwaveout);
+
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+        "gst_waveform_sink_reset: Error reseting waveform-audio device => %s",
+        wfsink->error_string);
+  }
+}
+
+GstCaps *
+gst_waveform_sink_create_caps (gint rate, gint channels, gint bits_per_sample)
+{
+  GstCaps *caps = NULL;
+
+  caps = gst_caps_new_simple ("audio/x-raw-int",
+      "width", G_TYPE_INT, bits_per_sample,
+      "depth", G_TYPE_INT, bits_per_sample,
+      "endianness", G_TYPE_INT, G_BYTE_ORDER,
+      "signed", G_TYPE_BOOLEAN, TRUE,
+      "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
+  return caps;
+}
+
+void CALLBACK
+waveOutProc (HWAVEOUT hwo,
+    UINT uMsg, unsigned long dwInstance, DWORD dwParam1, DWORD dwParam2)
+{
+  GstWaveFormSink *wfsink = (GstWaveFormSink *) dwInstance;
+
+  if (uMsg == WOM_DONE) {
+    EnterCriticalSection (&wfsink->critic_wave);
+    wfsink->free_buffers_count++;
+    LeaveCriticalSection (&wfsink->critic_wave);
+  }
+}
diff --git a/sys/waveform/gstwaveformsink.h b/sys/waveform/gstwaveformsink.h
new file mode 100644 (file)
index 0000000..7922779
--- /dev/null
@@ -0,0 +1,96 @@
+/* GStreamer
+ * Copyright (C)  2005 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstwaveformsink.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_WAVEFORMSINK_H__
+#define __GST_WAVEFORMSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#define WAVE_FORMAT_96M08       0x00001000       /* 96   kHz, Mono,   8-bit  */
+#define WAVE_FORMAT_96S08       0x00002000       /* 96   kHz, Stereo, 8-bit  */
+#define WAVE_FORMAT_96M16       0x00004000       /* 96   kHz, Mono,   16-bit */
+#define WAVE_FORMAT_96S16       0x00008000       /* 96   kHz, Stereo, 16-bit */
+
+#define ERROR_LENGTH MAXERRORLENGTH+50
+#define BUFFER_COUNT 20
+#define BUFFER_SIZE 8192
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVEFORM_SINK                (gst_waveform_sink_get_type())
+#define GST_WAVEFORM_SINK(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVEFORM_SINK,GstWaveFormSink))
+#define GST_WAVEFORM_SINK_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVEFORM_SINK,GstWaveFormSinkClass))
+#define GST_IS_WAVEFORM_SINK(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVEFORM_SINK))
+#define GST_IS_WAVEFORM_SINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVEFORM_SINK))
+typedef struct _GstWaveFormSink GstWaveFormSink;
+typedef struct _GstWaveFormSinkClass GstWaveFormSinkClass;
+
+struct _GstWaveFormSink
+{
+  /* parent object */
+  GstAudioSink sink;
+
+  /* supported caps */
+  GstCaps *cached_caps;
+  
+  /* handle to the waveform-audio output device */
+  HWAVEOUT hwaveout;
+  
+  /* table of buffer headers */
+  WAVEHDR *wave_buffers;
+
+  /* critical section protecting access to the number of free buffers */
+  CRITICAL_SECTION critic_wave;
+
+  /* number of free buffers available */
+  guint free_buffers_count;
+  
+  /* current free buffer where you have to write incoming data */
+  guint write_buffer;
+  
+  /* size of buffers streamed to the device */
+  guint buffer_size;
+
+  /* number of buffers streamed to the device */
+  guint buffer_count;
+
+  /* total of bytes in queue before they are written to the device */
+  guint bytes_in_queue;
+
+  /* bytes per sample from setcaps used to evaluate the number samples returned by delay */
+  guint bytes_per_sample;
+
+  /* wave form error string */
+  gchar error_string[ERROR_LENGTH];
+};
+
+struct _GstWaveFormSinkClass
+{
+  GstAudioSinkClass parent_class;
+};
+
+GType gst_waveform_sink_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_WAVEFORMSINK_H__ */
index d2fda78..cbb7c2d 100644 (file)
@@ -6,6 +6,7 @@ win32/vs6/libgstdirectdraw.dsp
 win32/vs6/libgstdirectsound.dsp
 win32/vs6/libgstneon.dsp
 win32/vs6/libgstqtdemux.dsp
+win32/vs6/libgstwaveform.dsp
 win32/vs7/gst-plugins-bad.sln
 win32/vs7/libgstdirectdraw.vcproj
 win32/vs7/libgstdirectsound.vcproj
diff --git a/win32/vs6/libgstwaveform.dsp b/win32/vs6/libgstwaveform.dsp
new file mode 100644 (file)
index 0000000..b74d618
--- /dev/null
@@ -0,0 +1,126 @@
+# Microsoft Developer Studio Project File - Name="libgstwaveform" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libgstwaveform - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libgstwaveform.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libgstwaveform.mak" CFG="libgstwaveform - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libgstwaveform - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libgstwaveform - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libgstwaveform - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTWAVEFORM_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "../.." /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTWAVEFORM_EXPORTS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 glib-2.0.lib gobject-2.0.lib Winmm.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib /nologo /dll /machine:I386 /libpath:"../../../gstreamer/win32/vs6/release" /libpath:"../../../gst-plugins-base/win32/vs6/release" /libpath:"./release"
+# Begin Special Build Tool
+TargetPath=.\Release\libgstwaveform.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ELSEIF  "$(CFG)" == "libgstwaveform - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTWAVEFORM_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTWAVEFORM_EXPORTS" /D "HAVE_CONFIG_H" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 glib-2.0D.lib gobject-2.0D.lib Winmm.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug"
+# SUBTRACT LINK32 /incremental:no
+# Begin Special Build Tool
+TargetPath=.\Debug\libgstwaveform.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\debug\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libgstwaveform - Win32 Release"
+# Name "libgstwaveform - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\sys\waveform\gstwaveformplugin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\sys\waveform\gstwaveformsink.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\sys\waveform\gstwaveformsink.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project