diff --git a/configure.ac b/configure.ac index b6db222943..1b573b5f4c 100644 --- a/configure.ac +++ b/configure.ac @@ -346,7 +346,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \ linsys vcd \ apexsink cdaudio dc1394 directfb \ gsettings \ - musepack nas openal sdl sndfile timidity \ + musepack nas sdl sndfile timidity \ directdraw direct3d9 acm wininet \ xvid lv2 teletextdec sndio osx_video quicktime" AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/ext/openal/gstopenal.c b/ext/openal/gstopenal.c index 770824b914..44bffb6f8d 100644 --- a/ext/openal/gstopenal.c +++ b/ext/openal/gstopenal.c @@ -1,8 +1,10 @@ /* - * GStreamer + * GStreamer openal plugin + * * Copyright (C) 2005 Wim Taymans * Copyright (C) 2006 Tim-Philipp Müller * Copyright (C) 2009-2010 Chris Robinson + * Copyright (C) 2013 Juan Manuel Borges Caño * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,18 +26,21 @@ #include "config.h" #endif -#include -#include - #include "gstopenalsink.h" #include "gstopenalsrc.h" +#include + +GST_DEBUG_CATEGORY (openal_debug); + static gboolean plugin_init (GstPlugin * plugin) { if (!gst_element_register (plugin, "openalsink", GST_RANK_SECONDARY, - GST_TYPE_OPENAL_SINK) || - !gst_element_register (plugin, "openalsrc", GST_RANK_SECONDARY, + GST_TYPE_OPENAL_SINK)) + return FALSE; + + if (!gst_element_register (plugin, "openalsrc", GST_RANK_SECONDARY, GST_TYPE_OPENAL_SRC)) return FALSE; @@ -44,12 +49,14 @@ plugin_init (GstPlugin * plugin) LOCALEDIR); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif /* ENABLE_NLS */ +#endif + GST_DEBUG_CATEGORY_INIT (openal_debug, "openal", 0, "openal plugins"); return TRUE; } -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, openal, - "OpenAL support for GStreamer", + "OpenAL plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/openal/gstopenalsink.c b/ext/openal/gstopenalsink.c index c6c4e9153c..86f4709cef 100644 --- a/ext/openal/gstopenalsink.c +++ b/ext/openal/gstopenalsink.c @@ -1,8 +1,10 @@ /* * GStreamer + * * Copyright (C) 2005 Wim Taymans * Copyright (C) 2006 Tim-Philipp Müller * Copyright (C) 2009-2010 Chris Robinson + * Copyright (C) 2013 Juan Manuel Borges Caño * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,56 +22,70 @@ * Boston, MA 02110-1301, USA. */ -/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - /** * SECTION:element-openalsink + * @see_also: openalsrc + * @short_description: capture raw audio samples through OpenAL * - * This element renders raw audio samples using the OpenAL API + * This element plays raw audio samples through OpenAL. + * + * Unfortunately the capture API doesn't have a format enumeration/check. all you can do is try opening it and see if it works. * * * Example pipelines * |[ - * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.1 ! openalsink - * ]| will output a sine wave (continuous beep sound) to your sound card (with - * a very low volume as precaution). + * gst-launch audiotestsrc ! audioconvert ! volume volume=0.5 ! openalsink + * ]| will play a sine wave (continuous beep sound) through OpenAL. * |[ - * gst-launch -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! openalsink - * ]| will play an Ogg/Vorbis audio file and output it using OpenAL. + * gst-launch filesrc location=stream.wav ! decodebin ! audioconvert ! openalsink + * ]| will play a wav audio file through OpenAL. + * |[ + * gst-launch openalsrc ! "audio/x-raw,format=S16LE,rate=44100" ! audioconvert ! volume volume=0.25 ! openalsink + * ]| will capture and play audio through OpenAL. * */ +/* + * DEV: + * To get better timing/delay information you may also be interested in this: + * http://kcat.strangesoft.net/openal-extensions/SOFT_source_latency.txt + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "gstopenalsink.h" +#include +#include -GST_DEBUG_CATEGORY (openalsink_debug); +GST_DEBUG_CATEGORY_EXTERN (openal_debug); +#define GST_CAT_DEFAULT openal_debug + +#include "gstopenalsink.h" static void gst_openal_sink_dispose (GObject * object); static void gst_openal_sink_finalize (GObject * object); static void gst_openal_sink_get_property (GObject * object, guint prop_id, - GValue * val, GParamSpec * pspec); + GValue * value, GParamSpec * pspec); static void gst_openal_sink_set_property (GObject * object, guint prop_id, - const GValue * val, GParamSpec * pspec); - -static GstCaps *gst_openal_sink_getcaps (GstBaseSink * bsink); - -static gboolean gst_openal_sink_open (GstAudioSink * asink); -static gboolean gst_openal_sink_close (GstAudioSink * asink); -static gboolean gst_openal_sink_prepare (GstAudioSink * asink, - GstRingBufferSpec * spec); -static gboolean gst_openal_sink_unprepare (GstAudioSink * asink); -static guint gst_openal_sink_write (GstAudioSink * asink, gpointer data, + const GValue * value, GParamSpec * pspec); +static GstCaps *gst_openal_sink_getcaps (GstBaseSink * basesink, + GstCaps * filter); +static gboolean gst_openal_sink_open (GstAudioSink * audiosink); +static gboolean gst_openal_sink_close (GstAudioSink * audiosink); +static gboolean gst_openal_sink_prepare (GstAudioSink * audiosink, + GstAudioRingBufferSpec * spec); +static gboolean gst_openal_sink_unprepare (GstAudioSink * audiosink); +static gint gst_openal_sink_write (GstAudioSink * audiosink, gpointer data, guint length); -static guint gst_openal_sink_delay (GstAudioSink * asink); -static void gst_openal_sink_reset (GstAudioSink * asink); +static guint gst_openal_sink_delay (GstAudioSink * audiosink); +static void gst_openal_sink_reset (GstAudioSink * audiosink); -#define DEFAULT_DEVICE NULL +#define OPENAL_DEFAULT_DEVICE NULL + +#define OPENAL_MIN_RATE 8000 +#define OPENAL_MAX_RATE 192000 enum { @@ -78,60 +94,56 @@ enum PROP_DEVICE, PROP_DEVICE_NAME, - PROP_DEVICE_HDL, - PROP_CONTEXT_HDL, - PROP_SOURCE_ID + PROP_USER_DEVICE, + PROP_USER_CONTEXT, + PROP_USER_SOURCE }; -static GstStaticPadTemplate openalsink_sink_factory = +static GstStaticPadTemplate openalsink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " - "width = (int) 32, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " - "signed = (boolean) TRUE, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "signed = (boolean) FALSE, " - "width = (int) 8, " - "depth = (int) 8, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, MAX ]; " - "audio/x-mulaw, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") + GST_STATIC_CAPS ("audio/x-raw, " "format = (string) " GST_AUDIO_NE (F64) + ", " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " + "audio/x-raw, " "format = (string) " GST_AUDIO_NE (F32) ", " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " + "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S16) ", " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " + "audio/x-raw, " "format = (string) " G_STRINGIFY (U8) ", " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " + /* These caps do not work on my card */ + // "audio/x-adpcm, " "layout = (string) ima, " + // "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " + // "audio/x-alaw, " "rate = (int) [ 1, MAX ], " + // "channels = (int) [ 1, 2 ]; " + // "audio/x-mulaw, " "rate = (int) [ 1, MAX ], " + // "channels = (int) [ 1, MAX ]" + ) ); static PFNALCSETTHREADCONTEXTPROC palcSetThreadContext; static PFNALCGETTHREADCONTEXTPROC palcGetThreadContext; static inline ALCcontext * -pushContext (ALCcontext * ctx) +pushContext (ALCcontext * context) { ALCcontext *old; if (!palcGetThreadContext || !palcSetThreadContext) return NULL; old = palcGetThreadContext (); - if (old != ctx) - palcSetThreadContext (ctx); + if (old != context) + palcSetThreadContext (context); return old; } static inline void -popContext (ALCcontext * old, ALCcontext * ctx) +popContext (ALCcontext * old, ALCcontext * context) { if (!palcGetThreadContext || !palcSetThreadContext) return; - if (old != ctx) + if (old != context) palcSetThreadContext (old); } @@ -146,8 +158,7 @@ checkALError (const char *fname, unsigned int fline) #define checkALError() checkALError(__FILE__, __LINE__) -GST_BOILERPLATE (GstOpenALSink, gst_openal_sink, GstAudioSink, - GST_TYPE_AUDIO_SINK); +G_DEFINE_TYPE (GstOpenALSink, gst_openal_sink, GST_TYPE_AUDIO_SINK); static void gst_openal_sink_dispose (GObject * object) @@ -158,41 +169,22 @@ gst_openal_sink_dispose (GObject * object) gst_caps_unref (sink->probed_caps); sink->probed_caps = NULL; - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (gst_openal_sink_parent_class)->dispose (object); } -/* GObject vmethod implementations */ -static void -gst_openal_sink_base_init (gpointer gclass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - GstPadTemplate *pad_template; - - gst_element_class_set_static_metadata (element_class, "Audio sink (OpenAL)", - "Sink/Audio", - "Output to a sound device via OpenAL", - "Chris Robinson "); - - pad_template = gst_static_pad_template_get (&openalsink_sink_factory); - gst_element_class_add_pad_template (element_class, pad_template); -} - -/* initialize the plugin's class */ static void gst_openal_sink_class_init (GstOpenALSinkClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass; GstAudioSinkClass *gstaudiosink_class = (GstAudioSinkClass *) klass; - GParamSpec *spec; if (alcIsExtensionPresent (NULL, "ALC_EXT_thread_local_context")) { palcSetThreadContext = alcGetProcAddress (NULL, "alcSetThreadContext"); palcGetThreadContext = alcGetProcAddress (NULL, "alcGetThreadContext"); } - GST_DEBUG_CATEGORY_INIT (openalsink_debug, "openalsink", 0, "OpenAL sink"); - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_openal_sink_dispose); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_openal_sink_finalize); gobject_class->set_property = @@ -200,27 +192,7 @@ gst_openal_sink_class_init (GstOpenALSinkClass * klass) gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_openal_sink_get_property); - spec = g_param_spec_string ("device-name", "Device name", - "Opened OpenAL device name", "", G_PARAM_READABLE); - g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, spec); - - spec = g_param_spec_string ("device", "Device", "OpenAL device string", - DEFAULT_DEVICE, G_PARAM_READWRITE); - g_object_class_install_property (gobject_class, PROP_DEVICE, spec); - - spec = g_param_spec_pointer ("device-handle", "ALCdevice", - "Custom playback device", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (gobject_class, PROP_DEVICE_HDL, spec); - - spec = g_param_spec_pointer ("context-handle", "ALCcontext", - "Custom playback context", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (gobject_class, PROP_CONTEXT_HDL, spec); - - spec = g_param_spec_uint ("source-id", "Source ID", "Custom playback sID", - 0, UINT_MAX, 0, G_PARAM_READWRITE); - g_object_class_install_property (gobject_class, PROP_SOURCE_ID, spec); - - parent_class = g_type_class_peek_parent (klass); + gst_openal_sink_parent_class = g_type_class_peek_parent (klass); gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_openal_sink_getcaps); @@ -231,32 +203,61 @@ gst_openal_sink_class_init (GstOpenALSinkClass * klass) gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_openal_sink_write); gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_openal_sink_delay); gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_openal_sink_reset); + + g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, + g_param_spec_string ("device-name", "Device name", + "Human-readable name of the opened device", "", G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "Human-readable name of the device", OPENAL_DEFAULT_DEVICE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_USER_DEVICE, + g_param_spec_pointer ("user-device", "ALCdevice", "User device", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_USER_CONTEXT, + g_param_spec_pointer ("user-context", "ALCcontext", "User context", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_USER_SOURCE, + g_param_spec_uint ("user-source", "ALsource", "User source", 0, UINT_MAX, + 0, G_PARAM_READWRITE)); + + gst_element_class_set_static_metadata (gstelement_class, "OpenAL Audio Sink", + "Sink/Audio", "Output audio through OpenAL", + "Juan Manuel Borges Caño "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&openalsink_factory)); + } static void -gst_openal_sink_init (GstOpenALSink * sink, GstOpenALSinkClass * klass) +gst_openal_sink_init (GstOpenALSink * sink) { - GST_DEBUG_OBJECT (sink, "initializing openalsink"); + GST_DEBUG_OBJECT (sink, "initializing"); - sink->devname = g_strdup (DEFAULT_DEVICE); + sink->device_name = g_strdup (OPENAL_DEFAULT_DEVICE); - sink->custom_dev = NULL; - sink->custom_ctx = NULL; - sink->custom_sID = 0; + sink->user_device = NULL; + sink->user_context = NULL; + sink->user_source = 0; - sink->device = NULL; - sink->context = NULL; - sink->sID = 0; + sink->default_device = NULL; + sink->default_context = NULL; + sink->default_source = 0; - sink->bID_idx = 0; - sink->bID_count = 0; - sink->bIDs = NULL; - sink->bID_length = 0; + sink->buffer_idx = 0; + sink->buffer_count = 0; + sink->buffers = NULL; + sink->buffer_length = 0; sink->write_reset = AL_FALSE; sink->probed_caps = NULL; - sink->openal_lock = g_mutex_new (); + g_mutex_init (&sink->openal_lock); } static void @@ -264,12 +265,11 @@ gst_openal_sink_finalize (GObject * object) { GstOpenALSink *sink = GST_OPENAL_SINK (object); - g_free (sink->devname); - sink->devname = NULL; - g_mutex_free (sink->openal_lock); - sink->openal_lock = NULL; + g_free (sink->device_name); + sink->device_name = NULL; + g_mutex_clear (&sink->openal_lock); - G_OBJECT_CLASS (parent_class)->finalize (object); + G_OBJECT_CLASS (gst_openal_sink_parent_class)->finalize (object); } static void @@ -280,23 +280,23 @@ gst_openal_sink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_DEVICE: - g_free (sink->devname); - sink->devname = g_value_dup_string (value); + g_free (sink->device_name); + sink->device_name = g_value_dup_string (value); if (sink->probed_caps) gst_caps_unref (sink->probed_caps); sink->probed_caps = NULL; break; - case PROP_DEVICE_HDL: - if (!sink->device) - sink->custom_dev = g_value_get_pointer (value); + case PROP_USER_DEVICE: + if (!sink->default_device) + sink->user_device = g_value_get_pointer (value); break; - case PROP_CONTEXT_HDL: - if (!sink->device) - sink->custom_ctx = g_value_get_pointer (value); + case PROP_USER_CONTEXT: + if (!sink->default_device) + sink->user_context = g_value_get_pointer (value); break; - case PROP_SOURCE_ID: - if (!sink->device) - sink->custom_sID = g_value_get_uint (value); + case PROP_USER_SOURCE: + if (!sink->default_device) + sink->user_source = g_value_get_uint (value); break; default: @@ -306,38 +306,38 @@ gst_openal_sink_set_property (GObject * object, guint prop_id, } static void -gst_openal_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) +gst_openal_sink_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) { GstOpenALSink *sink = GST_OPENAL_SINK (object); - const ALCchar *name = sink->devname; - ALCdevice *device = sink->device; - ALCcontext *context = sink->context; - ALuint sourceID = sink->sID; + const ALCchar *device_name = sink->device_name; + ALCdevice *device = sink->default_device; + ALCcontext *context = sink->default_context; + ALuint source = sink->default_source; switch (prop_id) { case PROP_DEVICE_NAME: - name = ""; + device_name = ""; if (device) - name = alcGetString (device, ALC_DEVICE_SPECIFIER); + device_name = alcGetString (device, ALC_DEVICE_SPECIFIER); /* fall-through */ case PROP_DEVICE: - g_value_set_string (value, name); + g_value_set_string (value, device_name); break; - case PROP_DEVICE_HDL: + case PROP_USER_DEVICE: if (!device) - device = sink->custom_dev; + device = sink->user_device; g_value_set_pointer (value, device); break; - case PROP_CONTEXT_HDL: + case PROP_USER_CONTEXT: if (!context) - context = sink->custom_ctx; + context = sink->user_context; g_value_set_pointer (value, context); break; - case PROP_SOURCE_ID: - if (!sourceID) - sourceID = sink->custom_sID; - g_value_set_uint (value, sourceID); + case PROP_USER_SOURCE: + if (!source) + source = sink->user_source; + g_value_set_uint (value, source); break; default: @@ -347,200 +347,251 @@ gst_openal_sink_get_property (GObject * object, guint prop_id, } static GstCaps * -gst_openal_helper_probe_caps (ALCcontext * ctx) +gst_openal_helper_probe_caps (ALCcontext * context) { static const struct { gint count; - GstAudioChannelPosition pos[8]; + GstAudioChannelPosition positions[8]; } chans[] = { { 1, { - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, { + GST_AUDIO_CHANNEL_POSITION_MONO} + }, { 2, { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}}, { + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT} + }, { 4, { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}}, { + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT} + }, { 6, { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}}, { + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT} + }, { 7, { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}}, { + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT} + }, { 8, { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}},}; + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT} + },}; GstStructure *structure; - ALCcontext *old; + guint64 channel_mask; GstCaps *caps; + ALCcontext *old; - old = pushContext (ctx); + old = pushContext (context); caps = gst_caps_new_empty (); + if (alIsExtensionPresent ("AL_EXT_MCFORMATS")) { const char *fmt32[] = { - "AL_FORMAT_MONO_FLOAT32", "AL_FORMAT_STEREO_FLOAT32", - "AL_FORMAT_QUAD32", "AL_FORMAT_51CHN32", "AL_FORMAT_61CHN32", - "AL_FORMAT_71CHN32", NULL + "AL_FORMAT_MONO_FLOAT32", + "AL_FORMAT_STEREO_FLOAT32", + "AL_FORMAT_QUAD32", + "AL_FORMAT_51CHN32", + "AL_FORMAT_61CHN32", + "AL_FORMAT_71CHN32", + NULL }, *fmt16[] = { - "AL_FORMAT_MONO16", "AL_FORMAT_STEREO16", "AL_FORMAT_QUAD16", - "AL_FORMAT_51CHN16", "AL_FORMAT_61CHN16", "AL_FORMAT_71CHN16", NULL}, - *fmt8[] = { - "AL_FORMAT_MONO8", "AL_FORMAT_STEREO8", "AL_FORMAT_QUAD8", + "AL_FORMAT_MONO16", + "AL_FORMAT_STEREO16", + "AL_FORMAT_QUAD16", + "AL_FORMAT_51CHN16", + "AL_FORMAT_61CHN16", "AL_FORMAT_71CHN16", NULL}, *fmt8[] = { + "AL_FORMAT_MONO8", + "AL_FORMAT_STEREO8", + "AL_FORMAT_QUAD8", "AL_FORMAT_51CHN8", "AL_FORMAT_61CHN8", "AL_FORMAT_71CHN8", NULL}; int i; if (alIsExtensionPresent ("AL_EXT_FLOAT32")) { for (i = 0; fmt32[i]; i++) { - ALenum val = alGetEnumValue (fmt32[i]); - if (checkALError () != AL_NO_ERROR || val == 0 || val == -1) + ALenum value = alGetEnumValue (fmt32[i]); + if (checkALError () != AL_NO_ERROR || value == 0 || value == -1) continue; - structure = gst_structure_new ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, - OPENAL_MAX_RATE, "width", G_TYPE_INT, 32, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if (chans[i].count > 2) - gst_audio_set_channel_positions (structure, chans[i].pos); + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (F32), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL); + if (chans[i].count > 2) { + gst_audio_channel_positions_to_mask (chans[i].positions, + chans[i].count, FALSE, &channel_mask); + gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK, + channel_mask, NULL); + } gst_caps_append_structure (caps, structure); } } + for (i = 0; fmt16[i]; i++) { - ALenum val = alGetEnumValue (fmt16[i]); - if (checkALError () != AL_NO_ERROR || val == 0 || val == -1) + ALenum value = alGetEnumValue (fmt16[i]); + if (checkALError () != AL_NO_ERROR || value == 0 || value == -1) continue; - structure = gst_structure_new ("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if (chans[i].count > 2) - gst_audio_set_channel_positions (structure, chans[i].pos); + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (S16), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL); + if (chans[i].count > 2) { + gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count, + FALSE, &channel_mask); + gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK, + channel_mask, NULL); + } gst_caps_append_structure (caps, structure); } for (i = 0; fmt8[i]; i++) { - ALenum val = alGetEnumValue (fmt8[i]); - if (checkALError () != AL_NO_ERROR || val == 0 || val == -1) + ALenum value = alGetEnumValue (fmt8[i]); + if (checkALError () != AL_NO_ERROR || value == 0 || value == -1) continue; - structure = gst_structure_new ("audio/x-raw-int", - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if (chans[i].count > 2) - gst_audio_set_channel_positions (structure, chans[i].pos); + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + G_STRINGIFY (U8), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL); + if (chans[i].count > 2) { + gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count, + FALSE, &channel_mask); + gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK, + channel_mask, NULL); + } gst_caps_append_structure (caps, structure); } } else { if (alIsExtensionPresent ("AL_EXT_FLOAT32")) { - structure = gst_structure_new ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "width", G_TYPE_INT, 32, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (F32), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); gst_caps_append_structure (caps, structure); } - structure = gst_structure_new ("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed", G_TYPE_BOOLEAN, TRUE, - "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (S16), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); gst_caps_append_structure (caps, structure); - structure = gst_structure_new ("audio/x-raw-int", + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + G_STRINGIFY (U8), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure (caps, structure); + } + + if (alIsExtensionPresent ("AL_EXT_double")) { + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (F64), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure (caps, structure); + } + + if (alIsExtensionPresent ("AL_EXT_IMA4")) { + structure = + gst_structure_new ("audio/x-adpcm", "layout", G_TYPE_STRING, "ima", "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed", G_TYPE_BOOLEAN, FALSE, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); gst_caps_append_structure (caps, structure); } + if (alIsExtensionPresent ("AL_EXT_ALAW")) { + structure = + gst_structure_new ("audio/x-alaw", "rate", GST_TYPE_INT_RANGE, + OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, + NULL); + gst_caps_append_structure (caps, structure); + } + if (alIsExtensionPresent ("AL_EXT_MULAW_MCFORMATS")) { const char *fmtmulaw[] = { - "AL_FORMAT_MONO_MULAW", "AL_FORMAT_STEREO_MULAW", - "AL_FORMAT_QUAD_MULAW", "AL_FORMAT_51CHN_MULAW", - "AL_FORMAT_61CHN_MULAW", "AL_FORMAT_71CHN_MULAW", NULL + "AL_FORMAT_MONO_MULAW", + "AL_FORMAT_STEREO_MULAW", + "AL_FORMAT_QUAD_MULAW", + "AL_FORMAT_51CHN_MULAW", + "AL_FORMAT_61CHN_MULAW", + "AL_FORMAT_71CHN_MULAW", + NULL }; int i; for (i = 0; fmtmulaw[i]; i++) { - ALenum val = alGetEnumValue (fmtmulaw[i]); - if (checkALError () != AL_NO_ERROR || val == 0 || val == -1) + ALenum value = alGetEnumValue (fmtmulaw[i]); + if (checkALError () != AL_NO_ERROR || value == 0 || value == -1) continue; - structure = gst_structure_new ("audio/x-mulaw", - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, + structure = + gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE, + OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", G_TYPE_INT, chans[i].count, NULL); - if (chans[i].count > 2) - gst_audio_set_channel_positions (structure, chans[i].pos); + if (chans[i].count > 2) { + gst_audio_channel_positions_to_mask (chans[i].positions, chans[i].count, + FALSE, &channel_mask); + gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK, + channel_mask, NULL); + } gst_caps_append_structure (caps, structure); } } else if (alIsExtensionPresent ("AL_EXT_MULAW")) { - structure = gst_structure_new ("audio/x-mulaw", - "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, - "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + structure = + gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE, + OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", GST_TYPE_INT_RANGE, 1, 2, + NULL); gst_caps_append_structure (caps, structure); } - popContext (old, ctx); + popContext (old, context); + return caps; } static GstCaps * -gst_openal_sink_getcaps (GstBaseSink * bsink) +gst_openal_sink_getcaps (GstBaseSink * basesink, GstCaps * filter) { - GstOpenALSink *sink = GST_OPENAL_SINK (bsink); + GstOpenALSink *sink = GST_OPENAL_SINK (basesink); GstCaps *caps; - if (sink->device == NULL) { - GstPad *pad = GST_BASE_SINK_PAD (bsink); + if (sink->default_device == NULL) { + GstPad *pad = GST_BASE_SINK_PAD (basesink); caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); } else if (sink->probed_caps) caps = gst_caps_copy (sink->probed_caps); else { - if (sink->context) - caps = gst_openal_helper_probe_caps (sink->context); - else if (sink->custom_ctx) - caps = gst_openal_helper_probe_caps (sink->custom_ctx); + if (sink->default_context) + caps = gst_openal_helper_probe_caps (sink->default_context); + else if (sink->user_context) + caps = gst_openal_helper_probe_caps (sink->user_context); else { - ALCcontext *ctx = alcCreateContext (sink->device, NULL); - if (ctx) { - caps = gst_openal_helper_probe_caps (ctx); - alcDestroyContext (ctx); + ALCcontext *context = alcCreateContext (sink->default_device, NULL); + if (context) { + caps = gst_openal_helper_probe_caps (context); + alcDestroyContext (context); } else { GST_ELEMENT_WARNING (sink, RESOURCE, FAILED, ("Could not create temporary context."), - GST_ALC_ERROR (sink->device)); + GST_ALC_ERROR (sink->default_device)); caps = NULL; } } @@ -549,30 +600,37 @@ gst_openal_sink_getcaps (GstBaseSink * bsink) sink->probed_caps = gst_caps_copy (caps); } - return caps; + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + return intersection; + } else { + return caps; + } } static gboolean -gst_openal_sink_open (GstAudioSink * asink) +gst_openal_sink_open (GstAudioSink * audiosink) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); - if (openal->custom_dev) { - ALCint val = -1; - alcGetIntegerv (openal->custom_dev, ALC_ATTRIBUTES_SIZE, 1, &val); - if (val > 0) { - if (!openal->custom_ctx || - alcGetContextsDevice (openal->custom_ctx) == openal->custom_dev) - openal->device = openal->custom_dev; + if (sink->user_device) { + ALCint value = -1; + alcGetIntegerv (sink->user_device, ALC_ATTRIBUTES_SIZE, 1, &value); + if (value > 0) { + if (!sink->user_context + || alcGetContextsDevice (sink->user_context) == sink->user_device) + sink->default_device = sink->user_device; } - } else if (openal->custom_ctx) - openal->device = alcGetContextsDevice (openal->custom_ctx); + } else if (sink->user_context) + sink->default_device = alcGetContextsDevice (sink->user_context); else - openal->device = alcOpenDevice (openal->devname); - if (!openal->device) { - GST_ELEMENT_ERROR (openal, RESOURCE, OPEN_WRITE, - ("Could not open audio device for playback."), - GST_ALC_ERROR (openal->device)); + sink->default_device = alcOpenDevice (sink->device_name); + if (!sink->default_device) { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, + ("Could not open device."), GST_ALC_ERROR (sink->default_device)); return FALSE; } @@ -580,114 +638,180 @@ gst_openal_sink_open (GstAudioSink * asink) } static gboolean -gst_openal_sink_close (GstAudioSink * asink) +gst_openal_sink_close (GstAudioSink * audiosink) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); - if (!openal->custom_dev && !openal->custom_ctx) { - if (alcCloseDevice (openal->device) == ALC_FALSE) { - GST_ELEMENT_ERROR (openal, RESOURCE, CLOSE, - ("Could not close audio device."), GST_ALC_ERROR (openal->device)); + if (!sink->user_device && !sink->user_context) { + if (alcCloseDevice (sink->default_device) == ALC_FALSE) { + GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE, + ("Could not close device."), GST_ALC_ERROR (sink->default_device)); return FALSE; } } - openal->device = NULL; + sink->default_device = NULL; - if (openal->probed_caps) - gst_caps_unref (openal->probed_caps); - openal->probed_caps = NULL; + if (sink->probed_caps) + gst_caps_unref (sink->probed_caps); + sink->probed_caps = NULL; return TRUE; } static void -gst_openal_sink_parse_spec (GstOpenALSink * openal, - const GstRingBufferSpec * spec) +gst_openal_sink_parse_spec (GstOpenALSink * sink, + const GstAudioRingBufferSpec * spec) { ALuint format = AL_NONE; - GST_DEBUG_OBJECT (openal, "Looking up format for type %d, gst-format %d, " - "and %d channels", spec->type, spec->format, spec->channels); + GST_DEBUG_OBJECT (sink, + "looking up format for type %d, gst-format %d, and %d channels", + spec->type, GST_AUDIO_INFO_FORMAT (&spec->info), + GST_AUDIO_INFO_CHANNELS (&spec->info)); /* Don't need to verify supported formats, since the probed caps will only * report what was detected and we shouldn't get anything different */ switch (spec->type) { - case GST_BUFTYPE_LINEAR: - switch (spec->format) { - case GST_U8: - if (spec->channels == 1) - format = AL_FORMAT_MONO8; - if (spec->channels == 2) - format = AL_FORMAT_STEREO8; - if (spec->channels == 4) - format = AL_FORMAT_QUAD8; - if (spec->channels == 6) - format = AL_FORMAT_51CHN8; - if (spec->channels == 7) - format = AL_FORMAT_61CHN8; - if (spec->channels == 8) - format = AL_FORMAT_71CHN8; + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW: + switch (GST_AUDIO_INFO_FORMAT (&spec->info)) { + case GST_AUDIO_FORMAT_U8: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO8; + break; + case 2: + format = AL_FORMAT_STEREO8; + break; + case 4: + format = AL_FORMAT_QUAD8; + break; + case 6: + format = AL_FORMAT_51CHN8; + break; + case 7: + format = AL_FORMAT_61CHN8; + break; + case 8: + format = AL_FORMAT_71CHN8; + break; + default: + break; + } break; - case GST_S16_NE: - if (spec->channels == 1) - format = AL_FORMAT_MONO16; - if (spec->channels == 2) - format = AL_FORMAT_STEREO16; - if (spec->channels == 4) - format = AL_FORMAT_QUAD16; - if (spec->channels == 6) - format = AL_FORMAT_51CHN16; - if (spec->channels == 7) - format = AL_FORMAT_61CHN16; - if (spec->channels == 8) - format = AL_FORMAT_71CHN16; + case GST_AUDIO_FORMAT_S16: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO16; + break; + case 2: + format = AL_FORMAT_STEREO16; + break; + case 4: + format = AL_FORMAT_QUAD16; + break; + case 6: + format = AL_FORMAT_51CHN16; + break; + case 7: + format = AL_FORMAT_61CHN16; + break; + case 8: + format = AL_FORMAT_71CHN16; + break; + default: + break; + } break; + case GST_AUDIO_FORMAT_F32: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_FLOAT32; + break; + case 2: + format = AL_FORMAT_STEREO_FLOAT32; + break; + case 4: + format = AL_FORMAT_QUAD32; + break; + case 6: + format = AL_FORMAT_51CHN32; + break; + case 7: + format = AL_FORMAT_61CHN32; + break; + case 8: + format = AL_FORMAT_71CHN32; + break; + default: + break; + } + break; + + case GST_AUDIO_FORMAT_F64: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_DOUBLE_EXT; + break; + case 2: + format = AL_FORMAT_STEREO_DOUBLE_EXT; + break; + default: + break; + } + break; default: break; } break; - case GST_BUFTYPE_FLOAT: - switch (spec->format) { - case GST_FLOAT32_NE: - if (spec->channels == 1) - format = AL_FORMAT_MONO_FLOAT32; - if (spec->channels == 2) - format = AL_FORMAT_STEREO_FLOAT32; - if (spec->channels == 4) - format = AL_FORMAT_QUAD32; - if (spec->channels == 6) - format = AL_FORMAT_51CHN32; - if (spec->channels == 7) - format = AL_FORMAT_61CHN32; - if (spec->channels == 8) - format = AL_FORMAT_71CHN32; + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_IMA4; + break; + case 2: + format = AL_FORMAT_STEREO_IMA4; break; - default: break; } break; - case GST_BUFTYPE_MU_LAW: - switch (spec->format) { - case GST_MU_LAW: - if (spec->channels == 1) - format = AL_FORMAT_MONO_MULAW; - if (spec->channels == 2) - format = AL_FORMAT_STEREO_MULAW; - if (spec->channels == 4) - format = AL_FORMAT_QUAD_MULAW; - if (spec->channels == 6) - format = AL_FORMAT_51CHN_MULAW; - if (spec->channels == 7) - format = AL_FORMAT_61CHN_MULAW; - if (spec->channels == 8) - format = AL_FORMAT_71CHN_MULAW; + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_ALAW_EXT; break; + case 2: + format = AL_FORMAT_STEREO_ALAW_EXT; + break; + default: + break; + } + break; + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_MULAW; + break; + case 2: + format = AL_FORMAT_STEREO_MULAW; + break; + case 4: + format = AL_FORMAT_QUAD_MULAW; + break; + case 6: + format = AL_FORMAT_51CHN_MULAW; + break; + case 7: + format = AL_FORMAT_61CHN_MULAW; + break; + case 8: + format = AL_FORMAT_71CHN_MULAW; + break; default: break; } @@ -697,175 +821,180 @@ gst_openal_sink_parse_spec (GstOpenALSink * openal, break; } - openal->bytes_per_sample = spec->bytes_per_sample; - openal->srate = spec->rate; - openal->bID_count = spec->segtotal; - openal->bID_length = spec->segsize; - openal->format = format; + sink->bytes_per_sample = GST_AUDIO_INFO_BPS (&spec->info); + sink->rate = GST_AUDIO_INFO_RATE (&spec->info); + sink->channels = GST_AUDIO_INFO_CHANNELS (&spec->info); + sink->format = format; + sink->buffer_count = spec->segtotal; + sink->buffer_length = spec->segsize; } static gboolean -gst_openal_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +gst_openal_sink_prepare (GstAudioSink * audiosink, + GstAudioRingBufferSpec * spec) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); - ALCcontext *ctx, *old; + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); + ALCcontext *context, *old; - if (openal->context && !gst_openal_sink_unprepare (asink)) + if (sink->default_context && !gst_openal_sink_unprepare (audiosink)) return FALSE; - if (openal->custom_ctx) - ctx = openal->custom_ctx; + if (sink->user_context) + context = sink->user_context; else { ALCint attribs[3] = { 0, 0, 0 }; /* Don't try to change the playback frequency of an app's device */ - if (!openal->custom_dev) { + if (!sink->user_device) { attribs[0] = ALC_FREQUENCY; - attribs[1] = spec->rate; + attribs[1] = GST_AUDIO_INFO_RATE (&spec->info); attribs[2] = 0; } - ctx = alcCreateContext (openal->device, attribs); - if (!ctx) { - GST_ELEMENT_ERROR (openal, RESOURCE, FAILED, - ("Unable to prepare device."), GST_ALC_ERROR (openal->device)); + context = alcCreateContext (sink->default_device, attribs); + if (!context) { + GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, + ("Unable to prepare device."), GST_ALC_ERROR (sink->default_device)); return FALSE; } } - old = pushContext (ctx); + old = pushContext (context); - if (openal->custom_sID) { - if (!openal->custom_ctx || !alIsSource (openal->custom_sID)) { - GST_ELEMENT_ERROR (openal, RESOURCE, NOT_FOUND, (NULL), - ("Invalid source ID specified for context")); + if (sink->user_source) { + if (!sink->user_context || !alIsSource (sink->user_source)) { + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL), + ("Invalid source specified for context")); goto fail; } - openal->sID = openal->custom_sID; + sink->default_source = sink->user_source; } else { - ALuint sourceID; + ALuint source; - alGenSources (1, &sourceID); + alGenSources (1, &source); if (checkALError () != AL_NO_ERROR) { - GST_ELEMENT_ERROR (openal, RESOURCE, NO_SPACE_LEFT, (NULL), + GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), ("Unable to generate source")); goto fail; } - openal->sID = sourceID; + sink->default_source = source; } - gst_openal_sink_parse_spec (openal, spec); - if (openal->format == AL_NONE) { - GST_ELEMENT_ERROR (openal, RESOURCE, SETTINGS, (NULL), - ("Unable to get type %d, format %d, and %d channels", - spec->type, spec->format, spec->channels)); + gst_openal_sink_parse_spec (sink, spec); + if (sink->format == AL_NONE) { + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Unable to get type %d, format %d, and %d channels", spec->type, + GST_AUDIO_INFO_FORMAT (&spec->info), + GST_AUDIO_INFO_CHANNELS (&spec->info))); goto fail; } - openal->bIDs = g_malloc (openal->bID_count * sizeof (*openal->bIDs)); - if (!openal->bIDs) { - GST_ELEMENT_ERROR (openal, RESOURCE, FAILED, ("Out of memory."), - ("Unable to allocate buffer IDs")); + sink->buffers = g_malloc (sink->buffer_count * sizeof (*sink->buffers)); + if (!sink->buffers) { + GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, ("Out of memory."), + ("Unable to allocate buffers")); goto fail; } - alGenBuffers (openal->bID_count, openal->bIDs); + alGenBuffers (sink->buffer_count, sink->buffers); if (checkALError () != AL_NO_ERROR) { - GST_ELEMENT_ERROR (openal, RESOURCE, NO_SPACE_LEFT, (NULL), - ("Unable to generate %d buffers", openal->bID_count)); + GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), + ("Unable to generate %d buffers", sink->buffer_count)); goto fail; } - openal->bID_idx = 0; + sink->buffer_idx = 0; - popContext (old, ctx); - openal->context = ctx; + popContext (old, context); + sink->default_context = context; return TRUE; fail: - if (!openal->custom_sID && openal->sID) - alDeleteSources (1, &openal->sID); - openal->sID = 0; + if (!sink->user_source && sink->default_source) + alDeleteSources (1, &sink->default_source); + sink->default_source = 0; - g_free (openal->bIDs); - openal->bIDs = NULL; - openal->bID_count = 0; - openal->bID_length = 0; + g_free (sink->buffers); + sink->buffers = NULL; + sink->buffer_count = 0; + sink->buffer_length = 0; - popContext (old, ctx); - if (!openal->custom_ctx) - alcDestroyContext (ctx); + popContext (old, context); + if (!sink->user_context) + alcDestroyContext (context); return FALSE; } static gboolean -gst_openal_sink_unprepare (GstAudioSink * asink) +gst_openal_sink_unprepare (GstAudioSink * audiosink) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); ALCcontext *old; - if (!openal->context) + if (!sink->default_context) return TRUE; - old = pushContext (openal->context); + old = pushContext (sink->default_context); - alSourceStop (openal->sID); - alSourcei (openal->sID, AL_BUFFER, 0); + alSourceStop (sink->default_source); + alSourcei (sink->default_source, AL_BUFFER, 0); - if (!openal->custom_sID) - alDeleteSources (1, &openal->sID); - openal->sID = 0; + if (!sink->user_source) + alDeleteSources (1, &sink->default_source); + sink->default_source = 0; - alDeleteBuffers (openal->bID_count, openal->bIDs); - g_free (openal->bIDs); - openal->bIDs = NULL; - openal->bID_idx = 0; - openal->bID_count = 0; - openal->bID_length = 0; + alDeleteBuffers (sink->buffer_count, sink->buffers); + g_free (sink->buffers); + sink->buffers = NULL; + sink->buffer_idx = 0; + sink->buffer_count = 0; + sink->buffer_length = 0; checkALError (); - popContext (old, openal->context); - if (!openal->custom_ctx) - alcDestroyContext (openal->context); - openal->context = NULL; + popContext (old, sink->default_context); + if (!sink->user_context) + alcDestroyContext (sink->default_context); + sink->default_context = NULL; return TRUE; } -static guint -gst_openal_sink_write (GstAudioSink * asink, gpointer data, guint length) +static gint +gst_openal_sink_write (GstAudioSink * audiosink, gpointer data, guint length) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); ALint processed, queued, state; ALCcontext *old; gulong rest_us; - g_assert (length == openal->bID_length); + g_assert (length == sink->buffer_length); - old = pushContext (openal->context); + old = pushContext (sink->default_context); - rest_us = (guint64) (openal->bID_length / openal->bytes_per_sample) * - G_USEC_PER_SEC / openal->srate / 2; + rest_us = + (guint64) (sink->buffer_length / sink->bytes_per_sample) * + G_USEC_PER_SEC / sink->rate / sink->channels; do { - alGetSourcei (openal->sID, AL_SOURCE_STATE, &state); - alGetSourcei (openal->sID, AL_BUFFERS_QUEUED, &queued); - alGetSourcei (openal->sID, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei (sink->default_source, AL_SOURCE_STATE, &state); + alGetSourcei (sink->default_source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei (sink->default_source, AL_BUFFERS_PROCESSED, &processed); if (checkALError () != AL_NO_ERROR) { - GST_ELEMENT_ERROR (openal, RESOURCE, WRITE, (NULL), + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Source state error detected")); length = 0; goto out_nolock; } - if (processed > 0 || queued < openal->bID_count) + if (processed > 0 || queued < sink->buffer_count) break; if (state != AL_PLAYING) - alSourcePlay (openal->sID); + alSourcePlay (sink->default_source); g_usleep (rest_us); - } while (1); + } + while (1); - GST_OPENAL_SINK_LOCK (openal); - if (openal->write_reset != AL_FALSE) { - openal->write_reset = AL_FALSE; + GST_OPENAL_SINK_LOCK (sink); + if (sink->write_reset != AL_FALSE) { + sink->write_reset = AL_FALSE; length = 0; goto out; } @@ -873,84 +1002,93 @@ gst_openal_sink_write (GstAudioSink * asink, gpointer data, guint length) queued -= processed; while (processed-- > 0) { ALuint bid; - alSourceUnqueueBuffers (openal->sID, 1, &bid); + alSourceUnqueueBuffers (sink->default_source, 1, &bid); } if (state == AL_STOPPED) { /* "Restore" from underruns (not actually needed, but it keeps delay * calculations correct while rebuffering) */ - alSourceRewind (openal->sID); + alSourceRewind (sink->default_source); } - alBufferData (openal->bIDs[openal->bID_idx], openal->format, - data, openal->bID_length, openal->srate); - alSourceQueueBuffers (openal->sID, 1, &openal->bIDs[openal->bID_idx]); - openal->bID_idx = (openal->bID_idx + 1) % openal->bID_count; + alBufferData (sink->buffers[sink->buffer_idx], sink->format, + data, sink->buffer_length, sink->rate); + alSourceQueueBuffers (sink->default_source, 1, + &sink->buffers[sink->buffer_idx]); + sink->buffer_idx = (sink->buffer_idx + 1) % sink->buffer_count; queued++; - if (state != AL_PLAYING && queued == openal->bID_count) - alSourcePlay (openal->sID); + if (state != AL_PLAYING && queued == sink->buffer_count) + alSourcePlay (sink->default_source); - if (checkALError () != ALC_NO_ERROR) { - GST_ELEMENT_ERROR (openal, RESOURCE, WRITE, (NULL), + if (checkALError () != AL_NO_ERROR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Source queue error detected")); goto out; } out: - GST_OPENAL_SINK_UNLOCK (openal); + GST_OPENAL_SINK_UNLOCK (sink); out_nolock: - popContext (old, openal->context); + popContext (old, sink->default_context); return length; } static guint -gst_openal_sink_delay (GstAudioSink * asink) +gst_openal_sink_delay (GstAudioSink * audiosink) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); ALint queued, state, offset, delay; ALCcontext *old; - if (!openal->context) + if (!sink->default_context) return 0; - GST_OPENAL_SINK_LOCK (openal); - old = pushContext (openal->context); + GST_OPENAL_SINK_LOCK (sink); + old = pushContext (sink->default_context); delay = 0; - alGetSourcei (openal->sID, AL_BUFFERS_QUEUED, &queued); + alGetSourcei (sink->default_source, AL_BUFFERS_QUEUED, &queued); /* Order here is important. If the offset is queried after the state and an * underrun occurs in between the two calls, it can end up with a 0 offset * in a playing state, incorrectly reporting a len*queued/bps delay. */ - alGetSourcei (openal->sID, AL_BYTE_OFFSET, &offset); - alGetSourcei (openal->sID, AL_SOURCE_STATE, &state); + alGetSourcei (sink->default_source, AL_BYTE_OFFSET, &offset); + alGetSourcei (sink->default_source, AL_SOURCE_STATE, &state); /* Note: state=stopped is an underrun, meaning all buffers are processed * and there's no delay when writing the next buffer. Pre-buffering is * state=initial, which will introduce a delay while writing. */ if (checkALError () == AL_NO_ERROR && state != AL_STOPPED) - delay = ((queued * openal->bID_length) - offset) / openal->bytes_per_sample; + delay = + ((queued * sink->buffer_length) - + offset) / sink->bytes_per_sample / sink->channels / GST_MSECOND; - popContext (old, openal->context); - GST_OPENAL_SINK_UNLOCK (openal); + popContext (old, sink->default_context); + GST_OPENAL_SINK_UNLOCK (sink); + + if (G_UNLIKELY (delay < 0)) { + /* make sure we never return a negative delay */ + GST_WARNING_OBJECT (openal_debug, "negative delay"); + delay = 0; + } return delay; } static void -gst_openal_sink_reset (GstAudioSink * asink) +gst_openal_sink_reset (GstAudioSink * audiosink) { - GstOpenALSink *openal = GST_OPENAL_SINK (asink); + GstOpenALSink *sink = GST_OPENAL_SINK (audiosink); ALCcontext *old; - GST_OPENAL_SINK_LOCK (openal); - old = pushContext (openal->context); + GST_OPENAL_SINK_LOCK (sink); + old = pushContext (sink->default_context); - openal->write_reset = AL_TRUE; - alSourceStop (openal->sID); - alSourceRewind (openal->sID); - alSourcei (openal->sID, AL_BUFFER, 0); + sink->write_reset = AL_TRUE; + alSourceStop (sink->default_source); + alSourceRewind (sink->default_source); + alSourcei (sink->default_source, AL_BUFFER, 0); checkALError (); - popContext (old, openal->context); - GST_OPENAL_SINK_UNLOCK (openal); + popContext (old, sink->default_context); + GST_OPENAL_SINK_UNLOCK (sink); } diff --git a/ext/openal/gstopenalsink.h b/ext/openal/gstopenalsink.h index 31f99dfcc5..6088251985 100644 --- a/ext/openal/gstopenalsink.h +++ b/ext/openal/gstopenalsink.h @@ -1,9 +1,11 @@ /* * GStreamer + * * Copyright (C) 2005 Thomas Vander Stichele * Copyright (C) 2005 Ronald S. Bultje * Copyright (C) 2009-2010 Chris Robinson - * + * Copyright (C) 2013 Juan Manuel Borges Caño + * * 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 @@ -24,8 +26,7 @@ #define __GST_OPENALSINK_H__ #include -#include -#include +#include #ifdef _WIN32 #include @@ -43,7 +44,8 @@ G_BEGIN_DECLS -#define GST_TYPE_OPENAL_SINK (gst_openal_sink_get_type()) +#define GST_TYPE_OPENAL_SINK \ + (gst_openal_sink_get_type()) #define GST_OPENAL_SINK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPENAL_SINK,GstOpenALSink)) #define GST_OPENAL_SINK_CLASS(klass) \ @@ -52,6 +54,8 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPENAL_SINK)) #define GST_IS_OPENAL_SINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPENAL_SINK)) +#define GST_OPENAL_SINK_CAST(obj) \ + ((GstOpenALSink*)obj) #if 1 #define GST_ALC_ERROR(Device) ("ALC error: %s", alcGetString((Device), alcGetError((Device)))) @@ -62,61 +66,51 @@ G_BEGIN_DECLS typedef struct _GstOpenALSink GstOpenALSink; typedef struct _GstOpenALSinkClass GstOpenALSinkClass; -#define GST_OPENAL_SINK_CAST(obj) ((GstOpenALSink*)obj) -#define GST_OPENAL_SINK_GET_LOCK(obj) (GST_OPENAL_SINK_CAST(obj)->openal_lock) +#define GST_OPENAL_SINK_GET_LOCK(obj) (&GST_OPENAL_SINK_CAST(obj)->openal_lock) #define GST_OPENAL_SINK_LOCK(obj) (g_mutex_lock(GST_OPENAL_SINK_GET_LOCK(obj))) #define GST_OPENAL_SINK_UNLOCK(obj) (g_mutex_unlock(GST_OPENAL_SINK_GET_LOCK(obj))) -struct _GstOpenALSink { - GstAudioSink sink; +struct _GstOpenALSink +{ + GstAudioSink sink; - gchar *devname; + gchar *device_name; - /* When set, we don't own device */ - ALCdevice *custom_dev; - /* When set, we don't own device or context */ - ALCcontext *custom_ctx; - /* When set, we don't own sID */ - ALuint custom_sID; + ALCdevice *default_device; + /* When set, device is not owned */ + ALCdevice *user_device; - ALCdevice *device; - ALCcontext *context; - ALuint sID; + ALCcontext *default_context; + /* When set, device or context is not owned */ + ALCcontext *user_context; - ALuint bID_idx; - ALuint bID_count; - ALuint *bIDs; - ALuint bID_length; + ALuint default_source; + /* When set, source is not owned */ + ALuint user_source; - ALenum format; - ALuint srate; - ALuint bytes_per_sample; + ALuint buffer_idx; + ALuint buffer_count; + ALuint *buffers; + ALuint buffer_length; - ALboolean write_reset; + ALenum format; + ALuint rate; + ALuint channels; + ALuint bytes_per_sample; - GstCaps *probed_caps; + ALboolean write_reset; - GMutex *openal_lock; + GstCaps *probed_caps; + + GMutex openal_lock; }; -struct _GstOpenALSinkClass { - GstAudioSinkClass parent_class; +struct _GstOpenALSinkClass +{ + GstAudioSinkClass parent_class; }; -GType gst_openal_sink_get_type(void); - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define GST_S16_NE GST_S16_LE -#define GST_FLOAT32_NE GST_FLOAT32_LE -#define GST_FLOAT64_NE GST_FLOAT64_LE -#else -#define GST_S16_NE GST_S16_BE -#define GST_FLOAT32_NE GST_FLOAT32_BE -#define GST_FLOAT64_NE GST_FLOAT64_BE -#endif - -#define OPENAL_MIN_RATE 8000 -#define OPENAL_MAX_RATE 192000 +GType gst_openal_sink_get_type (void); G_END_DECLS diff --git a/ext/openal/gstopenalsrc.c b/ext/openal/gstopenalsrc.c index 4987e2b69a..3bc62aa9cf 100644 --- a/ext/openal/gstopenalsrc.c +++ b/ext/openal/gstopenalsrc.c @@ -1,8 +1,10 @@ /* * GStreamer + * * Copyright (C) 2005 Thomas Vander Stichele * Copyright (C) 2005 Ronald S. Bultje * Copyright (C) 2008 Victor Lin + * Copyright (C) 2013 Juan Manuel Borges Caño * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -27,6 +29,8 @@ * which case the following provisions apply instead of the ones * mentioned above: * + * Copyright (C) 2013 Juan Manuel Borges Caño + * * 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 @@ -45,51 +49,63 @@ /** * SECTION:element-openalsrc - * @short_description: record sound from your sound card using OpenAL + * @see_also: openalsink + * @short_description: capture raw audio samples through OpenAL + * + * This element captures raw audio samples through OpenAL. * * - * - * This element lets you record sound using the OpenAL - * * Example pipelines - * - * - * gst-launch -v openalsrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg - * - * will record sound from your sound card using OpenAL and encode it to an Ogg/Vorbis file - * + * |[ + * gst-launch -v openalsrc ! audioconvert ! wavenc ! filesink location=stream.wav + * ]| * will capture sound through OpenAL and encode it to a wav file. + * |[ + * gst-launch openalsrc ! "audio/x-raw,format=S16LE,rate=44100" ! audioconvert ! volume volume=0.25 ! openalsink + * ]| will capture and play audio through OpenAL. * */ +/* + * DEV: + * To get better timing/delay information you may also be interested in this: + * http://kcat.strangesoft.net/openal-extensions/SOFT_source_latency.txt + */ + #ifdef HAVE_CONFIG_H -# include +#include #endif #include #include +GST_DEBUG_CATEGORY_EXTERN (openal_debug); +#define GST_CAT_DEFAULT openal_debug + #include "gstopenalsrc.h" -GST_DEBUG_CATEGORY_STATIC (openalsrc_debug); +static void gst_openal_src_dispose (GObject * object); +static void gst_openal_src_finalize (GObject * object); +static void gst_openal_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_openal_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstCaps *gst_openal_src_getcaps (GstBaseSrc * basesrc, GstCaps * filter); +static gboolean gst_openal_src_open (GstAudioSrc * audiosrc); +static gboolean gst_openal_src_prepare (GstAudioSrc * audiosrc, + GstAudioRingBufferSpec * spec); +static gboolean gst_openal_src_unprepare (GstAudioSrc * audiosrc); +static gboolean gst_openal_src_close (GstAudioSrc * audiosrc); +static guint gst_openal_src_read (GstAudioSrc * audiosrc, gpointer data, + guint length, GstClockTime * timestamp); +static guint gst_openal_src_delay (GstAudioSrc * audiosrc); +static void gst_openal_src_reset (GstAudioSrc * audiosrc); -#define GST_CAT_DEFAULT openalsrc_debug +#define OPENAL_DEFAULT_DEVICE_NAME NULL +#define OPENAL_DEFAULT_DEVICE NULL -#define DEFAULT_DEVICE NULL -#define DEFAULT_DEVICE_NAME NULL +#define OPENAL_MIN_RATE 8000 +#define OPENAL_MAX_RATE 192000 -/** - Filter signals and args -**/ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - - -/** - Properties -**/ enum { PROP_0, @@ -97,116 +113,137 @@ enum PROP_DEVICE_NAME }; -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", +static GstStaticPadTemplate openalsrc_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) TRUE, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " - "audio/x-raw-int, " - "signed = (boolean) TRUE, " - "width = (int) 8, " - "depth = (int) 8, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") + GST_STATIC_CAPS ( + /* These caps do not work on my card */ + // "audio/x-adpcm, " "layout = (string) ima, " + // "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " + // "audio/x-alaw, " "rate = (int) [ 1, MAX ], " + // "channels = (int) 1; " + // "audio/x-mulaw, " "rate = (int) [ 1, MAX ], " + // "channels = (int) 1; " + // "audio/x-raw, " "format = (string) " GST_AUDIO_NE (F64) ", " + // "rate = (int) [ 1, MAX ], " "channels = (int) 1; " + // "audio/x-raw, " "format = (string) " GST_AUDIO_NE (F32) ", " + // "rate = (int) [ 1, MAX ], " "channels = (int) 1; " + "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S16) ", " + "rate = (int) [ 1, MAX ], " "channels = (int) 1; " + /* These caps work wrongly on my card */ + // "audio/x-raw, " "format = (string) " GST_AUDIO_NE (U16) ", " + // "rate = (int) [ 1, MAX ], " "channels = (int) 1; " + // "audio/x-raw, " "format = (string) " G_STRINGIFY (S8) ", " + // "rate = (int) [ 1, MAX ], " "channels = (int) 1")); + "audio/x-raw, " "format = (string) " G_STRINGIFY (U8) ", " + "rate = (int) [ 1, MAX ], " "channels = (int) 1") ); -GST_BOILERPLATE (GstOpenalSrc, gst_openal_src, GstAudioSrc, GST_TYPE_AUDIO_SRC); +static inline ALenum +checkALError (const char *fname, unsigned int fline) +{ + ALenum err = alGetError (); + if (err != AL_NO_ERROR) + g_warning ("%s:%u: context error: %s", fname, fline, alGetString (err)); + return err; +} -static void gst_openal_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_openal_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static gboolean gst_openal_src_open (GstAudioSrc * src); -static gboolean -gst_openal_src_prepare (GstAudioSrc * src, GstRingBufferSpec * spec); -static gboolean gst_openal_src_unprepare (GstAudioSrc * src); -static gboolean gst_openal_src_close (GstAudioSrc * src); -static guint -gst_openal_src_read (GstAudioSrc * src, gpointer data, guint length); -static guint gst_openal_src_delay (GstAudioSrc * src); -static void gst_openal_src_reset (GstAudioSrc * src); +#define checkALError() checkALError(__FILE__, __LINE__) -static void gst_openal_src_finalize (GObject * object); +G_DEFINE_TYPE (GstOpenalSrc, gst_openal_src, GST_TYPE_AUDIO_SRC); static void -gst_openal_src_base_init (gpointer gclass) +gst_openal_src_dispose (GObject * object) { + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (object); - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); + if (openalsrc->probed_caps) + gst_caps_unref (openalsrc->probed_caps); + openalsrc->probed_caps = NULL; - gst_element_class_set_static_metadata (element_class, "OpenAL src", - "Source/Audio", - "OpenAL source capture audio from device", - "Victor Lin "); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory) - ); + G_OBJECT_CLASS (gst_openal_src_parent_class)->dispose (object); } static void gst_openal_src_class_init (GstOpenalSrcClass * klass) { - GObjectClass *gobject_class; - GstAudioSrcClass *gstaudio_src_class; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = (GstElementClass *) klass; + GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass; + GstAudioSrcClass *gstaudiosrc_class = (GstAudioSrcClass *) (klass); - gobject_class = G_OBJECT_CLASS (klass); - gstaudio_src_class = GST_AUDIO_SRC_CLASS (klass); + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_openal_src_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_openal_src_finalize); + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_openal_src_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_openal_src_get_property); - GST_DEBUG_CATEGORY_INIT (openalsrc_debug, "openalsrc", - 0, "OpenAL source capture audio from device"); + gst_openal_src_parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = gst_openal_src_set_property; - gobject_class->get_property = gst_openal_src_get_property; - gobject_class->finalize = gst_openal_src_finalize; + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_openal_src_getcaps); - gstaudio_src_class->open = GST_DEBUG_FUNCPTR (gst_openal_src_open); - gstaudio_src_class->prepare = GST_DEBUG_FUNCPTR (gst_openal_src_prepare); - gstaudio_src_class->unprepare = GST_DEBUG_FUNCPTR (gst_openal_src_unprepare); - gstaudio_src_class->close = GST_DEBUG_FUNCPTR (gst_openal_src_close); - gstaudio_src_class->read = GST_DEBUG_FUNCPTR (gst_openal_src_read); - gstaudio_src_class->delay = GST_DEBUG_FUNCPTR (gst_openal_src_delay); - gstaudio_src_class->reset = GST_DEBUG_FUNCPTR (gst_openal_src_reset); + gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_openal_src_open); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_openal_src_prepare); + gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_openal_src_unprepare); + gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_openal_src_close); + gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_openal_src_read); + gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_openal_src_delay); + gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_openal_src_reset); - g_object_class_install_property (gobject_class, - PROP_DEVICE, - g_param_spec_string ("device", - "Device", - "Specific capture device to open, NULL indicate default device", - DEFAULT_DEVICE, G_PARAM_READWRITE) - ); + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "ALCdevice", + "User device, default device if NULL", OPENAL_DEFAULT_DEVICE, + G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, - PROP_DEVICE_NAME, - g_param_spec_string ("device-name", - "Device name", - "Readable name of device", DEFAULT_DEVICE_NAME, G_PARAM_READABLE) - ); + g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, + g_param_spec_string ("device-name", "Device name", + "Human-readable name of the device", OPENAL_DEFAULT_DEVICE_NAME, + G_PARAM_READABLE)); + + gst_element_class_set_static_metadata (gstelement_class, + "OpenAL Audio Source", "Source/Audio", "Input audio through OpenAL", + "Juan Manuel Borges Caño "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&openalsrc_factory)); } static void -gst_openal_src_init (GstOpenalSrc * osrc, GstOpenalSrcClass * gclass) +gst_openal_src_init (GstOpenalSrc * openalsrc) { - osrc->deviceName = g_strdup (DEFAULT_DEVICE_NAME); - osrc->device = DEFAULT_DEVICE; - osrc->deviceHandle = NULL; + GST_DEBUG_OBJECT (openalsrc, "initializing"); + + openalsrc->default_device_name = g_strdup (OPENAL_DEFAULT_DEVICE_NAME); + openalsrc->default_device = OPENAL_DEFAULT_DEVICE; + openalsrc->device = NULL; + + openalsrc->buffer_length = 0; + + openalsrc->probed_caps = NULL; +} + +static void +gst_openal_src_finalize (GObject * object) +{ + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (object); + + g_free (openalsrc->default_device_name); + g_free (openalsrc->default_device); + + G_OBJECT_CLASS (gst_openal_src_parent_class)->finalize (object); } static void gst_openal_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstOpenalSrc *osrc = GST_OPENAL_SRC (object); + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (object); switch (prop_id) { case PROP_DEVICE: - osrc->device = g_value_dup_string (value); + openalsrc->default_device = g_value_dup_string (value); break; case PROP_DEVICE_NAME: - osrc->deviceName = g_value_dup_string (value); + openalsrc->default_device_name = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -218,14 +255,14 @@ static void gst_openal_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstOpenalSrc *osrc = GST_OPENAL_SRC (object); + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (object); switch (prop_id) { case PROP_DEVICE: - g_value_set_string (value, osrc->device); + g_value_set_string (value, openalsrc->default_device); break; case PROP_DEVICE_NAME: - g_value_set_string (value, osrc->deviceName); + g_value_set_string (value, openalsrc->default_device_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -233,127 +270,324 @@ gst_openal_src_get_property (GObject * object, guint prop_id, GValue * value, } } -static gboolean -gst_openal_src_open (GstAudioSrc * asrc) +static GstCaps * +gst_openal_helper_probe_caps (ALCcontext * context) +{ + GstStructure *structure; + GstCaps *caps; +// ALCcontext *old; + +// old = pushContext(context); + + caps = gst_caps_new_empty (); + + if (alIsExtensionPresent ("AL_EXT_DOUBLE")) { + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (F64), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + } + + if (alIsExtensionPresent ("AL_EXT_FLOAT32")) { + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (F32), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + } + + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + GST_AUDIO_NE (S16), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + + structure = + gst_structure_new ("audio/x-raw", "format", G_TYPE_STRING, + G_STRINGIFY (U8), "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, + OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + + if (alIsExtensionPresent ("AL_EXT_IMA4")) { + structure = + gst_structure_new ("audio/x-adpcm", "layout", G_TYPE_STRING, "ima", + "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE, + "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + } + + if (alIsExtensionPresent ("AL_EXT_ALAW")) { + structure = + gst_structure_new ("audio/x-alaw", "rate", GST_TYPE_INT_RANGE, + OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + } + + if (alIsExtensionPresent ("AL_EXT_MULAW")) { + structure = + gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE, + OPENAL_MIN_RATE, OPENAL_MAX_RATE, "channels", G_TYPE_INT, 1, NULL); + gst_caps_append_structure (caps, structure); + } +// popContext(old, context); + + return caps; +} + +static GstCaps * +gst_openal_src_getcaps (GstBaseSrc * basesrc, GstCaps * filter) +{ + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (basesrc); + GstCaps *caps; + ALCdevice *device; + + device = alcOpenDevice (NULL); + + if (device == NULL) { + GstPad *pad = GST_BASE_SRC_PAD (basesrc); + GST_ELEMENT_WARNING (openalsrc, RESOURCE, OPEN_WRITE, + ("Could not open temporary device."), GST_ALC_ERROR (device)); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + } else if (openalsrc->probed_caps) + caps = gst_caps_copy (openalsrc->probed_caps); + else { + ALCcontext *context = alcCreateContext (device, NULL); + if (context) { + caps = gst_openal_helper_probe_caps (context); + alcDestroyContext (context); + } else { + GST_ELEMENT_WARNING (openalsrc, RESOURCE, FAILED, + ("Could not create temporary context."), GST_ALC_ERROR (device)); + caps = NULL; + } + + if (caps && !gst_caps_is_empty (caps)) + openalsrc->probed_caps = gst_caps_copy (caps); + } + + if (device != NULL) { + if (alcCloseDevice (device) == ALC_FALSE) { + GST_ELEMENT_WARNING (openalsrc, RESOURCE, CLOSE, + ("Could not close temporary device."), GST_ALC_ERROR (device)); + } + } + + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + return intersection; + } else { + return caps; + } +} + + +static gboolean +gst_openal_src_open (GstAudioSrc * audiosrc) { - /* We don't do anything here */ return TRUE; } -static gboolean -gst_openal_src_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +static void +gst_openal_src_parse_spec (GstOpenalSrc * openalsrc, + const GstAudioRingBufferSpec * spec) { + ALuint format = AL_NONE; - GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc); - ALenum format; - guint64 bufferSize; + GST_DEBUG_OBJECT (openalsrc, + "looking up format for type %d, gst-format %d, and %d channels", + spec->type, GST_AUDIO_INFO_FORMAT (&spec->info), + GST_AUDIO_INFO_CHANNELS (&spec->info)); - switch (spec->width) { - case 8: - format = AL_FORMAT_STEREO8; + switch (spec->type) { + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW: + switch (GST_AUDIO_INFO_FORMAT (&spec->info)) { + case GST_AUDIO_FORMAT_U8: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO8; + break; + default: + break; + } + break; + + case GST_AUDIO_FORMAT_U16: + case GST_AUDIO_FORMAT_S16: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO16; + break; + default: + break; + } + break; + + case GST_AUDIO_FORMAT_F32: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_FLOAT32; + break; + default: + break; + } + break; + + case GST_AUDIO_FORMAT_F64: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_DOUBLE_EXT; + break; + default: + break; + } + break; + + default: + break; + } break; - case 16: - format = AL_FORMAT_STEREO16; + + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_IMA4; + break; + default: + break; + } break; + + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_ALAW_EXT; + break; + default: + break; + } + break; + + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW: + switch (GST_AUDIO_INFO_CHANNELS (&spec->info)) { + case 1: + format = AL_FORMAT_MONO_MULAW; + break; + default: + break; + } + break; + default: - g_assert_not_reached (); + break; } - bufferSize = - spec->buffer_time * spec->rate * spec->bytes_per_sample / 1000000; + openalsrc->bytes_per_sample = GST_AUDIO_INFO_BPS (&spec->info); + openalsrc->rate = GST_AUDIO_INFO_RATE (&spec->info); + openalsrc->buffer_length = spec->segsize; + openalsrc->format = format; +} - GST_INFO_OBJECT (osrc, "Open device : %s", osrc->deviceName); - osrc->deviceHandle = - alcCaptureOpenDevice (osrc->device, spec->rate, format, bufferSize); +static gboolean +gst_openal_src_prepare (GstAudioSrc * audiosrc, GstAudioRingBufferSpec * spec) +{ + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc); - if (!osrc->deviceHandle) { - GST_ELEMENT_ERROR (osrc, - RESOURCE, - FAILED, - ("Can't open device \"%s\"", osrc->device), - ("Can't open device \"%s\"", osrc->device) - ); + gst_openal_src_parse_spec (openalsrc, spec); + if (openalsrc->format == AL_NONE) { + GST_ELEMENT_ERROR (openalsrc, RESOURCE, SETTINGS, (NULL), + ("Unable to get type %d, format %d, and %d channels", spec->type, + GST_AUDIO_INFO_FORMAT (&spec->info), + GST_AUDIO_INFO_CHANNELS (&spec->info))); return FALSE; } - osrc->deviceName = - g_strdup (alcGetString (osrc->deviceHandle, ALC_DEVICE_SPECIFIER)); - osrc->bytes_per_sample = spec->bytes_per_sample; + openalsrc->device = + alcCaptureOpenDevice (openalsrc->default_device, openalsrc->rate, + openalsrc->format, openalsrc->buffer_length); - GST_INFO_OBJECT (osrc, "Start capture"); - alcCaptureStart (osrc->deviceHandle); + if (!openalsrc->device) { + GST_ELEMENT_ERROR (openalsrc, RESOURCE, OPEN_READ, + ("Could not open device."), GST_ALC_ERROR (openalsrc->device)); + return FALSE; + } + + openalsrc->default_device_name = + g_strdup (alcGetString (openalsrc->device, ALC_DEVICE_SPECIFIER)); + + alcCaptureStart (openalsrc->device); return TRUE; } static gboolean -gst_openal_src_unprepare (GstAudioSrc * asrc) +gst_openal_src_unprepare (GstAudioSrc * audiosrc) { + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc); - GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc); + if (openalsrc->device) { + alcCaptureStop (openalsrc->device); - GST_INFO_OBJECT (osrc, "Close device : %s", osrc->deviceName); - if (osrc->deviceHandle) { - alcCaptureStop (osrc->deviceHandle); - alcCaptureCloseDevice (osrc->deviceHandle); + if (alcCaptureCloseDevice (openalsrc->device) == ALC_FALSE) { + GST_ELEMENT_ERROR (openalsrc, RESOURCE, CLOSE, + ("Could not close device."), GST_ALC_ERROR (openalsrc->device)); + return FALSE; + } } return TRUE; } static gboolean -gst_openal_src_close (GstAudioSrc * asrc) +gst_openal_src_close (GstAudioSrc * audiosrc) { - /* We don't do anything here */ return TRUE; } static guint -gst_openal_src_read (GstAudioSrc * asrc, gpointer data, guint length) +gst_openal_src_read (GstAudioSrc * audiosrc, gpointer data, guint length, + GstClockTime * timestamp) { - GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc); + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc); gint samples; - alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples), + alcGetIntegerv (openalsrc->device, ALC_CAPTURE_SAMPLES, sizeof (samples), &samples); - if (samples * osrc->bytes_per_sample > length) { - samples = length / osrc->bytes_per_sample; + if (samples * openalsrc->bytes_per_sample > length) { + samples = length / openalsrc->bytes_per_sample; } if (samples) { - GST_DEBUG_OBJECT (osrc, "Read samples : %d", samples); - alcCaptureSamples (osrc->deviceHandle, data, samples); + GST_DEBUG_OBJECT (openalsrc, "read samples : %d", samples); + alcCaptureSamples (openalsrc->device, data, samples); } - return samples * osrc->bytes_per_sample; + return samples * openalsrc->bytes_per_sample; } static guint -gst_openal_src_delay (GstAudioSrc * asrc) +gst_openal_src_delay (GstAudioSrc * audiosrc) { - GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc); - gint samples; + GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc); + ALint samples; - alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples), + alcGetIntegerv (openalsrc->device, ALC_CAPTURE_SAMPLES, sizeof (samples), &samples); + if (G_UNLIKELY (samples < 0)) { + /* make sure we never return a negative delay */ + GST_WARNING_OBJECT (openal_debug, "negative delay"); + samples = 0; + } + return samples; } static void -gst_openal_src_reset (GstAudioSrc * asrc) +gst_openal_src_reset (GstAudioSrc * audiosrc) { - /* We don't do anything here */ -} - -static void -gst_openal_src_finalize (GObject * object) -{ - GstOpenalSrc *osrc = GST_OPENAL_SRC (object); - - g_free (osrc->deviceName); - g_free (osrc->device); - - G_OBJECT_CLASS (parent_class)->finalize (object); } diff --git a/ext/openal/gstopenalsrc.h b/ext/openal/gstopenalsrc.h index a127460349..248d4c4134 100644 --- a/ext/openal/gstopenalsrc.h +++ b/ext/openal/gstopenalsrc.h @@ -1,105 +1,122 @@ -/* - * GStreamer - * Copyright (C) 2005 Thomas Vander Stichele - * Copyright (C) 2005 Ronald S. Bultje - * Copyright (C) 2008 Victor Lin - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_OPENAL_SRC_H__ -#define __GST_OPENAL_SRC_H__ - -#include -#include - -#ifdef _WIN32 -#include -#include -#include -#elif defined(__APPLE__) -#include -#include -#include -#else -#include -#include -#include -#endif - -G_BEGIN_DECLS - -#define GST_TYPE_OPENAL_SRC \ - (gst_openal_src_get_type()) -#define GST_OPENAL_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPENAL_SRC,GstOpenalSrc)) -#define GST_OPENAL_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPENAL_SRC,GstOpenalSrcClass)) -#define GST_IS_OPENAL_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPENAL_SRC)) -#define GST_IS_OPENAL_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPENAL_SRC)) - -typedef struct _GstOpenalSrc GstOpenalSrc; -typedef struct _GstOpenalSrcClass GstOpenalSrcClass; - -struct _GstOpenalSrc { - GstAudioSrc element; - GstPad *srcpad; - gboolean silent; - - /* readable name of device */ - gchar *deviceName; - /* name of device to open, default is a NULL pointer to get default device */ - gchar *device; - /* OpenAL device handle */ - ALCdevice *deviceHandle; - - guint bytes_per_sample; -}; - -struct _GstOpenalSrcClass { - GstAudioSrcClass parent_class; -}; - -GType gst_openal_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_OPENAL_SRC_H__ */ +/* + * GStreamer + * + * Copyright (C) 2005 Thomas Vander Stichele + * Copyright (C) 2005 Ronald S. Bultje + * Copyright (C) 2008 Victor Lin + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * Copyright (C) 2013 Juan Manuel Borges Caño + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_OPENAL_SRC_H__ +#define __GST_OPENAL_SRC_H__ + +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#elif defined(__APPLE__) +#include +#include +#include +#else +#include +#include +#include +#endif + +G_BEGIN_DECLS + +#define GST_TYPE_OPENAL_SRC \ + (gst_openal_src_get_type()) +#define GST_OPENAL_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OPENAL_SRC, GstOpenalSrc)) +#define GST_OPENAL_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OPENAL_SRC, GstOpenalSrcClass)) +#define GST_IS_OPENAL_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OPENAL_SRC)) +#define GST_IS_OPENAL_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OPENAL_SRC)) + +#if 1 +#define GST_ALC_ERROR(Device) ("ALC error: %s", alcGetString((Device), alcGetError((Device)))) +#else +#define GST_ALC_ERROR(Device) ("ALC error: 0x%x", alcGetError((Device))) +#endif + +typedef struct _GstOpenalSrc GstOpenalSrc; +typedef struct _GstOpenalSrcClass GstOpenalSrcClass; + +struct _GstOpenalSrc +{ + GstAudioSrc element; + GstPad *srcpad; + gboolean silent; + + /* readable name of device */ + gchar *default_device_name; + /* name of device to open, default is a NULL pointer to get default device */ + gchar *default_device; + /* OpenAL device handle */ + ALCdevice *device; + + guint64 buffer_length; + + ALenum format; + ALuint rate; + ALuint bytes_per_sample; + + GstCaps *probed_caps; +}; + +struct _GstOpenalSrcClass +{ + GstAudioSrcClass parent_class; +}; + +GType gst_openal_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_OPENAL_SRC_H__ */