|
1 /* GStreamer |
|
2 * Copyright (C) 2003-2004 Ronald Bultje <rbultje@ronald.bitfreak.net> |
|
3 * Copyright (C) 2005-2006 Tim-Philipp Müller <tim centricular net> |
|
4 * |
|
5 * This library is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU Library General Public |
|
7 * License as published by the Free Software Foundation; either |
|
8 * version 2 of the License, or (at your option) any later version. |
|
9 * |
|
10 * This library is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 * Library General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Library General Public |
|
16 * License along with this library; if not, write to the |
|
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
18 * Boston, MA 02111-1307, USA. |
|
19 */ |
|
20 |
|
21 /** |
|
22 * SECTION:gstaudiomixerutils |
|
23 * @short_description: utility functions to find available audio mixers |
|
24 * from the plugin registry |
|
25 * |
|
26 * <refsect2> |
|
27 * <para> |
|
28 * Provides some utility functions to detect available audio mixers |
|
29 * on the system. |
|
30 * </para> |
|
31 * </refsect2> |
|
32 */ |
|
33 |
|
34 #ifdef HAVE_CONFIG_H |
|
35 #include "config.h" |
|
36 #endif |
|
37 |
|
38 #include "mixerutils.h" |
|
39 |
|
40 #include <gst/interfaces/propertyprobe.h> |
|
41 |
|
42 #include <string.h> |
|
43 |
|
44 static void |
|
45 gst_audio_mixer_filter_do_filter (GstAudioMixerFilterFunc filter_func, |
|
46 GstElementFactory * factory, |
|
47 GstElement ** p_element, GList ** p_collection, gpointer user_data) |
|
48 { |
|
49 /* so, the element is a mixer, let's see if the caller wants it */ |
|
50 if (filter_func != NULL) { |
|
51 if (filter_func (GST_MIXER (*p_element), user_data) == TRUE) { |
|
52 *p_collection = g_list_prepend (*p_collection, *p_element); |
|
53 /* do not set state back to NULL here on purpose, caller |
|
54 * might want to keep the mixer open */ |
|
55 *p_element = NULL; |
|
56 } |
|
57 } else { |
|
58 gst_element_set_state (*p_element, GST_STATE_NULL); |
|
59 *p_collection = g_list_prepend (*p_collection, *p_element); |
|
60 *p_element = NULL; |
|
61 } |
|
62 |
|
63 /* create new element for further probing if the old one was cleared */ |
|
64 if (*p_element == NULL) { |
|
65 *p_element = gst_element_factory_create (factory, NULL); |
|
66 } |
|
67 } |
|
68 |
|
69 static gboolean |
|
70 gst_audio_mixer_filter_check_element (GstElement * element) |
|
71 { |
|
72 GstStateChangeReturn ret; |
|
73 |
|
74 /* open device (only then we can know for sure whether it is a mixer) */ |
|
75 gst_element_set_state (element, GST_STATE_READY); |
|
76 ret = gst_element_get_state (element, NULL, NULL, 1 * GST_SECOND); |
|
77 if (ret != GST_STATE_CHANGE_SUCCESS) { |
|
78 GST_DEBUG ("could not open device / set element to READY"); |
|
79 gst_element_set_state (element, GST_STATE_NULL); |
|
80 return FALSE; |
|
81 } |
|
82 |
|
83 /* is this device a mixer? */ |
|
84 if (!GST_IS_MIXER (element)) { |
|
85 GST_DEBUG ("element is not a mixer"); |
|
86 gst_element_set_state (element, GST_STATE_NULL); |
|
87 return FALSE; |
|
88 } |
|
89 |
|
90 /* any tracks? */ |
|
91 if (!gst_mixer_list_tracks (GST_MIXER (element))) { |
|
92 GST_DEBUG ("element is a mixer, but has no tracks"); |
|
93 gst_element_set_state (element, GST_STATE_NULL); |
|
94 return FALSE; |
|
95 } |
|
96 |
|
97 GST_DEBUG ("element is a mixer with mixer tracks"); |
|
98 return TRUE; |
|
99 } |
|
100 |
|
101 static void |
|
102 gst_audio_mixer_filter_probe_feature (GstAudioMixerFilterFunc filter_func, |
|
103 GstElementFactory * factory, |
|
104 GList ** p_collection, gboolean first, gpointer user_data) |
|
105 { |
|
106 GstElement *element; |
|
107 |
|
108 GST_DEBUG ("probing %s ...", gst_element_factory_get_longname (factory)); |
|
109 |
|
110 /* create element */ |
|
111 element = gst_element_factory_create (factory, NULL); |
|
112 |
|
113 if (element == NULL) { |
|
114 GST_DEBUG ("could not create element from factory"); |
|
115 return; |
|
116 } |
|
117 |
|
118 GST_DEBUG ("created element %s (%p)", GST_ELEMENT_NAME (element), element); |
|
119 |
|
120 if (GST_IS_PROPERTY_PROBE (element)) { |
|
121 GstPropertyProbe *probe; |
|
122 const GParamSpec *devspec; |
|
123 |
|
124 probe = GST_PROPERTY_PROBE (element); |
|
125 |
|
126 GST_DEBUG ("probing available devices ..."); |
|
127 if ((devspec = gst_property_probe_get_property (probe, "device"))) { |
|
128 GValueArray *array; |
|
129 |
|
130 if ((array = gst_property_probe_probe_and_get_values (probe, devspec))) { |
|
131 guint n; |
|
132 |
|
133 GST_DEBUG ("there are %d available devices", array->n_values); |
|
134 |
|
135 /* set all devices and test for mixer */ |
|
136 for (n = 0; n < array->n_values; n++) { |
|
137 GValue *device; |
|
138 |
|
139 /* set this device */ |
|
140 device = g_value_array_get_nth (array, n); |
|
141 g_object_set_property (G_OBJECT (element), "device", device); |
|
142 |
|
143 GST_DEBUG ("trying device %s ..", g_value_get_string (device)); |
|
144 |
|
145 if (gst_audio_mixer_filter_check_element (element)) { |
|
146 gst_audio_mixer_filter_do_filter (filter_func, factory, &element, |
|
147 p_collection, user_data); |
|
148 |
|
149 if (first && *p_collection != NULL) { |
|
150 GST_DEBUG ("Stopping after first found mixer, as requested"); |
|
151 break; |
|
152 } |
|
153 } |
|
154 } |
|
155 g_value_array_free (array); |
|
156 } |
|
157 } |
|
158 } else { |
|
159 GST_DEBUG ("element does not support the property probe interface"); |
|
160 |
|
161 if (gst_audio_mixer_filter_check_element (element)) { |
|
162 gst_audio_mixer_filter_do_filter (filter_func, factory, &element, |
|
163 p_collection, user_data); |
|
164 } |
|
165 } |
|
166 |
|
167 if (element) { |
|
168 gst_element_set_state (element, GST_STATE_NULL); |
|
169 gst_object_unref (element); |
|
170 } |
|
171 } |
|
172 |
|
173 static gint |
|
174 element_factory_rank_compare_func (gconstpointer a, gconstpointer b) |
|
175 { |
|
176 gint rank_a = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (a)); |
|
177 gint rank_b = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (b)); |
|
178 |
|
179 /* make order chosen in the end more determinable */ |
|
180 if (rank_a == rank_b) { |
|
181 const gchar *name_a = GST_PLUGIN_FEATURE_NAME (GST_PLUGIN_FEATURE (a)); |
|
182 const gchar *name_b = GST_PLUGIN_FEATURE_NAME (GST_PLUGIN_FEATURE (b)); |
|
183 |
|
184 return g_ascii_strcasecmp (name_a, name_b); |
|
185 } |
|
186 |
|
187 return rank_b - rank_a; |
|
188 } |
|
189 |
|
190 /** |
|
191 * gst_audio_default_registry_mixer_filter: |
|
192 * @filter_func: filter function, or #NULL |
|
193 * @first: set to #TRUE if you only want the first suitable mixer element |
|
194 * @user_data: user data to pass to the filter function |
|
195 * |
|
196 * Utility function to find audio mixer elements. |
|
197 * |
|
198 * Will traverse the default plugin registry in order of plugin rank and |
|
199 * find usable audio mixer elements. The caller may optionally fine-tune |
|
200 * the selection by specifying a filter function. |
|
201 * |
|
202 * Returns: a #GList of audio mixer #GstElement<!-- -->s. You must free each |
|
203 * element in the list by setting it to NULL state and calling |
|
204 * gst_object_unref(). After that the list itself should be freed |
|
205 * using g_list_free(). |
|
206 * |
|
207 * Since: 0.10.2 |
|
208 */ |
|
209 #ifdef __SYMBIAN32__ |
|
210 EXPORT_C |
|
211 #endif |
|
212 |
|
213 GList * |
|
214 gst_audio_default_registry_mixer_filter (GstAudioMixerFilterFunc filter_func, |
|
215 gboolean first, gpointer data) |
|
216 { |
|
217 GList *mixer_list = NULL; |
|
218 GList *feature_list; |
|
219 GList *walk; |
|
220 |
|
221 /* go through all elements of a certain class and check whether |
|
222 * they implement a mixer. If so, add it to the list. */ |
|
223 feature_list = gst_registry_get_feature_list (gst_registry_get_default (), |
|
224 GST_TYPE_ELEMENT_FACTORY); |
|
225 |
|
226 feature_list = g_list_sort (feature_list, element_factory_rank_compare_func); |
|
227 |
|
228 for (walk = feature_list; walk != NULL; walk = walk->next) { |
|
229 GstElementFactory *factory; |
|
230 const gchar *klass; |
|
231 |
|
232 factory = GST_ELEMENT_FACTORY (walk->data); |
|
233 |
|
234 /* check category */ |
|
235 klass = gst_element_factory_get_klass (factory); |
|
236 if (strcmp (klass, "Generic/Audio") == 0) { |
|
237 gst_audio_mixer_filter_probe_feature (filter_func, factory, |
|
238 &mixer_list, first, data); |
|
239 } |
|
240 |
|
241 if (first && mixer_list != NULL) { |
|
242 GST_DEBUG ("Stopping after first found mixer, as requested"); |
|
243 break; |
|
244 } |
|
245 } |
|
246 |
|
247 gst_plugin_feature_list_free (feature_list); |
|
248 |
|
249 return g_list_reverse (mixer_list); |
|
250 } |