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