| /* GStreamer |
| * Copyright (C) 2003-2004 Ronald Bultje <rbultje@ronald.bitfreak.net> |
| * Copyright (C) 2005-2006 Tim-Philipp Müller <tim centricular net> |
| * |
| * 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. |
| */ |
| |
| /** |
| * SECTION:gstaudiomixerutils |
| * @short_description: utility functions to find available audio mixers |
| * from the plugin registry |
| * |
| * <refsect2> |
| * <para> |
| * Provides some utility functions to detect available audio mixers |
| * on the system. |
| * </para> |
| * </refsect2> |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "mixerutils.h" |
| |
| #include <gst/interfaces/propertyprobe.h> |
| |
| #include <string.h> |
| |
| static void |
| gst_audio_mixer_filter_do_filter (GstAudioMixerFilterFunc filter_func, |
| GstElementFactory * factory, |
| GstElement ** p_element, GList ** p_collection, gpointer user_data) |
| { |
| /* so, the element is a mixer, let's see if the caller wants it */ |
| if (filter_func != NULL) { |
| if (filter_func (GST_MIXER (*p_element), user_data) == TRUE) { |
| *p_collection = g_list_prepend (*p_collection, *p_element); |
| /* do not set state back to NULL here on purpose, caller |
| * might want to keep the mixer open */ |
| *p_element = NULL; |
| } |
| } else { |
| gst_element_set_state (*p_element, GST_STATE_NULL); |
| *p_collection = g_list_prepend (*p_collection, *p_element); |
| *p_element = NULL; |
| } |
| |
| /* create new element for further probing if the old one was cleared */ |
| if (*p_element == NULL) { |
| *p_element = gst_element_factory_create (factory, NULL); |
| } |
| } |
| |
| static gboolean |
| gst_audio_mixer_filter_check_element (GstElement * element) |
| { |
| GstStateChangeReturn ret; |
| |
| /* open device (only then we can know for sure whether it is a mixer) */ |
| gst_element_set_state (element, GST_STATE_READY); |
| ret = gst_element_get_state (element, NULL, NULL, 1 * GST_SECOND); |
| if (ret != GST_STATE_CHANGE_SUCCESS) { |
| GST_DEBUG ("could not open device / set element to READY"); |
| gst_element_set_state (element, GST_STATE_NULL); |
| return FALSE; |
| } |
| |
| /* is this device a mixer? */ |
| if (!GST_IS_MIXER (element)) { |
| GST_DEBUG ("element is not a mixer"); |
| gst_element_set_state (element, GST_STATE_NULL); |
| return FALSE; |
| } |
| |
| /* any tracks? */ |
| if (!gst_mixer_list_tracks (GST_MIXER (element))) { |
| GST_DEBUG ("element is a mixer, but has no tracks"); |
| gst_element_set_state (element, GST_STATE_NULL); |
| return FALSE; |
| } |
| |
| GST_DEBUG ("element is a mixer with mixer tracks"); |
| return TRUE; |
| } |
| |
| static void |
| gst_audio_mixer_filter_probe_feature (GstAudioMixerFilterFunc filter_func, |
| GstElementFactory * factory, |
| GList ** p_collection, gboolean first, gpointer user_data) |
| { |
| GstElement *element; |
| |
| GST_DEBUG ("probing %s ...", gst_element_factory_get_longname (factory)); |
| |
| /* create element */ |
| element = gst_element_factory_create (factory, NULL); |
| |
| if (element == NULL) { |
| GST_DEBUG ("could not create element from factory"); |
| return; |
| } |
| |
| GST_DEBUG ("created element %s (%p)", GST_ELEMENT_NAME (element), element); |
| |
| if (GST_IS_PROPERTY_PROBE (element)) { |
| GstPropertyProbe *probe; |
| const GParamSpec *devspec; |
| |
| probe = GST_PROPERTY_PROBE (element); |
| |
| GST_DEBUG ("probing available devices ..."); |
| if ((devspec = gst_property_probe_get_property (probe, "device"))) { |
| GValueArray *array; |
| |
| if ((array = gst_property_probe_probe_and_get_values (probe, devspec))) { |
| guint n; |
| |
| GST_DEBUG ("there are %d available devices", array->n_values); |
| |
| /* set all devices and test for mixer */ |
| for (n = 0; n < array->n_values; n++) { |
| GValue *device; |
| |
| /* set this device */ |
| device = g_value_array_get_nth (array, n); |
| g_object_set_property (G_OBJECT (element), "device", device); |
| |
| GST_DEBUG ("trying device %s ..", g_value_get_string (device)); |
| |
| if (gst_audio_mixer_filter_check_element (element)) { |
| gst_audio_mixer_filter_do_filter (filter_func, factory, &element, |
| p_collection, user_data); |
| |
| if (first && *p_collection != NULL) { |
| GST_DEBUG ("Stopping after first found mixer, as requested"); |
| break; |
| } |
| } |
| } |
| g_value_array_free (array); |
| } |
| } |
| } else { |
| GST_DEBUG ("element does not support the property probe interface"); |
| |
| if (gst_audio_mixer_filter_check_element (element)) { |
| gst_audio_mixer_filter_do_filter (filter_func, factory, &element, |
| p_collection, user_data); |
| } |
| } |
| |
| if (element) { |
| gst_element_set_state (element, GST_STATE_NULL); |
| gst_object_unref (element); |
| } |
| } |
| |
| static gint |
| element_factory_rank_compare_func (gconstpointer a, gconstpointer b) |
| { |
| gint rank_a = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (a)); |
| gint rank_b = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (b)); |
| |
| /* make order chosen in the end more determinable */ |
| if (rank_a == rank_b) { |
| const gchar *name_a = GST_OBJECT_NAME (GST_PLUGIN_FEATURE (a)); |
| const gchar *name_b = GST_OBJECT_NAME (GST_PLUGIN_FEATURE (b)); |
| |
| return g_ascii_strcasecmp (name_a, name_b); |
| } |
| |
| return rank_b - rank_a; |
| } |
| |
| /** |
| * gst_audio_default_registry_mixer_filter: |
| * @filter_func: filter function, or #NULL |
| * @first: set to #TRUE if you only want the first suitable mixer element |
| * @user_data: user data to pass to the filter function |
| * |
| * Utility function to find audio mixer elements. |
| * |
| * Will traverse the default plugin registry in order of plugin rank and |
| * find usable audio mixer elements. The caller may optionally fine-tune |
| * the selection by specifying a filter function. |
| * |
| * Returns: a #GList of audio mixer #GstElement<!-- -->s. You must free each |
| * element in the list by setting it to NULL state and calling |
| * gst_object_unref(). After that the list itself should be freed |
| * using g_list_free(). |
| * |
| * Since: 0.10.2 |
| */ |
| GList * |
| gst_audio_default_registry_mixer_filter (GstAudioMixerFilterFunc filter_func, |
| gboolean first, gpointer data) |
| { |
| GList *mixer_list = NULL; |
| GList *feature_list; |
| GList *walk; |
| |
| /* go through all elements of a certain class and check whether |
| * they implement a mixer. If so, add it to the list. */ |
| feature_list = gst_registry_get_feature_list (gst_registry_get_default (), |
| GST_TYPE_ELEMENT_FACTORY); |
| |
| feature_list = g_list_sort (feature_list, element_factory_rank_compare_func); |
| |
| for (walk = feature_list; walk != NULL; walk = walk->next) { |
| GstElementFactory *factory; |
| const gchar *klass; |
| |
| factory = GST_ELEMENT_FACTORY (walk->data); |
| |
| /* check category */ |
| klass = gst_element_factory_get_klass (factory); |
| if (strcmp (klass, "Generic/Audio") == 0) { |
| gst_audio_mixer_filter_probe_feature (filter_func, factory, |
| &mixer_list, first, data); |
| } |
| |
| if (first && mixer_list != NULL) { |
| GST_DEBUG ("Stopping after first found mixer, as requested"); |
| break; |
| } |
| } |
| |
| gst_plugin_feature_list_free (feature_list); |
| |
| return g_list_reverse (mixer_list); |
| } |