From 296687a398ba315f40fb1ead0de97ae4727162b0 Mon Sep 17 00:00:00 2001 From: Sébastien Moutte Date: Tue, 20 Feb 2007 21:34:00 +0000 Subject: sys/directsound/gstdirectsoundsink.*: Remove include of unused headers. 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. --- sys/directsound/gstdirectsoundsink.c | 16 +- sys/directsound/gstdirectsoundsink.h | 2 - sys/waveform/gstwaveformplugin.c | 42 +++ sys/waveform/gstwaveformsink.c | 601 +++++++++++++++++++++++++++++++++++ sys/waveform/gstwaveformsink.h | 96 ++++++ win32/vs6/libgstwaveform.dsp | 126 ++++++++ 6 files changed, 866 insertions(+), 17 deletions(-) create mode 100644 sys/waveform/gstwaveformplugin.c create mode 100644 sys/waveform/gstwaveformsink.c create mode 100644 sys/waveform/gstwaveformsink.h create mode 100644 win32/vs6/libgstwaveform.dsp diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c index 46a57e8b..94b5579f 100644 --- a/sys/directsound/gstdirectsoundsink.c +++ b/sys/directsound/gstdirectsoundsink.c @@ -20,7 +20,7 @@ */ /** - * SECTION:element-directsound + * SECTION:element-directsoundsink * @short_description: output sound using Directsound API * * @@ -56,13 +56,6 @@ #include "gstdirectsoundsink.h" -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - 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); diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h index d1a47aac..dd0a04f4 100644 --- a/sys/directsound/gstdirectsoundsink.h +++ b/sys/directsound/gstdirectsoundsink.h @@ -19,7 +19,6 @@ * Boston, MA 02111-1307, USA. */ - #ifndef __GST_DIRECTSOUNDSINK_H__ #define __GST_DIRECTSOUNDSINK_H__ @@ -30,7 +29,6 @@ #include #include - 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 index 00000000..0d7943e9 --- /dev/null +++ b/sys/waveform/gstwaveformplugin.c @@ -0,0 +1,42 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 index 00000000..e709d649 --- /dev/null +++ b/sys/waveform/gstwaveformsink.c @@ -0,0 +1,601 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 + * + * + * + * This element lets you output sound using the WaveForm API. + * + * + * 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). + * + * Example pipelines + * + * + * gst-launch-0.10 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! waveformsink + * + * will output a sine wave (continuous beep sound) to your sound card (with + * a very low volume as precaution). + * + * + * + * gst-launch-0.10 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! waveformsink + * + * will play an Ogg/Vorbis audio file and output it. + * + * + */ + +#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 "); + +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 index 00000000..79227794 --- /dev/null +++ b/sys/waveform/gstwaveformsink.h @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) 2005 Sebastien Moutte + * + * 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 +#include + +#include +#include + +#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__ */ diff --git a/win32/vs6/libgstwaveform.dsp b/win32/vs6/libgstwaveform.dsp new file mode 100644 index 00000000..b74d618f --- /dev/null +++ b/win32/vs6/libgstwaveform.dsp @@ -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 -- cgit