gst_plugins_base/ext/alsa/gstalsadeviceprobe.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
       
    20  */
       
    21 
       
    22 #ifdef HAVE_CONFIG_H
       
    23 #include "config.h"
       
    24 #endif
       
    25 
       
    26 #include "gstalsadeviceprobe.h"
       
    27 #include "gst/interfaces/propertyprobe.h"
       
    28 
       
    29 static const GList *
       
    30 gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe)
       
    31 {
       
    32   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
       
    33   static GList *list = NULL;
       
    34 
       
    35   /* well, not perfect, but better than no locking at all.
       
    36    * In the worst case we leak a list node, so who cares? */
       
    37   GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
       
    38 
       
    39   if (!list) {
       
    40     GParamSpec *pspec;
       
    41 
       
    42     pspec = g_object_class_find_property (klass, "device");
       
    43     list = g_list_append (NULL, pspec);
       
    44   }
       
    45 
       
    46   GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
       
    47 
       
    48   return list;
       
    49 }
       
    50 
       
    51 static GList *
       
    52 gst_alsa_get_device_list (snd_pcm_stream_t stream)
       
    53 {
       
    54   snd_ctl_t *handle;
       
    55   int card, err, dev;
       
    56   snd_ctl_card_info_t *info;
       
    57   snd_pcm_info_t *pcminfo;
       
    58   gboolean mixer = (stream == -1);
       
    59   GList *list = NULL;
       
    60 
       
    61   if (stream == -1)
       
    62     stream = 0;
       
    63 
       
    64   snd_ctl_card_info_malloc (&info);
       
    65   snd_pcm_info_malloc (&pcminfo);
       
    66   card = -1;
       
    67 
       
    68   if (snd_card_next (&card) < 0 || card < 0) {
       
    69     /* no soundcard found */
       
    70     return NULL;
       
    71   }
       
    72 
       
    73   while (card >= 0) {
       
    74     gchar name[32];
       
    75 
       
    76     g_snprintf (name, sizeof (name), "hw:%d", card);
       
    77     if ((err = snd_ctl_open (&handle, name, 0)) < 0) {
       
    78       goto next_card;
       
    79     }
       
    80     if ((err = snd_ctl_card_info (handle, info)) < 0) {
       
    81       snd_ctl_close (handle);
       
    82       goto next_card;
       
    83     }
       
    84 
       
    85     if (mixer) {
       
    86       list = g_list_append (list, g_strdup (name));
       
    87     } else {
       
    88       dev = -1;
       
    89       while (1) {
       
    90         gchar *gst_device;
       
    91 
       
    92         snd_ctl_pcm_next_device (handle, &dev);
       
    93 
       
    94         if (dev < 0)
       
    95           break;
       
    96         snd_pcm_info_set_device (pcminfo, dev);
       
    97         snd_pcm_info_set_subdevice (pcminfo, 0);
       
    98         snd_pcm_info_set_stream (pcminfo, stream);
       
    99         if ((err = snd_ctl_pcm_info (handle, pcminfo)) < 0) {
       
   100           continue;
       
   101         }
       
   102 
       
   103         gst_device = g_strdup_printf ("hw:%d,%d", card, dev);
       
   104         list = g_list_append (list, gst_device);
       
   105       }
       
   106     }
       
   107     snd_ctl_close (handle);
       
   108   next_card:
       
   109     if (snd_card_next (&card) < 0) {
       
   110       break;
       
   111     }
       
   112   }
       
   113 
       
   114   snd_ctl_card_info_free (info);
       
   115   snd_pcm_info_free (pcminfo);
       
   116 
       
   117   return list;
       
   118 }
       
   119 
       
   120 static void
       
   121 gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe,
       
   122     guint prop_id, const GParamSpec * pspec)
       
   123 {
       
   124   if (!g_str_equal (pspec->name, "device")) {
       
   125     G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
       
   126   }
       
   127 }
       
   128 
       
   129 static gboolean
       
   130 gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe,
       
   131     guint prop_id, const GParamSpec * pspec)
       
   132 {
       
   133   /* don't cache probed data */
       
   134   return TRUE;
       
   135 }
       
   136 
       
   137 static GValueArray *
       
   138 gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe,
       
   139     guint prop_id, const GParamSpec * pspec)
       
   140 {
       
   141   GstElementClass *klass;
       
   142   const GList *templates;
       
   143   snd_pcm_stream_t mode = -1;
       
   144   GValueArray *array;
       
   145   GValue value = { 0, };
       
   146   GList *l, *list;
       
   147 
       
   148   if (!g_str_equal (pspec->name, "device")) {
       
   149     G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
       
   150     return NULL;
       
   151   }
       
   152 
       
   153   klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe));
       
   154 
       
   155   /* I'm pretty sure ALSA has a good way to do this. However, their cool
       
   156    * auto-generated documentation is pretty much useless if you try to
       
   157    * do function-wise look-ups. */
       
   158   /* we assume one pad template at max [zero=mixer] */
       
   159   templates = gst_element_class_get_pad_template_list (klass);
       
   160   if (templates) {
       
   161     if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC)
       
   162       mode = SND_PCM_STREAM_CAPTURE;
       
   163     else
       
   164       mode = SND_PCM_STREAM_PLAYBACK;
       
   165   }
       
   166 
       
   167   list = gst_alsa_get_device_list (mode);
       
   168 
       
   169   if (list == NULL) {
       
   170     GST_LOG_OBJECT (probe, "No devices found");
       
   171     return NULL;
       
   172   }
       
   173 
       
   174   array = g_value_array_new (g_list_length (list));
       
   175   g_value_init (&value, G_TYPE_STRING);
       
   176   for (l = list; l != NULL; l = l->next) {
       
   177     GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data);
       
   178     g_value_take_string (&value, (gchar *) l->data);
       
   179     l->data = NULL;
       
   180     g_value_array_append (array, &value);
       
   181   }
       
   182   g_value_unset (&value);
       
   183   g_list_free (list);
       
   184 
       
   185   return array;
       
   186 }
       
   187 
       
   188 static void
       
   189 gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface)
       
   190 {
       
   191   iface->get_properties = gst_alsa_device_property_probe_get_properties;
       
   192   iface->probe_property = gst_alsa_device_property_probe_probe_property;
       
   193   iface->needs_probe = gst_alsa_device_property_probe_needs_probe;
       
   194   iface->get_values = gst_alsa_device_property_probe_get_values;
       
   195 }
       
   196 
       
   197 void
       
   198 gst_alsa_type_add_device_property_probe_interface (GType type)
       
   199 {
       
   200   static const GInterfaceInfo probe_iface_info = {
       
   201     (GInterfaceInitFunc) gst_alsa_property_probe_interface_init,
       
   202     NULL,
       
   203     NULL,
       
   204   };
       
   205 
       
   206   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
       
   207       &probe_iface_info);
       
   208 }