From f1ffa33d9ec0155ab660dc1a5f6ed40ce3f73abf Mon Sep 17 00:00:00 2001 From: Balamurali Viswanathan Date: Wed, 18 Aug 2004 04:52:41 +0000 Subject: sys/sunaudio/: Fix caps to handle full range of rates and channels. Make debugging less obnoxious. Original commit message from CVS: * sys/sunaudio/Makefile.am: * sys/sunaudio/gstsunaudio.c: Fix caps to handle full range of rates and channels. Make debugging less obnoxious. Patch from Balamurali Viswanathan implementing a mixer for Sun audio. (bug #144091): * sys/sunaudio/gstsunelement.c: * sys/sunaudio/gstsunelement.h: * sys/sunaudio/gstsunmixer.c: * sys/sunaudio/gstsunmixer.h: --- sys/sunaudio/Makefile.am | 8 +- sys/sunaudio/gstsunaudio.c | 31 +-- sys/sunaudio/gstsunelement.c | 497 +++++++++++++++++++++++++++++++++++++++++++ sys/sunaudio/gstsunelement.h | 63 ++++++ sys/sunaudio/gstsunmixer.c | 305 ++++++++++++++++++++++++++ sys/sunaudio/gstsunmixer.h | 43 ++++ 6 files changed, 933 insertions(+), 14 deletions(-) create mode 100644 sys/sunaudio/gstsunelement.c create mode 100644 sys/sunaudio/gstsunelement.h create mode 100644 sys/sunaudio/gstsunmixer.c create mode 100644 sys/sunaudio/gstsunmixer.h (limited to 'sys') diff --git a/sys/sunaudio/Makefile.am b/sys/sunaudio/Makefile.am index 29221858..5773575f 100644 --- a/sys/sunaudio/Makefile.am +++ b/sys/sunaudio/Makefile.am @@ -1,8 +1,14 @@ plugin_LTLIBRARIES = libgstsunaudio.la -libgstsunaudio_la_SOURCES = gstsunaudio.c +libgstsunaudio_la_SOURCES = gstsunaudio.c \ + gstsunelement.c \ + gstsunmixer.c + libgstsunaudio_la_CFLAGS = $(GST_CFLAGS) libgstsunaudio_la_LIBADD = $(top_builddir)/gst-libs/gst/libgstinterfaces-@GST_MAJORMINOR@.la libgstsunaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +noinst_HEADERS = gstsunelement.h \ + gstsunmixer.h + diff --git a/sys/sunaudio/gstsunaudio.c b/sys/sunaudio/gstsunaudio.c index de24afc3..057ec2bc 100644 --- a/sys/sunaudio/gstsunaudio.c +++ b/sys/sunaudio/gstsunaudio.c @@ -29,6 +29,8 @@ #include #include #include +#include "gstsunelement.h" +#include "gstsunmixer.h" #define GST_TYPE_SUNAUDIOSINK \ @@ -97,10 +99,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " "endianness = (int) BYTE_ORDER, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) { 8, 16 }, " - "depth = (int) { 8, 16 }, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") + "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16, " + /* [5510,48000] seems to be a Solaris limit */ + "rate = (int) [ 5510, 48000 ], " "channels = (int) [ 1, 2 ]") ); static void gst_sunaudiosink_base_init (gpointer g_class); @@ -192,6 +193,8 @@ gst_sunaudiosink_class_init (GstSunAudioSinkClass * klass) static void gst_sunaudiosink_init (GstSunAudioSink * sunaudiosink) { + const char *audiodev; + sunaudiosink->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&gst_sunaudiosink_sink_factory), "sink"); @@ -203,7 +206,11 @@ gst_sunaudiosink_init (GstSunAudioSink * sunaudiosink) gst_pad_set_chain_function (sunaudiosink->sinkpad, gst_sunaudiosink_chain); sunaudiosink->buffer_size = 64; - sunaudiosink->device = g_strdup ("/dev/audio"); + + audiodev = g_getenv ("AUDIODEV"); + if (audiodev == NULL) + audiodev = "/dev/audio"; + sunaudiosink->device = g_strdup (audiodev); } static GstCaps * @@ -212,12 +219,8 @@ gst_sunaudiosink_getcaps (GstPad * pad) GstSunAudioSink *sunaudiosink = GST_SUNAUDIOSINK (gst_pad_get_parent (pad)); GstCaps *caps; - caps = gst_caps_from_string ("audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) TRUE, " - "width = (int) 16, " - "depth = (int) 16, " "rate = (int) 44100, " "channels = (int) 1"); - GST_ERROR ("getcaps called on %" GST_PTR_FORMAT ", returning %" + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + GST_DEBUG ("getcaps called on %" GST_PTR_FORMAT ", returning %" GST_PTR_FORMAT, pad, caps); return caps; @@ -241,7 +244,7 @@ gst_sunaudiosink_pad_link (GstPad * pad, const GstCaps * caps) } else { ret = GST_PAD_LINK_REFUSED; } - GST_ERROR ("pad_link called on %" GST_PTR_FORMAT " with caps %" + GST_DEBUG ("pad_link called on %" GST_PTR_FORMAT " with caps %" GST_PTR_FORMAT ", returning %d", pad, caps, ret); return ret; @@ -426,7 +429,9 @@ static gboolean plugin_init (GstPlugin * plugin) { if (!gst_element_register (plugin, "sunaudiosink", GST_RANK_NONE, - GST_TYPE_SUNAUDIOSINK)) + GST_TYPE_SUNAUDIOSINK) || + !gst_element_register (plugin, "sunaudiomixer", GST_RANK_NONE, + GST_TYPE_SUNAUDIOELEMENT)) return FALSE; return TRUE; diff --git a/sys/sunaudio/gstsunelement.c b/sys/sunaudio/gstsunelement.c new file mode 100644 index 00000000..64184041 --- /dev/null +++ b/sys/sunaudio/gstsunelement.c @@ -0,0 +1,497 @@ +/* + * GStreamer + * Copyright (C) 1999-2001 Erik Walthinsen + * Copyright (C) 2004 David A. Schleef + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "gstsunelement.h" +#include "gstsunmixer.h" + +#include + +enum +{ + ARG_0, + ARG_DEVICE, + ARG_MIXERDEV, + ARG_DEVICE_NAME, +}; + +/* elementfactory information */ +static GstElementDetails gst_sunaudioelement_details = +GST_ELEMENT_DETAILS ("SunAudioMixer", + "Generic/Audio", + "Audio mixer for Sun Audio devices", + "Balamurali Viswanathan "); + +static void gst_sunaudioelement_base_init (GstSunAudioElementClass * klass); +static void gst_sunaudioelement_class_init (GstSunAudioElementClass * klass); + +static void gst_sunaudioprobe_interface_init (GstPropertyProbeInterface * + iface); +static void gst_sunaudioelement_init (GstSunAudioElement * sunaudio); +static void gst_sunaudioelement_dispose (GObject * object); + +static void gst_sunaudioelement_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); + +static void gst_sunaudioelement_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +static GstElementStateReturn gst_sunaudioelement_change_state (GstElement * + element); + +static GstElementClass *parent_class = NULL; + +static gboolean gst_sunaudioelement_open_audio (GstSunAudioElement * sunaudio); +static gboolean gst_sunaudioelement_close_audio (GstSunAudioElement * sunaudio); +void gst_sunaudioelement_reset (GstSunAudioElement * sunaudio); + +GType +gst_sunaudioelement_get_type (void) +{ + static GType sunaudioelement_type = 0; + + if (!sunaudioelement_type) { + static const GTypeInfo sunaudioelement_info = { + sizeof (GstSunAudioElementClass), + (GBaseInitFunc) gst_sunaudioelement_base_init, + NULL, + (GClassInitFunc) gst_sunaudioelement_class_init, + NULL, + NULL, + sizeof (GstSunAudioElement), + 0, + (GInstanceInitFunc) gst_sunaudioelement_init + }; + static const GInterfaceInfo sunaudioiface_info = { + (GInterfaceInitFunc) gst_sunaudio_interface_init, + NULL, + NULL + }; + static const GInterfaceInfo sunaudiomixer_info = { + (GInterfaceInitFunc) gst_sunaudiomixer_interface_init, + NULL, + NULL + }; + static const GInterfaceInfo sunaudioprobe_info = { + (GInterfaceInitFunc) gst_sunaudioprobe_interface_init, + NULL, + NULL + }; + + sunaudioelement_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstSunAudioElement", &sunaudioelement_info, 0); + g_type_add_interface_static (sunaudioelement_type, + GST_TYPE_IMPLEMENTS_INTERFACE, &sunaudioiface_info); + g_type_add_interface_static (sunaudioelement_type, + GST_TYPE_MIXER, &sunaudiomixer_info); + g_type_add_interface_static (sunaudioelement_type, + GST_TYPE_PROPERTY_PROBE, &sunaudioprobe_info); + } + + return sunaudioelement_type; +} + +static void +gst_sunaudioelement_base_init (GstSunAudioElementClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + klass->device_combinations = NULL; + + gst_element_class_set_details (element_class, &gst_sunaudioelement_details); +} + +static void +gst_sunaudioelement_class_init (GstSunAudioElementClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE, + g_param_spec_string ("device", "Device", + "SunAudio device (/dev/audioctl usually)", "default", + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIXERDEV, + g_param_spec_string ("mixerdev", "Mixer device", + "SunAudio mixer device (/dev/audioctl usually)", "default", + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE_NAME, + g_param_spec_string ("device_name", "Device name", "Name of the device", + NULL, G_PARAM_READABLE)); + + gobject_class->set_property = gst_sunaudioelement_set_property; + gobject_class->get_property = gst_sunaudioelement_get_property; + gobject_class->dispose = gst_sunaudioelement_dispose; + + gstelement_class->change_state = gst_sunaudioelement_change_state; +} + +static GList * +device_combination_append (GList * device_combinations, + GstSunAudioDeviceCombination * combi) +{ + GList *it; + + for (it = device_combinations; it != NULL; it = it->next) { + GstSunAudioDeviceCombination *cur; + + cur = (GstSunAudioDeviceCombination *) it->data; + if (cur->dev == combi->dev) { + return device_combinations; + } + } + + return g_list_append (device_combinations, combi); +} + +static gboolean +gst_sunaudioelement_class_probe_devices (GstSunAudioElementClass * klass, + gboolean check) +{ + GstElementClass *eklass = GST_ELEMENT_CLASS (klass); + gint openmode = O_RDONLY; + GList *padtempllist; + static GList *device_combinations; + static gboolean init = FALSE; + int fd; + + padtempllist = gst_element_class_get_pad_template_list (eklass); + if (padtempllist != NULL) { + GstPadTemplate *firstpadtempl = padtempllist->data; + + if (GST_PAD_TEMPLATE_DIRECTION (firstpadtempl) == GST_PAD_SINK) { + openmode = O_WRONLY; + } + } + + + if (!init && !check) { + if ((fd = open ("/dev/audioctl", openmode | O_NONBLOCK)) > 0 + || errno == EBUSY) { + GstSunAudioDeviceCombination *combi; + + if (fd > 0) + close (fd); + + combi = g_new0 (GstSunAudioDeviceCombination, 1); + combi->mixer = g_strdup ("/dev/audioctl"); + device_combinations = + device_combination_append (device_combinations, combi); + } + init = TRUE; + } + + klass->device_combinations = device_combinations; + + return init; +} + +static void +gst_sunaudioprobe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstSunAudioElementClass *klass = GST_SUNAUDIOELEMENT_GET_CLASS (probe); + + switch (prop_id) { + case ARG_DEVICE: + gst_sunaudioelement_class_probe_devices (klass, FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +static gboolean +gst_sunaudioprobe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstSunAudioElementClass *klass = GST_SUNAUDIOELEMENT_GET_CLASS (probe); + gboolean ret = FALSE; + + switch (prop_id) { + case ARG_DEVICE: + ret = !gst_sunaudioelement_class_probe_devices (klass, TRUE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return ret; +} + +static const GList * +gst_sunaudioprobe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + + if (!list) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + } + + return list; +} + +static GValueArray * +gst_sunaudioelement_class_list_devices (GstSunAudioElementClass * klass) +{ + GValueArray *array; + GValue value = { 0 }; + GList *item; + + if (!klass->device_combinations) { + return NULL; + } + + array = g_value_array_new (g_list_length (klass->device_combinations)); + item = klass->device_combinations; + g_value_init (&value, G_TYPE_STRING); + while (item) { + GstSunAudioDeviceCombination *combi = item->data; + + g_value_set_string (&value, combi->mixer); + g_value_array_append (array, &value); + + item = item->next; + } + g_value_unset (&value); + + return array; +} + +static GValueArray * +gst_sunaudioprobe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstSunAudioElementClass *klass = GST_SUNAUDIOELEMENT_GET_CLASS (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case ARG_DEVICE: + array = gst_sunaudioelement_class_list_devices (klass); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +static void +gst_sunaudioprobe_interface_init (GstPropertyProbeInterface * iface) +{ + iface->get_properties = gst_sunaudioprobe_get_properties; + iface->probe_property = gst_sunaudioprobe_probe_property; + iface->needs_probe = gst_sunaudioprobe_needs_probe; + iface->get_values = gst_sunaudioprobe_get_values; +} + +static void +gst_sunaudioelement_init (GstSunAudioElement * sunaudio) +{ + sunaudio->device = g_strdup ("/dev/audio"); + sunaudio->mixer_dev = g_strdup ("/dev/audioctl"); + sunaudio->fd = -1; + sunaudio->mixer_fd = -1; + sunaudio->tracklist = NULL; + sunaudio->device_name = NULL; + + gst_sunaudioelement_reset (sunaudio); +} + +void +gst_sunaudioelement_reset (GstSunAudioElement * sunaudio) +{ + return; +} + +static void +gst_sunaudioelement_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (object); + + switch (prop_id) { + case ARG_DEVICE: + if (gst_element_get_state (GST_ELEMENT (sunaudio)) == GST_STATE_NULL) { + g_free (sunaudio->device); + sunaudio->device = g_strdup (g_value_get_string (value)); + + if (GST_SUNAUDIOELEMENT_GET_CLASS (sunaudio)->device_combinations != + NULL) { + GList *list = + GST_SUNAUDIOELEMENT_GET_CLASS (sunaudio)->device_combinations; + + while (list) { + GstSunAudioDeviceCombination *combi = list->data; + + if (!strcmp (combi->mixer, sunaudio->device)) { + g_free (sunaudio->mixer_dev); + sunaudio->mixer_dev = g_strdup (combi->mixer); + break; + } + + list = list->next; + } + } + } + break; + case ARG_MIXERDEV: + if (gst_element_get_state (GST_ELEMENT (sunaudio)) == GST_STATE_NULL) { + g_free (sunaudio->mixer_dev); + sunaudio->mixer_dev = g_strdup (g_value_get_string (value)); + } + break; + default: + break; + } +} + +static void +gst_sunaudioelement_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_string (value, sunaudio->device); + break; + case ARG_MIXERDEV: + g_value_set_string (value, sunaudio->mixer_dev); + break; + case ARG_DEVICE_NAME: + g_value_set_string (value, sunaudio->device_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_sunaudioelement_dispose (GObject * object) +{ + GstSunAudioElement *sunaudio = (GstSunAudioElement *) object; + + g_free (sunaudio->device); + g_free (sunaudio->mixer_dev); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static GstElementStateReturn +gst_sunaudioelement_change_state (GstElement * element) +{ + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!gst_sunaudioelement_open_audio (sunaudio)) { + return GST_STATE_FAILURE; + } + GST_INFO ("opened sound device"); + break; + case GST_STATE_READY_TO_NULL: + gst_sunaudioelement_close_audio (sunaudio); + gst_sunaudioelement_reset (sunaudio); + GST_INFO ("closed sound device"); + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +static gboolean +gst_sunaudioelement_open_audio (GstSunAudioElement * sunaudio) +{ + gint caps; + GstSunAudioOpenMode mode = GST_SUNAUDIOELEMENT_READ; + const GList *padlist; + + g_return_val_if_fail (sunaudio->fd == -1, FALSE); + + padlist = gst_element_get_pad_list (GST_ELEMENT (sunaudio)); + + if (padlist != NULL) { + GstPad *firstpad = padlist->data; + + if (GST_PAD_IS_SINK (firstpad)) { + mode = GST_SUNAUDIOELEMENT_WRITE; + } + } + + if (mode == GST_SUNAUDIOELEMENT_WRITE) { + sunaudio->fd = open (sunaudio->device, O_WRONLY | O_NONBLOCK); + + if (sunaudio->fd >= 0) { + close (sunaudio->fd); + + sunaudio->fd = open (sunaudio->device, O_WRONLY); + } + } else { + sunaudio->fd = open (sunaudio->device, O_RDONLY); + } + + if (sunaudio->fd < 0) { + switch (errno) { + default: + printf ("could not open device\n"); + } + return FALSE; + } + + sunaudio->mode = mode; + gst_sunaudiomixer_build_list (sunaudio); + return TRUE; + +} + +static gboolean +gst_sunaudioelement_close_audio (GstSunAudioElement * sunaudio) +{ + close (sunaudio->fd); + sunaudio->fd = -1; +} diff --git a/sys/sunaudio/gstsunelement.h b/sys/sunaudio/gstsunelement.h new file mode 100644 index 00000000..86d5ca93 --- /dev/null +++ b/sys/sunaudio/gstsunelement.h @@ -0,0 +1,63 @@ +#ifndef __GST_SUNAUDIO_ELEMENT_H__ +#define __GST_SUNAUDIO_ELEMENT_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_SUNAUDIOELEMENT \ + (gst_sunaudioelement_get_type()) +#define GST_SUNAUDIOELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUNAUDIOELEMENT,GstSunAudioElement)) +#define GST_SUNAUDIOELEMENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUNAUDIOELEMENT,GstSunAudioElementClass)) +#define GST_IS_SUNAUDIOELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUNAUDIOELEMENT)) +#define GST_IS_SUNAUDIOELEMENT_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUNAUDIOELEMENT)) +#define GST_SUNAUDIOELEMENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SUNAUDIOELEMENT, GstSunAudioElementClass)) + +typedef enum { + GST_SUNAUDIOELEMENT_READ, + GST_SUNAUDIOELEMENT_WRITE, +} GstSunAudioOpenMode; + + +struct _GstSunAudioElement +{ + /* yes, we're a gstelement too */ + GstElement parent; + + gchar *device, + *mixer_dev; + + /* device state */ + int fd; + GstSunAudioOpenMode mode; + + /* mixer stuff */ + GList *tracklist; + gint mixer_fd; + gchar *device_name; +}; + +struct _GstSunAudioElementClass { + GstElementClass klass; + + GList *device_combinations; +}; + +typedef struct _GstSunAudioDeviceCombination { + gchar *mixer; + dev_t dev; +} GstSunAudioDeviceCombination; + +typedef struct _GstSunAudioElement GstSunAudioElement; +typedef struct _GstSunAudioElementClass GstSunAudioElementClass; + +GType gst_sunaudioelement_get_type (void); + +G_END_DECLS + +#endif diff --git a/sys/sunaudio/gstsunmixer.c b/sys/sunaudio/gstsunmixer.c new file mode 100644 index 00000000..f79b7725 --- /dev/null +++ b/sys/sunaudio/gstsunmixer.c @@ -0,0 +1,305 @@ +/* + * GStreamer + * Copyright (C) 1999-2001 Erik Walthinsen + * Copyright (C) 2004 David A. Schleef + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "gst/gst-i18n-plugin.h" +#include "gstsunmixer.h" + +static void gst_sunaudiomixer_track_class_init (GstSunAudioMixerTrackClass * + klass); +static void gst_sunaudiomixer_track_init (GstSunAudioMixerTrack * track); + +static gboolean gst_sunaudiomixer_supported (GstImplementsInterface * iface, + GType iface_type); +static const GList *gst_sunaudiomixer_list_tracks (GstMixer * sunaudiomixer); +static void gst_sunaudiomixer_set_volume (GstMixer * sunaudiomixer, + GstMixerTrack * track, gint * volumes); +static void gst_sunaudiomixer_get_volume (GstMixer * sunaudiomixer, + GstMixerTrack * track, gint * volumes); +static void gst_sunaudiomixer_set_mute (GstMixer * sunaudiomixer, + GstMixerTrack * track, gboolean mute); +static void gst_sunaudiomixer_set_record (GstMixer * sunaudiomixer, + GstMixerTrack * track, gboolean record); + +#define MIXER_DEVICES 3 +static gchar **labels = NULL; +static GstMixerTrackClass *parent_class = NULL; + +GType +gst_sunaudiomixer_track_get_type (void) +{ + static GType gst_sunaudiomixer_track_type = 0; + + if (!gst_sunaudiomixer_track_type) { + static const GTypeInfo sunaudiomixer_track_info = { + sizeof (GstSunAudioMixerTrackClass), + NULL, + NULL, + (GClassInitFunc) gst_sunaudiomixer_track_class_init, + NULL, + NULL, + sizeof (GstSunAudioMixerTrack), + 0, + (GInstanceInitFunc) gst_sunaudiomixer_track_init, + NULL + }; + + gst_sunaudiomixer_track_type = g_type_register_static (GST_TYPE_MIXER_TRACK, + "GstSunAudioMixerTrack", &sunaudiomixer_track_info, 0); + + } + + return gst_sunaudiomixer_track_type; +} + +static void +gst_sunaudiomixer_track_class_init (GstSunAudioMixerTrackClass * klass) +{ + parent_class = g_type_class_ref (GST_TYPE_MIXER_TRACK); +} + +static void +gst_sunaudiomixer_track_init (GstSunAudioMixerTrack * track) +{ + track->lvol = track->rvol = 0; + track->track_num = 0; +} + +void +gst_sunaudio_interface_init (GstImplementsInterfaceClass * klass) +{ + /* default virtual functions */ + klass->supported = gst_sunaudiomixer_supported; +} + +static gboolean +gst_sunaudiomixer_supported (GstImplementsInterface * iface, GType iface_type) +{ + g_assert (iface_type == GST_TYPE_MIXER); + + return (GST_SUNAUDIOELEMENT (iface)->mixer_fd != -1); +} + +void +gst_sunaudiomixer_interface_init (GstMixerClass * klass) +{ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; + + klass->list_tracks = gst_sunaudiomixer_list_tracks; + klass->set_volume = gst_sunaudiomixer_set_volume; + klass->get_volume = gst_sunaudiomixer_get_volume; + klass->set_mute = gst_sunaudiomixer_set_mute; + klass->set_record = gst_sunaudiomixer_set_record; +} + +static void +fill_labels (void) +{ + int i; + struct + { + gchar *given, *wanted; + } + cases[] = + { + { + "Vol ", N_("Volume")} + , { + "Gain ", N_("Gain")} + , { + "Mon ", N_("Monitor")} + , { + NULL, NULL} + }; + + labels = g_malloc (sizeof (gchar *) * MIXER_DEVICES); + + for (i = 0; i < MIXER_DEVICES; i++) { + labels[i] = g_strdup (cases[i].wanted); + } +} + +GstMixerTrack * +gst_sunaudiomixer_track_new (GstSunAudioElement * sunaudio, + gint track_num, gint max_chans, gint flags) +{ + GstSunAudioMixerTrack *sunaudiotrack; + GstMixerTrack *track; + gint volume; + + if (!labels) + fill_labels (); + + sunaudiotrack = g_object_new (GST_TYPE_SUNAUDIOMIXER_TRACK, NULL); + track = GST_MIXER_TRACK (sunaudiotrack); + track->label = g_strdup (labels[track_num]); + track->num_channels = max_chans; + track->flags = flags; + track->min_volume = 0; + track->max_volume = 100; + sunaudiotrack->track_num = track_num; + + sunaudiotrack->lvol = (0 & 0xff); + + return track; +} + +void +gst_sunaudiomixer_build_list (GstSunAudioElement * sunaudio) +{ + GstMixerTrack *track; + + sunaudio->mixer_fd = open (sunaudio->mixer_dev, O_RDWR); + + if (sunaudio->mixer_fd == -1) { + return; + } + + sunaudio->device_name = g_strdup ("Unknown"); + + track = gst_sunaudiomixer_track_new (sunaudio, 0, 1, GST_MIXER_TRACK_OUTPUT); + sunaudio->tracklist = g_list_append (sunaudio->tracklist, track); + track = gst_sunaudiomixer_track_new (sunaudio, 1, 1, 0); + sunaudio->tracklist = g_list_append (sunaudio->tracklist, track); + track = gst_sunaudiomixer_track_new (sunaudio, 2, 1, 0); + sunaudio->tracklist = g_list_append (sunaudio->tracklist, track); +} + +static const GList * +gst_sunaudiomixer_list_tracks (GstMixer * mixer) +{ + return (const GList *) GST_SUNAUDIOELEMENT (mixer)->tracklist; +} + +static void +gst_sunaudiomixer_set_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint volume; + gchar buf[100]; + struct audio_info audioinfo; + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (mixer); + GstSunAudioMixerTrack *sunaudiotrack = GST_SUNAUDIOMIXER_TRACK (track); + + g_return_if_fail (sunaudio->mixer_fd != -1); + volume = (volumes[0] * 255) / 100; + + /* Set the volume */ + AUDIO_INITINFO (&audioinfo); + + switch (sunaudiotrack->track_num) { + case 0: + audioinfo.play.gain = volume; + break; + case 1: + audioinfo.record.gain = volume; + break; + case 2: + audioinfo.monitor_gain = volume; + break; + } + + + if (ioctl (sunaudio->mixer_fd, AUDIO_SETINFO, &audioinfo) < 0) { + g_warning ("Error setting volume"); + return; + } +} + +static void +gst_sunaudiomixer_get_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint volume; + struct audio_info audioinfo; + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (mixer); + GstSunAudioMixerTrack *sunaudiotrack = GST_SUNAUDIOMIXER_TRACK (track); + + g_return_if_fail (sunaudio->mixer_fd != -1); + + if (ioctl (sunaudio->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error setting volume device"); + return; + } + + switch (sunaudiotrack->track_num) { + case 0: + sunaudiotrack->lvol = volumes[0] = (audioinfo.play.gain * 100) / 255; + break; + case 1: + sunaudiotrack->lvol = volumes[0] = (audioinfo.record.gain * 100) / 255; + break; + case 2: + sunaudiotrack->lvol = volumes[0] = (audioinfo.monitor_gain * 100) / 255; + break; + } + +} + +static void +gst_sunaudiomixer_set_mute (GstMixer * mixer, + GstMixerTrack * track, gboolean mute) +{ + struct audio_info audioinfo; + GstSunAudioElement *sunaudio = GST_SUNAUDIOELEMENT (mixer); + GstSunAudioMixerTrack *sunaudiotrack = GST_SUNAUDIOMIXER_TRACK (track); + + g_return_if_fail (sunaudio->mixer_fd != -1); + if (sunaudiotrack->track_num != 0) + return; + + AUDIO_INITINFO (&audioinfo); + ioctl (sunaudio->mixer_fd, AUDIO_GETINFO, &audioinfo); + + if (mute) { + audioinfo.play.port = audioinfo.play.avail_ports; + audioinfo.output_muted = 1; + } else { + audioinfo.play.port = 0; + audioinfo.output_muted = 0; + } + + if (ioctl (sunaudio->mixer_fd, AUDIO_SETINFO, &audioinfo) < 0) { + g_warning ("Error setting volume device"); + return; + } +} + +static void +gst_sunaudiomixer_set_record (GstMixer * mixer, + GstMixerTrack * track, gboolean record) +{ + + /* Implementation Pending */ + +} diff --git a/sys/sunaudio/gstsunmixer.h b/sys/sunaudio/gstsunmixer.h new file mode 100644 index 00000000..dd3a7f7e --- /dev/null +++ b/sys/sunaudio/gstsunmixer.h @@ -0,0 +1,43 @@ +#ifndef __GST_SUNAUDIO_MIXER_H +#define __GST_SUNAUDIO_MIXER_H + +#include +#include +#include "gstsunelement.h" + +G_BEGIN_DECLS + +#define GST_TYPE_SUNAUDIOMIXER_TRACK \ + (gst_sunaudiomixer_track_get_type ()) +#define GST_SUNAUDIOMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SUNAUDIOMIXER_TRACK, \ + GstSunAudioMixerTrack)) +#define GST_SUNAUDIOMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SUNAUDIOMIXER_TRACK, \ + GstSunAudioMixerTrackClass)) +#define GST_IS_SUNAUDIOMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SUNAUDIOMIXER_TRACK)) +#define GST_IS_SUNAUDIOMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SUNAUDIOMIXER_TRACK)) + +typedef struct _GstSunAudioMixerTrack { + GstMixerTrack parent; + + gint lvol, rvol; + gint track_num; +} GstSunAudioMixerTrack; + +typedef struct _GstSunAudioMixerTrackClass { + GstMixerTrackClass parent; +} GstSunAudioMixerTrackClass; + +GType gst_sunaudiomixer_track_get_type (void); + +void gst_sunaudiomixer_interface_init (GstMixerClass *klass); +void gst_sunaudio_interface_init (GstImplementsInterfaceClass *klass); +void gst_sunaudiomixer_build_list (GstSunAudioElement *sunaudio); +void gst_sunaudiomixer_free_list (GstSunAudioElement *sunaudio); + +G_END_DECLS + +#endif -- cgit v1.2.1