2 * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:element-waveformsink
24 * @short_description: output sound using WaveForm API
28 * This element lets you output sound using the WaveForm API.
31 * Note that you should almost always use generic audio conversion elements
32 * like audioconvert and audioresample in front of an audiosink to make sure
33 * your pipeline works under all circumstances (those conversion elements will
34 * act in passthrough-mode if no conversion is necessary).
36 * <title>Example pipelines</title>
39 * gst-launch-0.10 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! waveformsink
41 * will output a sine wave (continuous beep sound) to your sound card (with
42 * a very low volume as precaution).
46 * gst-launch-0.10 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! waveformsink
48 * will play an Ogg/Vorbis audio file and output it.
57 #include "gstwaveformsink.h"
59 GST_DEBUG_CATEGORY_STATIC (waveformsink_debug);
61 /* elementfactory information */
62 static const GstElementDetails gst_waveform_sink_details =
63 GST_ELEMENT_DETAILS ("WaveForm Audio Sink",
65 "Output to a sound card via WaveForm API",
66 "Sebastien Moutte <sebastien@moutte.net>");
68 static void gst_waveform_sink_base_init (gpointer g_class);
69 static void gst_waveform_sink_class_init (GstWaveFormSinkClass * klass);
70 static void gst_waveform_sink_init (GstWaveFormSink * wfsink,
71 GstWaveFormSinkClass * g_class);
72 static void gst_waveform_sink_finalise (GObject * object);
73 static void gst_waveform_sink_set_property (GObject * object,
74 guint prop_id, const GValue * value, GParamSpec * pspec);
75 static void gst_waveform_sink_get_property (GObject * object,
76 guint prop_id, GValue * value, GParamSpec * pspec);
77 static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink);
79 /************************************************************************/
80 /* GstAudioSink functions */
81 /************************************************************************/
82 static gboolean gst_waveform_sink_prepare (GstAudioSink * asink,
83 GstRingBufferSpec * spec);
84 static gboolean gst_waveform_sink_unprepare (GstAudioSink * asink);
85 static gboolean gst_waveform_sink_open (GstAudioSink * asink);
86 static gboolean gst_waveform_sink_close (GstAudioSink * asink);
87 static guint gst_waveform_sink_write (GstAudioSink * asink, gpointer data,
89 static guint gst_waveform_sink_delay (GstAudioSink * asink);
90 static void gst_waveform_sink_reset (GstAudioSink * asink);
92 /************************************************************************/
94 /************************************************************************/
95 GstCaps *gst_waveform_sink_create_caps (gint rate, gint channels,
96 gint bits_per_sample);
97 WAVEHDR *bufferpool_get_buffer (GstWaveFormSink * wfsink, gpointer data,
99 void CALLBACK waveOutProc (HWAVEOUT hwo, UINT uMsg, unsigned long dwInstance,
100 DWORD dwParam1, DWORD dwParam2);
102 static GstStaticPadTemplate waveformsink_sink_factory =
103 GST_STATIC_PAD_TEMPLATE ("sink",
106 GST_STATIC_CAPS ("audio/x-raw-int, "
107 "signed = (boolean) { TRUE, FALSE }, "
110 "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
112 "signed = (boolean) { TRUE, FALSE }, "
115 "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
117 GST_BOILERPLATE (GstWaveFormSink, gst_waveform_sink, GstAudioSink,
118 GST_TYPE_AUDIO_SINK);
121 gst_waveform_sink_base_init (gpointer g_class)
123 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
125 gst_element_class_set_details (element_class, &gst_waveform_sink_details);
126 gst_element_class_add_pad_template (element_class,
127 gst_static_pad_template_get (&waveformsink_sink_factory));
131 gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
133 GObjectClass *gobject_class;
134 GstElementClass *gstelement_class;
135 GstBaseSinkClass *gstbasesink_class;
136 GstBaseAudioSinkClass *gstbaseaudiosink_class;
137 GstAudioSinkClass *gstaudiosink_class;
139 gobject_class = (GObjectClass *) klass;
140 gstelement_class = (GstElementClass *) klass;
141 gstbasesink_class = (GstBaseSinkClass *) klass;
142 gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
143 gstaudiosink_class = (GstAudioSinkClass *) klass;
145 parent_class = g_type_class_peek_parent (klass);
147 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_waveform_sink_finalise);
148 gobject_class->get_property =
149 GST_DEBUG_FUNCPTR (gst_waveform_sink_get_property);
150 gobject_class->set_property =
151 GST_DEBUG_FUNCPTR (gst_waveform_sink_set_property);
153 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_waveform_sink_getcaps);
155 gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_waveform_sink_prepare);
156 gstaudiosink_class->unprepare =
157 GST_DEBUG_FUNCPTR (gst_waveform_sink_unprepare);
158 gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_waveform_sink_open);
159 gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_waveform_sink_close);
160 gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_waveform_sink_write);
161 gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_waveform_sink_delay);
162 gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_waveform_sink_reset);
164 GST_DEBUG_CATEGORY_INIT (waveformsink_debug, "waveformsink", 0,
169 gst_waveform_sink_set_property (GObject * object, guint prop_id,
170 const GValue * value, GParamSpec * pspec)
172 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
182 gst_waveform_sink_get_property (GObject * object, guint prop_id,
183 GValue * value, GParamSpec * pspec)
185 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
189 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195 gst_waveform_sink_init (GstWaveFormSink * wfsink,
196 GstWaveFormSinkClass * g_class)
198 /* initialize members */
199 wfsink->hwaveout = NULL;
200 wfsink->cached_caps = NULL;
201 wfsink->wave_buffers = NULL;
202 wfsink->write_buffer = 0;
203 wfsink->buffer_count = BUFFER_COUNT;
204 wfsink->buffer_size = BUFFER_SIZE;
205 wfsink->free_buffers_count = wfsink->buffer_count;
206 wfsink->bytes_in_queue = 0;
208 InitializeCriticalSection (&wfsink->critic_wave);
212 gst_waveform_sink_finalise (GObject * object)
214 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
216 if (wfsink->cached_caps) {
217 gst_caps_unref (wfsink->cached_caps);
218 wfsink->cached_caps = NULL;
221 DeleteCriticalSection (&wfsink->critic_wave);
223 G_OBJECT_CLASS (parent_class)->finalize (object);
227 gst_waveform_sink_getcaps (GstBaseSink * bsink)
229 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink);
232 GstCaps *caps, *caps_temp;
234 /* return the cached caps if already defined */
235 if (wfsink->cached_caps) {
236 return gst_caps_ref (wfsink->cached_caps);
239 /* get the default device caps */
240 mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps));
241 if (mmresult != MMSYSERR_NOERROR) {
242 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
243 GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS,
244 ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s",
245 wfsink->error_string), (NULL));
249 caps = gst_caps_new_empty ();
251 /* create a caps for all wave formats supported by the device
252 starting by the best quality format */
253 if (wocaps.dwFormats & WAVE_FORMAT_96S16) {
254 caps_temp = gst_waveform_sink_create_caps (96000, 2, 16);
256 gst_caps_append (caps, caps_temp);
259 if (wocaps.dwFormats & WAVE_FORMAT_96S08) {
260 caps_temp = gst_waveform_sink_create_caps (96000, 2, 8);
262 gst_caps_append (caps, caps_temp);
265 if (wocaps.dwFormats & WAVE_FORMAT_96M16) {
266 caps_temp = gst_waveform_sink_create_caps (96000, 1, 16);
268 gst_caps_append (caps, caps_temp);
271 if (wocaps.dwFormats & WAVE_FORMAT_96M08) {
272 caps_temp = gst_waveform_sink_create_caps (96000, 1, 8);
274 gst_caps_append (caps, caps_temp);
277 if (wocaps.dwFormats & WAVE_FORMAT_4S16) {
278 caps_temp = gst_waveform_sink_create_caps (44100, 2, 16);
280 gst_caps_append (caps, caps_temp);
283 if (wocaps.dwFormats & WAVE_FORMAT_4S08) {
284 caps_temp = gst_waveform_sink_create_caps (44100, 2, 8);
286 gst_caps_append (caps, caps_temp);
289 if (wocaps.dwFormats & WAVE_FORMAT_4M16) {
290 caps_temp = gst_waveform_sink_create_caps (44100, 1, 16);
292 gst_caps_append (caps, caps_temp);
295 if (wocaps.dwFormats & WAVE_FORMAT_4M08) {
296 caps_temp = gst_waveform_sink_create_caps (44100, 1, 8);
298 gst_caps_append (caps, caps_temp);
301 if (wocaps.dwFormats & WAVE_FORMAT_2S16) {
302 caps_temp = gst_waveform_sink_create_caps (22050, 2, 16);
304 gst_caps_append (caps, caps_temp);
307 if (wocaps.dwFormats & WAVE_FORMAT_2S08) {
308 caps_temp = gst_waveform_sink_create_caps (22050, 2, 8);
310 gst_caps_append (caps, caps_temp);
313 if (wocaps.dwFormats & WAVE_FORMAT_2M16) {
314 caps_temp = gst_waveform_sink_create_caps (22050, 1, 16);
316 gst_caps_append (caps, caps_temp);
319 if (wocaps.dwFormats & WAVE_FORMAT_2M08) {
320 caps_temp = gst_waveform_sink_create_caps (22050, 1, 8);
322 gst_caps_append (caps, caps_temp);
325 if (wocaps.dwFormats & WAVE_FORMAT_1S16) {
326 caps_temp = gst_waveform_sink_create_caps (11025, 2, 16);
328 gst_caps_append (caps, caps_temp);
331 if (wocaps.dwFormats & WAVE_FORMAT_1S08) {
332 caps_temp = gst_waveform_sink_create_caps (11025, 2, 8);
334 gst_caps_append (caps, caps_temp);
337 if (wocaps.dwFormats & WAVE_FORMAT_1M16) {
338 caps_temp = gst_waveform_sink_create_caps (11025, 1, 16);
340 gst_caps_append (caps, caps_temp);
343 if (wocaps.dwFormats & WAVE_FORMAT_1M08) {
344 caps_temp = gst_waveform_sink_create_caps (11025, 1, 8);
346 gst_caps_append (caps, caps_temp);
350 if (gst_caps_is_empty (caps)) {
351 gst_caps_unref (caps);
354 wfsink->cached_caps = gst_caps_ref (caps);
357 GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "Returning caps %s",
358 gst_caps_to_string (caps));
364 gst_waveform_sink_open (GstAudioSink * asink)
366 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
368 /* nothing to do here as the device needs to be opened with the format we will use */
374 gst_waveform_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
376 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
381 /* setup waveformex struture with the input ringbuffer specs */
382 memset (&wfx, 0, sizeof (wfx));
384 wfx.wFormatTag = WAVE_FORMAT_PCM;
385 wfx.nChannels = spec->channels;
386 wfx.nSamplesPerSec = spec->rate;
387 wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels;
388 wfx.nBlockAlign = spec->bytes_per_sample;
389 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
391 /* save bytes per sample to use it in delay */
392 wfsink->bytes_per_sample = spec->bytes_per_sample;
394 /* open the default audio device with the given caps */
395 mmresult = waveOutOpen (&wfsink->hwaveout, WAVE_MAPPER,
396 &wfx, (DWORD) waveOutProc, (DWORD) wfsink, CALLBACK_FUNCTION);
397 if (mmresult != MMSYSERR_NOERROR) {
398 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
399 GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
400 ("gst_waveform_sink_prepare: waveOutOpen failed error=>%s",
401 wfsink->error_string), (NULL));
405 /* evaluate the buffer size and the number of buffers needed */
406 wfsink->free_buffers_count = wfsink->buffer_count;
408 /* allocate wave buffers */
409 wfsink->wave_buffers = (WAVEHDR *) g_new0 (WAVEHDR, wfsink->buffer_count);
410 if (!wfsink->wave_buffers) {
411 GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
412 ("gst_waveform_sink_prepare: Failed to allocate wave buffer headers (buffer count=%d)",
413 wfsink->buffer_count), (NULL));
416 memset (wfsink->wave_buffers, 0, sizeof (WAVEHDR) * wfsink->buffer_count);
419 for (index = 0; index < wfsink->buffer_count; index++) {
420 wfsink->wave_buffers[index].dwBufferLength = wfsink->buffer_size;
421 wfsink->wave_buffers[index].lpData = g_new0 (gchar, wfsink->buffer_size);
428 gst_waveform_sink_unprepare (GstAudioSink * asink)
430 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
432 /* free wave buffers */
433 if (wfsink->wave_buffers) {
436 for (index = 0; index < wfsink->buffer_count; index++) {
437 if (wfsink->wave_buffers[index].dwFlags & WHDR_PREPARED) {
439 waveOutUnprepareHeader (wfsink->hwaveout,
440 &wfsink->wave_buffers[index], sizeof (WAVEHDR));
441 if (mmresult != MMSYSERR_NOERROR) {
442 waveOutGetErrorText (mmresult, wfsink->error_string,
444 GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
445 "gst_waveform_sink_unprepare: Error unpreparing buffer => %s",
446 wfsink->error_string);
449 g_free (wfsink->wave_buffers[index].lpData);
451 g_free (wfsink->wave_buffers);
452 wfsink->wave_buffers = NULL;
455 /* close waveform-audio output device */
456 if (wfsink->hwaveout) {
457 waveOutClose (wfsink->hwaveout);
458 wfsink->hwaveout = NULL;
465 gst_waveform_sink_close (GstAudioSink * asink)
467 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
473 gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length)
475 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
478 guint bytes_to_write = length;
479 guint remaining_length = length;
481 wfsink->bytes_in_queue += length;
483 while (remaining_length > 0) {
484 if (wfsink->free_buffers_count == 0) {
485 /* no free buffer available, wait for one */
490 /* get the current write buffer header */
491 waveheader = &wfsink->wave_buffers[wfsink->write_buffer];
493 /* unprepare the header if needed */
494 if (waveheader->dwFlags & WHDR_PREPARED) {
496 waveOutUnprepareHeader (wfsink->hwaveout, waveheader,
498 if (mmresult != MMSYSERR_NOERROR) {
499 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
500 GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
501 "Error unpreparing buffer => %s", wfsink->error_string);
505 if (wfsink->buffer_size - waveheader->dwUser >= remaining_length)
506 bytes_to_write = remaining_length;
508 bytes_to_write = wfsink->buffer_size - waveheader->dwUser;
510 memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write);
511 waveheader->dwUser += bytes_to_write;
512 remaining_length -= bytes_to_write;
513 data = (byte *) data + bytes_to_write;
515 if (waveheader->dwUser == wfsink->buffer_size) {
516 /* we have filled a buffer, let's prepare it and next write it to the device */
518 waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
519 if (mmresult != MMSYSERR_NOERROR) {
520 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
521 GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
522 "gst_waveform_sink_write: Error preparing header => %s",
523 wfsink->error_string);
525 mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
526 if (mmresult != MMSYSERR_NOERROR) {
527 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
528 GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
529 "gst_waveform_sink_write: Error writting buffer to the device => %s",
530 wfsink->error_string);
533 EnterCriticalSection (&wfsink->critic_wave);
534 wfsink->free_buffers_count--;
535 LeaveCriticalSection (&wfsink->critic_wave);
537 wfsink->write_buffer++;
538 wfsink->write_buffer %= wfsink->buffer_count;
539 waveheader->dwUser = 0;
540 wfsink->bytes_in_queue = 0;
541 GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink,
542 "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)",
543 wfsink->free_buffers_count, wfsink->write_buffer);
551 gst_waveform_sink_delay (GstAudioSink * asink)
553 /* return the number of samples in queue (device+internal queue) */
554 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
555 guint bytes_in_device =
556 (wfsink->buffer_count - wfsink->free_buffers_count) * wfsink->buffer_size;
558 (bytes_in_device + wfsink->bytes_in_queue) / wfsink->bytes_per_sample;
563 gst_waveform_sink_reset (GstAudioSink * asink)
565 GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
566 MMRESULT mmresult = waveOutReset (wfsink->hwaveout);
568 if (mmresult != MMSYSERR_NOERROR) {
569 waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
570 GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
571 "gst_waveform_sink_reset: Error reseting waveform-audio device => %s",
572 wfsink->error_string);
577 gst_waveform_sink_create_caps (gint rate, gint channels, gint bits_per_sample)
579 GstCaps *caps = NULL;
581 caps = gst_caps_new_simple ("audio/x-raw-int",
582 "width", G_TYPE_INT, bits_per_sample,
583 "depth", G_TYPE_INT, bits_per_sample,
584 "endianness", G_TYPE_INT, G_BYTE_ORDER,
585 "signed", G_TYPE_BOOLEAN, TRUE,
586 "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
591 waveOutProc (HWAVEOUT hwo,
592 UINT uMsg, unsigned long dwInstance, DWORD dwParam1, DWORD dwParam2)
594 GstWaveFormSink *wfsink = (GstWaveFormSink *) dwInstance;
596 if (uMsg == WOM_DONE) {
597 EnterCriticalSection (&wfsink->critic_wave);
598 wfsink->free_buffers_count++;
599 LeaveCriticalSection (&wfsink->critic_wave);