+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),
libgstalsa_la_SOURCES = \
gstalsaplugin.c \
gstalsamixer.c \
+ gstalsamixerelement.c \
gstalsamixertrack.c \
gstalsamixeroptions.c \
gstalsasink.c \
gstalsasink.h \
gstalsasrc.h \
gstalsamixer.h \
+ gstalsamixerelement.h \
gstalsamixertrack.h \
gstalsamixeroptions.h
#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++) {
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;
}
}
}
-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)) {
}
}
-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)) {
}
}
-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++) {
}
}
-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;
}
}
-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;
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)) {
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)
#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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
#include "gstalsasink.h"
#include "gstalsasrc.h"
-#include "gstalsamixer.h"
+#include "gstalsamixerelement.h"
GST_DEBUG_CATEGORY (alsa_debug);
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))
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);
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);
"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)
{
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);
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);
}
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);
("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,
}
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
#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
typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
struct _GstAlsaSrc {
- GstAudioSrc src;
+ GstAudioSrc src;
gchar *device;
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 {
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);
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 =
}
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;
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;
gst_buffer_unref (buf->data);
buf->data = NULL;
- if (csrc->close)
- result = csrc->close (src);
+ if (csrc->unprepare)
+ result = csrc->unprepare (src);
return result;
}
/* 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];