From a5ff454e6a20d677e8546523c1c62efccd713c10 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 20 Apr 2012 18:13:01 +0200 Subject: [PATCH] oss4: port to 0.11 --- configure.ac | 1 - docs/plugins/Makefile.am | 1 - .../gst-plugins-good-plugins-docs.sgml | 1 - .../gst-plugins-good-plugins-sections.txt | 24 - sys/oss4/Makefile.am | 10 - sys/oss4/oss4-audio.c | 184 +- sys/oss4/oss4-audio.h | 4 +- sys/oss4/oss4-mixer-enum.c | 269 --- sys/oss4/oss4-mixer-enum.h | 67 - sys/oss4/oss4-mixer-slider.c | 311 --- sys/oss4/oss4-mixer-slider.h | 70 - sys/oss4/oss4-mixer-switch.c | 150 -- sys/oss4/oss4-mixer-switch.h | 65 - sys/oss4/oss4-mixer.c | 1857 ----------------- sys/oss4/oss4-mixer.h | 128 -- sys/oss4/oss4-property-probe.c | 20 +- sys/oss4/oss4-property-probe.h | 7 + sys/oss4/oss4-sink.c | 78 +- sys/oss4/oss4-sink.h | 2 - sys/oss4/oss4-source.c | 511 +---- sys/oss4/oss4-source.h | 30 - 21 files changed, 208 insertions(+), 3582 deletions(-) delete mode 100644 sys/oss4/oss4-mixer-enum.c delete mode 100644 sys/oss4/oss4-mixer-enum.h delete mode 100644 sys/oss4/oss4-mixer-slider.c delete mode 100644 sys/oss4/oss4-mixer-slider.h delete mode 100644 sys/oss4/oss4-mixer-switch.c delete mode 100644 sys/oss4/oss4-mixer-switch.h delete mode 100644 sys/oss4/oss4-mixer.c delete mode 100644 sys/oss4/oss4-mixer.h diff --git a/configure.ac b/configure.ac index 13911757ac..4bb2e2786b 100644 --- a/configure.ac +++ b/configure.ac @@ -310,7 +310,6 @@ dnl Non ported plugins (non-dependant, then dependant) dnl Make sure you have a space before and after all plugins GST_PLUGINS_NONPORTED="deinterlace \ cairo cairo_gobject gdk_pixbuf \ - oss4 \ osx_video osx_audio " AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 7e2b6a59ab..5c73726beb 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -191,7 +191,6 @@ EXTRA_HFILES = \ $(top_srcdir)/gst/wavparse/gstwavparse.h \ $(top_srcdir)/gst/y4m/gsty4mencode.h \ $(top_srcdir)/sys/directsound/gstdirectsoundsink.h \ - $(top_srcdir)/sys/oss4/oss4-mixer.h \ $(top_srcdir)/sys/oss4/oss4-sink.h \ $(top_srcdir)/sys/oss4/oss4-source.h \ $(top_srcdir)/sys/oss/gstosssink.h \ diff --git a/docs/plugins/gst-plugins-good-plugins-docs.sgml b/docs/plugins/gst-plugins-good-plugins-docs.sgml index 7b02a2bd6d..cbedd70652 100644 --- a/docs/plugins/gst-plugins-good-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-good-plugins-docs.sgml @@ -111,7 +111,6 @@ - diff --git a/docs/plugins/gst-plugins-good-plugins-sections.txt b/docs/plugins/gst-plugins-good-plugins-sections.txt index a5e7cec653..d37038c95f 100644 --- a/docs/plugins/gst-plugins-good-plugins-sections.txt +++ b/docs/plugins/gst-plugins-good-plugins-sections.txt @@ -1396,30 +1396,6 @@ GST_IS_MULTIUDPSINK_CLASS gst_multiudpsink_get_type -
-element-oss4mixer -oss4mixer -GstOss4Mixer - -GstOss4MixerClass -GST_OSS4_MIXER -GST_OSS4_MIXER_CLASS -GST_IS_OSS4_MIXER -GST_IS_OSS4_MIXER_CLASS -GST_TYPE_OSS4_MIXER -gst_oss4_mixer_get_type -GST_OSS4_MIXER_CAST -GST_OSS4_MIXER_IS_OPEN -MIXEXT_ENUM_IS_AVAILABLE -MIXEXT_HAS_DESCRIPTION -MIXEXT_IS_ROOT -MIXEXT_IS_SLIDER -gst_oss4_mixer_get_control_val -gst_oss4_mixer_set_control_val -gst_oss4_source_input_get_type -GstOss4MixerControl -
-
element-oss4sink oss4sink diff --git a/sys/oss4/Makefile.am b/sys/oss4/Makefile.am index 8f8793c5d4..8e7b4664c3 100644 --- a/sys/oss4/Makefile.am +++ b/sys/oss4/Makefile.am @@ -2,10 +2,6 @@ plugin_LTLIBRARIES = libgstoss4audio.la libgstoss4audio_la_SOURCES = \ oss4-audio.c \ - oss4-mixer.c \ - oss4-mixer-enum.c \ - oss4-mixer-slider.c \ - oss4-mixer-switch.c \ oss4-property-probe.c \ oss4-sink.c \ oss4-source.c @@ -13,7 +9,6 @@ libgstoss4audio_la_SOURCES = \ libgstoss4audio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) libgstoss4audio_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) \ - -lgstinterfaces-$(GST_API_VERSION) \ -lgstaudio-$(GST_API_VERSION) \ $(GST_LIBS) libgstoss4audio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) @@ -21,13 +16,8 @@ libgstoss4audio_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ oss4-audio.h \ - oss4-mixer.h \ - oss4-mixer-enum.h \ - oss4-mixer-slider.h \ - oss4-mixer-switch.h \ oss4-property-probe.h \ oss4-sink.h \ oss4-soundcard.h \ oss4-source.h - diff --git a/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c index 2661ffe94f..11f6e5e71f 100644 --- a/sys/oss4/oss4-audio.c +++ b/sys/oss4/oss4-audio.c @@ -33,10 +33,9 @@ #include #include "gst/gst-i18n-plugin.h" -#include +#include #include "oss4-audio.h" -#include "oss4-mixer.h" #include "oss4-property-probe.h" #include "oss4-sink.h" #include "oss4-source.h" @@ -51,33 +50,42 @@ GST_DEBUG_CATEGORY (oss4_debug); typedef struct { - const GstBufferFormat gst_fmt; + const GstAudioRingBufferFormatType gst_rbfmt; + const GstAudioFormat gst_rfmt; const gint oss_fmt; const gchar name[16]; - const gint depth; - const gint width; - const gint endianness; - const gboolean signedness; } GstOss4AudioFormat; /* *INDENT-OFF* */ static const GstOss4AudioFormat fmt_map[] = { /* note: keep sorted by preference, prefered formats first */ { - GST_MU_LAW, AFMT_MU_LAW, "audio/x-mulaw", 0, 0, 0, FALSE}, { - GST_A_LAW, AFMT_A_LAW, "audio/x-alaw", 0, 0, 0, FALSE}, { - GST_S32_LE, AFMT_S32_LE, "audio/x-raw-int", 32, 32, G_LITTLE_ENDIAN, TRUE}, { - GST_S32_BE, AFMT_S32_BE, "audio/x-raw-int", 32, 32, G_BIG_ENDIAN, TRUE}, { - GST_S24_LE, AFMT_S24_LE, "audio/x-raw-int", 24, 32, G_LITTLE_ENDIAN, TRUE}, { - GST_S24_BE, AFMT_S24_BE, "audio/x-raw-int", 24, 32, G_BIG_ENDIAN, TRUE}, { - GST_S24_3LE, AFMT_S24_PACKED, "audio/x-raw-int", 24, 24, G_LITTLE_ENDIAN, - TRUE}, { - GST_S16_LE, AFMT_S16_LE, "audio/x-raw-int", 16, 16, G_LITTLE_ENDIAN, TRUE}, { - GST_S16_BE, AFMT_S16_BE, "audio/x-raw-int", 16, 16, G_BIG_ENDIAN, TRUE}, { - GST_U16_LE, AFMT_U16_LE, "audio/x-raw-int", 16, 16, G_LITTLE_ENDIAN, FALSE}, { - GST_U16_BE, AFMT_U16_BE, "audio/x-raw-int", 16, 16, G_BIG_ENDIAN, FALSE}, { - GST_S8, AFMT_S8, "audio/x-raw-int", 8, 8, 0, TRUE}, { - GST_U8, AFMT_U8, "audio/x-raw-int", 8, 8, 0, FALSE} + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW, 0, + AFMT_MU_LAW, "audio/x-mulaw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW, 0, + AFMT_A_LAW, "audio/x-alaw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32LE, + AFMT_S32_LE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32BE, + AFMT_S32_BE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32LE, + AFMT_S24_LE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32BE, + AFMT_S24_BE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24LE, + AFMT_S24_PACKED, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16LE, + AFMT_S16_LE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16BE, + AFMT_S16_BE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16LE, + AFMT_U16_LE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16BE, + AFMT_U16_BE, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S8, + AFMT_S8, "audio/x-raw"}, { + GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U8, + AFMT_U8, "audio/x-raw"} }; /* *INDENT-ON* */ @@ -96,24 +104,23 @@ gst_oss4_append_format_to_caps (const GstOss4AudioFormat * fmt, GstCaps * caps) { GstStructure *s; - s = gst_structure_empty_new (fmt->name); - if (fmt->width != 0 && fmt->depth != 0) { - gst_structure_set (s, "width", G_TYPE_INT, fmt->width, "depth", G_TYPE_INT, - fmt->depth, "signed", G_TYPE_BOOLEAN, fmt->signedness, NULL); - } - if (fmt->endianness != 0) { - gst_structure_set (s, "endianness", G_TYPE_INT, fmt->endianness, NULL); + s = gst_structure_new_empty (fmt->name); + if (fmt->gst_rbfmt == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) { + gst_structure_set (s, "format", G_TYPE_STRING, + gst_audio_format_to_string (fmt->gst_rfmt), + "layout", G_TYPE_STRING, "interleaved", NULL); } gst_caps_append_structure (caps, s); } static gint -gst_oss4_audio_get_oss_format (GstBufferFormat fmt) +gst_oss4_audio_get_oss_format (GstAudioRingBufferFormatType fmt, + GstAudioFormat rfmt) { guint i; for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) { - if (fmt_map[i].gst_fmt == fmt) + if (fmt_map[i].gst_rbfmt == fmt && fmt_map[i].gst_rfmt == rfmt) return fmt_map[i].oss_fmt; } return 0; @@ -200,15 +207,15 @@ gst_oss4_audio_detect_rates (GstObject * obj, oss_audioinfo * ai, } static void -gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout, - guint num_channels, GstStructure * s) +gst_oss4_audio_get_channel_layout (GstObject * obj, guint64 layout, + guint num_channels, GstAudioChannelPosition * ch_layout) { const GstAudioChannelPosition pos_map[16] = { GST_AUDIO_CHANNEL_POSITION_NONE, /* 0 = dunno */ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, /* 1 = left */ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, /* 2 = right */ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, /* 3 = center */ - GST_AUDIO_CHANNEL_POSITION_LFE, /* 4 = lfe */ + GST_AUDIO_CHANNEL_POSITION_LFE1, /* 4 = lfe */ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, /* 5 = left surround */ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, /* 6 = right surround */ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, /* 7 = left rear */ @@ -221,12 +228,9 @@ gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE }; - GstAudioChannelPosition ch_layout[8] = { 0, }; guint speaker_pos; /* speaker position as defined by OSS */ guint i; - g_return_if_fail (num_channels <= G_N_ELEMENTS (ch_layout)); - for (i = 0; i < num_channels; ++i) { /* layout contains up to 16 speaker positions, with each taking up 4 bits */ speaker_pos = (guint) ((layout >> (i * 4)) & 0x0f); @@ -238,7 +242,7 @@ gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout, ch_layout[i] = pos_map[speaker_pos]; } - gst_audio_set_channel_positions (s, ch_layout); + return; no_layout: @@ -253,11 +257,64 @@ no_layout: for (i = 0; i < num_channels; ++i) { ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE; } - gst_audio_set_channel_positions (s, ch_layout); return; } } +static void +gst_oss4_audio_set_ringbuffer_channel_layout (GstObject * obj, gint fd, + GstAudioRingBufferSpec * spec) +{ + guint num_channels; + guint64 layout = 0; + GstAudioRingBuffer *rb; + GstAudioChannelPosition ch_layout[8] = { 0, }; + + num_channels = GST_AUDIO_INFO_CHANNELS (&spec->info); + if (num_channels < 3 || num_channels > 9) + return; + + if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) + return; + + if (GST_IS_OSS4_SINK (obj)) { + rb = GST_AUDIO_BASE_SINK (obj)->ringbuffer; + } else if (GST_IS_OSS4_SOURCE (obj)) { + rb = GST_AUDIO_BASE_SRC (obj)->ringbuffer; + } else + g_assert_not_reached (); + + /* -1 = get info for currently open device (fd). This will fail with + * OSS build <= 1013 because of a bug in OSS */ + if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) { + GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default"); + layout = CHNORDER_NORMAL; + } + GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout); + + + gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout); + gst_audio_ring_buffer_set_channel_positions (rb, ch_layout); + + return; +} + +static void +gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout, + guint num_channels, GstStructure * s) +{ + GstAudioChannelPosition ch_layout[8] = { 0, }; + guint64 mask; + + g_return_if_fail (num_channels <= G_N_ELEMENTS (ch_layout)); + + gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout); + if (gst_audio_channel_positions_to_mask (ch_layout, num_channels, &mask)) + gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, mask, NULL); + + return; +} + /* arbitrary max. limit */ #define GST_OSS4_MIN_CHANNELS 1 #define GST_OSS4_MAX_CHANNELS 4096 @@ -403,8 +460,8 @@ done: chan_s = gst_caps_get_structure (chan_caps, j); if ((val = gst_structure_get_value (chan_s, "channels"))) gst_structure_set_value (s, "channels", val); - if ((val = gst_structure_get_value (chan_s, "channel-positions"))) - gst_structure_set_value (s, "channel-positions", val); + if ((val = gst_structure_get_value (chan_s, "channel-mask"))) + gst_structure_set_value (s, "channel-mask", val); gst_caps_append_structure (out_caps, s); s = NULL; @@ -458,7 +515,7 @@ gst_oss4_audio_probe_caps (GstObject * obj, int fd) } } - caps = gst_caps_do_simplify (caps); + caps = gst_caps_simplify (caps); GST_LOG_OBJECT (obj, "formats: %" GST_PTR_FORMAT, caps); if (!gst_oss4_audio_detect_rates (obj, &ai, caps)) @@ -505,7 +562,7 @@ gst_oss4_audio_get_template_caps (void) gst_oss4_append_format_to_caps (&fmt_map[i], caps); } - caps = gst_caps_do_simplify (caps); + caps = gst_caps_simplify (caps); for (i = 0; i < gst_caps_get_size (caps); ++i) { GstStructure *s; @@ -521,17 +578,25 @@ gst_oss4_audio_get_template_caps (void) /* called by gst_oss4_sink_prepare() and gst_oss4_source_prepare() */ gboolean -gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec) +gst_oss4_audio_set_format (GstObject * obj, int fd, + GstAudioRingBufferSpec * spec) { struct audio_buf_info info = { 0, }; - int fmt, chans, rate; + int ofmt, fmt, chans, rate, width; + + fmt = gst_oss4_audio_get_oss_format (spec->type, + GST_AUDIO_INFO_FORMAT (&spec->info)); - fmt = gst_oss4_audio_get_oss_format (spec->format); if (fmt == 0) goto wrong_format; - if (spec->type == GST_BUFTYPE_LINEAR && spec->width != 32 && - spec->width != 24 && spec->width != 16 && spec->width != 8) { + ofmt = fmt; + chans = GST_AUDIO_INFO_CHANNELS (&spec->info); + rate = GST_AUDIO_INFO_RATE (&spec->info); + width = GST_AUDIO_INFO_WIDTH (&spec->info); + + if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && + width != 32 && width != 24 && width != 16 && width != 8) { goto dodgy_width; } @@ -541,14 +606,12 @@ gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec) goto set_format_failed; /* channels */ - GST_LOG_OBJECT (obj, "setting channels: %d", spec->channels); - chans = spec->channels; + GST_LOG_OBJECT (obj, "setting channels: %d", chans); if (ioctl (fd, SNDCTL_DSP_CHANNELS, &chans) == -1) goto set_channels_failed; /* rate */ - GST_LOG_OBJECT (obj, "setting rate: %d", spec->rate); - rate = spec->rate; + GST_LOG_OBJECT (obj, "setting rate: %d", rate); if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1) goto set_rate_failed; @@ -557,8 +620,8 @@ gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec) GST_DEBUG_OBJECT (obj, "effective rate : %d", rate); /* make sure format, channels, and rate are the ones we requested */ - if (fmt != gst_oss4_audio_get_oss_format (spec->format) || - chans != spec->channels || rate != spec->rate) { + if (fmt != ofmt || chans != GST_AUDIO_INFO_CHANNELS (&spec->info) || + rate != GST_AUDIO_INFO_RATE (&spec->info)) { /* This shouldn't happen, but hey */ goto format_not_what_was_requested; } @@ -579,24 +642,25 @@ gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec) * being too large, and the buffer will wrap. */ spec->segtotal = info.fragstotal + 4; - spec->bytes_per_sample = (spec->width / 8) * spec->channels; - GST_DEBUG_OBJECT (obj, "got segsize: %d, segtotal: %d, value: %08x", spec->segsize, spec->segtotal, info.fragsize); + gst_oss4_audio_set_ringbuffer_channel_layout (obj, fd, spec); + return TRUE; /* ERRORS */ wrong_format: { GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), - ("Unable to get format %d", spec->format)); + ("Unable to get format (%d, %d)", spec->type, + GST_AUDIO_INFO_FORMAT (&spec->info))); return FALSE; } dodgy_width: { GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), - ("unexpected width %d", spec->width)); + ("unexpected width %d", width)); return FALSE; } set_format_failed: @@ -664,8 +728,7 @@ gst_oss4_audio_find_device (GstObject * oss) GValueArray *arr; gchar *ret = NULL; - arr = gst_property_probe_probe_and_get_values_name (GST_PROPERTY_PROBE (oss), - "device"); + arr = gst_oss4_property_probe_get_values (GST_OBJECT (oss), "device"); if (arr != NULL) { if (arr->n_values > 0) { @@ -703,8 +766,7 @@ plugin_init (GstPlugin * plugin) rank = GST_RANK_SECONDARY + 1; if (!gst_element_register (plugin, "oss4sink", rank, GST_TYPE_OSS4_SINK) || - !gst_element_register (plugin, "oss4src", rank, GST_TYPE_OSS4_SOURCE) || - !gst_element_register (plugin, "oss4mixer", rank, GST_TYPE_OSS4_MIXER)) { + !gst_element_register (plugin, "oss4src", rank, GST_TYPE_OSS4_SOURCE)) { return FALSE; } diff --git a/sys/oss4/oss4-audio.h b/sys/oss4/oss4-audio.h index d220364173..fcfbb8e8cc 100644 --- a/sys/oss4/oss4-audio.h +++ b/sys/oss4/oss4-audio.h @@ -21,7 +21,7 @@ #define GST_OSS4_AUDIO_H_ #include -#include +#include /* This is the minimum version we require */ #define GST_MIN_OSS4_VERSION 0x040003 @@ -32,7 +32,7 @@ gboolean gst_oss4_audio_check_version (GstObject * obj, int fd); GstCaps * gst_oss4_audio_probe_caps (GstObject * obj, int fd); -gboolean gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec); +gboolean gst_oss4_audio_set_format (GstObject * obj, int fd, GstAudioRingBufferSpec * spec); GstCaps * gst_oss4_audio_get_template_caps (void); diff --git a/sys/oss4/oss4-mixer-enum.c b/sys/oss4/oss4-mixer-enum.c deleted file mode 100644 index 4b64bb1fc4..0000000000 --- a/sys/oss4/oss4-mixer-enum.c +++ /dev/null @@ -1,269 +0,0 @@ -/* GStreamer OSS4 mixer enumeration control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -/* An 'enum' in gnome-volume-control / GstMixer is represented by a - * GstMixerOptions object - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#define NO_LEGACY_MIXER -#include "oss4-mixer.h" -#include "oss4-mixer-enum.h" -#include "oss4-soundcard.h" - -GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); -#define GST_CAT_DEFAULT oss4mixer_debug - -static GList *gst_oss4_mixer_enum_get_values (GstMixerOptions * options); - -/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ -G_DEFINE_TYPE (GstOss4MixerEnum, gst_oss4_mixer_enum, GST_TYPE_MIXER_OPTIONS); - -static void -gst_oss4_mixer_enum_init (GstOss4MixerEnum * e) -{ - e->need_update = TRUE; -} - -static void -gst_oss4_mixer_enum_dispose (GObject * obj) -{ - GstMixerOptions *options = GST_MIXER_OPTIONS (obj); - - /* our list is a flat list with constant strings, but the GstMixerOptions - * dispose will try to g_free the contained strings, so clean up the list - * before chaining up to GstMixerOptions */ - g_list_free (options->values); - options->values = NULL; - - G_OBJECT_CLASS (gst_oss4_mixer_enum_parent_class)->dispose (obj); -} - -static void -gst_oss4_mixer_enum_class_init (GstOss4MixerEnumClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstMixerOptionsClass *mixeroptions_class = (GstMixerOptionsClass *) klass; - - gobject_class->dispose = gst_oss4_mixer_enum_dispose; - mixeroptions_class->get_values = gst_oss4_mixer_enum_get_values; -} - -static GList * -gst_oss4_mixer_enum_get_values_locked (GstMixerOptions * options) -{ - GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (options); - GList *oldlist, *list = NULL; - int i; - - /* if current list of values is empty, update/re-check in any case */ - if (!e->need_update && options->values != NULL) - return options->values; - - GST_LOG_OBJECT (e, "updating available values for %s", e->mc->mixext.extname); - - for (i = 0; i < e->mc->mixext.maxvalue; ++i) { - const gchar *s; - - s = g_quark_to_string (e->mc->enum_vals[i]); - if (MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) { - GST_LOG_OBJECT (e, "option '%s' is available", s); - list = g_list_prepend (list, (gpointer) s); - } else { - GST_LOG_OBJECT (e, "option '%s' is currently not available", s); - } - } - - list = g_list_reverse (list); - - /* this is not thread-safe, but then the entire GstMixer API isn't really, - * since we return foo->list and not a copy and don't take any locks, so - * not much we can do here but pray; we're usually either called from _new() - * or from within _get_values() though, so it should be okay. We could use - * atomic ops here, but I'm not sure how much more that really buys us.*/ - oldlist = options->values; /* keep window small */ - options->values = list; - g_list_free (oldlist); - - e->need_update = FALSE; - - return options->values; -} - -static GList * -gst_oss4_mixer_enum_get_values (GstMixerOptions * options) -{ - GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM (options); - GList *list; - - /* we take the lock here mostly to serialise ioctls with the watch thread */ - GST_OBJECT_LOCK (e->mixer); - - list = gst_oss4_mixer_enum_get_values_locked (options); - - GST_OBJECT_UNLOCK (e->mixer); - - return list; -} - -static const gchar * -gst_oss4_mixer_enum_get_current_value (GstOss4MixerEnum * e) -{ - const gchar *cur_val = NULL; - - if (e->mc->enum_vals != NULL && e->mc->last_val < e->mc->mixext.maxvalue) { - cur_val = g_quark_to_string (e->mc->enum_vals[e->mc->last_val]); - } - - return cur_val; -} - -static gboolean -gst_oss4_mixer_enum_update_current (GstOss4MixerEnum * e) -{ - int cur = -1; - - if (!gst_oss4_mixer_get_control_val (e->mixer, e->mc, &cur)) - return FALSE; - - if (cur < 0 || cur >= e->mc->mixext.maxvalue) { - GST_WARNING_OBJECT (e, "read value %d out of bounds [0-%d]", cur, - e->mc->mixext.maxvalue - 1); - e->mc->last_val = 0; - return FALSE; - } - - return TRUE; -} - -gboolean -gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value) -{ - GQuark q; - int i; - - q = g_quark_try_string (value); - if (q == 0) { - GST_WARNING_OBJECT (e, "unknown option '%s'", value); - return FALSE; - } - - for (i = 0; i < e->mc->mixext.maxvalue; ++i) { - if (q == e->mc->enum_vals[i]) - break; - } - - if (i >= e->mc->mixext.maxvalue) { - GST_WARNING_OBJECT (e, "option '%s' is not valid for this control", value); - return FALSE; - } - - GST_LOG_OBJECT (e, "option '%s' = %d", value, i); - - if (!MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) { - GST_WARNING_OBJECT (e, "option '%s' is not selectable currently", value); - return FALSE; - } - - if (!gst_oss4_mixer_set_control_val (e->mixer, e->mc, i)) { - GST_WARNING_OBJECT (e, "could not set option '%s' (%d)", value, i); - return FALSE; - } - - /* and re-read current value with sanity checks (or could just assign here) */ - gst_oss4_mixer_enum_update_current (e); - - return TRUE; -} - -const gchar * -gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e) -{ - const gchar *cur_str = NULL; - - if (!gst_oss4_mixer_enum_update_current (e)) { - GST_WARNING_OBJECT (e, "failed to read current value"); - return NULL; - } - - cur_str = gst_oss4_mixer_enum_get_current_value (e); - GST_LOG_OBJECT (e, "%s (%d)", GST_STR_NULL (cur_str), e->mc->last_val); - return cur_str; -} - -GstMixerTrack * -gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) -{ - GstOss4MixerEnum *e; - GstMixerTrack *track; - - e = g_object_new (GST_TYPE_OSS4_MIXER_ENUM, "untranslated-label", - mc->mixext.extname, NULL); - e->mixer = mixer; - e->mc = mc; - - track = GST_MIXER_TRACK (e); - - /* caller will set track->label and track->flags */ - - track->num_channels = 0; - track->min_volume = 0; - track->max_volume = 0; - - (void) gst_oss4_mixer_enum_get_values_locked (GST_MIXER_OPTIONS (track)); - - if (!gst_oss4_mixer_enum_update_current (e)) { - GST_WARNING_OBJECT (track, "failed to read current value, returning NULL"); - g_object_unref (track); - track = NULL; - } - - GST_LOG_OBJECT (e, "current value: %d (%s)", e->mc->last_val, - gst_oss4_mixer_enum_get_current_value (e)); - - return track; -} - -/* This is called from the watch thread */ -void -gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track) -{ - GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (track); - - gchar *cur; - - if (!e->mc->changed && !e->mc->list_changed) - return; - - if (e->mc->list_changed) { - gst_mixer_options_list_changed (GST_MIXER (e->mixer), - GST_MIXER_OPTIONS (e)); - } - - GST_OBJECT_LOCK (e->mixer); - cur = (gchar *) gst_oss4_mixer_enum_get_current_value (e); - GST_OBJECT_UNLOCK (e->mixer); - - gst_mixer_option_changed (GST_MIXER (e->mixer), GST_MIXER_OPTIONS (e), cur); -} diff --git a/sys/oss4/oss4-mixer-enum.h b/sys/oss4/oss4-mixer-enum.h deleted file mode 100644 index 9fd8166907..0000000000 --- a/sys/oss4/oss4-mixer-enum.h +++ /dev/null @@ -1,67 +0,0 @@ -/* GStreamer OSS4 mixer on/off enum control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -#ifndef GST_OSS4_MIXER_ENUM_H -#define GST_OSS4_MIXER_ENUM_H - -#include -#include - -#include "oss4-mixer.h" - -G_BEGIN_DECLS - -#define GST_TYPE_OSS4_MIXER_ENUM (gst_oss4_mixer_enum_get_type()) -#define GST_OSS4_MIXER_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_ENUM,GstOss4MixerEnum)) -#define GST_OSS4_MIXER_ENUM_CAST(obj) ((GstOss4MixerEnum *)(obj)) -#define GST_OSS4_MIXER_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_ENUM,GstOss4MixerEnumClass)) -#define GST_IS_OSS4_MIXER_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_ENUM)) -#define GST_IS_OSS4_MIXER_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_ENUM)) - -typedef struct _GstOss4MixerEnum GstOss4MixerEnum; -typedef struct _GstOss4MixerEnumClass GstOss4MixerEnumClass; - -struct _GstOss4MixerEnum { - GstMixerOptions mixer_option; - - GstOss4MixerControl * mc; - GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ - - gboolean need_update; -}; - -struct _GstOss4MixerEnumClass { - GstMixerOptionsClass mixer_option_class; -}; - -GType gst_oss4_mixer_enum_get_type (void); - -gboolean gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value); - -const gchar * gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e); - -GstMixerTrack * gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); - -void gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track); - -G_END_DECLS - -#endif /* GST_OSS4_MIXER_ENUM_H */ - - diff --git a/sys/oss4/oss4-mixer-slider.c b/sys/oss4/oss4-mixer-slider.c deleted file mode 100644 index e71d1348fe..0000000000 --- a/sys/oss4/oss4-mixer-slider.c +++ /dev/null @@ -1,311 +0,0 @@ -/* GStreamer OSS4 mixer slider control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -/* A 'slider' in gnome-volume-control / GstMixer is represented by a - * GstMixerTrack with one or more channels. - * - * A slider should be either flagged as INPUT or OUTPUT (mostly because of - * gnome-volume-control being littered with g_asserts for everything it doesn't - * expect). - * - * From mixertrack.h: - * "Input tracks can have 'recording' enabled, which means that any input will - * be hearable into the speakers that are attached to the output. Mute is - * obvious." - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define NO_LEGACY_MIXER -#include "oss4-mixer-slider.h" - -GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); -#define GST_CAT_DEFAULT oss4mixer_debug - -/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ -G_DEFINE_TYPE (GstOss4MixerSlider, gst_oss4_mixer_slider, GST_TYPE_MIXER_TRACK); - -static void -gst_oss4_mixer_slider_class_init (GstOss4MixerSliderClass * klass) -{ - /* nothing to do here */ -} - -static void -gst_oss4_mixer_slider_init (GstOss4MixerSlider * s) -{ - /* nothing to do here */ -} - -static int -gst_oss4_mixer_slider_pack_volume (GstOss4MixerSlider * s, const gint * volumes) -{ - int val = 0; - - switch (s->mc->mixext.type) { - case MIXT_MONOSLIDER: - case MIXT_MONOSLIDER16: - case MIXT_SLIDER: - val = volumes[0]; - break; - case MIXT_STEREOSLIDER: - val = ((volumes[1] & 0xff) << 8) | (volumes[0] & 0xff); - break; - case MIXT_STEREOSLIDER16: - val = ((volumes[1] & 0xffff) << 16) | (volumes[0] & 0xffff); - break; - default: - g_return_val_if_reached (0); - } - return val; -} - -static void -gst_oss4_mixer_slider_unpack_volume (GstOss4MixerSlider * s, int v, - gint * volumes) -{ - guint32 val; /* use uint so bitshifting the highest bit works right */ - - val = (guint32) v; - switch (s->mc->mixext.type) { - case MIXT_SLIDER: - volumes[0] = val; - break; - case MIXT_MONOSLIDER: - /* oss repeats the value in the upper bits, as if it was stereo */ - volumes[0] = val & 0x00ff; - break; - case MIXT_MONOSLIDER16: - /* oss repeats the value in the upper bits, as if it was stereo */ - volumes[0] = val & 0x0000ffff; - break; - case MIXT_STEREOSLIDER: - volumes[0] = (val & 0x00ff); - volumes[1] = (val & 0xff00) >> 8; - break; - case MIXT_STEREOSLIDER16: - volumes[0] = (val & 0x0000ffff); - volumes[1] = (val & 0xffff0000) >> 16; - break; - default: - g_return_if_reached (); - } -} - -gboolean -gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes) -{ - GstMixerTrack *track = GST_MIXER_TRACK (s); - int v = 0; - - /* if we're supposed to be muted, and don't have an actual mute control - * (ie. 'simulate' the mute), then just return the volume as saved, not - * the actually set volume which is most likely 0 */ - if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) { - volumes[0] = s->volumes[0]; - if (track->num_channels == 2) - volumes[1] = s->volumes[1]; - return TRUE; - } - - if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &v)) - return FALSE; - - gst_oss4_mixer_slider_unpack_volume (s, v, volumes); - - if (track->num_channels > 1) { - GST_LOG_OBJECT (s, "volume: left=%d, right=%d", volumes[0], volumes[1]); - } else { - GST_LOG_OBJECT (s, "volume: mono=%d", volumes[0]); - } - - return TRUE; -} - -gboolean -gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes) -{ - GstMixerTrack *track = GST_MIXER_TRACK (s); - int val = 0; - - /* if we're supposed to be muted, and are 'simulating' the mute because - * we don't have a mute control, don't actually change the volume, just - * save it as the new desired volume for later when we get unmuted again */ - if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE)) { - if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) - goto done; - } - - val = gst_oss4_mixer_slider_pack_volume (s, volumes); - - if (track->num_channels > 1) { - GST_LOG_OBJECT (s, "left=%d, right=%d", volumes[0], volumes[1]); - } else { - GST_LOG_OBJECT (s, "mono=%d", volumes[0]); - } - - if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, val)) - return FALSE; - -done: - - s->volumes[0] = volumes[0]; - if (track->num_channels == 2) - s->volumes[1] = volumes[1]; - - return TRUE; -} - -gboolean -gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record) -{ - /* There doesn't seem to be a way to do this using the OSS4 mixer API, so - * just do nothing here for now. */ - return FALSE; -} - -gboolean -gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute) -{ - GstMixerTrack *track = GST_MIXER_TRACK (s); - gboolean ret; - - /* if the control does not support muting, then do not do anything */ - if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE)) { - return TRUE; - } - - /* If we do not have a mute control, simulate mute (which is a bit broken, - * since we can not differentiate between capture/playback volume etc., so - * we just assume that setting the volume to 0 would be the same as muting - * this control) */ - if (s->mc->mute == NULL) { - int volume; - - if (mute) { - /* make sure the current volume values get saved. */ - gst_oss4_mixer_slider_get_volume (s, s->volumes); - volume = 0; - } else { - volume = gst_oss4_mixer_slider_pack_volume (s, s->volumes); - } - ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc, volume); - } else { - ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, !!mute); - } - - if (mute) { - track->flags |= GST_MIXER_TRACK_MUTE; - } else { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } - - return ret; -} - -GstMixerTrack * -gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) -{ - GstOss4MixerSlider *s; - GstMixerTrack *track; - gint volumes[2] = { 0, }; - - s = g_object_new (GST_TYPE_OSS4_MIXER_SLIDER, "untranslated-label", - mc->mixext.extname, NULL); - - track = GST_MIXER_TRACK (s); - - /* caller will set track->label and track->flags */ - - s->mc = mc; - s->mixer = mixer; - - /* we don't do value scaling but just present a scale of 0-maxvalue */ - track->min_volume = 0; - track->max_volume = mc->mixext.maxvalue; - - switch (mc->mixext.type) { - case MIXT_MONOSLIDER: - case MIXT_MONOSLIDER16: - case MIXT_SLIDER: - track->num_channels = 1; - break; - case MIXT_STEREOSLIDER: - case MIXT_STEREOSLIDER16: - track->num_channels = 2; - break; - default: - g_return_val_if_reached (NULL); - } - - GST_LOG_OBJECT (track, "min=%d, max=%d, channels=%d", track->min_volume, - track->max_volume, track->num_channels); - - if (!gst_oss4_mixer_slider_get_volume (s, volumes)) { - GST_WARNING_OBJECT (track, "failed to read volume, returning NULL"); - g_object_unref (track); - track = NULL; - } - - return track; -} - -/* This is called from the watch thread */ -void -gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track) -{ - GstOss4MixerSlider *s = GST_OSS4_MIXER_SLIDER_CAST (track); - - if (s->mc->mute != NULL && s->mc->mute->changed) { - gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, - !!s->mc->mute->last_val); - } else { - /* nothing to do here, since we don't/can't easily implement the record - * flag */ - } - - if (s->mc->changed) { - gint volumes[2] = { 0, 0 }; - - gst_oss4_mixer_slider_unpack_volume (s, s->mc->last_val, volumes); - - /* if we 'simulate' the mute, update flag when the volume changes */ - if (s->mc->mute == NULL) { - if (volumes[0] == 0 && volumes[1] == 0) { - track->flags |= GST_MIXER_TRACK_MUTE; - } else { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } - } - - gst_mixer_volume_changed (GST_MIXER (s->mixer), track, volumes); - } -} diff --git a/sys/oss4/oss4-mixer-slider.h b/sys/oss4/oss4-mixer-slider.h deleted file mode 100644 index 3bee33f806..0000000000 --- a/sys/oss4/oss4-mixer-slider.h +++ /dev/null @@ -1,70 +0,0 @@ -/* GStreamer OSS4 mixer slider control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -#ifndef GST_OSS4_MIXER_SLIDER_H -#define GST_OSS4_MIXER_SLIDER_H - -#include -#include - -#include "oss4-mixer.h" - -G_BEGIN_DECLS - -#define GST_TYPE_OSS4_MIXER_SLIDER (gst_oss4_mixer_slider_get_type()) -#define GST_OSS4_MIXER_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_SLIDER,GstOss4MixerSlider)) -#define GST_OSS4_MIXER_SLIDER_CAST(obj) ((GstOss4MixerSlider *)(obj)) -#define GST_OSS4_MIXER_SLIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_SLIDER,GstOss4MixerSliderClass)) -#define GST_IS_OSS4_MIXER_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_SLIDER)) -#define GST_IS_OSS4_MIXER_SLIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_SLIDER)) - -typedef struct _GstOss4MixerSlider GstOss4MixerSlider; -typedef struct _GstOss4MixerSliderClass GstOss4MixerSliderClass; - -struct _GstOss4MixerSlider { - GstMixerTrack mixer_track; - - GstOss4MixerControl * mc; - GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ - gint volumes[2]; /* left/mono, right */ -}; - -struct _GstOss4MixerSliderClass { - GstMixerTrackClass mixer_track_class; -}; - -GType gst_oss4_mixer_slider_get_type (void); - -GstMixerTrack * gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); - -gboolean gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes); - -gboolean gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes); - -gboolean gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record); - -gboolean gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute); - -void gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track); - -G_END_DECLS - -#endif /* GST_OSS4_MIXER_SLIDER_H */ - - diff --git a/sys/oss4/oss4-mixer-switch.c b/sys/oss4/oss4-mixer-switch.c deleted file mode 100644 index 0a6ce5b93d..0000000000 --- a/sys/oss4/oss4-mixer-switch.c +++ /dev/null @@ -1,150 +0,0 @@ -/* GStreamer OSS4 mixer on/off switch control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -/* A simple ON/OFF 'switch' in gnome-volume-control / GstMixer is represented - * by a GstMixerTrack with no channels. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#define NO_LEGACY_MIXER -#include "oss4-mixer-switch.h" -#include "oss4-soundcard.h" - -GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); -#define GST_CAT_DEFAULT oss4mixer_debug - -/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ -G_DEFINE_TYPE (GstOss4MixerSwitch, gst_oss4_mixer_switch, GST_TYPE_MIXER_TRACK); - -static void -gst_oss4_mixer_switch_class_init (GstOss4MixerSwitchClass * klass) -{ - /* nothing to do here */ -} - -static void -gst_oss4_mixer_switch_init (GstOss4MixerSwitch * s) -{ - /* nothing to do here */ -} - -gboolean -gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean disabled) -{ - GstMixerTrack *track; - int newval; - - track = GST_MIXER_TRACK (s); - - newval = disabled ? GST_MIXER_TRACK_MUTE : 0; - - if (newval == (track->flags & GST_MIXER_TRACK_MUTE)) { - GST_LOG_OBJECT (s, "switch is already %d, doing nothing", newval); - return TRUE; - } - - if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, !disabled)) { - GST_WARNING_OBJECT (s, "could not set switch to %d", !disabled); - return FALSE; - } - - if (disabled) { - track->flags |= GST_MIXER_TRACK_MUTE; - } else { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } - - GST_LOG_OBJECT (s, "set switch to %d", newval); - - return TRUE; -} - -gboolean -gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean * disabled) -{ - GstMixerTrack *track; - int enabled = -1; - - track = GST_MIXER_TRACK (s); - - if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &enabled) - || (enabled < 0)) { - GST_WARNING_OBJECT (s, "could not get switch state"); - return FALSE; - } - - if (enabled) { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } else { - track->flags |= GST_MIXER_TRACK_MUTE; - } - *disabled = (enabled == 0); - - return TRUE; -} - -GstMixerTrack * -gst_oss4_mixer_switch_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) -{ - GstOss4MixerSwitch *s; - GstMixerTrack *track; - int cur = -1; - - s = g_object_new (GST_TYPE_OSS4_MIXER_SWITCH, "untranslated-label", - mc->mixext.extname, NULL); - - s->mixer = mixer; - s->mc = mc; - - track = GST_MIXER_TRACK (s); - - /* caller will set track->label and track->flags */ - - track->num_channels = 0; - track->min_volume = 0; - track->max_volume = 0; - - if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &cur) || cur < 0) - return NULL; - - if (cur) { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } else { - track->flags |= GST_MIXER_TRACK_MUTE; - } - - return track; -} - -/* This is called from the watch thread */ -void -gst_oss4_mixer_switch_process_change_unlocked (GstMixerTrack * track) -{ - GstOss4MixerSwitch *s = GST_OSS4_MIXER_SWITCH_CAST (track); - - if (!s->mc->changed) - return; - - gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, !s->mc->last_val); -} diff --git a/sys/oss4/oss4-mixer-switch.h b/sys/oss4/oss4-mixer-switch.h deleted file mode 100644 index a8ab83ffab..0000000000 --- a/sys/oss4/oss4-mixer-switch.h +++ /dev/null @@ -1,65 +0,0 @@ -/* GStreamer OSS4 mixer on/off switch control - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -#ifndef GST_OSS4_MIXER_SWITCH_H -#define GST_OSS4_MIXER_SWITCH_H - -#include -#include - -#include "oss4-mixer.h" - -G_BEGIN_DECLS - -#define GST_TYPE_OSS4_MIXER_SWITCH (gst_oss4_mixer_switch_get_type()) -#define GST_OSS4_MIXER_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_SWITCH,GstOss4MixerSwitch)) -#define GST_OSS4_MIXER_SWITCH_CAST(obj) ((GstOss4MixerSwitch *)(obj)) -#define GST_OSS4_MIXER_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_SWITCH,GstOss4MixerSwitchClass)) -#define GST_IS_OSS4_MIXER_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_SWITCH)) -#define GST_IS_OSS4_MIXER_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_SWITCH)) - -typedef struct _GstOss4MixerSwitch GstOss4MixerSwitch; -typedef struct _GstOss4MixerSwitchClass GstOss4MixerSwitchClass; - -struct _GstOss4MixerSwitch { - GstMixerTrack mixer_track; - - GstOss4MixerControl * mc; - GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ -}; - -struct _GstOss4MixerSwitchClass { - GstMixerTrackClass mixer_track_class; -}; - -GType gst_oss4_mixer_switch_get_type (void); - -gboolean gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean enabled); - -gboolean gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean * enabled); - -GstMixerTrack * gst_oss4_mixer_switch_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); - -void gst_oss4_mixer_switch_process_change_unlocked (GstMixerTrack * track); - -G_END_DECLS - -#endif /* GST_OSS4_MIXER_SWITCH_H */ - - diff --git a/sys/oss4/oss4-mixer.c b/sys/oss4/oss4-mixer.c deleted file mode 100644 index b1e652bc37..0000000000 --- a/sys/oss4/oss4-mixer.c +++ /dev/null @@ -1,1857 +0,0 @@ -/* GStreamer OSS4 mixer implementation - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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 mixer library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-oss4mixer - * - * This element lets you adjust sound input and output levels with the - * Open Sound System (OSS) version 4. It supports the GstMixer interface, which - * can be used to obtain a list of available mixer tracks. Set the mixer - * element to READY state before using the GstMixer interface on it. - * - * - * Example pipelines - * - * oss4mixer can't be used in a sensible way in gst-launch. - * - * - * - * Since: 0.10.7 - */ - -/* Note: ioctl calls on the same open mixer device are serialised via - * the object lock to make sure we don't do concurrent ioctls from two - * different threads (e.g. app thread and mixer watch thread), since that - * will probably confuse OSS. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "gst/glib-compat-private.h" - -#include - -#define NO_LEGACY_MIXER - -#include "oss4-audio.h" -#include "oss4-mixer.h" -#include "oss4-mixer-enum.h" -#include "oss4-mixer-slider.h" -#include "oss4-mixer-switch.h" -#include "oss4-property-probe.h" -#include "oss4-soundcard.h" - -#define GST_OSS4_MIXER_WATCH_INTERVAL 500 /* in millisecs, ie. 0.5s */ - -GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); -#define GST_CAT_DEFAULT oss4mixer_debug - -#define DEFAULT_DEVICE NULL -#define DEFAULT_DEVICE_NAME NULL - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME -}; - -static void gst_oss4_mixer_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstOss4Mixer, gst_oss4_mixer, GstElement, - GST_TYPE_ELEMENT, gst_oss4_mixer_init_interfaces); - -static GstStateChangeReturn gst_oss4_mixer_change_state (GstElement * - element, GstStateChange transition); - -static void gst_oss4_mixer_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_oss4_mixer_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_oss4_mixer_finalize (GObject * object); - -static gboolean gst_oss4_mixer_open (GstOss4Mixer * mixer, - gboolean silent_errors); -static void gst_oss4_mixer_close (GstOss4Mixer * mixer); - -static gboolean gst_oss4_mixer_enum_control_update_enum_list (GstOss4Mixer * m, - GstOss4MixerControl * mc); - -#ifndef GST_DISABLE_GST_DEBUG -static const gchar *mixer_ext_type_get_name (gint type); -static const gchar *mixer_ext_flags_get_string (gint flags); -#endif - -static void -gst_oss4_mixer_base_init (gpointer klass) -{ - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), - "OSS v4 Audio Mixer", "Generic/Audio", - "Control sound input and output levels with OSS4", - "Tim-Philipp Müller "); -} - -static void -gst_oss4_mixer_class_init (GstOss4MixerClass * klass) -{ - GstElementClass *element_class; - GObjectClass *gobject_class; - - element_class = (GstElementClass *) klass; - gobject_class = (GObjectClass *) klass; - - gobject_class->finalize = gst_oss4_mixer_finalize; - gobject_class->set_property = gst_oss4_mixer_set_property; - gobject_class->get_property = gst_oss4_mixer_get_property; - - /** - * GstOss4Mixer:device - * - * OSS4 mixer device (e.g. /dev/oss/hdaudio0/mix0 or /dev/mixerN) - * - **/ - g_object_class_install_property (gobject_class, PROP_DEVICE, - g_param_spec_string ("device", "Device", - "OSS mixer device (e.g. /dev/oss/hdaudio0/mix0 or /dev/mixerN) " - "(NULL = use first mixer device found)", DEFAULT_DEVICE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstOss4Mixer:device-name - * - * Human-readable name of the sound device. May be NULL if the device is - * not open (ie. when the mixer is in NULL state) - * - **/ - g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, - g_param_spec_string ("device-name", "Device name", - "Human-readable name of the sound device", DEFAULT_DEVICE_NAME, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_oss4_mixer_change_state); -} - -static void -gst_oss4_mixer_finalize (GObject * obj) -{ - GstOss4Mixer *mixer = GST_OSS4_MIXER (obj); - - g_free (mixer->device); - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_oss4_mixer_reset (GstOss4Mixer * mixer) -{ - mixer->fd = -1; - mixer->need_update = TRUE; - memset (&mixer->last_mixext, 0, sizeof (oss_mixext)); -} - -static void -gst_oss4_mixer_init (GstOss4Mixer * mixer, GstOss4MixerClass * g_class) -{ - mixer->device = g_strdup (DEFAULT_DEVICE); - mixer->device_name = NULL; - - gst_oss4_mixer_reset (mixer); -} - -static void -gst_oss4_mixer_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstOss4Mixer *mixer = GST_OSS4_MIXER (object); - - switch (prop_id) { - case PROP_DEVICE: - GST_OBJECT_LOCK (mixer); - if (!GST_OSS4_MIXER_IS_OPEN (mixer)) { - g_free (mixer->device); - mixer->device = g_value_dup_string (value); - /* unset any cached device-name */ - g_free (mixer->device_name); - mixer->device_name = NULL; - } else { - g_warning ("%s: can't change \"device\" property while mixer is open", - GST_OBJECT_NAME (mixer)); - } - GST_OBJECT_UNLOCK (mixer); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_oss4_mixer_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstOss4Mixer *mixer = GST_OSS4_MIXER (object); - - switch (prop_id) { - case PROP_DEVICE: - GST_OBJECT_LOCK (mixer); - g_value_set_string (value, mixer->device); - GST_OBJECT_UNLOCK (mixer); - break; - case PROP_DEVICE_NAME: - GST_OBJECT_LOCK (mixer); - /* If device is set, try to retrieve the name even if we're not open */ - if (mixer->fd == -1 && mixer->device != NULL) { - if (gst_oss4_mixer_open (mixer, TRUE)) { - g_value_set_string (value, mixer->device_name); - gst_oss4_mixer_close (mixer); - } else { - g_value_set_string (value, mixer->device_name); - } - } else { - g_value_set_string (value, mixer->device_name); - } - GST_OBJECT_UNLOCK (mixer); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_oss4_mixer_open (GstOss4Mixer * mixer, gboolean silent_errors) -{ - struct oss_mixerinfo mi = { 0, }; - gchar *device; - - g_return_val_if_fail (!GST_OSS4_MIXER_IS_OPEN (mixer), FALSE); - - if (mixer->device) - device = g_strdup (mixer->device); - else - device = gst_oss4_audio_find_device (GST_OBJECT_CAST (mixer)); - - /* desperate times, desperate measures */ - if (device == NULL) - device = g_strdup ("/dev/mixer"); - - GST_INFO_OBJECT (mixer, "Trying to open OSS4 mixer device '%s'", device); - - mixer->fd = open (device, O_RDWR, 0); - if (mixer->fd < 0) - goto open_failed; - - /* Make sure it's OSS4. If it's old OSS, let the old ossmixer handle it */ - if (!gst_oss4_audio_check_version (GST_OBJECT (mixer), mixer->fd)) - goto legacy_oss; - - GST_INFO_OBJECT (mixer, "Opened mixer device '%s', which is mixer %d", - device, mi.dev); - - /* Get device name for currently open fd */ - mi.dev = -1; - if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == 0) { - mixer->modify_counter = mi.modify_counter; - if (mi.name[0] != '\0') { - mixer->device_name = g_strdup (mi.name); - } - } else { - mixer->modify_counter = 0; - } - - if (mixer->device_name == NULL) { - mixer->device_name = g_strdup ("Unknown"); - } - GST_INFO_OBJECT (mixer, "device name = '%s'", mixer->device_name); - - mixer->open_device = device; - - return TRUE; - - /* ERRORS */ -open_failed: - { - if (!silent_errors) { - GST_ELEMENT_ERROR (mixer, RESOURCE, OPEN_READ_WRITE, - (_("Could not open audio device for mixer control handling.")), - GST_ERROR_SYSTEM); - } else { - GST_DEBUG_OBJECT (mixer, "open failed: %s (ignoring errors)", - g_strerror (errno)); - } - g_free (device); - return FALSE; - } -legacy_oss: - { - gst_oss4_mixer_close (mixer); - if (!silent_errors) { - GST_ELEMENT_ERROR (mixer, RESOURCE, OPEN_READ_WRITE, - (_("Could not open audio device for mixer control handling. " - "This version of the Open Sound System is not supported by this " - "element.")), ("Try the 'ossmixer' element instead")); - } else { - GST_DEBUG_OBJECT (mixer, "open failed: legacy oss (ignoring errors)"); - } - g_free (device); - return FALSE; - } -} - -static void -gst_oss4_mixer_control_free (GstOss4MixerControl * mc) -{ - g_list_free (mc->children); - g_list_free (mc->mute_group); - g_free (mc->enum_vals); - memset (mc, 0, sizeof (GstOss4MixerControl)); - g_free (mc); -} - -static void -gst_oss4_mixer_free_tracks (GstOss4Mixer * mixer) -{ - g_list_foreach (mixer->tracks, (GFunc) g_object_unref, NULL); - g_list_free (mixer->tracks); - mixer->tracks = NULL; - - g_list_foreach (mixer->controls, (GFunc) gst_oss4_mixer_control_free, NULL); - g_list_free (mixer->controls); - mixer->controls = NULL; -} - -static void -gst_oss4_mixer_close (GstOss4Mixer * mixer) -{ - g_free (mixer->device_name); - mixer->device_name = NULL; - - g_free (mixer->open_device); - mixer->open_device = NULL; - - gst_oss4_mixer_free_tracks (mixer); - - if (mixer->fd != -1) { - close (mixer->fd); - mixer->fd = -1; - } - - gst_oss4_mixer_reset (mixer); -} - -static void -gst_oss4_mixer_watch_process_changes (GstOss4Mixer * mixer) -{ - GList *c, *t, *tracks = NULL; - - GST_INFO_OBJECT (mixer, "mixer interface or control changed"); - - /* this is all with the mixer object lock held */ - - /* we go through the list backwards so we can bail out faster when the entire - * interface needs to be rebuilt */ - for (c = g_list_last (mixer->controls); c != NULL; c = c->prev) { - GstOss4MixerControl *mc = c->data; - oss_mixer_value ossval = { 0, }; - - mc->changed = FALSE; - mc->list_changed = FALSE; - - /* not interested in controls we don't expose in the mixer interface */ - if (!mc->used) - continue; - - /* don't try to read a value from controls that don't have one */ - if (mc->mixext.type == MIXT_DEVROOT || mc->mixext.type == MIXT_GROUP) - continue; - - /* is this an enum control whose list may change? */ - if (mc->mixext.type == MIXT_ENUM && mc->enum_version != 0) { - if (gst_oss4_mixer_enum_control_update_enum_list (mixer, mc)) - mc->list_changed = TRUE; - } - - ossval.dev = mc->mixext.dev; - ossval.ctrl = mc->mixext.ctrl; - ossval.timestamp = mc->mixext.timestamp; - - if (ioctl (mixer->fd, SNDCTL_MIX_READ, &ossval) == -1) { - if (errno == EIDRM || errno == EFAULT) { - GST_DEBUG ("%s has disappeared", mc->mixext.extname); - goto mixer_changed; - } - GST_WARNING_OBJECT (mixer, "MIX_READ failed: %s", g_strerror (errno)); - /* just ignore, move on to next one */ - continue; - } - - if (ossval.value == mc->last_val) { /* no change */ - /* GST_LOG_OBJECT (mixer, "%s hasn't changed", mc->mixext.extname); */ - continue; - } - - mc->last_val = ossval.value; - GST_LOG_OBJECT (mixer, "%s changed value to %u 0x%08x", - mc->mixext.extname, ossval.value, ossval.value); - mc->changed = TRUE; - } - - /* copy list and take track refs, so we can safely drop the object lock, - * which we need to do to be able to post messages on the bus */ - tracks = g_list_copy (mixer->tracks); - g_list_foreach (tracks, (GFunc) g_object_ref, NULL); - - GST_OBJECT_UNLOCK (mixer); - - /* since we don't know (or want to know exactly) which controls belong to - * which track, we just go through the tracks one-by-one now and make them - * check themselves if any of their controls have changed and which messages - * to post on the bus as a result */ - for (t = tracks; t != NULL; t = t->next) { - GstMixerTrack *track = t->data; - - if (GST_IS_OSS4_MIXER_SLIDER (track)) { - gst_oss4_mixer_slider_process_change_unlocked (track); - } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { - gst_oss4_mixer_switch_process_change_unlocked (track); - } else if (GST_IS_OSS4_MIXER_ENUM (track)) { - gst_oss4_mixer_enum_process_change_unlocked (track); - } - - g_object_unref (track); - } - g_list_free (tracks); - - GST_OBJECT_LOCK (mixer); - return; - -mixer_changed: - { - GST_OBJECT_UNLOCK (mixer); - gst_mixer_mixer_changed (GST_MIXER (mixer)); - GST_OBJECT_LOCK (mixer); - return; - } -} - -/* This thread watches the mixer for changes in a somewhat inefficient way - * (running an ioctl every half second or so). This is still better and - * cheaper than apps polling all tracks for changes a few times a second - * though. Needs more thought. There's probably (hopefully) a way to get - * notifications via the fd directly somehow. */ -static gpointer -gst_oss4_mixer_watch_thread (gpointer thread_data) -{ - GstOss4Mixer *mixer = GST_OSS4_MIXER_CAST (thread_data); - - GST_DEBUG_OBJECT (mixer, "watch thread running"); - - GST_OBJECT_LOCK (mixer); - while (!mixer->watch_shutdown) { - oss_mixerinfo mi = { 0, }; - GTimeVal tv; - - mi.dev = -1; - if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == 0) { - if (mixer->modify_counter != mi.modify_counter) { - /* GST_LOG ("processing changes"); */ - gst_oss4_mixer_watch_process_changes (mixer); - mixer->modify_counter = mi.modify_counter; - } else { - /* GST_LOG ("no changes"); */ - } - } else { - GST_WARNING_OBJECT (mixer, "MIXERINFO failed: %s", g_strerror (errno)); - } - - /* we could move the _get_current_time out of the loop and just do the - * add in ever iteration, which would be less exact, but who cares */ - g_get_current_time (&tv); - g_time_val_add (&tv, GST_OSS4_MIXER_WATCH_INTERVAL * 1000); - (void) g_cond_timed_wait (mixer->watch_cond, GST_OBJECT_GET_LOCK (mixer), - &tv); - } - GST_OBJECT_UNLOCK (mixer); - - GST_DEBUG_OBJECT (mixer, "watch thread done"); - gst_object_unref (mixer); - return NULL; -} - -/* call with object lock held */ -static void -gst_oss4_mixer_wake_up_watch_task (GstOss4Mixer * mixer) -{ - GST_LOG_OBJECT (mixer, "signalling watch thread to wake up"); - g_cond_signal (mixer->watch_cond); -} - -static void -gst_oss4_mixer_stop_watch_task (GstOss4Mixer * mixer) -{ - if (mixer->watch_thread) { - GST_OBJECT_LOCK (mixer); - mixer->watch_shutdown = TRUE; - GST_LOG_OBJECT (mixer, "signalling watch thread to stop"); - g_cond_signal (mixer->watch_cond); - GST_OBJECT_UNLOCK (mixer); - GST_LOG_OBJECT (mixer, "waiting for watch thread to join"); - g_thread_join (mixer->watch_thread); - GST_DEBUG_OBJECT (mixer, "watch thread stopped"); - mixer->watch_thread = NULL; - } - - if (mixer->watch_cond) { - g_cond_free (mixer->watch_cond); - mixer->watch_cond = NULL; - } -} - -static void -gst_oss4_mixer_start_watch_task (GstOss4Mixer * mixer) -{ - GError *err = NULL; - - mixer->watch_cond = g_cond_new (); - mixer->watch_shutdown = FALSE; - - mixer->watch_thread = g_thread_try_new ("oss4-mixer-thread", - gst_oss4_mixer_watch_thread, gst_object_ref (mixer), &err); - - if (mixer->watch_thread == NULL) { - GST_ERROR_OBJECT (mixer, "Could not create watch thread: %s", err->message); - g_cond_free (mixer->watch_cond); - mixer->watch_cond = NULL; - g_error_free (err); - } -} - -static GstStateChangeReturn -gst_oss4_mixer_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstOss4Mixer *mixer = GST_OSS4_MIXER (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_oss4_mixer_open (mixer, FALSE)) - return GST_STATE_CHANGE_FAILURE; - gst_oss4_mixer_start_watch_task (mixer); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_oss4_mixer_stop_watch_task (mixer); - gst_oss4_mixer_close (mixer); - break; - default: - break; - } - - return ret; -} - -/* === GstMixer interface === */ - -static inline gboolean -gst_oss4_mixer_contains_track (GstMixer * mixer, GstMixerTrack * track) -{ - return (g_list_find (GST_OSS4_MIXER (mixer)->tracks, track) != NULL); -} - -static inline gboolean -gst_oss4_mixer_contains_options (GstMixer * mixer, GstMixerOptions * options) -{ - return (g_list_find (GST_OSS4_MIXER (mixer)->tracks, options) != NULL); -} - -static void -gst_oss4_mixer_post_mixer_changed_msg (GstOss4Mixer * mixer) -{ - /* only post mixer-changed message once */ - if (!mixer->need_update) { - gst_mixer_mixer_changed (GST_MIXER (mixer)); - mixer->need_update = TRUE; - } -} - -/* call with mixer object lock held to serialise ioctl */ -gboolean -gst_oss4_mixer_get_control_val (GstOss4Mixer * mixer, GstOss4MixerControl * mc, - int *val) -{ - oss_mixer_value ossval = { 0, }; - - if (GST_OBJECT_TRYLOCK (mixer)) { - GST_ERROR ("must be called with mixer lock held"); - GST_OBJECT_UNLOCK (mixer); - } - - ossval.dev = mc->mixext.dev; - ossval.ctrl = mc->mixext.ctrl; - ossval.timestamp = mc->mixext.timestamp; - - if (ioctl (mixer->fd, SNDCTL_MIX_READ, &ossval) == -1) { - if (errno == EIDRM) { - GST_DEBUG_OBJECT (mixer, "MIX_READ failed: mixer interface has changed"); - gst_oss4_mixer_post_mixer_changed_msg (mixer); - } else { - GST_WARNING_OBJECT (mixer, "MIX_READ failed: %s", g_strerror (errno)); - } - *val = 0; - mc->last_val = 0; - return FALSE; - } - - *val = ossval.value; - mc->last_val = ossval.value; - GST_LOG_OBJECT (mixer, "got value 0x%08x from %s)", *val, mc->mixext.extname); - return TRUE; -} - -/* call with mixer object lock held to serialise ioctl */ -gboolean -gst_oss4_mixer_set_control_val (GstOss4Mixer * mixer, GstOss4MixerControl * mc, - int val) -{ - oss_mixer_value ossval = { 0, }; - - ossval.dev = mc->mixext.dev; - ossval.ctrl = mc->mixext.ctrl; - ossval.timestamp = mc->mixext.timestamp; - ossval.value = val; - - if (GST_OBJECT_TRYLOCK (mixer)) { - GST_ERROR ("must be called with mixer lock held"); - GST_OBJECT_UNLOCK (mixer); - } - - if (ioctl (mixer->fd, SNDCTL_MIX_WRITE, &ossval) == -1) { - if (errno == EIDRM) { - GST_LOG_OBJECT (mixer, "MIX_WRITE failed: mixer interface has changed"); - gst_oss4_mixer_post_mixer_changed_msg (mixer); - } else { - GST_WARNING_OBJECT (mixer, "MIX_WRITE failed: %s", g_strerror (errno)); - } - return FALSE; - } - - mc->last_val = val; - GST_LOG_OBJECT (mixer, "set value 0x%08x on %s", val, mc->mixext.extname); - return TRUE; -} - -#if 0 -static gchar * -gst_oss4_mixer_control_get_pretty_name (GstOss4MixerControl * mc) -{ - gchar *name; - - const gchar *name, *u; - - /* "The id field is the original name given by the driver when it called - * mixer_ext_create_control. This name can be used by fully featured GUI - * mixers. However this name should be downshifted and cut before the last - * underscore ("_") to get the proper name. For example mixer control name - * created as "MYDRV_MAINVOL" will become just "mainvol" after this - * transformation." */ - name = mc->mixext.extname; - u = MAX (strrchr (name, '_'), strrchr (name, '.')); - if (u != NULL) - name = u + 1; - - /* maybe capitalize the first letter? */ - return g_ascii_strdown (name, -1); - /* the .id thing doesn't really seem to work right, ie. for some sliders - * it's just '-' so you have to use the name of the parent control etc. - * let's not use it for now, much too painful. */ - if (g_str_has_prefix (mc->mixext.extname, "misc.")) - name = g_strdup (mc->mixext.extname + 5); - else - name = g_strdup (mc->mixext.extname); - /* chop off trailing digit (only one for now) */ - if (strlen (name) > 0 && g_ascii_isdigit (name[strlen (name) - 1])) - name[strlen (name) - 1] = '\0'; - g_strdelimit (name, ".", ' '); - return name; -} -#endif - -/* these translations are a bit ad-hoc and horribly incomplete; it is not - * really going to work this way with all the different chipsets and drivers. - * We also use these for translating option values. */ -static struct -{ - const gchar oss_name[32]; - const gchar *label; -} labels[] = { - { - "volume", N_("Volume")}, { - "master", N_("Master")}, { - "front", N_("Front")}, { - "rear", N_("Rear")}, { - "headphones", N_("Headphones")}, { - "center", N_("Center")}, { - "lfe", N_("LFE")}, { - "surround", N_("Surround")}, { - "side", N_("Side")}, { - "speaker", N_("Built-in Speaker")}, { - "aux1-out", N_("AUX 1 Out")}, { - "aux2-out", N_("AUX 2 Out")}, { - "aux-out", N_("AUX Out")}, { - "bass", N_("Bass")}, { - "treble", N_("Treble")}, { - "3d-depth", N_("3D Depth")}, { - "3d-center", N_("3D Center")}, { - "3d-enhance", N_("3D Enhance")}, { - "phone", N_("Telephone")}, { - "mic", N_("Microphone")}, { - "line-out", N_("Line Out")}, { - "line-in", N_("Line In")}, { - "linein", N_("Line In")}, { - "cd", N_("Internal CD")}, { - "video", N_("Video In")}, { - "aux1-in", N_("AUX 1 In")}, { - "aux2-in", N_("AUX 2 In")}, { - "aux-in", N_("AUX In")}, { - "pcm", N_("PCM")}, { - "record-gain", N_("Record Gain")}, { - "igain", N_("Record Gain")}, { - "ogain", N_("Output Gain")}, { - "micboost", N_("Microphone Boost")}, { - "loopback", N_("Loopback")}, { - "diag", N_("Diagnostic")}, { - "loudness", N_("Bass Boost")}, { - "outputs", N_("Playback Ports")}, { - "input", N_("Input")}, { - "inputs", N_("Record Source")}, { - "record-source", N_("Record Source")}, { - "monitor-source", N_("Monitor Source")}, { - "beep", N_("Keyboard Beep")}, { - "monitor-gain", N_("Monitor")}, { - "stereo-simulate", N_("Simulate Stereo")}, { - "stereo", N_("Stereo")}, { - "multich", N_("Surround Sound")}, { - "mic-gain", N_("Microphone Gain")}, { - "speaker-source", N_("Speaker Source")}, { - "mic-source", N_("Microphone Source")}, { - "jack", N_("Jack")}, { - "center/lfe", N_("Center / LFE")}, { - "stereo-mix", N_("Stereo Mix")}, { - "mono-mix", N_("Mono Mix")}, { - "input-mix", N_("Input Mix")}, { - "spdif-in", N_("SPDIF In")}, { - "spdif-out", N_("SPDIF Out")}, { - "mic1", N_("Microphone 1")}, { - "mic2", N_("Microphone 2")}, { - "digital-out", N_("Digital Out")}, { - "digital-in", N_("Digital In")}, { - "hdmi", N_("HDMI")}, { - "modem", N_("Modem")}, { - "handset", N_("Handset")}, { - "other", N_("Other")}, { - "stereo", N_("Stereo")}, { - "none", N_("None")}, { - "on", N_("On")}, { - "off", N_("Off")}, { - "mute", N_("Mute")}, { - "fast", N_("Fast")}, { - /* TRANSLATORS: "Very Low" is a quality setting here */ - "very-low", N_("Very Low")}, { - /* TRANSLATORS: "Low" is a quality setting here */ - "low", N_("Low")}, { - /* TRANSLATORS: "Medium" is a quality setting here */ - "medium", N_("Medium")}, { - /* TRANSLATORS: "High" is a quality setting here */ - "high", N_("High")}, { - /* TRANSLATORS: "Very High" is a quality setting here */ - "very-high", N_("Very High")}, { - "high+", N_("Very High")}, { - /* TRANSLATORS: "Production" is a quality setting here */ - "production", N_("Production")}, { - "fp-mic", N_("Front Panel Microphone")}, { - "fp-linein", N_("Front Panel Line In")}, { - "fp-headphones", N_("Front Panel Headphones")}, { - "fp-lineout", N_("Front Panel Line Out")}, { - "green", N_("Green Connector")}, { - "pink", N_("Pink Connector")}, { - "blue", N_("Blue Connector")}, { - "white", N_("White Connector")}, { - "black", N_("Black Connector")}, { - "gray", N_("Gray Connector")}, { - "orange", N_("Orange Connector")}, { - "red", N_("Red Connector")}, { - "yellow", N_("Yellow Connector")}, { - "fp-green", N_("Green Front Panel Connector")}, { - "fp-pink", N_("Pink Front Panel Connector")}, { - "fp-blue", N_("Blue Front Panel Connector")}, { - "fp-white", N_("White Front Panel Connector")}, { - "fp-black", N_("Black Front Panel Connector")}, { - "fp-gray", N_("Gray Front Panel Connector")}, { - "fp-orange", N_("Orange Front Panel Connector")}, { - "fp-red", N_("Red Front Panel Connector")}, { - "fp-yellow", N_("Yellow Front Panel Connector")}, { - "spread", N_("Spread Output")}, { - "downmix", N_("Downmix")}, - /* FIXME translate Audigy NX USB labels) */ -/* - { "rec.src", N_("Record Source") }, - { "output.mute", N_("Mute output") } - headph (Controller group) - headph.src (Enumeration control) - headph.mute (On/Off switch) - digital2 (Controller group) - digital2.src (Enumeration control) - digital2.mute (On/Off switch) - digital (Controller group) - digital.mute1 (On/Off switch) - digital.vol (Controller group) - digital.vol.front (Stereo slider (0-255)) - digital.vol.surr (Stereo slider (0-255)) - digital.vol.c/l (Stereo slider (0-255)) - digital.vol.center (Stereo slider (0-255)) - digital.mute2 (On/Off switch) - digital.vol (Stereo slider (0-255)) - line (Controller group) - line.mute (On/Off switch) - line.vol (Stereo slider (0-255)) - play-altset (Enumeration control) - rec-altset (Enumeration control) -*/ -}; - -/* Decent i18n is pretty much impossible with OSS's way of providing us with - * mixer labels (and the fact that they are pretty much random), but that - * doesn't mean we shouldn't at least try. */ -static gchar * -gst_oss4_mixer_control_get_translated_name (GstOss4MixerControl * mc) -{ - gchar name[128] = { 0, }; - gchar vmix_str[32] = { '\0', }; - gchar *ptr; - int dummy, i; - int num = -1; - gboolean function_suffix = FALSE; - - /* main virtual mixer controls (we hide the stream volumes) */ - if (sscanf (mc->mixext.extname, "vmix%d-%32c", &dummy, vmix_str) == 2) { - if (strcmp (vmix_str, "src") == 0) - return g_strdup (_("Virtual Mixer Input")); - else if (strcmp (vmix_str, "vol") == 0) - return g_strdup (_("Virtual Mixer Output")); - else if (strcmp (vmix_str, "channels") == 0) - return g_strdup (_("Virtual Mixer Channels")); - } - - g_strlcpy (name, mc->mixext.extname, sizeof (name)); - - /* we deal with either "connector." or "jack." */ - if ((g_str_has_prefix (name, "connector.")) || - (g_str_has_prefix (name, "jack."))) { - ptr = strchr (mc->mixext.extname, '.'); - ptr++; - g_strlcpy (name, ptr, sizeof (name)); - } - - /* special handling for jack retasking suffixes */ - if (g_str_has_suffix (name, ".function") || g_str_has_suffix (name, ".mode")) { - function_suffix = TRUE; - ptr = strrchr (name, '.'); - *ptr = 0; - } - - /* parse off trailing numbers */ - i = strlen (name); - while ((i > 0) && (g_ascii_isdigit (name[i - 1]))) { - i--; - } - /* the check catches the case where the control name is just a number */ - if ((i > 0) && (name[i] != '\0')) { - num = atoi (name + i); - name[i] = '\0'; - } - - /* look for a match, progressively skipping '.' delimited prefixes as we go */ - ptr = name; - do { - if (*ptr == '.') - ptr++; - for (i = 0; i < G_N_ELEMENTS (labels); ++i) { - if (g_ascii_strcasecmp (ptr, labels[i].oss_name) == 0) { - g_strlcpy (name, _(labels[i].label), sizeof (name)); - goto append_suffixes; - } - } - } while ((ptr = strchr (ptr, '.')) != NULL); - - /* failing that, just replace periods with spaces */ - g_strdelimit (name, ".", ' '); - -append_suffixes: - if (num > -1) { - if (function_suffix) { - /* TRANSLATORS: name + number of a volume mixer control */ - return g_strdup_printf (_("%s %d Function"), name, num); - } else { - return g_strdup_printf ("%s %d", name, num); - } - } else { - if (function_suffix) { - /* TRANSLATORS: name of a volume mixer control */ - return g_strdup_printf (_("%s Function"), name); - } else { - return g_strdup (name); - } - } -} - -static const gchar * -gst_oss4_mixer_control_get_translated_option (const gchar * name) -{ - int i; - for (i = 0; i < G_N_ELEMENTS (labels); ++i) { - if (g_ascii_strcasecmp (name, labels[i].oss_name) == 0) { - return _(labels[i].label); - } - } - return (name); -} - -#ifndef GST_DISABLE_GST_DEBUG -static const gchar * -mixer_ext_type_get_name (gint type) -{ - switch (type) { - case MIXT_DEVROOT: - return "Device root entry"; - case MIXT_GROUP: - return "Controller group"; - case MIXT_ONOFF: - return "On/Off switch"; - case MIXT_ENUM: - return "Enumeration control"; - case MIXT_MONOSLIDER: - return "Mono slider (0-255)"; - case MIXT_STEREOSLIDER: - return "Stereo slider (0-255)"; - case MIXT_MESSAGE: - return "Textual message"; /* whatever this is */ - case MIXT_MONOVU: - return "Mono VU meter value"; - case MIXT_STEREOVU: - return "Stereo VU meter value"; - case MIXT_MONOPEAK: - return "Mono VU meter peak value"; - case MIXT_STEREOPEAK: - return "Stereo VU meter peak value"; - case MIXT_RADIOGROUP: - return "Radio button group"; - case MIXT_MARKER: /* Separator between normal and extension entries */ - return "Separator"; - case MIXT_VALUE: - return "Decimal value entry"; - case MIXT_HEXVALUE: - return "Hex value entry"; - case MIXT_SLIDER: - return "Mono slider (31-bit value range)"; - case MIXT_3D: - return "3D"; /* what's this? */ - case MIXT_MONOSLIDER16: - return "Mono slider (0-32767)"; - case MIXT_STEREOSLIDER16: - return "Stereo slider (0-32767)"; - case MIXT_MUTE: - return "Mute switch"; - default: - break; - } - return "unknown"; -} -#endif /* GST_DISABLE_GST_DEBUG */ - -#ifndef GST_DISABLE_GST_DEBUG -static const gchar * -mixer_ext_flags_get_string (gint flags) -{ - struct - { - gint flag; - gchar nick[16]; - } all_flags[] = { - /* first the important ones */ - { - MIXF_MAINVOL, "MAINVOL"}, { - MIXF_PCMVOL, "PCMVOL"}, { - MIXF_RECVOL, "RECVOL"}, { - MIXF_MONVOL, "MONVOL"}, { - MIXF_DESCR, "DESCR"}, - /* now the rest in the right order */ - { - MIXF_READABLE, "READABLE"}, { - MIXF_WRITEABLE, "WRITABLE"}, { - MIXF_POLL, "POLL"}, { - MIXF_HZ, "HZ"}, { - MIXF_STRING, "STRING"}, { - MIXF_DYNAMIC, "DYNAMIC"}, { - MIXF_OKFAIL, "OKFAIL"}, { - MIXF_FLAT, "FLAT"}, { - MIXF_LEGACY, "LEGACY"}, { - MIXF_CENTIBEL, "CENTIBEL"}, { - MIXF_DECIBEL, "DECIBEL"}, { - MIXF_WIDE, "WIDE"} - }; - GString *s; - GQuark q; - gint i; - - if (flags == 0) - return "None"; - - s = g_string_new (""); - for (i = 0; i < G_N_ELEMENTS (all_flags); ++i) { - if ((flags & all_flags[i].flag)) { - if (s->len > 0) - g_string_append (s, " | "); - g_string_append (s, all_flags[i].nick); - flags &= ~all_flags[i].flag; /* unset */ - } - } - - /* unknown flags? */ - if (flags != 0) { - if (s->len > 0) - g_string_append (s, " | "); - g_string_append (s, "???"); - } - - /* we'll just put it into the global quark table (cheeky, eh?) */ - q = g_quark_from_string (s->str); - g_string_free (s, TRUE); - - return g_quark_to_string (q); -} -#endif /* GST_DISABLE_GST_DEBUG */ - -#ifndef GST_DISABLE_GST_DEBUG -static void -gst_oss4_mixer_control_dump_tree (GstOss4MixerControl * mc, gint depth) -{ - GList *c; - gchar spaces[64]; - gint i; - - depth = MIN (sizeof (spaces) - 1, depth); - for (i = 0; i < depth; ++i) - spaces[i] = ' '; - spaces[i] = '\0'; - - GST_LOG ("%s%s (%s)", spaces, mc->mixext.extname, - mixer_ext_type_get_name (mc->mixext.type)); - for (c = mc->children; c != NULL; c = c->next) { - GstOss4MixerControl *child_mc = (GstOss4MixerControl *) c->data; - - gst_oss4_mixer_control_dump_tree (child_mc, depth + 2); - } -} -#endif /* GST_DISABLE_GST_DEBUG */ - -static GList * -gst_oss4_mixer_get_controls (GstOss4Mixer * mixer) -{ - GstOss4MixerControl *root_mc = NULL; - oss_mixerinfo mi = { 0, }; - GList *controls = NULL; - GList *l; - guint i; - - /* Get info for currently open fd */ - mi.dev = -1; - if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == -1) - goto no_mixerinfo; - - if (mi.nrext <= 0) { - GST_DEBUG ("mixer %s has no controls", mi.id); - return NULL; - } - - GST_INFO ("Reading controls for mixer %s", mi.id); - - for (i = 0; i < mi.nrext; ++i) { - GstOss4MixerControl *mc; - oss_mixext mix_ext = { 0, }; - - mix_ext.dev = mi.dev; - mix_ext.ctrl = i; - - if (ioctl (mixer->fd, SNDCTL_MIX_EXTINFO, &mix_ext) == -1) { - GST_DEBUG ("SNDCTL_MIX_EXTINFO failed on mixer %s, control %d: %s", - mi.id, i, g_strerror (errno)); - continue; - } - - /* if this is the last one, save it for is-interface-up-to-date checking */ - if (i == mi.nrext) - mixer->last_mixext = mix_ext; - - mc = g_new0 (GstOss4MixerControl, 1); - mc->mixext = mix_ext; - - /* both control_no and desc fields are pretty useless, ie. not always set, - * if ever, so not listed here */ - GST_INFO ("Control %d", mix_ext.ctrl); - GST_INFO (" name : %s", mix_ext.extname); - GST_INFO (" type : %s (%d)", mixer_ext_type_get_name (mix_ext.type), - mix_ext.type); - GST_INFO (" flags : %s (0x%04x)", - mixer_ext_flags_get_string (mix_ext.flags), mix_ext.flags); - GST_INFO (" parent : %d", mix_ext.parent); - - if (!MIXEXT_IS_ROOT (mix_ext)) { - /* find parent (we assume it comes in the list before the child) */ - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *parent_mc = (GstOss4MixerControl *) l->data; - - if (parent_mc->mixext.ctrl == mix_ext.parent) { - mc->parent = parent_mc; - parent_mc->children = g_list_append (parent_mc->children, mc); - break; - } - } - if (mc->parent == NULL) { - GST_ERROR_OBJECT (mixer, "couldn't find parent for control %d", i); - g_free (mc); - continue; - } - } else if (root_mc == NULL) { - root_mc = mc; - } else { - GST_WARNING_OBJECT (mixer, "two root controls?!"); - } - - controls = g_list_prepend (controls, mc); - } - -#ifndef GST_DISABLE_GST_DEBUG - gst_oss4_mixer_control_dump_tree (root_mc, 0); -#endif - - return g_list_reverse (controls); - -/* ERRORS */ -no_mixerinfo: - { - GST_WARNING ("SNDCTL_MIXERINFO failed on mixer device %s: %s", mi.id, - g_strerror (errno)); - return NULL; - } -} - -static void -gst_oss4_mixer_controls_guess_master (GstOss4Mixer * mixer, - const GList * controls) -{ - GstOss4MixerControl *master_mc = NULL; - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - - /* do we need to check if it's a slider type here? */ - if ((mc->mixext.flags & MIXF_PCMVOL)) { - GST_INFO_OBJECT (mixer, "First PCM control: %s", mc->mixext.extname); - master_mc = mc; - break; - } - - if (((mc->mixext.flags & MIXF_MAINVOL)) && master_mc == NULL) { - GST_INFO_OBJECT (mixer, "First main volume control: %s", - mc->mixext.extname); - master_mc = mc; - } - } - - if (master_mc != NULL) - master_mc->is_master = TRUE; -} - -/* type: -1 for all types, otherwise just return siblings with requested type */ -static GList * -gst_oss4_mixer_control_get_siblings (GstOss4MixerControl * mc, gint type) -{ - GList *s, *siblings = NULL; - - if (mc->parent == NULL) - return NULL; - - for (s = mc->parent->children; s != NULL; s = s->next) { - GstOss4MixerControl *sibling = (GstOss4MixerControl *) s->data; - - if (mc != sibling && (type < 0 || sibling->mixext.type == type)) - siblings = g_list_append (siblings, sibling); - } - - return siblings; -} - -static void -gst_oss4_mixer_controls_find_sliders (GstOss4Mixer * mixer, - const GList * controls) -{ - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - GList *s, *siblings; - - if (!MIXEXT_IS_SLIDER (mc->mixext) || mc->parent == NULL || mc->used) - continue; - - mc->is_slider = TRUE; - mc->used = TRUE; - - siblings = gst_oss4_mixer_control_get_siblings (mc, -1); - - /* Note: the names can be misleading and may not reflect the actual - * hierarchy of the controls, e.g. it's possible that a slider is called - * connector.green and the mute control then connector.green.mute, but - * both controls are in fact siblings and both children of the group - * 'green' instead of mute being a child of connector.green as the naming - * would seem to suggest */ - GST_LOG ("Slider: %s, parent=%s, %d siblings", mc->mixext.extname, - mc->parent->mixext.extname, g_list_length (siblings)); - - for (s = siblings; s != NULL; s = s->next) { - GstOss4MixerControl *sibling = (GstOss4MixerControl *) s->data; - - GST_LOG (" %s (%s)", sibling->mixext.extname, - mixer_ext_type_get_name (sibling->mixext.type)); - - if (sibling->mixext.type == MIXT_MUTE || - g_str_has_suffix (sibling->mixext.extname, ".mute")) { - /* simple case: slider with single mute sibling. We assume the .mute - * suffix in the name won't change - can't really do much else anyway */ - if (sibling->mixext.type == MIXT_ONOFF || - sibling->mixext.type == MIXT_MUTE) { - GST_LOG (" mute control for %s is %s", mc->mixext.extname, - sibling->mixext.extname); - mc->mute = sibling; - sibling->used = TRUE; - } - /* a group of .mute controls. We assume they are all switches here */ - if (sibling->mixext.type == MIXT_GROUP) { - GList *m; - - for (m = sibling->children; m != NULL; m = m->next) { - GstOss4MixerControl *grouped_sibling = m->data; - - if (grouped_sibling->mixext.type == MIXT_ONOFF || - grouped_sibling->mixext.type == MIXT_MUTE) { - GST_LOG (" %s is grouped mute control for %s", - grouped_sibling->mixext.extname, mc->mixext.extname); - mc->mute_group = g_list_append (mc->mute_group, grouped_sibling); - } - } - - GST_LOG (" %s has a group of %d mute controls", - mc->mixext.extname, g_list_length (mc->mute_group)); - - /* we don't mark the individual mute controls as used, only the - * group control, as we still want individual switches for the - * individual controls */ - sibling->used = TRUE; - } - } - } - g_list_free (siblings); - } -} - -/* should be called with the mixer object lock held because of the ioctl; - * returns TRUE if the list was read the first time or modified */ -static gboolean -gst_oss4_mixer_enum_control_update_enum_list (GstOss4Mixer * mixer, - GstOss4MixerControl * mc) -{ - oss_mixer_enuminfo ei = { 0, }; - guint num_existing = 0; - int i; - - /* count and existing values */ - while (mc->enum_vals != NULL && mc->enum_vals[num_existing] != 0) - ++num_existing; - - ei.dev = mc->mixext.dev; - ei.ctrl = mc->mixext.ctrl; - - /* if we have create a generic list with numeric IDs already and the - * number of values hasn't changed, then there's not much to do here */ - if (mc->no_list && mc->enum_vals != NULL && - num_existing == mc->mixext.maxvalue) { - return FALSE; - } - - /* if we have a list and it doesn't change, there's nothing to do either */ - if (mc->enum_vals != NULL && mc->enum_version == 0) - return FALSE; - - if (ioctl (mixer->fd, SNDCTL_MIX_ENUMINFO, &ei) == -1) { - g_free (mc->enum_vals); - mc->enum_vals = g_new0 (GQuark, mc->mixext.maxvalue + 1); - - GST_DEBUG ("no enum info available, creating numeric values from 0-%d", - mc->mixext.maxvalue - 1); - - /* "It is possible that some enum controls don't have any name list - * available. In this case the application should automatically generate - * list of numbers (0 to N-1)" */ - for (i = 0; i < mc->mixext.maxvalue; ++i) { - gchar num_str[8]; - - g_snprintf (num_str, sizeof (num_str), "%d", i); - mc->enum_vals[i] = g_quark_from_string (num_str); - } - mc->enum_version = 0; /* the only way to change is via maxvalue */ - } else { - /* old list same as current list? */ - if (mc->enum_vals != NULL && mc->enum_version == ei.version) - return FALSE; - - /* no list yet, or the list has changed */ - GST_LOG ("%s", (mc->enum_vals) ? "enum list has changed" : "reading list"); - if (ei.nvalues != mc->mixext.maxvalue) { - GST_WARNING_OBJECT (mixer, "Enum: %s, nvalues %d != maxvalue %d", - mc->mixext.extname, ei.nvalues, mc->mixext.maxvalue); - mc->mixext.maxvalue = MIN (ei.nvalues, mc->mixext.maxvalue); - } - - mc->mixext.maxvalue = MIN (mc->mixext.maxvalue, OSS_ENUM_MAXVALUE); - - g_free (mc->enum_vals); - mc->enum_vals = g_new0 (GQuark, mc->mixext.maxvalue + 1); - for (i = 0; i < mc->mixext.maxvalue; ++i) { - GST_LOG (" %s", ei.strings + ei.strindex[i]); - mc->enum_vals[i] = - g_quark_from_string (gst_oss4_mixer_control_get_translated_option - (ei.strings + ei.strindex[i])); - } - } - - return TRUE; -} - -static void -gst_oss4_mixer_controls_find_enums (GstOss4Mixer * mixer, - const GList * controls) -{ - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - - if (mc->mixext.type != MIXT_ENUM || mc->used) - continue; - - mc->is_enum = TRUE; - mc->used = TRUE; - - /* Note: enums are special: for most controls, the maxvalue is inclusive, - * but for enum controls it's actually exclusive (boggle), so that - * mixext.maxvalue = num_values */ - - GST_LOG ("Enum: %s, parent=%s, num_enums=%d", mc->mixext.extname, - mc->parent->mixext.extname, mc->mixext.maxvalue); - - gst_oss4_mixer_enum_control_update_enum_list (mixer, mc); - } -} - -static void -gst_oss4_mixer_controls_find_switches (GstOss4Mixer * mixer, - const GList * controls) -{ - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - - if (mc->used) - continue; - - if (mc->mixext.type != MIXT_ONOFF && mc->mixext.type != MIXT_MUTE) - continue; - - mc->is_switch = TRUE; - mc->used = TRUE; - - GST_LOG ("Switch: %s, parent=%s", mc->mixext.extname, - mc->parent->mixext.extname); - } -} - -static void -gst_oss4_mixer_controls_find_virtual (GstOss4Mixer * mixer, - const GList * controls) -{ - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - - /* or sscanf (mc->mixext.extname, "vmix%d-out.", &n) == 1 ? */ - /* for now we just flag all virtual controls with managed labels, those - * are really more appropriate for a pavucontrol-type control thing than - * the (more hardware-oriented) mixer interface */ - if (mc->mixext.id[0] == '@') { - mc->is_virtual = TRUE; - GST_LOG ("%s is virtual control with managed label", mc->mixext.extname); - } - } -} - -static void -gst_oss4_mixer_controls_dump_unused (GstOss4Mixer * mixer, - const GList * controls) -{ - const GList *l; - - for (l = controls; l != NULL; l = l->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; - - if (mc->used) - continue; - - switch (mc->mixext.type) { - case MIXT_DEVROOT: - case MIXT_GROUP: - case MIXT_MESSAGE: - case MIXT_MONOVU: - case MIXT_STEREOVU: - case MIXT_MONOPEAK: - case MIXT_STEREOPEAK: - case MIXT_MARKER: - continue; /* not interested in these types of controls */ - case MIXT_MONODB: - case MIXT_STEREODB: - GST_DEBUG ("obsolete control type %d", mc->mixext.type); - continue; - case MIXT_MONOSLIDER: - case MIXT_STEREOSLIDER: - case MIXT_SLIDER: - case MIXT_MONOSLIDER16: - case MIXT_STEREOSLIDER16: - /* this shouldn't happen */ - GST_ERROR ("unused slider control?!"); - continue; - case MIXT_VALUE: - case MIXT_HEXVALUE: - /* value entry, not sure what to do with that, skip for now */ - continue; - case MIXT_ONOFF: - case MIXT_MUTE: - case MIXT_ENUM: - case MIXT_3D: - case MIXT_RADIOGROUP: - GST_DEBUG ("FIXME: handle %s %s", - mixer_ext_type_get_name (mc->mixext.type), mc->mixext.extname); - break; - default: - GST_WARNING ("unknown control type %d", mc->mixext.type); - continue; - } - } -} - -static GList * -gst_oss4_mixer_create_tracks (GstOss4Mixer * mixer, const GList * controls) -{ - const GList *c; - GList *tracks = NULL; - - for (c = controls; c != NULL; c = c->next) { - GstOss4MixerControl *mc = (GstOss4MixerControl *) c->data; - GstMixerTrack *track = NULL; - - if (mc->is_virtual) - continue; - - if (mc->is_slider) { - track = gst_oss4_mixer_slider_new (mixer, mc); - } else if (mc->is_enum) { - track = gst_oss4_mixer_enum_new (mixer, mc); - } else if (mc->is_switch) { - track = gst_oss4_mixer_switch_new (mixer, mc); - } - - if (track == NULL) - continue; - - track->label = gst_oss4_mixer_control_get_translated_name (mc); - track->flags = 0; - - GST_LOG ("translated label: %s [%s] = %s", track->label, mc->mixext.id, - track->label); - - /* This whole 'a track is either INPUT or OUTPUT' model is just flawed, - * esp. if a slider's role can be changed on the fly, like when you change - * function of a connector. What should we do in that case? Change the flag - * and make the app rebuild the interface? Ignore it? */ - if (mc->mixext.flags & (MIXF_MAINVOL | MIXF_PCMVOL)) { - track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST; - - } else if (mc->mixext.flags & MIXF_RECVOL) { - /* record gain whitelisted by default */ - track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD | - GST_MIXER_TRACK_WHITELIST; - - } else if (mc->mixext.flags & MIXF_MONVOL) { - /* monitor sources not whitelisted by default */ - track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD; - } - - /* - * The kernel may give us better clues about the scope of a control. - * If so, try to honor it. - */ - switch (mc->mixext.desc & MIXEXT_SCOPE_MASK) { - case MIXEXT_SCOPE_INPUT: - case MIXEXT_SCOPE_RECSWITCH: - track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD | - GST_MIXER_TRACK_WHITELIST; - break; - case MIXEXT_SCOPE_MONITOR: - /* don't whitelist monitor tracks by default */ - track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD; - break; - case MIXEXT_SCOPE_OUTPUT: - track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST; - break; - } - - if (mc->is_master) { - track->flags |= GST_MIXER_TRACK_OUTPUT; - } - - if (mc->is_master) - track->flags |= GST_MIXER_TRACK_MASTER; - - tracks = g_list_append (tracks, track); - } - - return tracks; -} - -static void -gst_oss4_mixer_update_tracks (GstOss4Mixer * mixer) -{ - GList *controls, *tracks; - - /* read and process controls */ - controls = gst_oss4_mixer_get_controls (mixer); - - gst_oss4_mixer_controls_guess_master (mixer, controls); - - gst_oss4_mixer_controls_find_sliders (mixer, controls); - - gst_oss4_mixer_controls_find_enums (mixer, controls); - - gst_oss4_mixer_controls_find_switches (mixer, controls); - - gst_oss4_mixer_controls_find_virtual (mixer, controls); - - gst_oss4_mixer_controls_dump_unused (mixer, controls); - - tracks = gst_oss4_mixer_create_tracks (mixer, controls); - - /* free old tracks and controls */ - gst_oss4_mixer_free_tracks (mixer); - - /* replace old with new */ - mixer->tracks = tracks; - mixer->controls = controls; -} - -static const GList * -gst_oss4_mixer_list_tracks (GstMixer * mixer_iface) -{ - GstOss4Mixer *mixer = GST_OSS4_MIXER (mixer_iface); - - g_return_val_if_fail (mixer != NULL, NULL); - g_return_val_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer), NULL); - - GST_OBJECT_LOCK (mixer); - - /* Do a read on the last control to check if the interface has changed */ - if (!mixer->need_update && mixer->last_mixext.ctrl > 0) { - GstOss4MixerControl mc = { {0,} - , - }; - int val; - - mc.mixext = mixer->last_mixext; - gst_oss4_mixer_get_control_val (mixer, &mc, &val); - } - - if (mixer->need_update || mixer->tracks == NULL) { - gst_oss4_mixer_update_tracks (mixer); - mixer->need_update = FALSE; - } - - GST_OBJECT_UNLOCK (mixer); - - return (const GList *) mixer->tracks; -} - -static void -gst_oss4_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - GstOss4Mixer *oss; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); - g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); - g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); - g_return_if_fail (volumes != NULL); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - if (GST_IS_OSS4_MIXER_SLIDER (track)) { - gst_oss4_mixer_slider_set_volume (GST_OSS4_MIXER_SLIDER (track), volumes); - } - - GST_OBJECT_UNLOCK (oss); -} - -static void -gst_oss4_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - GstOss4Mixer *oss; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); - g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); - g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); - g_return_if_fail (volumes != NULL); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - memset (volumes, 0, track->num_channels * sizeof (gint)); - - if (GST_IS_OSS4_MIXER_SWITCH (track)) { - gboolean enabled = FALSE; - gst_oss4_mixer_switch_get (GST_OSS4_MIXER_SWITCH (track), &enabled); - } - if (GST_IS_OSS4_MIXER_SLIDER (track)) { - gst_oss4_mixer_slider_get_volume (GST_OSS4_MIXER_SLIDER (track), volumes); - } - - GST_OBJECT_UNLOCK (oss); -} - -static void -gst_oss4_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, - gboolean record) -{ - GstOss4Mixer *oss; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); - g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); - g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - if (GST_IS_OSS4_MIXER_SLIDER (track)) { - gst_oss4_mixer_slider_set_record (GST_OSS4_MIXER_SLIDER (track), record); - } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { - if ((track->flags & GST_MIXER_TRACK_INPUT)) { - gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), record); - } else { - GST_WARNING_OBJECT (track, "set_record called on non-INPUT track"); - } - } - - GST_OBJECT_UNLOCK (oss); -} - -static void -gst_oss4_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) -{ - GstOss4Mixer *oss; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); - g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); - g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - if (GST_IS_OSS4_MIXER_SLIDER (track)) { - gst_oss4_mixer_slider_set_mute (GST_OSS4_MIXER_SLIDER (track), mute); - } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { - gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), mute); - } - - GST_OBJECT_UNLOCK (oss); -} - -static void -gst_oss4_mixer_set_option (GstMixer * mixer, GstMixerOptions * options, - gchar * value) -{ - GstOss4Mixer *oss; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (value != NULL); - g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); - g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); - g_return_if_fail (GST_IS_OSS4_MIXER_ENUM (options)); - g_return_if_fail (gst_oss4_mixer_contains_options (mixer, options)); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - if (!gst_oss4_mixer_enum_set_option (GST_OSS4_MIXER_ENUM (options), value)) { - /* not much we can do here but wake up the watch thread early, so it - * can do its thing and post messages if anything has changed */ - gst_oss4_mixer_wake_up_watch_task (oss); - } - - GST_OBJECT_UNLOCK (oss); -} - -static const gchar * -gst_oss4_mixer_get_option (GstMixer * mixer, GstMixerOptions * options) -{ - GstOss4Mixer *oss; - const gchar *current_val; - - g_return_val_if_fail (mixer != NULL, NULL); - g_return_val_if_fail (GST_IS_OSS4_MIXER (mixer), NULL); - g_return_val_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer), NULL); - g_return_val_if_fail (GST_IS_OSS4_MIXER_ENUM (options), NULL); - g_return_val_if_fail (gst_oss4_mixer_contains_options (mixer, options), NULL); - - oss = GST_OSS4_MIXER (mixer); - - GST_OBJECT_LOCK (oss); - - current_val = gst_oss4_mixer_enum_get_option (GST_OSS4_MIXER_ENUM (options)); - - if (current_val == NULL) { - /* not much we can do here but wake up the watch thread early, so it - * can do its thing and post messages if anything has changed */ - gst_oss4_mixer_wake_up_watch_task (oss); - } - - GST_OBJECT_UNLOCK (oss); - - return current_val; -} - -static GstMixerFlags -gst_oss4_mixer_get_mixer_flags (GstMixer * mixer) -{ - return GST_MIXER_FLAG_AUTO_NOTIFICATIONS | GST_MIXER_FLAG_HAS_WHITELIST | - GST_MIXER_FLAG_GROUPING; -} - -static void -gst_oss4_mixer_interface_init (GstMixerInterface * iface) -{ - GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE; - - iface->list_tracks = gst_oss4_mixer_list_tracks; - iface->set_volume = gst_oss4_mixer_set_volume; - iface->get_volume = gst_oss4_mixer_get_volume; - iface->set_mute = gst_oss4_mixer_set_mute; - iface->set_record = gst_oss4_mixer_set_record; - iface->set_option = gst_oss4_mixer_set_option; - iface->get_option = gst_oss4_mixer_get_option; - iface->get_mixer_flags = gst_oss4_mixer_get_mixer_flags; -} - -/* Implement the horror that is GstImplementsInterface */ - -static gboolean -gst_oss4_mixer_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstOss4Mixer *mixer; - - g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); - - mixer = GST_OSS4_MIXER (iface); - - return GST_OSS4_MIXER_IS_OPEN (mixer); -} - -static void -gst_oss4_mixer_implements_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_oss4_mixer_supported; -} - -static void -gst_oss4_mixer_init_interfaces (GType type) -{ - static const GInterfaceInfo implements_iface_info = { - (GInterfaceInitFunc) gst_oss4_mixer_implements_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo mixer_iface_info = { - (GInterfaceInitFunc) gst_oss4_mixer_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, - &implements_iface_info); - g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info); - - gst_oss4_add_property_probe_interface (type); -} diff --git a/sys/oss4/oss4-mixer.h b/sys/oss4/oss4-mixer.h deleted file mode 100644 index 4eaff50c5c..0000000000 --- a/sys/oss4/oss4-mixer.h +++ /dev/null @@ -1,128 +0,0 @@ -/* GStreamer OSS4 mixer implementation - * Copyright (C) 2007-2008 Tim-Philipp Müller - * - * 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. - */ - -#ifndef OSS4_MIXER_H -#define OSS4_MIXER_H - -#include - -#include "oss4-soundcard.h" - -#define GST_OSS4_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER,GstOss4Mixer)) -#define GST_OSS4_MIXER_CAST(obj) ((GstOss4Mixer *)(obj)) -#define GST_OSS4_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER,GstOss4MixerClass)) -#define GST_IS_OSS4_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER)) -#define GST_IS_OSS4_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER)) -#define GST_TYPE_OSS4_MIXER (gst_oss4_mixer_get_type()) - -#define GST_OSS4_MIXER_IS_OPEN(obj) (GST_OSS4_MIXER(obj)->fd != -1) - -typedef struct _GstOss4Mixer GstOss4Mixer; -typedef struct _GstOss4MixerClass GstOss4MixerClass; - -struct _GstOss4Mixer { - GstElement element; - - /*< private >*/ - - /* element bits'n'bops */ - gchar * device; - - /* mixer details */ - gint fd; /* file descriptor if open, or -1 */ - gchar * device_name; /* device description, or NULL */ - gchar * open_device; /* the device we opened */ - - GList * tracks; /* list of available tracks */ - GList * controls; /* list of available controls */ - gboolean need_update; /* re-read list of available tracks? */ - - oss_mixext last_mixext; /* we keep this around so we can - * easily check if the mixer - * interface has changed */ - - GThread * watch_thread; /* thread watching for value changes */ - GCond * watch_cond; - gint watch_shutdown; - gint modify_counter; /* from MIXERINFO */ - - /* for property probe interface */ - GList * property_probe_list; -}; - -struct _GstOss4MixerClass { - GstElementClass element_class; -}; - -/* helper struct holding info about one control */ -typedef struct _GstOss4MixerControl GstOss4MixerControl; - -struct _GstOss4MixerControl { - oss_mixext mixext; - GstOss4MixerControl *parent; /* NULL if root */ - GstOss4MixerControl *mute; /* sibling with mute function, or NULL */ - GList *mute_group; /* group of mute controls, or NULL */ - GList *children; /* GstOss4MixerControls (no ownership) */ - - GQuark *enum_vals; /* 0-terminated array of values or NULL */ - int enum_version; /* 0 = list won't change */ - - int last_val; /* last value seen */ - - gboolean is_virtual : 1; /* is a vmix control with dynamic label */ - gboolean is_master : 1; - gboolean is_slider : 1; /* represent as slider */ - gboolean is_switch : 1; /* represent as switch */ - gboolean is_enum : 1; /* represent as combo/enumeration */ - gboolean no_list : 1; /* enumeration with no list available */ - gboolean is_input : 1; /* is an input-related control */ - gboolean is_output : 1; /* is an output-related control */ - gboolean used : 1; /* whether we know what to do with this */ - - gboolean changed : 1; /* transient flag used by watch thread */ - gboolean list_changed : 1; /* transient flag used by watch thread */ -}; - -/* header says parent=-1 means root, but it can also be parent=ctrl */ -#define MIXEXT_IS_ROOT(me) ((me).parent == -1 || (me).parent == (me).ctrl) - -#define MIXEXT_IS_SLIDER(me) ((me).type == MIXT_MONOSLIDER || \ - (me).type == MIXT_STEREOSLIDER || (me).type == MIXT_MONOSLIDER16 || \ - (me).type == MIXT_STEREOSLIDER16 || (me).type == MIXT_SLIDER) - -#define MIXEXT_HAS_DESCRIPTION(me) (((me).flags & MIXF_DESCR) != 0) - -#define MIXEXT_ENUM_IS_AVAILABLE(me,num) \ - (((me).enum_present[num/8]) & (1 << (num % 8))) - - -GType gst_oss4_mixer_get_type (void); - -gboolean gst_oss4_mixer_get_control_val (GstOss4Mixer * mixer, - GstOss4MixerControl * mc, - int * val); - -gboolean gst_oss4_mixer_set_control_val (GstOss4Mixer * mixer, - GstOss4MixerControl * mc, - int val); - -G_END_DECLS - -#endif /* OSS4_MIXER_H */ - diff --git a/sys/oss4/oss4-property-probe.c b/sys/oss4/oss4-property-probe.c index 5674da50a4..c628af81a4 100644 --- a/sys/oss4/oss4-property-probe.c +++ b/sys/oss4/oss4-property-probe.c @@ -27,9 +27,9 @@ #include + #define NO_LEGACY_MIXER #include "oss4-audio.h" -#include "oss4-mixer.h" #include "oss4-sink.h" #include "oss4-source.h" #include "oss4-soundcard.h" @@ -43,6 +43,8 @@ #include #include +#if 0 + GST_DEBUG_CATEGORY_EXTERN (oss4_debug); #define GST_CAT_DEFAULT oss4_debug @@ -110,6 +112,8 @@ gst_oss4_property_probe_needs_probe (GstPropertyProbe * probe, return TRUE; } +#endif + static gint oss4_mixerinfo_priority_cmp (struct oss_mixerinfo *mi1, struct oss_mixerinfo *mi2) @@ -282,9 +286,8 @@ gst_oss4_property_probe_get_audio_devices (GstObject * obj, int fd, return g_list_reverse (devices); } -static GValueArray * -gst_oss4_property_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) +GValueArray * +gst_oss4_property_probe_get_values (GstObject * probe, const gchar * pname) { struct oss_sysinfo si = { {0,}, }; GValueArray *array = NULL; @@ -292,8 +295,8 @@ gst_oss4_property_probe_get_values (GstPropertyProbe * probe, GList *devices, *l; int cap_mask, fd = -1; - if (!g_str_equal (pspec->name, "device")) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + if (!g_str_equal (pname, "device")) { + GST_WARNING_OBJECT (probe, "invalid property"); return NULL; } @@ -310,9 +313,6 @@ gst_oss4_property_probe_get_values (GstPropertyProbe * probe, GST_DEBUG_OBJECT (probe, "probing available input devices"); cap_mask = PCM_CAP_INPUT; fd = GST_OSS4_SOURCE (probe)->fd; - } else if (GST_IS_OSS4_MIXER (probe)) { - fd = GST_OSS4_MIXER (probe)->fd; - cap_mask = 0; } else { GST_OBJECT_UNLOCK (obj); g_return_val_if_reached (NULL); @@ -393,6 +393,7 @@ no_sysinfo: } } +#if 0 static void gst_oss4_property_probe_interface_init (GstPropertyProbeInterface * iface) { @@ -414,3 +415,4 @@ gst_oss4_add_property_probe_interface (GType type) g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, &probe_iface_info); } +#endif diff --git a/sys/oss4/oss4-property-probe.h b/sys/oss4/oss4-property-probe.h index 707af024c9..8426bb6047 100644 --- a/sys/oss4/oss4-property-probe.h +++ b/sys/oss4/oss4-property-probe.h @@ -20,10 +20,14 @@ #ifndef GST_OSS4_PROPERTY_PROBE_H #define GST_OSS4_PROPERTY_PROBE_H +#if 0 + #include void gst_oss4_add_property_probe_interface (GType type); +#endif + gboolean gst_oss4_property_probe_find_device_name (GstObject * obj, int fd, const gchar * device_handle, @@ -33,6 +37,9 @@ gboolean gst_oss4_property_probe_find_device_name_nofd (GstObject * obj, const gchar * device_handle, gchar ** device_name); +GValueArray *gst_oss4_property_probe_get_values (GstObject * obj, const gchar * pname); + + #endif /* GST_OSS4_PROPERTY_PROBE_H */ diff --git a/sys/oss4/oss4-sink.c b/sys/oss4/oss4-sink.c index fe1b2bb7e1..ababa0eb14 100644 --- a/sys/oss4/oss4-sink.c +++ b/sys/oss4/oss4-sink.c @@ -55,7 +55,7 @@ #include #include -#include +#include #define NO_LEGACY_MIXER #include "oss4-audio.h" @@ -66,7 +66,6 @@ GST_DEBUG_CATEGORY_EXTERN (oss4sink_debug); #define GST_CAT_DEFAULT oss4sink_debug -static void gst_oss4_sink_init_interfaces (GType type); static void gst_oss4_sink_dispose (GObject * object); static void gst_oss4_sink_finalize (GObject * object); @@ -75,15 +74,15 @@ static void gst_oss4_sink_get_property (GObject * object, guint prop_id, static void gst_oss4_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static GstCaps *gst_oss4_sink_getcaps (GstBaseSink * bsink); +static GstCaps *gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter); static gboolean gst_oss4_sink_open (GstAudioSink * asink, gboolean silent_errors); static gboolean gst_oss4_sink_open_func (GstAudioSink * asink); static gboolean gst_oss4_sink_close (GstAudioSink * asink); static gboolean gst_oss4_sink_prepare (GstAudioSink * asink, - GstRingBufferSpec * spec); + GstAudioRingBufferSpec * spec); static gboolean gst_oss4_sink_unprepare (GstAudioSink * asink); -static guint gst_oss4_sink_write (GstAudioSink * asink, gpointer data, +static gint gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length); static guint gst_oss4_sink_delay (GstAudioSink * asink); static void gst_oss4_sink_reset (GstAudioSink * asink); @@ -104,8 +103,9 @@ enum PROP_LAST }; -GST_BOILERPLATE_FULL (GstOss4Sink, gst_oss4_sink, GstAudioSink, - GST_TYPE_AUDIO_SINK, gst_oss4_sink_init_interfaces); +#define gst_oss4_sink_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstOss4Sink, gst_oss4_sink, + GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)); static void gst_oss4_sink_dispose (GObject * object) @@ -120,28 +120,14 @@ gst_oss4_sink_dispose (GObject * object) G_OBJECT_CLASS (parent_class)->dispose (object); } -static void -gst_oss4_sink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstPadTemplate *templ; - - gst_element_class_set_static_metadata (element_class, - "OSS v4 Audio Sink", "Sink/Audio", - "Output to a sound card via OSS version 4", - "Tim-Philipp Müller "); - - templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - gst_oss4_audio_get_template_caps ()); - gst_element_class_add_pad_template (element_class, templ); -} - static void gst_oss4_sink_class_init (GstOss4SinkClass * klass) { GstAudioSinkClass *audiosink_class = (GstAudioSinkClass *) klass; GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; GObjectClass *gobject_class = (GObjectClass *) klass; + GstPadTemplate *templ; gobject_class->dispose = gst_oss4_sink_dispose; gobject_class->finalize = gst_oss4_sink_finalize; @@ -180,10 +166,19 @@ gst_oss4_sink_class_init (GstOss4SinkClass * klass) audiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss4_sink_write); audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_sink_delay); audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_sink_reset); + + gst_element_class_set_static_metadata (gstelement_class, + "OSS v4 Audio Sink", "Sink/Audio", + "Output to a sound card via OSS version 4", + "Tim-Philipp Müller "); + + templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + gst_oss4_audio_get_template_caps ()); + gst_element_class_add_pad_template (gstelement_class, templ); } static void -gst_oss4_sink_init (GstOss4Sink * osssink, GstOss4SinkClass * klass) +gst_oss4_sink_init (GstOss4Sink * osssink) { const gchar *device; @@ -206,9 +201,6 @@ gst_oss4_sink_finalize (GObject * object) g_free (osssink->device); osssink->device = NULL; - g_list_free (osssink->property_probe_list); - osssink->property_probe_list = NULL; - G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -383,7 +375,7 @@ gst_oss4_sink_get_property (GObject * object, guint prop_id, } static GstCaps * -gst_oss4_sink_getcaps (GstBaseSink * bsink) +gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstOss4Sink *oss; GstCaps *caps; @@ -401,7 +393,16 @@ gst_oss4_sink_getcaps (GstBaseSink * bsink) } } - return caps; + if (filter && caps) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + return intersection; + } else { + return caps; + } } /* note: we must not take the object lock here unless we fix up get_property */ @@ -576,7 +577,7 @@ gst_oss4_sink_close (GstAudioSink * asink) } static gboolean -gst_oss4_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +gst_oss4_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) { GstOss4Sink *oss; @@ -588,7 +589,8 @@ gst_oss4_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) return FALSE; } - oss->bytes_per_sample = spec->bytes_per_sample; + oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info); + return TRUE; } @@ -619,7 +621,7 @@ couldnt_reopen: } } -static guint +static gint gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length) { GstOss4Sink *oss; @@ -681,15 +683,3 @@ gst_oss4_sink_reset (GstAudioSink * asink) * same device/fd from multiple threads and might deadlock or blow up in * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */ } - -static void -gst_oss4_sink_init_interfaces (GType type) -{ - static const GInterfaceInfo svol_iface_info = { - NULL, NULL, NULL - }; - - g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_iface_info); - - gst_oss4_add_property_probe_interface (type); -} diff --git a/sys/oss4/oss4-sink.h b/sys/oss4/oss4-sink.h index b1489a7d80..47221955d8 100644 --- a/sys/oss4/oss4-sink.h +++ b/sys/oss4/oss4-sink.h @@ -47,8 +47,6 @@ struct _GstOss4Sink { gint mute_volume; GstCaps * probed_caps; - - GList * property_probe_list; }; struct _GstOss4SinkClass { diff --git a/sys/oss4/oss4-source.c b/sys/oss4/oss4-source.c index 5e4d447a04..4b39ce4ed9 100644 --- a/sys/oss4/oss4-source.c +++ b/sys/oss4/oss4-source.c @@ -50,7 +50,6 @@ #include #include -#include #include #define NO_LEGACY_MIXER @@ -74,10 +73,8 @@ enum PROP_DEVICE_NAME }; -static void gst_oss4_source_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstOss4Source, gst_oss4_source, GstAudioSrc, - GST_TYPE_AUDIO_SRC, gst_oss4_source_init_interfaces); +#define gst_oss4_source_parent_class parent_class +G_DEFINE_TYPE (GstOss4Source, gst_oss4_source, GST_TYPE_AUDIO_SRC); static void gst_oss4_source_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); @@ -87,44 +84,31 @@ static void gst_oss4_source_set_property (GObject * object, guint prop_id, static void gst_oss4_source_dispose (GObject * object); static void gst_oss4_source_finalize (GstOss4Source * osssrc); -static GstCaps *gst_oss4_source_getcaps (GstBaseSrc * bsrc); +static GstCaps *gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter); static gboolean gst_oss4_source_open (GstAudioSrc * asrc, gboolean silent_errors); static gboolean gst_oss4_source_open_func (GstAudioSrc * asrc); static gboolean gst_oss4_source_close (GstAudioSrc * asrc); static gboolean gst_oss4_source_prepare (GstAudioSrc * asrc, - GstRingBufferSpec * spec); + GstAudioRingBufferSpec * spec); static gboolean gst_oss4_source_unprepare (GstAudioSrc * asrc); static guint gst_oss4_source_read (GstAudioSrc * asrc, gpointer data, guint length); static guint gst_oss4_source_delay (GstAudioSrc * asrc); static void gst_oss4_source_reset (GstAudioSrc * asrc); -static void -gst_oss4_source_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstPadTemplate *templ; - - gst_element_class_set_static_metadata (element_class, - "OSS v4 Audio Source", "Source/Audio", - "Capture from a sound card via OSS version 4", - "Tim-Philipp Müller "); - - templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - gst_oss4_audio_get_template_caps ()); - gst_element_class_add_pad_template (element_class, templ); -} - static void gst_oss4_source_class_init (GstOss4SourceClass * klass) { GObjectClass *gobject_class; + GstElementClass *gstelement_class; GstBaseSrcClass *gstbasesrc_class; GstAudioSrcClass *gstaudiosrc_class; + GstPadTemplate *templ; gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; gstbasesrc_class = (GstBaseSrcClass *) klass; gstaudiosrc_class = (GstAudioSrcClass *) klass; @@ -153,10 +137,19 @@ gst_oss4_source_class_init (GstOss4SourceClass * klass) g_param_spec_string ("device-name", "Device name", "Human-readable name of the sound device", DEFAULT_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_set_static_metadata (gstelement_class, + "OSS v4 Audio Source", "Source/Audio", + "Capture from a sound card via OSS version 4", + "Tim-Philipp Müller "); + + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_oss4_audio_get_template_caps ()); + gst_element_class_add_pad_template (gstelement_class, templ); } static void -gst_oss4_source_init (GstOss4Source * osssrc, GstOss4SourceClass * g_class) +gst_oss4_source_init (GstOss4Source * osssrc) { const gchar *device; @@ -176,9 +169,6 @@ gst_oss4_source_finalize (GstOss4Source * oss) g_free (oss->device); oss->device = NULL; - g_list_free (oss->property_probe_list); - oss->property_probe_list = NULL; - G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (oss)); } @@ -265,7 +255,7 @@ gst_oss4_source_get_property (GObject * object, guint prop_id, } static GstCaps * -gst_oss4_source_getcaps (GstBaseSrc * bsrc) +gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter) { GstOss4Source *oss; GstCaps *caps; @@ -283,7 +273,16 @@ gst_oss4_source_getcaps (GstBaseSrc * bsrc) } } - return caps; + if (filter && caps) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + return intersection; + } else { + return caps; + } } /* note: we must not take the object lock here unless we fix up get_property */ @@ -414,14 +413,6 @@ gst_oss4_source_open_func (GstAudioSrc * asrc) return gst_oss4_source_open (asrc, FALSE); } -static void -gst_oss4_source_free_mixer_tracks (GstOss4Source * oss) -{ - g_list_foreach (oss->tracks, (GFunc) g_object_unref, NULL); - g_list_free (oss->tracks); - oss->tracks = NULL; -} - static gboolean gst_oss4_source_close (GstAudioSrc * asrc) { @@ -445,13 +436,11 @@ gst_oss4_source_close (GstAudioSrc * asrc) g_free (oss->device_name); oss->device_name = NULL; - gst_oss4_source_free_mixer_tracks (oss); - return TRUE; } static gboolean -gst_oss4_source_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +gst_oss4_source_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstOss4Source *oss; @@ -463,7 +452,8 @@ gst_oss4_source_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) return FALSE; } - oss->bytes_per_sample = spec->bytes_per_sample; + oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info); + return TRUE; } @@ -555,442 +545,3 @@ gst_oss4_source_reset (GstAudioSrc * asrc) * same device/fd from multiple threads and might deadlock or blow up in * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */ } - -/* GstMixer interface, which we abuse here for input selection, because we - * don't have a proper interface for that and because that's what - * gnome-sound-recorder does. */ - -/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ -G_DEFINE_TYPE (GstOss4SourceInput, gst_oss4_source_input, GST_TYPE_MIXER_TRACK); - -static void -gst_oss4_source_input_class_init (GstOss4SourceInputClass * klass) -{ - /* nothing to do here */ -} - -static void -gst_oss4_source_input_init (GstOss4SourceInput * i) -{ - /* nothing to do here */ -} - -#if 0 - -static void -gst_ossmixer_ensure_track_list (GstOssMixer * mixer) -{ - gint i, master = -1; - - g_return_if_fail (mixer->fd != -1); - - if (mixer->tracklist) - return; - - /* find master volume */ - if (mixer->devmask & SOUND_MASK_VOLUME) - master = SOUND_MIXER_VOLUME; - else if (mixer->devmask & SOUND_MASK_PCM) - master = SOUND_MIXER_PCM; - else if (mixer->devmask & SOUND_MASK_SPEAKER) - master = SOUND_MIXER_SPEAKER; /* doubtful... */ - /* else: no master, so we won't set any */ - - /* build track list */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (mixer->devmask & (1 << i)) { - GstMixerTrack *track; - gboolean input = FALSE, stereo = FALSE, record = FALSE; - - /* track exists, make up capabilities */ - if (MASK_BIT_IS_SET (mixer->stereomask, i)) - stereo = TRUE; - if (MASK_BIT_IS_SET (mixer->recmask, i)) - input = TRUE; - if (MASK_BIT_IS_SET (mixer->recdevs, i)) - record = TRUE; - - /* do we want mixer in our list? */ - if (!((mixer->dir & GST_OSS_MIXER_CAPTURE && input == TRUE) || - (mixer->dir & GST_OSS_MIXER_PLAYBACK && i != SOUND_MIXER_PCM))) - /* the PLAYBACK case seems hacky, but that's how 0.8 had it */ - continue; - - /* add track to list */ - track = gst_ossmixer_track_new (mixer->fd, i, stereo ? 2 : 1, - (record ? GST_MIXER_TRACK_RECORD : 0) | - (input ? GST_MIXER_TRACK_INPUT : - GST_MIXER_TRACK_OUTPUT) | - ((master != i) ? 0 : GST_MIXER_TRACK_MASTER)); - mixer->tracklist = g_list_append (mixer->tracklist, track); - } - } -} - -/* unused with G_DISABLE_* */ -static G_GNUC_UNUSED gboolean -gst_ossmixer_contains_track (GstOssMixer * mixer, GstOssMixerTrack * osstrack) -{ - const GList *item; - - for (item = mixer->tracklist; item != NULL; item = item->next) - if (item->data == osstrack) - return TRUE; - - return FALSE; -} - -const GList * -gst_ossmixer_list_tracks (GstOssMixer * mixer) -{ - gst_ossmixer_ensure_track_list (mixer); - - return (const GList *) mixer->tracklist; -} - -void -gst_ossmixer_get_volume (GstOssMixer * mixer, - GstMixerTrack * track, gint * volumes) -{ - gint volume; - GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - - g_return_if_fail (mixer->fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); - - if (track->flags & GST_MIXER_TRACK_MUTE) { - volumes[0] = osstrack->lvol; - if (track->num_channels == 2) { - volumes[1] = osstrack->rvol; - } - } else { - /* get */ - if (ioctl (mixer->fd, MIXER_READ (osstrack->track_num), &volume) < 0) { - g_warning ("Error getting recording device (%d) volume: %s", - osstrack->track_num, g_strerror (errno)); - volume = 0; - } - - osstrack->lvol = volumes[0] = (volume & 0xff); - if (track->num_channels == 2) { - osstrack->rvol = volumes[1] = ((volume >> 8) & 0xff); - } - } -} - -void -gst_ossmixer_set_mute (GstOssMixer * mixer, GstMixerTrack * track, - gboolean mute) -{ - int volume; - GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - - g_return_if_fail (mixer->fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); - - if (mute) { - volume = 0; - } else { - volume = (osstrack->lvol & 0xff); - if (MASK_BIT_IS_SET (mixer->stereomask, osstrack->track_num)) { - volume |= ((osstrack->rvol & 0xff) << 8); - } - } - - if (ioctl (mixer->fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { - g_warning ("Error setting mixer recording device volume (0x%x): %s", - volume, g_strerror (errno)); - return; - } - - if (mute) { - track->flags |= GST_MIXER_TRACK_MUTE; - } else { - track->flags &= ~GST_MIXER_TRACK_MUTE; - } -} -#endif - -static gint -gst_oss4_source_mixer_get_current_input (GstOss4Source * oss) -{ - int cur = -1; - - if (ioctl (oss->fd, SNDCTL_DSP_GET_RECSRC, &cur) == -1 || cur < 0) - return -1; - - return cur; -} - -static const gchar * -gst_oss4_source_mixer_update_record_flags (GstOss4Source * oss, gint cur_route) -{ - const gchar *cur_name = ""; - GList *t; - - for (t = oss->tracks; t != NULL; t = t->next) { - GstMixerTrack *track = t->data; - - if (GST_OSS4_SOURCE_INPUT (track)->route == cur_route) { - if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) { - track->flags |= GST_MIXER_TRACK_RECORD; - /* no point in sending a mixer-record-changes message here */ - } - cur_name = track->label; - } else { - if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) { - track->flags &= ~GST_MIXER_TRACK_RECORD; - /* no point in sending a mixer-record-changes message here */ - } - } - } - - return cur_name; -} - -static const GList * -gst_oss4_source_mixer_list_tracks (GstMixer * mixer) -{ - oss_mixer_enuminfo names = { 0, }; - GstOss4Source *oss; - const gchar *cur_name; - GList *tracks = NULL; - gint i, cur; - - g_return_val_if_fail (mixer != NULL, NULL); - g_return_val_if_fail (GST_IS_OSS4_SOURCE (mixer), NULL); - g_return_val_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer), NULL); - - oss = GST_OSS4_SOURCE (mixer); - - if (oss->tracks != NULL && oss->tracks_static) - goto done; - - if (ioctl (oss->fd, SNDCTL_DSP_GET_RECSRC_NAMES, &names) == -1) - goto get_recsrc_names_error; - - oss->tracks_static = (names.version == 0); - - GST_INFO_OBJECT (oss, "%d inputs (list is static: %s):", names.nvalues, - (oss->tracks_static) ? "yes" : "no"); - - for (i = 0; i < MIN (names.nvalues, OSS_ENUM_MAXVALUE + 1); ++i) { - GstMixerTrack *track; - - track = g_object_new (GST_TYPE_OSS4_SOURCE_INPUT, NULL); - track->label = g_strdup (&names.strings[names.strindex[i]]); - track->flags = GST_MIXER_TRACK_INPUT; - track->num_channels = 2; - track->min_volume = 0; - track->max_volume = 100; - GST_OSS4_SOURCE_INPUT (track)->route = i; - - GST_INFO_OBJECT (oss, " [%d] %s", i, track->label); - tracks = g_list_append (tracks, track); - } - - gst_oss4_source_free_mixer_tracks (oss); - oss->tracks = tracks; - -done: - - /* update RECORD flags */ - cur = gst_oss4_source_mixer_get_current_input (oss); - cur_name = gst_oss4_source_mixer_update_record_flags (oss, cur); - GST_DEBUG_OBJECT (oss, "current input route: %d (%s)", cur, cur_name); - - return (const GList *) oss->tracks; - -/* ERRORS */ -get_recsrc_names_error: - { - GST_WARNING_OBJECT (oss, "GET_RECSRC_NAMES failed: %s", g_strerror (errno)); - return NULL; - } -} - -static void -gst_oss4_source_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - GstOss4Source *oss; - int new_vol, cur; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (track != NULL); - g_return_if_fail (GST_IS_MIXER_TRACK (track)); - g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); - g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); - - oss = GST_OSS4_SOURCE (mixer); - - cur = gst_oss4_source_mixer_get_current_input (oss); - if (cur != GST_OSS4_SOURCE_INPUT (track)->route) { - GST_DEBUG_OBJECT (oss, "track not selected input route, ignoring request"); - return; - } - - new_vol = (volumes[1] << 8) | volumes[0]; - if (ioctl (oss->fd, SNDCTL_DSP_SETRECVOL, &new_vol) == -1) { - GST_WARNING_OBJECT (oss, "SETRECVOL failed: %s", g_strerror (errno)); - } -} - -static void -gst_oss4_source_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - GstOss4Source *oss; - int cur; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); - g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); - - oss = GST_OSS4_SOURCE (mixer); - - cur = gst_oss4_source_mixer_get_current_input (oss); - if (cur != GST_OSS4_SOURCE_INPUT (track)->route) { - volumes[0] = 0; - volumes[1] = 0; - } else { - int vol = -1; - - if (ioctl (oss->fd, SNDCTL_DSP_GETRECVOL, &vol) == -1 || vol < 0) { - GST_WARNING_OBJECT (oss, "GETRECVOL failed: %s", g_strerror (errno)); - volumes[0] = 100; - volumes[1] = 100; - } else { - volumes[0] = MIN (100, vol & 0xff); - volumes[1] = MIN (100, (vol >> 8) & 0xff); - } - } -} - -static void -gst_oss4_source_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, - gboolean record) -{ - GstOss4Source *oss; - const gchar *cur_name; - gint cur; - - g_return_if_fail (mixer != NULL); - g_return_if_fail (track != NULL); - g_return_if_fail (GST_IS_MIXER_TRACK (track)); - g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); - g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); - - oss = GST_OSS4_SOURCE (mixer); - - cur = gst_oss4_source_mixer_get_current_input (oss); - - /* stop recording for an input that's not selected anyway => nothing to do */ - if (!record && cur != GST_OSS4_SOURCE_INPUT (track)->route) - goto done; - - /* select recording for an input that's already selected => nothing to do - * (or should we mess with the recording volume in this case maybe?) */ - if (record && cur == GST_OSS4_SOURCE_INPUT (track)->route) - goto done; - - /* make current input stop recording: we can't really make an input stop - * recording, we can only select an input FOR recording, so we'll just ignore - * all requests to stop for now */ - if (!record) { - GST_WARNING_OBJECT (oss, "Can't un-select an input as such, only switch " - "to a different input source"); - /* FIXME: set recording volume to 0 maybe? */ - } else { - int new_route = GST_OSS4_SOURCE_INPUT (track)->route; - - /* select this input for recording */ - - if (ioctl (oss->fd, SNDCTL_DSP_SET_RECSRC, &new_route) == -1) { - GST_WARNING_OBJECT (oss, "Could not select input %d for recording: %s", - new_route, g_strerror (errno)); - } else { - cur = new_route; - } - } - -done: - - cur_name = gst_oss4_source_mixer_update_record_flags (oss, cur); - GST_DEBUG_OBJECT (oss, "active input route: %d (%s)", cur, cur_name); -} - -static void -gst_oss4_source_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, - gboolean mute) -{ - g_return_if_fail (mixer != NULL); - g_return_if_fail (track != NULL); - g_return_if_fail (GST_IS_MIXER_TRACK (track)); - g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); - g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); - - /* FIXME: implement gst_oss4_source_mixer_set_mute() - what to do here? */ - /* oss4_mixer_set_mute (mixer->mixer, track, mute); */ -} - -static void -gst_oss4_source_mixer_interface_init (GstMixerInterface * iface) -{ - GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE; - - iface->list_tracks = gst_oss4_source_mixer_list_tracks; - iface->set_volume = gst_oss4_source_mixer_set_volume; - iface->get_volume = gst_oss4_source_mixer_get_volume; - iface->set_mute = gst_oss4_source_mixer_set_mute; - iface->set_record = gst_oss4_source_mixer_set_record; -} - -/* Implement the horror that is GstImplementsInterface */ - -static gboolean -gst_oss4_source_mixer_supported (GstImplementsInterface * iface, - GType iface_type) -{ - GstOss4Source *oss; - gboolean is_open; - - g_return_val_if_fail (GST_IS_OSS4_SOURCE (iface), FALSE); - g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); - - oss = GST_OSS4_SOURCE (iface); - - GST_OBJECT_LOCK (oss); - is_open = GST_OSS4_SOURCE_IS_OPEN (iface); - GST_OBJECT_UNLOCK (oss); - - return is_open; -} - -static void -gst_oss4_source_mixer_implements_interface_init (GstImplementsInterfaceClass * - klass) -{ - klass->supported = gst_oss4_source_mixer_supported; -} - -static void -gst_oss4_source_init_interfaces (GType type) -{ - static const GInterfaceInfo implements_iface_info = { - (GInterfaceInitFunc) gst_oss4_source_mixer_implements_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo mixer_iface_info = { - (GInterfaceInitFunc) gst_oss4_source_mixer_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, - &implements_iface_info); - g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info); - - gst_oss4_add_property_probe_interface (type); -} diff --git a/sys/oss4/oss4-source.h b/sys/oss4/oss4-source.h index 3a86b43ad1..f30021ee37 100644 --- a/sys/oss4/oss4-source.h +++ b/sys/oss4/oss4-source.h @@ -22,7 +22,6 @@ #include #include -#include G_BEGIN_DECLS @@ -46,13 +45,6 @@ struct _GstOss4Source { gint bytes_per_sample; GstCaps * probed_caps; - - /* property probe interface */ - GList * property_probe_list; - - /* mixer interface */ - GList * tracks; - gboolean tracks_static; /* FALSE if the list of inputs may change */ }; struct _GstOss4SourceClass { @@ -61,28 +53,6 @@ struct _GstOss4SourceClass { GType gst_oss4_source_get_type (void); -/* our mixer track for input selection */ -#define GST_TYPE_OSS4_SOURCE_INPUT (gst_oss4_source_input_get_type()) -#define GST_OSS4_SOURCE_INPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SOURCE_INPUT,GstOss4SourceInput)) -#define GST_OSS4_SOURCE_INPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SOURCE_INPUT,GstOss4SourceInputClass)) -#define GST_IS_OSS4_SOURCE_INPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SOURCE_INPUT)) -#define GST_IS_OSS4_SOURCE_INPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SOURCE_INPUT)) - -typedef struct _GstOss4SourceInput GstOss4SourceInput; -typedef struct _GstOss4SourceInputClass GstOss4SourceInputClass; - -struct _GstOss4SourceInput { - GstMixerTrack mixer_track; - - int route; /* number for SNDCTL_DSP_SET_RECSRC etc. */ -}; - -struct _GstOss4SourceInputClass { - GstMixerTrackClass mixer_track_class; -}; - -GType gst_oss4_source_input_get_type (void); - G_END_DECLS #endif /* GST_OSS4_SOURCE_H */