1 /* Copyright (C) 2001 CodeFactory AB 2 * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se> 3 * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu> 4 * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de> 5 * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public 18 * License along with this library; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 20 */ 21 22 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray 23 * with newer GLib versions (>= 2.31.0) */ 24 #define GLIB_DISABLE_DEPRECATION_WARNINGS 25 26 #ifdef HAVE_CONFIG_H 27 #include "config.h" 28 #endif 29 30 #include "gstalsadeviceprobe.h" 31 32 #if 0 33 G_LOCK_DEFINE_STATIC (probe_lock); 34 35 static const GList * 36 gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe) 37 { 38 GObjectClass *klass = G_OBJECT_GET_CLASS (probe); 39 static GList *list = NULL; 40 41 G_LOCK (probe_lock); 42 43 if (!list) { 44 GParamSpec *pspec; 45 46 pspec = g_object_class_find_property (klass, "device"); 47 list = g_list_append (NULL, pspec); 48 } 49 50 G_UNLOCK (probe_lock); 51 52 return list; 53 } 54 55 static GList * 56 gst_alsa_get_device_list (snd_pcm_stream_t stream) 57 { 58 snd_ctl_t *handle; 59 int card, dev; 60 snd_ctl_card_info_t *info; 61 snd_pcm_info_t *pcminfo; 62 gboolean mixer = (stream == -1); 63 GList *list = NULL; 64 65 if (stream == -1) 66 stream = 0; 67 68 snd_ctl_card_info_malloc (&info); 69 snd_pcm_info_malloc (&pcminfo); 70 card = -1; 71 72 if (snd_card_next (&card) < 0 || card < 0) { 73 /* no soundcard found */ 74 GST_WARNING ("No soundcard found"); 75 goto beach; 76 } 77 78 while (card >= 0) { 79 gchar name[32]; 80 81 g_snprintf (name, sizeof (name), "hw:%d", card); 82 if (snd_ctl_open (&handle, name, 0) < 0) { 83 goto next_card; 84 } 85 if (snd_ctl_card_info (handle, info) < 0) { 86 snd_ctl_close (handle); 87 goto next_card; 88 } 89 90 if (mixer) { 91 list = g_list_append (list, g_strdup (name)); 92 } else { 93 dev = -1; 94 while (1) { 95 gchar *gst_device; 96 97 snd_ctl_pcm_next_device (handle, &dev); 98 99 if (dev < 0) 100 break; 101 snd_pcm_info_set_device (pcminfo, dev); 102 snd_pcm_info_set_subdevice (pcminfo, 0); 103 snd_pcm_info_set_stream (pcminfo, stream); 104 if (snd_ctl_pcm_info (handle, pcminfo) < 0) { 105 continue; 106 } 107 108 gst_device = g_strdup_printf ("hw:%d,%d", card, dev); 109 list = g_list_append (list, gst_device); 110 } 111 } 112 snd_ctl_close (handle); 113 next_card: 114 if (snd_card_next (&card) < 0) { 115 break; 116 } 117 } 118 119 beach: 120 snd_ctl_card_info_free (info); 121 snd_pcm_info_free (pcminfo); 122 123 return list; 124 } 125 126 static void 127 gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe, 128 guint prop_id, const GParamSpec * pspec) 129 { 130 if (!g_str_equal (pspec->name, "device")) { 131 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); 132 } 133 } 134 135 static gboolean 136 gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe, 137 guint prop_id, const GParamSpec * pspec) 138 { 139 /* don't cache probed data */ 140 return TRUE; 141 } 142 143 static GValueArray * 144 gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe, 145 guint prop_id, const GParamSpec * pspec) 146 { 147 GstElementClass *klass; 148 const GList *templates; 149 snd_pcm_stream_t mode = -1; 150 GValueArray *array; 151 GValue value = { 0, }; 152 GList *l, *list; 153 154 if (!g_str_equal (pspec->name, "device")) { 155 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); 156 return NULL; 157 } 158 159 klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe)); 160 161 /* I'm pretty sure ALSA has a good way to do this. However, their cool 162 * auto-generated documentation is pretty much useless if you try to 163 * do function-wise look-ups. */ 164 /* we assume one pad template at max [zero=mixer] */ 165 templates = gst_element_class_get_pad_template_list (klass); 166 if (templates) { 167 if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC) 168 mode = SND_PCM_STREAM_CAPTURE; 169 else 170 mode = SND_PCM_STREAM_PLAYBACK; 171 } 172 173 list = gst_alsa_get_device_list (mode); 174 175 if (list == NULL) { 176 GST_LOG_OBJECT (probe, "No devices found"); 177 return NULL; 178 } 179 180 array = g_value_array_new (g_list_length (list)); 181 g_value_init (&value, G_TYPE_STRING); 182 for (l = list; l != NULL; l = l->next) { 183 GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data); 184 g_value_take_string (&value, (gchar *) l->data); 185 l->data = NULL; 186 g_value_array_append (array, &value); 187 } 188 g_value_unset (&value); 189 g_list_free (list); 190 191 return array; 192 } 193 194 static void 195 gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface) 196 { 197 iface->get_properties = gst_alsa_device_property_probe_get_properties; 198 iface->probe_property = gst_alsa_device_property_probe_probe_property; 199 iface->needs_probe = gst_alsa_device_property_probe_needs_probe; 200 iface->get_values = gst_alsa_device_property_probe_get_values; 201 } 202 203 void 204 gst_alsa_type_add_device_property_probe_interface (GType type) 205 { 206 static const GInterfaceInfo probe_iface_info = { 207 (GInterfaceInitFunc) gst_alsa_property_probe_interface_init, 208 NULL, 209 NULL, 210 }; 211 212 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, 213 &probe_iface_info); 214 } 215 #endif 216