gst_plugins_base/gst-libs/gst/audio/mixerutils.c
changeset 0 0e761a78d257
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 }