From 13b122a10606c4c247ccc626acaa6895cd791373 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Mon, 22 Aug 2005 15:11:31 +0000 Subject: [PATCH] gst-libs/gst/audio/gstaudiosrc.*: Implement open_device and close_device in the ring buffer, like gstaudiosink. Original commit message from CVS: 2005-08-22 Andy Wingo * gst-libs/gst/audio/gstaudiosrc.h: * gst-libs/gst/audio/gstaudiosrc.c: Implement open_device and close_device in the ring buffer, like gstaudiosink. * ext/alsa/gstalsamixer.h: * ext/alsa/gstalsamixer.c: Not a GObject any more. Include a nifty macro to implement the interface without much code. Cleanups. * ext/alsa/gstalsasrc.h: * ext/alsa/gstalsasrc.c: Be a mixer. Open device and mixer in READY. * ext/alsa/Makefile.am: Add new files. * ext/alsa/gstalsamixerelement.c: * ext/alsa/gstalsamixerelement.c: Split element code out from mixer code so that alsasrc can be a mixer too. --- ChangeLog | 19 ++ ext/alsa/Makefile.am | 2 + ext/alsa/gstalsamixer.c | 374 +++++++++++-------------------- ext/alsa/gstalsamixer.h | 155 +++++++++++-- ext/alsa/gstalsamixerelement.c | 92 ++++++++ ext/alsa/gstalsamixerelement.h | 59 +++++ ext/alsa/gstalsaplugin.c | 4 +- ext/alsa/gstalsasrc.c | 127 +++++++---- ext/alsa/gstalsasrc.h | 27 ++- gst-libs/gst/audio/gstaudiosrc.c | 62 ++++- gst-libs/gst/audio/gstaudiosrc.h | 14 +- 11 files changed, 607 insertions(+), 328 deletions(-) create mode 100644 ext/alsa/gstalsamixerelement.c create mode 100644 ext/alsa/gstalsamixerelement.h diff --git a/ChangeLog b/ChangeLog index 6a40450b3e..f926c68786 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2005-08-22 Andy Wingo + + * gst-libs/gst/audio/gstaudiosrc.h: + * gst-libs/gst/audio/gstaudiosrc.c: Implement open_device and + close_device in the ring buffer, like gstaudiosink. + + * ext/alsa/gstalsamixer.h: + * ext/alsa/gstalsamixer.c: Not a GObject any more. Include a nifty + macro to implement the interface without much code. Cleanups. + + * ext/alsa/gstalsasrc.h: + * ext/alsa/gstalsasrc.c: Be a mixer. Open device and mixer in + READY. + + * ext/alsa/Makefile.am: Add new files. + * ext/alsa/gstalsamixerelement.c: + * ext/alsa/gstalsamixerelement.c: Split element code out from + mixer code so that alsasrc can be a mixer too. + 2005-08-21 Thomas Vander Stichele * check/elements/volume.c: (setup_volume), (cleanup_volume), diff --git a/ext/alsa/Makefile.am b/ext/alsa/Makefile.am index d0f533a9fe..a8bfdeda2a 100644 --- a/ext/alsa/Makefile.am +++ b/ext/alsa/Makefile.am @@ -3,6 +3,7 @@ plugin_LTLIBRARIES = libgstalsa.la libgstalsa_la_SOURCES = \ gstalsaplugin.c \ gstalsamixer.c \ + gstalsamixerelement.c \ gstalsamixertrack.c \ gstalsamixeroptions.c \ gstalsasink.c \ @@ -20,5 +21,6 @@ noinst_HEADERS = \ gstalsasink.h \ gstalsasrc.h \ gstalsamixer.h \ + gstalsamixerelement.h \ gstalsamixertrack.h \ gstalsamixeroptions.h diff --git a/ext/alsa/gstalsamixer.c b/ext/alsa/gstalsamixer.c index 65db1d0e92..15b25f93d8 100644 --- a/ext/alsa/gstalsamixer.c +++ b/ext/alsa/gstalsamixer.c @@ -25,194 +25,92 @@ #include "gstalsamixer.h" -static GstElementDetails gst_alsa_mixer_details = -GST_ELEMENT_DETAILS ("Alsa Mixer", - "Generic/Audio", - "Control sound input and output levels with ALSA", - "Leif Johnson "); - - -#define GST_BOILERPLATE_WITH_INTERFACE(type, type_as_function, parent_type, \ - parent_type_as_macro, interface_type, interface_type_as_macro, \ - interface_as_function) \ - \ -static void interface_as_function ## _interface_init (interface_type ## Class *klass); \ -static gboolean interface_as_function ## _supported (type *object, GType iface_type); \ - \ -static void \ -type_as_function ## _implements_interface_init (GstImplementsInterfaceClass *klass) \ -{ \ - klass->supported = (gpointer)interface_as_function ## _supported; \ -} \ - \ -static void \ -type_as_function ## _init_interfaces (GType type) \ -{ \ - static const GInterfaceInfo implements_iface_info = { \ - (GInterfaceInitFunc) type_as_function ## _implements_interface_init, \ - NULL, \ - NULL, \ - }; \ - static const GInterfaceInfo iface_info = { \ - (GInterfaceInitFunc) interface_as_function ## _interface_init, \ - NULL, \ - NULL, \ - }; \ - \ - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, \ - &implements_iface_info); \ - g_type_add_interface_static (type, interface_type_as_macro, &iface_info); \ -} \ - \ -GST_BOILERPLATE_FULL (type, type_as_function, parent_type, \ - parent_type_as_macro, type_as_function ## _init_interfaces) - -GST_BOILERPLATE_WITH_INTERFACE (GstAlsaMixer, gst_alsa_mixer, GstElement, - GST_TYPE_ELEMENT, GstMixer, GST_TYPE_MIXER, gst_alsa_mixer); - -static GstElementStateReturn gst_alsa_mixer_change_state (GstElement * element); - -/* GstMixer */ -static const GList *gst_alsa_mixer_list_tracks (GstMixer * mixer); -static void gst_alsa_mixer_set_volume (GstMixer * mixer, - GstMixerTrack * track, gint * volumes); -static void gst_alsa_mixer_get_volume (GstMixer * mixer, - GstMixerTrack * track, gint * volumes); -static void gst_alsa_mixer_set_record (GstMixer * mixer, - GstMixerTrack * track, gboolean record); -static void gst_alsa_mixer_set_mute (GstMixer * mixer, - GstMixerTrack * track, gboolean mute); -static void gst_alsa_mixer_set_option (GstMixer * mixer, - GstMixerOptions * opts, gchar * value); -static const gchar *gst_alsa_mixer_get_option (GstMixer * mixer, - GstMixerOptions * opts); - -static void -gst_alsa_mixer_base_init (gpointer klass) -{ - gst_element_class_set_details (GST_ELEMENT_CLASS (klass), - &gst_alsa_mixer_details); -} - -static void -gst_alsa_mixer_class_init (GstAlsaMixerClass * klass) -{ - GstElementClass *element_class; - - element_class = (GstElementClass *) klass; - - element_class->change_state = gst_alsa_mixer_change_state; -} - -static void -gst_alsa_mixer_init (GstAlsaMixer * mixer) -{ - mixer->mixer_handle = NULL; -} +/* First some utils, then the mixer implementation */ static gboolean gst_alsa_mixer_open (GstAlsaMixer * mixer) { - gint err, device; - gchar *nocomma = NULL; + gint err, devicenum; - g_return_val_if_fail (mixer->mixer_handle == NULL, FALSE); + g_return_val_if_fail (mixer->handle == NULL, FALSE); /* open and initialize the mixer device */ - err = snd_mixer_open (&mixer->mixer_handle, 0); - if (err < 0 || mixer->mixer_handle == NULL) { - GST_ERROR_OBJECT (GST_OBJECT (mixer), "Cannot open mixer device."); - mixer->mixer_handle = NULL; + err = snd_mixer_open (&mixer->handle, 0); + if (err < 0 || mixer->handle == NULL) { + GST_WARNING ("Cannot open empty mixer."); + mixer->handle = NULL; return FALSE; } -#if 0 - GstAlsa *alsa = GST_ALSA (mixer); - if (!strncmp (alsa->device, "hw:", 3)) - nocomma = g_strdup (alsa->device); - else if (!strncmp (alsa->device, "plughw:", 7)) - nocomma = g_strdup (alsa->device + 4); - else - goto error; -#else - nocomma = g_strdup ("hw:0"); -#endif + /* hack hack hack hack hack!!!!! */ + if (strncmp (mixer->device, "default", 7) == 0) { + /* hack! */ + g_free (mixer->device); + mixer->device = g_strdup ("hw:0"); + } else if (strncmp (mixer->device, "hw:", 3) == 0) { + /* ok */ + } else if (strncmp (mixer->device, "plughw:", 7) == 0) { + gchar *freeme = mixer->device; - if (strchr (nocomma, ',')) - strchr (nocomma, ',')[0] = '\0'; - - if ((err = snd_mixer_attach (mixer->mixer_handle, nocomma)) < 0) { - GST_ERROR_OBJECT (GST_OBJECT (mixer), - "Cannot attach mixer to sound device `%s'.", nocomma); + mixer->device = g_strdup (freeme + 4); + g_free (freeme); + } else { goto error; } - if ((err = snd_mixer_selem_register (mixer->mixer_handle, NULL, NULL)) < 0) { - GST_ERROR_OBJECT (GST_OBJECT (mixer), "Cannot register mixer elements."); + if (strchr (mixer->device, ',')) + strchr (mixer->device, ',')[0] = '\0'; + + if ((err = snd_mixer_attach (mixer->handle, mixer->device)) < 0) { + GST_WARNING ("Cannot open mixer for sound device `%s'.", mixer->device); goto error; } - if ((err = snd_mixer_load (mixer->mixer_handle)) < 0) { - GST_ERROR_OBJECT (GST_OBJECT (mixer), "Cannot load mixer settings."); + if ((err = snd_mixer_selem_register (mixer->handle, NULL, NULL)) < 0) { + GST_WARNING ("Cannot register mixer elements."); + goto error; + } + + if ((err = snd_mixer_load (mixer->handle)) < 0) { + GST_WARNING ("Cannot load mixer settings."); goto error; } /* I don't know how to get a device name from a mixer handle. So on * to the ugly hacks here, then... */ - if (sscanf (nocomma, "hw:%d", &device) == 1) { + if (sscanf (mixer->device, "hw:%d", &devicenum) == 1) { gchar *name; - if (!snd_card_get_name (device, &name)) + if (!snd_card_get_name (devicenum, &name)) mixer->cardname = name; } - g_free (nocomma); + GST_INFO ("Successfully opened mixer for device `%s'.", mixer->device); return TRUE; error: - snd_mixer_close (mixer->mixer_handle); - mixer->mixer_handle = NULL; - g_free (nocomma); + snd_mixer_close (mixer->handle); + mixer->handle = NULL; return FALSE; } static void -gst_alsa_mixer_close (GstAlsaMixer * mixer) -{ - if (mixer->mixer_handle == NULL) - return; - - if (mixer->cardname) { - free (mixer->cardname); - mixer->cardname = NULL; - } - - snd_mixer_close (mixer->mixer_handle); - mixer->mixer_handle = NULL; -} - -static void -gst_alsa_mixer_build_list (GstAlsaMixer * mixer) +gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) { gint i, count; snd_mixer_elem_t *element; GstMixerTrack *track; GstMixerOptions *opts; - const GList *templates; - GstPadDirection dir = GST_PAD_UNKNOWN; gboolean first = TRUE; - g_return_if_fail (mixer->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - /* find direction */ - templates = - gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS (mixer)); - if (templates) - dir = GST_PAD_TEMPLATE (templates->data)->direction; + if (mixer->tracklist) + return; - count = snd_mixer_get_count (mixer->mixer_handle); - element = snd_mixer_first_elem (mixer->mixer_handle); + count = snd_mixer_get_count (mixer->handle); + element = snd_mixer_first_elem (mixer->handle); /* build track list */ for (i = 0; i < count; i++) { @@ -222,11 +120,11 @@ gst_alsa_mixer_build_list (GstAlsaMixer * mixer) gboolean got_it = FALSE; if (snd_mixer_selem_has_capture_switch (element)) { - if (dir != GST_PAD_SRC && dir != GST_PAD_UNKNOWN) + if (!(mixer->dir & GST_ALSA_MIXER_CAPTURE)) goto next; flags = GST_MIXER_TRACK_INPUT; } else { - if (dir != GST_PAD_SINK && dir != GST_PAD_UNKNOWN) + if (!(mixer->dir & GST_ALSA_MIXER_PLAYBACK)) goto next; } @@ -291,92 +189,81 @@ gst_alsa_mixer_build_list (GstAlsaMixer * mixer) } } -static void -gst_alsa_mixer_free_list (GstAlsaMixer * mixer) -{ - g_return_if_fail (mixer->mixer_handle != NULL); - g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); - g_list_free (mixer->tracklist); - mixer->tracklist = NULL; +/* API */ + +GstAlsaMixer * +gst_alsa_mixer_new (const char *device, GstAlsaMixerDirection dir) +{ + GstAlsaMixer *ret = NULL; + + g_return_val_if_fail (device != NULL, NULL); + + ret = g_new0 (GstAlsaMixer, 1); + + ret->device = g_strdup (device); + ret->dir = dir; + + if (!gst_alsa_mixer_open (ret)) + goto error; + + return ret; + +error: + if (ret) + gst_alsa_mixer_free (ret); + + return NULL; } -static GstElementStateReturn -gst_alsa_mixer_change_state (GstElement * element) +void +gst_alsa_mixer_free (GstAlsaMixer * mixer) { - GstAlsaMixer *this; + g_return_if_fail (mixer != NULL); - g_return_val_if_fail (element != NULL, FALSE); - this = GST_ALSA_MIXER (element); - - switch (GST_STATE_TRANSITION (element)) { - case GST_STATE_NULL_TO_READY: - if (gst_alsa_mixer_open (this)) - gst_alsa_mixer_build_list (this); - break; - case GST_STATE_READY_TO_NULL: - if (this->mixer_handle != NULL) { - gst_alsa_mixer_free_list (this); - gst_alsa_mixer_close (this); - } - break; - default: - break; + if (mixer->device) { + g_free (mixer->device); + mixer->device = NULL; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element); + if (mixer->cardname) { + g_free (mixer->cardname); + mixer->cardname = NULL; + } - return GST_STATE_SUCCESS; + if (mixer->tracklist) { + g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); + g_list_free (mixer->tracklist); + mixer->tracklist = NULL; + } + + if (mixer->handle) { + snd_mixer_close (mixer->handle); + mixer->handle = NULL; + } + + g_free (mixer); } -/*** INTERFACE IMPLEMENTATION *************************************************/ - -static void -gst_alsa_mixer_interface_init (GstMixerClass * klass) +const GList * +gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer) { - GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; + g_return_val_if_fail (mixer->handle != NULL, NULL); - /* set up the interface hooks */ - klass->list_tracks = gst_alsa_mixer_list_tracks; - klass->set_volume = gst_alsa_mixer_set_volume; - klass->get_volume = gst_alsa_mixer_get_volume; - klass->set_mute = gst_alsa_mixer_set_mute; - klass->set_record = gst_alsa_mixer_set_record; - klass->set_option = gst_alsa_mixer_set_option; - klass->get_option = gst_alsa_mixer_get_option; -} + gst_alsa_mixer_ensure_track_list (mixer); -gboolean -gst_alsa_mixer_supported (GstAlsaMixer * object, GType iface_type) -{ - g_assert (iface_type == GST_TYPE_MIXER); - - return (object->mixer_handle != NULL); -} - -static const GList * -gst_alsa_mixer_list_tracks (GstMixer * mixer) -{ - GstAlsaMixer *alsa_mixer = GST_ALSA_MIXER (mixer); - - if (!alsa_mixer->mixer_handle) - return NULL; - - return (const GList *) alsa_mixer->tracklist; + return (const GList *) mixer->tracklist; } static void -gst_alsa_mixer_update (GstAlsaMixer * alsa_mixer, - GstAlsaMixerTrack * alsa_track) +gst_alsa_mixer_update (GstAlsaMixer * mixer, GstAlsaMixerTrack * alsa_track) { - GstMixerTrack *track; + GstMixerTrack *track = (GstMixerTrack *) alsa_track; int v = 0; - snd_mixer_handle_events (alsa_mixer->mixer_handle); + snd_mixer_handle_events (mixer->handle); if (!alsa_track) return; - track = (GstMixerTrack *) alsa_track; /* Any updates in flags? */ if (snd_mixer_selem_has_playback_switch (alsa_track->element)) { @@ -395,16 +282,16 @@ gst_alsa_mixer_update (GstAlsaMixer * alsa_mixer, } } -static void -gst_alsa_mixer_get_volume (GstMixer * mixer, - GstMixerTrack * track, gint * volumes) +void +gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track, + gint * volumes) { gint i; - GstAlsaMixerTrack *alsa_track = (GstAlsaMixerTrack *) track; + GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - g_return_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), alsa_track); + gst_alsa_mixer_update (mixer, alsa_track); if (track->flags & GST_MIXER_TRACK_MUTE && !snd_mixer_selem_has_playback_switch (alsa_track->element)) { @@ -426,16 +313,16 @@ gst_alsa_mixer_get_volume (GstMixer * mixer, } } -static void -gst_alsa_mixer_set_volume (GstMixer * mixer, - GstMixerTrack * track, gint * volumes) +void +gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, GstMixerTrack * track, + gint * volumes) { gint i; - GstAlsaMixerTrack *alsa_track = (GstAlsaMixerTrack *) track; + GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - g_return_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), alsa_track); + gst_alsa_mixer_update (mixer, alsa_track); /* only set the volume with ALSA lib if the track isn't muted. */ for (i = 0; i < track->num_channels; i++) { @@ -454,15 +341,16 @@ gst_alsa_mixer_set_volume (GstMixer * mixer, } } -static void -gst_alsa_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) +void +gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, GstMixerTrack * track, + gboolean mute) { gint i; - GstAlsaMixerTrack *alsa_track = (GstAlsaMixerTrack *) track; + GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - g_return_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), alsa_track); + gst_alsa_mixer_update (mixer, alsa_track); if (mute) { track->flags |= GST_MIXER_TRACK_MUTE; @@ -485,15 +373,15 @@ gst_alsa_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) } } -static void -gst_alsa_mixer_set_record (GstMixer * mixer, +void +gst_alsa_mixer_set_record (GstAlsaMixer * mixer, GstMixerTrack * track, gboolean record) { - GstAlsaMixerTrack *alsa_track = (GstAlsaMixerTrack *) track; + GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - g_return_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), alsa_track); + gst_alsa_mixer_update (mixer, alsa_track); if (record) { track->flags |= GST_MIXER_TRACK_RECORD; @@ -504,17 +392,17 @@ gst_alsa_mixer_set_record (GstMixer * mixer, snd_mixer_selem_set_capture_switch_all (alsa_track->element, record ? 1 : 0); } -static void -gst_alsa_mixer_set_option (GstMixer * mixer, +void +gst_alsa_mixer_set_option (GstAlsaMixer * mixer, GstMixerOptions * opts, gchar * value) { gint idx = -1, n = 0; GList *item; - GstAlsaMixerOptions *alsa_opts = (GstAlsaMixerOptions *) opts; + GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts); - g_return_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL); + g_return_if_fail (mixer->handle != NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), NULL); + gst_alsa_mixer_update (mixer, NULL); for (item = opts->values; item != NULL; item = item->next, n++) { if (!strcmp (item->data, value)) { @@ -528,16 +416,16 @@ gst_alsa_mixer_set_option (GstMixer * mixer, snd_mixer_selem_set_enum_item (alsa_opts->element, 0, idx); } -static const gchar * -gst_alsa_mixer_get_option (GstMixer * mixer, GstMixerOptions * opts) +const gchar * +gst_alsa_mixer_get_option (GstAlsaMixer * mixer, GstMixerOptions * opts) { - GstAlsaMixerOptions *alsa_opts = (GstAlsaMixerOptions *) opts; gint ret; guint idx; + GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts); - g_return_val_if_fail (GST_ALSA_MIXER (mixer)->mixer_handle != NULL, NULL); + g_return_val_if_fail (mixer->handle != NULL, NULL); - gst_alsa_mixer_update (GST_ALSA_MIXER (mixer), NULL); + gst_alsa_mixer_update (mixer, NULL); ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx); if (ret == 0) diff --git a/ext/alsa/gstalsamixer.h b/ext/alsa/gstalsamixer.h index 9c983df331..46d71c50ef 100644 --- a/ext/alsa/gstalsamixer.h +++ b/ext/alsa/gstalsamixer.h @@ -22,8 +22,8 @@ #include "gstalsa.h" -#include +#include #include "gstalsamixeroptions.h" #include "gstalsamixertrack.h" @@ -31,33 +31,160 @@ G_BEGIN_DECLS -#define GST_ALSA_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER,GstAlsaMixer)) -#define GST_ALSA_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER,GstAlsaMixerClass)) -#define GST_IS_ALSA_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER)) -#define GST_IS_ALSA_MIXER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER)) -#define GST_TYPE_ALSA_MIXER (gst_alsa_mixer_get_type()) +#define GST_ALSA_MIXER(obj) ((GstAlsaMixer*)(obj)) +typedef enum { + GST_ALSA_MIXER_CAPTURE = 1<<0, + GST_ALSA_MIXER_PLAYBACK = 1<<1, + GST_ALSA_MIXER_ALL = GST_ALSA_MIXER_CAPTURE | GST_ALSA_MIXER_PLAYBACK +} GstAlsaMixerDirection; + + typedef struct _GstAlsaMixer GstAlsaMixer; -typedef struct _GstAlsaMixerClass GstAlsaMixerClass; struct _GstAlsaMixer { - GstElement parent; - GList * tracklist; /* list of available tracks */ - snd_mixer_t * mixer_handle; + snd_mixer_t * handle; + gchar * device; gchar * cardname; -}; -struct _GstAlsaMixerClass { - GstElementClass parent; + GstAlsaMixerDirection dir; }; -GType gst_alsa_mixer_get_type (void); +GstAlsaMixer* gst_alsa_mixer_new (const gchar *device, + GstAlsaMixerDirection dir); +void gst_alsa_mixer_free (GstAlsaMixer *mixer); + +const GList* gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer); +void gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_alsa_mixer_set_record (GstAlsaMixer * mixer, + GstMixerTrack * track, + gboolean record); +void gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, + GstMixerTrack * track, + gboolean mute); +void gst_alsa_mixer_set_option (GstAlsaMixer * mixer, + GstMixerOptions * opts, + gchar * value); +const gchar* gst_alsa_mixer_get_option (GstAlsaMixer * mixer, + GstMixerOptions * opts); + + +#define GST_IMPLEMENT_ALSA_MIXER_METHODS(Type, interface_as_function) \ +static gboolean \ +interface_as_function ## _supported (Type *this, GType iface_type) \ +{ \ + g_assert (iface_type == GST_TYPE_MIXER); \ + \ + return (this->mixer != NULL); \ +} \ + \ +static const GList* \ +interface_as_function ## _list_tracks (GstMixer * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_val_if_fail (this != NULL, NULL); \ + g_return_val_if_fail (this->mixer != NULL, NULL); \ + \ + return gst_alsa_mixer_list_tracks (this->mixer); \ +} \ + \ +static void \ +interface_as_function ## _set_volume (GstMixer * mixer, GstMixerTrack * track, \ + gint * volumes) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_alsa_mixer_set_volume (this->mixer, track, volumes); \ +} \ + \ +static void \ +interface_as_function ## _get_volume (GstMixer * mixer, GstMixerTrack * track, \ + gint * volumes) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_alsa_mixer_get_volume (this->mixer, track, volumes); \ +} \ + \ +static void \ +interface_as_function ## _set_record (GstMixer * mixer, GstMixerTrack * track, \ + gboolean record) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_alsa_mixer_set_record (this->mixer, track, record); \ +} \ + \ +static void \ +interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track, \ + gboolean mute) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_alsa_mixer_set_mute (this->mixer, track, mute); \ +} \ + \ +static void \ +interface_as_function ## _set_option (GstMixer * mixer, GstMixerOptions * opts, \ + gchar * value) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_alsa_mixer_set_option (this->mixer, opts, value); \ +} \ + \ +static const gchar* \ +interface_as_function ## _get_option (GstMixer * mixer, GstMixerOptions * opts) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_val_if_fail (this != NULL, NULL); \ + g_return_val_if_fail (this->mixer != NULL, NULL); \ + \ + return gst_alsa_mixer_get_option (this->mixer, opts); \ +} \ + \ +static void \ +interface_as_function ## _interface_init (GstMixerClass * klass) \ +{ \ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \ + \ + /* set up the interface hooks */ \ + klass->list_tracks = interface_as_function ## _list_tracks; \ + klass->set_volume = interface_as_function ## _set_volume; \ + klass->get_volume = interface_as_function ## _get_volume; \ + klass->set_mute = interface_as_function ## _set_mute; \ + klass->set_record = interface_as_function ## _set_record; \ + klass->set_option = interface_as_function ## _set_option; \ + klass->get_option = interface_as_function ## _get_option; \ +} G_END_DECLS diff --git a/ext/alsa/gstalsamixerelement.c b/ext/alsa/gstalsamixerelement.c new file mode 100644 index 0000000000..869815f01d --- /dev/null +++ b/ext/alsa/gstalsamixerelement.c @@ -0,0 +1,92 @@ +/* ALSA mixer implementation. + * Copyright (C) 2003 Leif Johnson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstalsamixerelement.h" + + +static GstElementDetails gst_alsa_mixer_element_details = +GST_ELEMENT_DETAILS ("Alsa Mixer", + "Generic/Audio", + "Control sound input and output levels with ALSA", + "Leif Johnson "); + + +GST_BOILERPLATE_WITH_INTERFACE (GstAlsaMixerElement, gst_alsa_mixer_element, + GstElement, GST_TYPE_ELEMENT, GstMixer, GST_TYPE_MIXER, + gst_alsa_mixer_element); + +GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element); + +static GstElementStateReturn gst_alsa_mixer_element_change_state (GstElement * + element); + +static void +gst_alsa_mixer_element_base_init (gpointer klass) +{ + gst_element_class_set_details (GST_ELEMENT_CLASS (klass), + &gst_alsa_mixer_element_details); +} + +static void +gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass) +{ + GstElementClass *element_class; + + element_class = (GstElementClass *) klass; + + element_class->change_state = gst_alsa_mixer_element_change_state; +} + +static void +gst_alsa_mixer_element_init (GstAlsaMixerElement * this) +{ + this->mixer = NULL; +} + +static GstElementStateReturn +gst_alsa_mixer_element_change_state (GstElement * element) +{ + GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!this->mixer) { + this->mixer = gst_alsa_mixer_new ("hw:0", GST_ALSA_MIXER_ALL); + } + break; + case GST_STATE_READY_TO_NULL: + if (this->mixer) { + gst_alsa_mixer_free (this->mixer); + this->mixer = NULL; + } + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/alsa/gstalsamixerelement.h b/ext/alsa/gstalsamixerelement.h new file mode 100644 index 0000000000..9678da2f12 --- /dev/null +++ b/ext/alsa/gstalsamixerelement.h @@ -0,0 +1,59 @@ +/* ALSA mixer interface implementation. + * Copyright (C) 2003 Leif Johnson + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __GST_ALSA_MIXER_ELEMENT_H__ +#define __GST_ALSA_MIXER_ELEMENT_H__ + + +#include "gstalsa.h" +#include "gstalsamixer.h" + + +G_BEGIN_DECLS + + +#define GST_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElement)) +#define GST_ALSA_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElementClass)) +#define GST_IS_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_ELEMENT)) +#define GST_IS_ALSA_MIXER_ELEMENT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_ELEMENT)) +#define GST_TYPE_ALSA_MIXER_ELEMENT (gst_alsa_mixer_element_get_type()) + + +typedef struct _GstAlsaMixerElement GstAlsaMixerElement; +typedef struct _GstAlsaMixerElementClass GstAlsaMixerElementClass; + + +struct _GstAlsaMixerElement { + GstElement parent; + + GstAlsaMixer *mixer; +}; + +struct _GstAlsaMixerElementClass { + GstElementClass parent; +}; + + +GType gst_alsa_mixer_element_get_type (void); + + +G_END_DECLS + + +#endif /* __GST_ALSA_MIXER_ELEMENT_H__ */ diff --git a/ext/alsa/gstalsaplugin.c b/ext/alsa/gstalsaplugin.c index 5fe1c36ca2..bce83a3035 100644 --- a/ext/alsa/gstalsaplugin.c +++ b/ext/alsa/gstalsaplugin.c @@ -25,7 +25,7 @@ #include "gstalsasink.h" #include "gstalsasrc.h" -#include "gstalsamixer.h" +#include "gstalsamixerelement.h" GST_DEBUG_CATEGORY (alsa_debug); @@ -57,7 +57,7 @@ plugin_init (GstPlugin * plugin) int err; if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE, - GST_TYPE_ALSA_MIXER)) + GST_TYPE_ALSA_MIXER_ELEMENT)) return FALSE; if (!gst_element_register (plugin, "alsasrc", GST_RANK_PRIMARY, GST_TYPE_ALSA_SRC)) diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c index bc69c0fe15..32879bf9e7 100644 --- a/ext/alsa/gstalsasrc.c +++ b/ext/alsa/gstalsasrc.c @@ -46,9 +46,11 @@ enum PROP_DEVICE, }; -static void gst_alsasrc_base_init (gpointer g_class); -static void gst_alsasrc_class_init (GstAlsaSrcClass * klass); -static void gst_alsasrc_init (GstAlsaSrc * alsasrc); +GST_BOILERPLATE_WITH_INTERFACE (GstAlsaSrc, gst_alsasrc, GstAudioSrc, + GST_TYPE_AUDIO_SRC, GstMixer, GST_TYPE_MIXER, gst_alsasrc_mixer); + +GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaSrc, gst_alsasrc_mixer); + static void gst_alsasrc_dispose (GObject * object); static void gst_alsasrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -57,7 +59,10 @@ static void gst_alsasrc_get_property (GObject * object, static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc); -static gboolean gst_alsasrc_open (GstAudioSrc * asrc, GstRingBufferSpec * spec); +static gboolean gst_alsasrc_open (GstAudioSrc * asrc); +static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc, + GstRingBufferSpec * spec); +static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc); static gboolean gst_alsasrc_close (GstAudioSrc * asrc); static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length); static guint gst_alsasrc_delay (GstAudioSrc * asrc); @@ -86,36 +91,6 @@ static GstStaticPadTemplate alsasrc_src_factory = "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") ); -static GstElementClass *parent_class = NULL; - -/* static guint gst_alsasrc_signals[LAST_SIGNAL] = { 0 }; */ - -GType -gst_alsasrc_get_type (void) -{ - static GType alsasrc_type = 0; - - if (!alsasrc_type) { - static const GTypeInfo alsasrc_info = { - sizeof (GstAlsaSrcClass), - gst_alsasrc_base_init, - NULL, - (GClassInitFunc) gst_alsasrc_class_init, - NULL, - NULL, - sizeof (GstAlsaSrc), - 0, - (GInstanceInitFunc) gst_alsasrc_init, - }; - - alsasrc_type = - g_type_register_static (GST_TYPE_AUDIO_SRC, "GstAlsaSrc", - &alsasrc_info, 0); - } - - return alsasrc_type; -} - static void gst_alsasrc_dispose (GObject * object) { @@ -147,8 +122,6 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass) gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass; gstaudiosrc_class = (GstAudioSrcClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_BASE_AUDIO_SRC); - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_alsasrc_dispose); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasrc_get_property); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasrc_set_property); @@ -156,6 +129,8 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass) gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps); gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare); + gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasrc_unprepare); gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_alsasrc_close); gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_alsasrc_read); gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_alsasrc_delay); @@ -475,7 +450,32 @@ error: } static gboolean -gst_alsasrc_open (GstAudioSrc * asrc, GstRingBufferSpec * spec) +gst_alsasrc_open (GstAudioSrc * asrc) +{ + GstAlsaSrc *alsa; + gint err; + + alsa = GST_ALSA_SRC (asrc); + + CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE, + SND_PCM_NONBLOCK), open_error); + + if (!alsa->mixer) + alsa->mixer = gst_alsa_mixer_new (alsa->device, GST_ALSA_MIXER_CAPTURE); + + return TRUE; + + /* ERRORS */ +open_error: + { + GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, + ("Capture open error: %s", snd_strerror (err)), (NULL)); + return FALSE; + } +} + +static gboolean +gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) { GstAlsaSrc *alsa; gint err; @@ -485,9 +485,6 @@ gst_alsasrc_open (GstAudioSrc * asrc, GstRingBufferSpec * spec) if (!alsasrc_parse_spec (alsa, spec)) goto spec_parse; - CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK), open_error); - CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); CHECK (set_hwparams (alsa), hw_params_failed); @@ -511,12 +508,6 @@ spec_parse: ("Error parsing spec"), (NULL)); return FALSE; } -open_error: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, - ("Recording open error: %s", snd_strerror (err)), (NULL)); - return FALSE; - } non_block: { GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, @@ -544,18 +535,58 @@ prepare_failed: } static gboolean -gst_alsasrc_close (GstAudioSrc * asrc) +gst_alsasrc_unprepare (GstAudioSrc * asrc) { GstAlsaSrc *alsa; + gint err; alsa = GST_ALSA_SRC (asrc); + CHECK (snd_pcm_drop (alsa->handle), drop); + + CHECK (snd_pcm_hw_free (alsa->handle), hw_free); + + CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block); + + return TRUE; + + /* ERRORS */ +drop: + { + GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, + ("Could not drop samples: %s", snd_strerror (err)), (NULL)); + return FALSE; + } +hw_free: + { + GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, + ("Could not free hw params: %s", snd_strerror (err)), (NULL)); + return FALSE; + } +non_block: + { + GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, + ("Could not set device to nonblocking: %s", snd_strerror (err)), + (NULL)); + return FALSE; + } +} + +static gboolean +gst_alsasrc_close (GstAudioSrc * asrc) +{ + GstAlsaSrc *alsa = GST_ALSA_SRC (asrc); + snd_pcm_close (alsa->handle); + if (alsa->mixer) { + gst_alsa_mixer_free (alsa->mixer); + alsa->mixer = NULL; + } + return TRUE; } - /* * Underrun and suspend recovery */ diff --git a/ext/alsa/gstalsasrc.h b/ext/alsa/gstalsasrc.h index 55e28575e3..bcbca9cb7a 100644 --- a/ext/alsa/gstalsasrc.h +++ b/ext/alsa/gstalsasrc.h @@ -24,9 +24,10 @@ #define __GST_ALSASRC_H__ -#include #include -#include +#include "gstalsa.h" +#include "gstalsamixer.h" + G_BEGIN_DECLS @@ -40,7 +41,7 @@ typedef struct _GstAlsaSrc GstAlsaSrc; typedef struct _GstAlsaSrcClass GstAlsaSrcClass; struct _GstAlsaSrc { - GstAudioSrc src; + GstAudioSrc src; gchar *device; @@ -48,16 +49,18 @@ struct _GstAlsaSrc { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; - snd_pcm_access_t access; - snd_pcm_format_t format; - guint rate; - guint channels; - gint bytes_per_sample; + snd_pcm_access_t access; + snd_pcm_format_t format; + guint rate; + guint channels; + gint bytes_per_sample; - guint buffer_time; - guint period_time; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t period_size; + guint buffer_time; + guint period_time; + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t period_size; + + GstAlsaMixer *mixer; }; struct _GstAlsaSrcClass { diff --git a/gst-libs/gst/audio/gstaudiosrc.c b/gst-libs/gst/audio/gstaudiosrc.c index 7d9ad751fe..305e9ad7d6 100644 --- a/gst-libs/gst/audio/gstaudiosrc.c +++ b/gst-libs/gst/audio/gstaudiosrc.c @@ -70,6 +70,8 @@ static void gst_audioringbuffer_finalize (GObject * object); static GstRingBufferClass *ring_parent_class = NULL; +static gboolean gst_audioringbuffer_open_device (GstRingBuffer * buf); +static gboolean gst_audioringbuffer_close_device (GstRingBuffer * buf); static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec); static gboolean gst_audioringbuffer_release (GstRingBuffer * buf); @@ -120,6 +122,10 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass) gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_audioringbuffer_dispose); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_audioringbuffer_finalize); + gstringbuffer_class->open_device = + GST_DEBUG_FUNCPTR (gst_audioringbuffer_open_device); + gstringbuffer_class->close_device = + GST_DEBUG_FUNCPTR (gst_audioringbuffer_close_device); gstringbuffer_class->acquire = GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire); gstringbuffer_class->release = @@ -232,6 +238,54 @@ gst_audioringbuffer_finalize (GObject * object) G_OBJECT_CLASS (ring_parent_class)->finalize (object); } +static gboolean +gst_audioringbuffer_open_device (GstRingBuffer * buf) +{ + GstAudioSrc *src; + GstAudioSrcClass *csrc; + gboolean result = TRUE; + + src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf)); + csrc = GST_AUDIO_SRC_GET_CLASS (src); + + if (csrc->open) + result = csrc->open (src); + + if (!result) + goto could_not_open; + + return result; + +could_not_open: + { + return FALSE; + } +} + +static gboolean +gst_audioringbuffer_close_device (GstRingBuffer * buf) +{ + GstAudioSrc *src; + GstAudioSrcClass *csrc; + gboolean result = TRUE; + + src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf)); + csrc = GST_AUDIO_SRC_GET_CLASS (src); + + if (csrc->close) + result = csrc->close (src); + + if (!result) + goto could_not_open; + + return result; + +could_not_open: + { + return FALSE; + } +} + static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) { @@ -243,8 +297,8 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf)); csrc = GST_AUDIO_SRC_GET_CLASS (src); - if (csrc->open) - result = csrc->open (src, spec); + if (csrc->prepare) + result = csrc->prepare (src, spec); if (!result) goto could_not_open; @@ -297,8 +351,8 @@ gst_audioringbuffer_release (GstRingBuffer * buf) gst_buffer_unref (buf->data); buf->data = NULL; - if (csrc->close) - result = csrc->close (src); + if (csrc->unprepare) + result = csrc->unprepare (src); return result; } diff --git a/gst-libs/gst/audio/gstaudiosrc.h b/gst-libs/gst/audio/gstaudiosrc.h index 41a311c8b9..6474df0e01 100644 --- a/gst-libs/gst/audio/gstaudiosrc.h +++ b/gst-libs/gst/audio/gstaudiosrc.h @@ -69,15 +69,19 @@ struct _GstAudioSrcClass { /* vtable */ /* open the device with given specs */ - gboolean (*open) (GstAudioSrc *src, GstRingBufferSpec *spec); + gboolean (*open) (GstAudioSrc *src); + /* prepare resources and state to operate with the given specs */ + gboolean (*prepare) (GstAudioSrc *src, GstRingBufferSpec *spec); + /* undo anything that was done in prepare() */ + gboolean (*unprepare) (GstAudioSrc *src); /* close the device */ - gboolean (*close) (GstAudioSrc *src); + gboolean (*close) (GstAudioSrc *src); /* read samples from the device */ - guint (*read) (GstAudioSrc *src, gpointer data, guint length); + guint (*read) (GstAudioSrc *src, gpointer data, guint length); /* get number of samples queued in the device */ - guint (*delay) (GstAudioSrc *src); + guint (*delay) (GstAudioSrc *src); /* reset the audio device, unblock from a write */ - void (*reset) (GstAudioSrc *src); + void (*reset) (GstAudioSrc *src); /*< private >*/ gpointer _gst_reserved[GST_PADDING];