diff options
author | Sébastien Moutte <sebastien@moutte.net> | 2007-02-20 21:34:00 +0000 |
---|---|---|
committer | Sébastien Moutte <sebastien@moutte.net> | 2007-02-20 21:34:00 +0000 |
commit | 296687a398ba315f40fb1ead0de97ae4727162b0 (patch) | |
tree | 6cc66cdba1652af7290b20650ee43b8479ff2937 /sys/waveform | |
parent | 2d1b42029af8c75e3539c11314f818b61c6e6a8e (diff) |
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.
Diffstat (limited to 'sys/waveform')
-rw-r--r-- | sys/waveform/gstwaveformplugin.c | 42 | ||||
-rw-r--r-- | sys/waveform/gstwaveformsink.c | 601 | ||||
-rw-r--r-- | sys/waveform/gstwaveformsink.h | 96 |
3 files changed, 739 insertions, 0 deletions
diff --git a/sys/waveform/gstwaveformplugin.c b/sys/waveform/gstwaveformplugin.c new file mode 100644 index 000000000..0d7943e91 --- /dev/null +++ b/sys/waveform/gstwaveformplugin.c @@ -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 index 000000000..e709d649a --- /dev/null +++ b/sys/waveform/gstwaveformsink.c @@ -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 index 000000000..79227794e --- /dev/null +++ b/sys/waveform/gstwaveformsink.h @@ -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__ */ |