gst-libs/gst/audio/gstaudiosrc.*: Implement open_device and close_device in the ring...
authorAndy Wingo <wingo@pobox.com>
Mon, 22 Aug 2005 15:11:31 +0000 (15:11 +0000)
committerAndy Wingo <wingo@pobox.com>
Mon, 22 Aug 2005 15:11:31 +0000 (15:11 +0000)
Original commit message from CVS:
2005-08-22  Andy Wingo  <wingo@pobox.com>

* 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
ext/alsa/Makefile.am
ext/alsa/gstalsamixer.c
ext/alsa/gstalsamixer.h
ext/alsa/gstalsamixerelement.c [new file with mode: 0644]
ext/alsa/gstalsamixerelement.h [new file with mode: 0644]
ext/alsa/gstalsaplugin.c
ext/alsa/gstalsasrc.c
ext/alsa/gstalsasrc.h
gst-libs/gst/audio/gstaudiosrc.c
gst-libs/gst/audio/gstaudiosrc.h

index 6a40450..f926c68 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2005-08-22  Andy Wingo  <wingo@pobox.com>
+
+       * 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  <thomas at apestaart dot org>
 
        * check/elements/volume.c: (setup_volume), (cleanup_volume),
index d0f533a..a8bfded 100644 (file)
@@ -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
index 65db1d0..15b25f9 100644 (file)
 #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 <leif@ambient.2y.net>");
-
-
-#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
+  /* 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;
+
+    mixer->device = g_strdup (freeme + 4);
+    g_free (freeme);
+  } else {
     goto error;
-#else
-  nocomma = g_strdup ("hw:0");
-#endif
+  }
 
-  if (strchr (nocomma, ','))
-    strchr (nocomma, ',')[0] = '\0';
+  if (strchr (mixer->device, ','))
+    strchr (mixer->device, ',')[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);
+  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_selem_register (mixer->mixer_handle, NULL, NULL)) < 0) {
-    GST_ERROR_OBJECT (GST_OBJECT (mixer), "Cannot register mixer elements.");
+  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->mixer_handle)) < 0) {
-    GST_ERROR_OBJECT (GST_OBJECT (mixer), "Cannot load mixer settings.");
+  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 */
 
-static GstElementStateReturn
-gst_alsa_mixer_change_state (GstElement * element)
+GstAlsaMixer *
+gst_alsa_mixer_new (const char *device, GstAlsaMixerDirection dir)
 {
-  GstAlsaMixer *this;
+  GstAlsaMixer *ret = NULL;
 
-  g_return_val_if_fail (element != NULL, FALSE);
-  this = GST_ALSA_MIXER (element);
+  g_return_val_if_fail (device != NULL, NULL);
 
-  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;
-  }
+  ret = g_new0 (GstAlsaMixer, 1);
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  ret->device = g_strdup (device);
+  ret->dir = dir;
 
-  return GST_STATE_SUCCESS;
-}
+  if (!gst_alsa_mixer_open (ret))
+    goto error;
 
-/*** INTERFACE IMPLEMENTATION *************************************************/
+  return ret;
 
-static void
-gst_alsa_mixer_interface_init (GstMixerClass * klass)
-{
-  GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE;
-
-  /* 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;
+error:
+  if (ret)
+    gst_alsa_mixer_free (ret);
+
+  return NULL;
 }
 
-gboolean
-gst_alsa_mixer_supported (GstAlsaMixer * object, GType iface_type)
+void
+gst_alsa_mixer_free (GstAlsaMixer * mixer)
 {
-  g_assert (iface_type == GST_TYPE_MIXER);
+  g_return_if_fail (mixer != NULL);
+
+  if (mixer->device) {
+    g_free (mixer->device);
+    mixer->device = NULL;
+  }
 
-  return (object->mixer_handle != NULL);
+  if (mixer->cardname) {
+    g_free (mixer->cardname);
+    mixer->cardname = NULL;
+  }
+
+  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);
 }
 
-static const GList *
-gst_alsa_mixer_list_tracks (GstMixer * mixer)
+const GList *
+gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer)
 {
-  GstAlsaMixer *alsa_mixer = GST_ALSA_MIXER (mixer);
+  g_return_val_if_fail (mixer->handle != NULL, NULL);
 
-  if (!alsa_mixer->mixer_handle)
-    return NULL;
+  gst_alsa_mixer_ensure_track_list (mixer);
 
-  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)
index 9c983df..46d71c5 100644 (file)
@@ -22,8 +22,8 @@
 
 
 #include "gstalsa.h"
-#include <gst/interfaces/mixer.h>
 
+#include <gst/interfaces/mixer.h>
 #include "gstalsamixeroptions.h"
 #include "gstalsamixertrack.h"
 
 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 (file)
index 0000000..869815f
--- /dev/null
@@ -0,0 +1,92 @@
+/* ALSA mixer implementation.
+ * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
+ *
+ * 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 <leif@ambient.2y.net>");
+
+
+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 (file)
index 0000000..9678da2
--- /dev/null
@@ -0,0 +1,59 @@
+/* ALSA mixer interface implementation.
+ * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
+ *
+ * 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__ */
index 5fe1c36..bce83a3 100644 (file)
@@ -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))
index bc69c0f..32879bf 100644 (file)
@@ -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,19 +450,41 @@ error:
 }
 
 static gboolean
-gst_alsasrc_open (GstAudioSrc * asrc, GstRingBufferSpec * spec)
+gst_alsasrc_open (GstAudioSrc * asrc)
 {
   GstAlsaSrc *alsa;
   gint err;
 
   alsa = GST_ALSA_SRC (asrc);
 
-  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);
 
+  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;
+
+  alsa = GST_ALSA_SRC (asrc);
+
+  if (!alsasrc_parse_spec (alsa, spec))
+    goto spec_parse;
+
   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,17 +535,57 @@ prepare_failed:
 }
 
 static gboolean
-gst_alsasrc_close (GstAudioSrc * asrc)
+gst_alsasrc_unprepare (GstAudioSrc * asrc)
 {
   GstAlsaSrc *alsa;
+  gint err;
 
   alsa = GST_ALSA_SRC (asrc);
 
-  snd_pcm_close (alsa->handle);
+  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
index 55e2857..bcbca9c 100644 (file)
 #define __GST_ALSASRC_H__
 
 
-#include <gst/gst.h>
 #include <gst/audio/gstaudiosrc.h>
-#include <alsa/asoundlib.h>
+#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 {
index 7d9ad75..305e9ad 100644 (file)
@@ -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 =
@@ -233,6 +239,54 @@ gst_audioringbuffer_finalize (GObject * 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)
 {
   GstAudioSrc *src;
@@ -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;
 }
index 41a311c..6474df0 100644 (file)
@@ -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];