diff options
author | Edgard Lima <edgard.lima@indt.org.br> | 2006-01-09 18:20:56 +0000 |
---|---|---|
committer | Edgard Lima <edgard.lima@indt.org.br> | 2006-01-09 18:20:56 +0000 |
commit | a438034608c14b446943fcc0fbb0fa04df93aa47 (patch) | |
tree | 765d96dbb8f9f3711cae0183c945612f09a84071 /ext/sdl/sdlaudiosink.c | |
parent | ce77e3b44bc291c54039918f2136dff8b44a4c9f (diff) | |
download | gst-plugins-bad-a438034608c14b446943fcc0fbb0fa04df93aa47.tar.gz gst-plugins-bad-a438034608c14b446943fcc0fbb0fa04df93aa47.tar.bz2 gst-plugins-bad-a438034608c14b446943fcc0fbb0fa04df93aa47.zip |
Created new element, sdlaudiosink.
Original commit message from CVS:
Created new element, sdlaudiosink.
Diffstat (limited to 'ext/sdl/sdlaudiosink.c')
-rw-r--r-- | ext/sdl/sdlaudiosink.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/ext/sdl/sdlaudiosink.c b/ext/sdl/sdlaudiosink.c new file mode 100644 index 00000000..4465a529 --- /dev/null +++ b/ext/sdl/sdlaudiosink.c @@ -0,0 +1,484 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br> + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sdlaudiosink.h" + +#include <SDL_byteorder.h> +#include <string.h> + +#include <unistd.h> + +GST_DEBUG_CATEGORY_EXTERN (sdl_debug); +#define GST_CAT_DEFAULT sdl_debug + +/* elementfactory information */ +static GstElementDetails gst_sdlaudio_sink_details = +GST_ELEMENT_DETAILS ("Audio Sink (SDLAUDIO)", + "Sink/Audio", + "Output to a sound card via SDLAUDIO", + "Edgard Lima <edgard.lima@indt.org.br>"); + +static void gst_sdlaudio_sink_base_init (gpointer g_class); +static void gst_sdlaudio_sink_class_init (GstSDLAudioSinkClass * klass); +static void gst_sdlaudio_sink_init (GstSDLAudioSink * sdlaudiosink); +static void gst_sdlaudio_sink_dispose (GObject * object); + +static void gst_sdlaudio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_sdlaudio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static GstCaps *gst_sdlaudio_sink_getcaps (GstBaseSink * bsink); + +static gboolean gst_sdlaudio_sink_open (GstAudioSink * asink); +static gboolean gst_sdlaudio_sink_close (GstAudioSink * asink); +static gboolean gst_sdlaudio_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_sdlaudio_sink_unprepare (GstAudioSink * asink); +static guint gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data, + guint length); + +#if 0 +static guint gst_sdlaudio_sink_delay (GstAudioSink * asink); +static void gst_sdlaudio_sink_reset (GstAudioSink * asink); +#endif + + +/* SdlaudioSink signals and args */ +enum +{ + LAST_SIGNAL +}; + +#define SEMAPHORE_INIT(s,f) \ + do { \ + s.cond = g_cond_new(); \ + s.mutex = g_mutex_new(); \ + s.mutexflag = f; \ + } while(0) + +#define SEMAPHORE_CLOSE(s) \ + do { \ + if ( s.cond ) { \ + g_cond_free(s.cond); \ + s.cond = NULL; \ + } \ + if ( s.mutex ) { \ + g_mutex_free(s.mutex); \ + s.mutex = NULL; \ + } \ + } while(0) + +#define SEMAPHORE_UP(s) \ + do \ + { \ + g_mutex_lock(s.mutex); \ + s.mutexflag = TRUE; \ + g_mutex_unlock(s.mutex); \ + g_cond_signal(s.cond); \ + } while(0) + +#define SEMAPHORE_DOWN(s, e) \ + do \ + { \ + while (1) { \ + g_mutex_lock(s.mutex); \ + if (!s.mutexflag) { \ + if ( e ) { \ + g_mutex_unlock(s.mutex); \ + break; \ + } \ + g_cond_wait(s.cond,s.mutex); \ + } \ + else { \ + s.mutexflag = FALSE; \ + g_mutex_unlock(s.mutex); \ + break; \ + } \ + g_mutex_unlock(s.mutex); \ + } \ + } while(0) + + +static GstStaticPadTemplate sdlaudiosink_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, 2 ]; " + "audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 8, " + "depth = (int) 8, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") + ); + +static GstElementClass *parent_class = NULL; + +GType +gst_sdlaudio_sink_get_type (void) +{ + static GType sdlaudiosink_type = 0; + + if (!sdlaudiosink_type) { + static const GTypeInfo sdlaudiosink_info = { + sizeof (GstSDLAudioSinkClass), + gst_sdlaudio_sink_base_init, + NULL, + (GClassInitFunc) gst_sdlaudio_sink_class_init, + NULL, + NULL, + sizeof (GstSDLAudioSink), + 0, + (GInstanceInitFunc) gst_sdlaudio_sink_init, + }; + + sdlaudiosink_type = + g_type_register_static (GST_TYPE_AUDIO_SINK, "GstSDLAudioSink", + &sdlaudiosink_info, 0); + } + + return sdlaudiosink_type; +} + +static void +gst_sdlaudio_sink_dispose (GObject * object) +{ + GstSDLAudioSink *sdlaudiosink = GST_SDLAUDIOSINK (object); + + SEMAPHORE_CLOSE (sdlaudiosink->semB); + + SEMAPHORE_CLOSE (sdlaudiosink->semA); + + if (sdlaudiosink->buffer) { + g_free (sdlaudiosink->buffer); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_sdlaudio_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &gst_sdlaudio_sink_details); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sdlaudiosink_sink_factory)); +} +static void +gst_sdlaudio_sink_class_init (GstSDLAudioSinkClass * 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_ref (GST_TYPE_BASE_AUDIO_SINK); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_dispose); + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_getcaps); + + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_close); + gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_prepare); + gstaudiosink_class->unprepare = + GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_unprepare); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_write); + +#if 0 + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_reset); +#endif + +} + +static void +gst_sdlaudio_sink_init (GstSDLAudioSink * sdlaudiosink) +{ + GST_DEBUG ("initializing sdlaudiosink"); + + memset (&sdlaudiosink->fmt, 0, sizeof (SDL_AudioSpec)); + + sdlaudiosink->buffer = NULL; + sdlaudiosink->eos = FALSE; + + SEMAPHORE_INIT (sdlaudiosink->semA, TRUE); + + SEMAPHORE_INIT (sdlaudiosink->semB, TRUE); + +} + +static GstCaps * +gst_sdlaudio_sink_getcaps (GstBaseSink * bsink) +{ + GstSDLAudioSink *sdlaudiosink; + GstCaps *caps = NULL; + + sdlaudiosink = GST_SDLAUDIOSINK (bsink); + + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD + (bsink))); + return caps; +} + +static gint +gst_sdlaudio_sink_get_format (GstBufferFormat fmt) +{ + gint result = GST_UNKNOWN; + + switch (fmt) { + case GST_U8: + result = AUDIO_U8; + break; + case GST_S8: + result = AUDIO_S8; + break; + case GST_S16_LE: + result = AUDIO_S16LSB; + break; + case GST_S16_BE: + result = AUDIO_S16MSB; + break; + case GST_U16_LE: + result = AUDIO_U16LSB; + break; + case GST_U16_BE: + result = AUDIO_U16MSB; + break; + default: + break; + } + return result; +} + +static gboolean +gst_sdlaudio_sink_open (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio; + int mode; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + if (SDL_Init (SDL_INIT_AUDIO) < 0) { + goto open_failed; + } + + return TRUE; + +open_failed: + { + GST_ELEMENT_ERROR (sdlaudio, LIBRARY, INIT, + ("Unable to init SDL: %s\n", SDL_GetError ()), (NULL)); + return FALSE; + } +} + +static gboolean +gst_sdlaudio_sink_close (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink); + + sdlaudio->eos = TRUE; + SEMAPHORE_UP (sdlaudio->semA); + SEMAPHORE_UP (sdlaudio->semB); + SDL_Quit (); + return TRUE; +} + +static guint +gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink); + + if (sdlaudio->fmt.size != length) { + GST_ERROR ("ring buffer segment lenght (%u) != sdl buffer len", length, + sdlaudio->fmt.size); + } + + SEMAPHORE_DOWN (sdlaudio->semA, sdlaudio->eos); + + if (!sdlaudio->eos) + memcpy (sdlaudio->buffer, data, length); + + SEMAPHORE_UP (sdlaudio->semB); + + return sdlaudio->fmt.size; +} + + +void +mixaudio (void *unused, Uint8 * stream, int len) +{ + GstSDLAudioSink *sdlaudio; + + sdlaudio = GST_SDLAUDIOSINK (unused); + + if (sdlaudio->fmt.size != len) { + GST_ERROR ("fmt buffer len (%u) != sdl callback len (%d)", + sdlaudio->fmt.size, len); + } + + SEMAPHORE_DOWN (sdlaudio->semB, sdlaudio->eos); + + if (!sdlaudio->eos) + SDL_MixAudio (stream, sdlaudio->buffer, sdlaudio->fmt.size, + SDL_MIX_MAXVOLUME); + + SEMAPHORE_UP (sdlaudio->semA); + +} + +static gboolean +gst_sdlaudio_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstSDLAudioSink *sdlaudio; + gint power2 = -1; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + sdlaudio->fmt.format = gst_sdlaudio_sink_get_format (spec->format); + if (sdlaudio->fmt.format == 0) + goto wrong_format; + + if (spec->width != 16 && spec->width != 8) + goto dodgy_width; + + sdlaudio->fmt.freq = spec->rate; + sdlaudio->fmt.channels = spec->channels; + sdlaudio->fmt.samples = + spec->segsize / (spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3)); + sdlaudio->fmt.callback = mixaudio; + sdlaudio->fmt.userdata = sdlaudio; + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + while (sdlaudio->fmt.samples) { + sdlaudio->fmt.samples >>= 1; + ++power2; + } + + sdlaudio->fmt.samples = 1; + sdlaudio->fmt.samples <<= power2; + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + if (SDL_OpenAudio (&sdlaudio->fmt, NULL) < 0) { + goto unable_open; + } + + spec->segsize = sdlaudio->fmt.size; + + sdlaudio->buffer = g_malloc (sdlaudio->fmt.size); + memset (sdlaudio->buffer, sdlaudio->fmt.silence, sdlaudio->fmt.size); + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + spec->bytes_per_sample = + spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3); + memset (spec->silence_sample, sdlaudio->fmt.silence, spec->bytes_per_sample); + + SDL_PauseAudio (0); + + return TRUE; + +unable_open: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("Unable to open audio: %s", SDL_GetError ()), NULL); + return FALSE; + } +wrong_format: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("Unable to get format %d", spec->format), NULL); + return FALSE; + } +dodgy_width: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("unexpected width %d", spec->width), NULL); + return FALSE; + } +} + +static gboolean +gst_sdlaudio_sink_unprepare (GstAudioSink * asink) +{ + + SDL_CloseAudio (); + + return TRUE; + +#if 0 + if (!gst_sdlaudio_sink_close (asink)) + goto couldnt_close; + + if (!gst_sdlaudio_sink_open (asink)) + goto couldnt_reopen; + + return TRUE; + +couldnt_close: + { + GST_DEBUG ("Could not close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG ("Could not reopen the audio device"); + return FALSE; + } +#endif + +} + +#if 0 +static guint +gst_sdlaudio_sink_delay (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + return 0; +} + +static void +gst_sdlaudio_sink_reset (GstAudioSink * asink) +{ +} +#endif |