1 /* GStreamer OSS4 audio property probe interface implementation
2 * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
21 * with newer GLib versions (>= 2.31.0) */
22 #define GLIB_DISABLE_DEPRECATION_WARNINGS
31 #define NO_LEGACY_MIXER
32 #include "oss4-audio.h"
33 #include "oss4-sink.h"
34 #include "oss4-source.h"
35 #include "oss4-soundcard.h"
36 #include "oss4-property-probe.h"
38 #include <sys/types.h>
40 #include <sys/ioctl.h>
48 GST_DEBUG_CATEGORY_EXTERN (oss4_debug);
49 #define GST_CAT_DEFAULT oss4_debug
52 gst_oss4_property_probe_get_properties (GstPropertyProbe * probe)
54 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
57 GST_OBJECT_LOCK (GST_OBJECT (probe));
59 /* we create a new list and store it in the instance struct, since apparently
60 * we forgot to update the API for 0.10 (and why don't we mark probable
61 * properties with a flag instead anyway?). A bit hackish, but what can you
62 * do (can't really use a static variable since the pspec will be different
63 * for src and sink class); this isn't particularly pretty, but the best
64 * we can do given that we can't create a common base class (we could do
65 * fancy things with the interface, or use g_object_set_data instead, but
66 * it's not really going to make it much better) */
67 if (GST_IS_AUDIO_SINK_CLASS (klass)) {
68 list = GST_OSS4_SINK (probe)->property_probe_list;
69 } else if (GST_IS_AUDIO_SRC_CLASS (klass)) {
70 list = GST_OSS4_SOURCE (probe)->property_probe_list;
71 } else if (GST_IS_OSS4_MIXER_CLASS (klass)) {
72 list = GST_OSS4_MIXER (probe)->property_probe_list;
74 GST_OBJECT_UNLOCK (GST_OBJECT (probe));
75 g_return_val_if_reached (NULL);
81 pspec = g_object_class_find_property (klass, "device");
82 list = g_list_prepend (NULL, pspec);
84 if (GST_IS_AUDIO_SINK_CLASS (klass)) {
85 GST_OSS4_SINK (probe)->property_probe_list = list;
86 } else if (GST_IS_AUDIO_SRC_CLASS (klass)) {
87 GST_OSS4_SOURCE (probe)->property_probe_list = list;
88 } else if (GST_IS_OSS4_MIXER_CLASS (klass)) {
89 GST_OSS4_MIXER (probe)->property_probe_list = list;
93 GST_OBJECT_UNLOCK (GST_OBJECT (probe));
99 gst_oss4_property_probe_probe_property (GstPropertyProbe * probe,
100 guint prop_id, const GParamSpec * pspec)
102 if (!g_str_equal (pspec->name, "device")) {
103 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
108 gst_oss4_property_probe_needs_probe (GstPropertyProbe * probe,
109 guint prop_id, const GParamSpec * pspec)
111 /* don't cache probed data */
117 /* caller must ensure LOCK is taken (e.g. if ioctls need to be serialised) */
119 gst_oss4_property_probe_find_device_name (GstObject * obj, int fd,
120 const gchar * device_handle, gchar ** device_name)
122 struct oss_sysinfo si = { {0,}, };
125 if (ioctl (fd, SNDCTL_SYSINFO, &si) == 0) {
128 for (i = 0; i < si.numaudios; ++i) {
129 struct oss_audioinfo ai = { 0, };
132 if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) {
133 GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i);
136 if (strcmp (ai.devnode, device_handle) == 0) {
137 name = g_strdup (ai.name);
142 GST_WARNING_OBJECT (obj, "SYSINFO ioctl failed: %s", g_strerror (errno));
145 /* try ENGINEINFO as fallback (which is better than nothing) */
147 struct oss_audioinfo ai = { 0, };
149 GST_LOG_OBJECT (obj, "device %s not listed in AUDIOINFO", device_handle);
151 if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == 0)
152 name = g_strdup (ai.name);
155 GST_DEBUG_OBJECT (obj, "Device name: %s", GST_STR_NULL (name));
160 return (name != NULL);
164 gst_oss4_property_probe_find_device_name_nofd (GstObject * obj,
165 const gchar * device_handle, gchar ** device_name)
170 fd = open ("/dev/mixer", O_RDONLY);
174 res = gst_oss4_property_probe_find_device_name (obj, fd, device_handle,
182 gst_oss4_property_probe_get_audio_devices (GstObject * obj, int fd,
183 struct oss_sysinfo *si, int cap_mask)
185 GList *devices = NULL;
188 GST_LOG_OBJECT (obj, "%d audio/dsp devices", si->numaudios);
190 for (i = 0; i < si->numaudios; ++i) {
191 struct oss_audioinfo ai = { 0, };
194 if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) {
195 GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i);
199 if ((ai.caps & cap_mask) == 0) {
200 GST_DEBUG_OBJECT (obj, "audio device %d is not an %s device", i,
201 (cap_mask == PCM_CAP_OUTPUT) ? "output" : "input");
206 GST_DEBUG_OBJECT (obj, "audio device %d is not usable/enabled", i);
210 GST_DEBUG_OBJECT (obj, "audio device %d looks ok: %s (\"%s\")", i,
211 ai.devnode, ai.name);
213 devices = g_list_prepend (devices, g_strdup (ai.devnode));
216 return g_list_reverse (devices);
220 gst_oss4_property_probe_get_values (GstObject * probe, const gchar * pname)
222 struct oss_sysinfo si = { {0,}, };
223 GValueArray *array = NULL;
226 int cap_mask, fd = -1;
228 if (!g_str_equal (pname, "device")) {
229 GST_WARNING_OBJECT (probe, "invalid property");
233 obj = GST_OBJECT (probe);
235 GST_OBJECT_LOCK (obj);
237 /* figure out whether the element is a source or sink */
238 if (GST_IS_OSS4_SINK (probe)) {
239 GST_DEBUG_OBJECT (probe, "probing available output devices");
240 cap_mask = PCM_CAP_OUTPUT;
241 fd = GST_OSS4_SINK (probe)->fd;
242 } else if (GST_IS_OSS4_SOURCE (probe)) {
243 GST_DEBUG_OBJECT (probe, "probing available input devices");
244 cap_mask = PCM_CAP_INPUT;
245 fd = GST_OSS4_SOURCE (probe)->fd;
247 GST_OBJECT_UNLOCK (obj);
248 g_assert_not_reached ();
252 /* copy fd if it's open, so we can just unconditionally close() later */
256 /* this will also catch the unlikely case where the above dup() failed */
258 fd = open ("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);
261 else if (!gst_oss4_audio_check_version (GST_OBJECT (probe), fd))
265 if (ioctl (fd, SNDCTL_SYSINFO, &si) == -1)
268 devices = gst_oss4_property_probe_get_audio_devices (obj, fd, &si, cap_mask);
270 if (devices == NULL) {
271 GST_OBJECT_UNLOCK (obj);
272 GST_DEBUG_OBJECT (obj, "No devices found");
276 array = g_value_array_new (1);
278 for (l = devices; l != NULL; l = l->next) {
281 g_value_init (&val, G_TYPE_STRING);
282 g_value_take_string (&val, (gchar *) l->data);
284 g_value_array_append (array, &val);
285 g_value_unset (&val);
288 GST_OBJECT_UNLOCK (obj);
290 g_list_free (devices);
301 GST_OBJECT_UNLOCK (GST_OBJECT (probe));
302 GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe "
303 "available devices: %s", g_strerror (errno));
309 GST_OBJECT_UNLOCK (GST_OBJECT (probe));
310 GST_DEBUG_OBJECT (probe, "Legacy OSS (ie. not OSSv4), not supported");
316 GST_OBJECT_UNLOCK (GST_OBJECT (probe));
317 GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe "
318 "available devices: %s", g_strerror (errno));
325 gst_oss4_property_probe_interface_init (GstPropertyProbeInterface * iface)
327 iface->get_properties = gst_oss4_property_probe_get_properties;
328 iface->probe_property = gst_oss4_property_probe_probe_property;
329 iface->needs_probe = gst_oss4_property_probe_needs_probe;
330 iface->get_values = gst_oss4_property_probe_get_values;
334 gst_oss4_add_property_probe_interface (GType type)
336 static const GInterfaceInfo probe_iface_info = {
337 (GInterfaceInitFunc) gst_oss4_property_probe_interface_init,
342 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,