Merge remote-tracking branch 'origin/master' into 0.11
[platform/upstream/gstreamer.git] / ext / alsa / gstalsasrc.c
index b9464b2..82615e1 100644 (file)
 
 /**
  * SECTION:element-alsasrc
- * @short_description: capture audio from an alsa device
  * @see_also: alsasink, alsamixer
  *
- * <refsect2>
- * <para>
  * This element reads data from an audio card using the ALSA API.
- * </para>
+ *
+ * <refsect2>
  * <title>Example pipelines</title>
- * <para>
- * Record from a sound card using ALSA and encode to Ogg/Vorbis.
- * </para>
- * <programlisting>
+ * |[
  * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
- * </programlisting>
+ * ]| Record from a sound card using ALSA and encode to Ogg/Vorbis.
  * </refsect2>
  *
  * Last reviewed on 2006-03-01 (0.10.4)
 
 #include "gstalsasrc.h"
 #include "gstalsadeviceprobe.h"
+#include "gst/glib-compat-private.h"
 
 #include <gst/gst-i18n-plugin.h>
 
-/* elementfactory information */
-static const GstElementDetails gst_alsasrc_details =
-GST_ELEMENT_DETAILS ("Audio source (ALSA)",
-    "Source/Audio",
-    "Read from a sound card via ALSA",
-    "Wim Taymans <wim@fluendo.com>");
-
 #define DEFAULT_PROP_DEVICE            "default"
 #define DEFAULT_PROP_DEVICE_NAME       ""
+#define DEFAULT_PROP_CARD_NAME         ""
 
 enum
 {
   PROP_0,
   PROP_DEVICE,
   PROP_DEVICE_NAME,
+  PROP_CARD_NAME,
+  PROP_LAST
 };
 
 static void gst_alsasrc_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaSrc, gst_alsasrc, GstAudioSrc,
-    GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces);
+#define gst_alsasrc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAlsaSrc, gst_alsasrc,
+    GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces (g_define_type_id));
 
 GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaSrc, gst_alsasrc_mixer);
 
@@ -86,11 +78,11 @@ static void gst_alsasrc_set_property (GObject * object,
 static void gst_alsasrc_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
 
-static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc);
+static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
 
 static gboolean gst_alsasrc_open (GstAudioSrc * asrc);
 static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc,
-    GstRingBufferSpec * spec);
+    GstAudioRingBufferSpec * spec);
 static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc);
 static gboolean gst_alsasrc_close (GstAudioSrc * asrc);
 static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length);
@@ -110,37 +102,11 @@ enum
 #endif
 
 static GstStaticPadTemplate alsasrc_src_factory =
-    GST_STATIC_PAD_TEMPLATE ("src",
+GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
-        "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
-        "signed = (boolean) { TRUE, FALSE }, "
-        "width = (int) 32, "
-        "depth = (int) 32, "
-        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
-        "audio/x-raw-int, "
-        "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
-        "signed = (boolean) { TRUE, FALSE }, "
-        "width = (int) 32, "
-        "depth = (int) 24, "
-        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
-        "audio/x-raw-int, "
-        "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
-        "signed = (boolean) { TRUE, FALSE }, "
-        "width = (int) 24, "
-        "depth = (int) 24, "
-        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
-        "audio/x-raw-int, "
-        "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
-        "signed = (boolean) { TRUE, FALSE }, "
-        "width = (int) 16, "
-        "depth = (int) 16, "
-        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
-        "audio/x-raw-int, "
-        "signed = (boolean) { TRUE, FALSE }, "
-        "width = (int) 8, "
-        "depth = (int) 8, "
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
     );
 
@@ -155,71 +121,43 @@ gst_alsasrc_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static gboolean
-gst_alsasrc_interface_supported (GstAlsaSrc * this, GType interface_type)
-{
-  /* only support this one interface (wrapped by GstImplementsInterface) */
-  g_assert (interface_type == GST_TYPE_MIXER);
-
-  return gst_alsasrc_mixer_supported (this, interface_type);
-}
-
-static void
-gst_implements_interface_init (GstImplementsInterfaceClass * klass)
-{
-  klass->supported = (gpointer) gst_alsasrc_interface_supported;
-}
-
 static void
 gst_alsasrc_init_interfaces (GType type)
 {
-  static const GInterfaceInfo implements_iface_info = {
-    (GInterfaceInitFunc) gst_implements_interface_init,
-    NULL,
-    NULL,
-  };
   static const GInterfaceInfo mixer_iface_info = {
     (GInterfaceInitFunc) gst_alsasrc_mixer_interface_init,
     NULL,
     NULL,
   };
 
-  g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
-      &implements_iface_info);
   g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
 
   gst_alsa_type_add_device_property_probe_interface (type);
 }
 
 static void
-gst_alsasrc_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_set_details (element_class, &gst_alsasrc_details);
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&alsasrc_src_factory));
-}
-
-static void
 gst_alsasrc_class_init (GstAlsaSrcClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
   GstBaseSrcClass *gstbasesrc_class;
-  GstBaseAudioSrcClass *gstbaseaudiosrc_class;
   GstAudioSrcClass *gstaudiosrc_class;
 
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
   gstbasesrc_class = (GstBaseSrcClass *) klass;
-  gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
   gstaudiosrc_class = (GstAudioSrcClass *) klass;
 
-  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_alsasrc_finalize);
-  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasrc_get_property);
-  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasrc_set_property);
+  gobject_class->finalize = gst_alsasrc_finalize;
+  gobject_class->get_property = gst_alsasrc_get_property;
+  gobject_class->set_property = gst_alsasrc_set_property;
+
+  gst_element_class_set_details_simple (gstelement_class,
+      "Audio source (ALSA)", "Source/Audio",
+      "Read from a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
+
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&alsasrc_src_factory));
 
   gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
 
@@ -234,12 +172,17 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass)
   g_object_class_install_property (gobject_class, PROP_DEVICE,
       g_param_spec_string ("device", "Device",
           "ALSA device, as defined in an asound configuration file",
-          DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
+          DEFAULT_PROP_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
       g_param_spec_string ("device-name", "Device name",
           "Human-readable name of the sound device",
-          DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE));
+          DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CARD_NAME,
+      g_param_spec_string ("card-name", "Card name",
+          "Human-readable name of the sound card",
+          DEFAULT_PROP_CARD_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -281,6 +224,11 @@ gst_alsasrc_get_property (GObject * object, guint prop_id,
           gst_alsa_find_device_name (GST_OBJECT_CAST (src),
               src->device, src->handle, SND_PCM_STREAM_CAPTURE));
       break;
+    case PROP_CARD_NAME:
+      g_value_take_string (value,
+          gst_alsa_find_card_name (GST_OBJECT_CAST (src),
+              src->device, SND_PCM_STREAM_CAPTURE));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -288,7 +236,7 @@ gst_alsasrc_get_property (GObject * object, guint prop_id,
 }
 
 static void
-gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class)
+gst_alsasrc_init (GstAlsaSrc * alsasrc)
 {
   GST_DEBUG_OBJECT (alsasrc, "initializing");
 
@@ -306,31 +254,39 @@ if ((err = call) < 0)           \
 
 
 static GstCaps *
-gst_alsasrc_getcaps (GstBaseSrc * bsrc)
+gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
 {
   GstElementClass *element_class;
   GstPadTemplate *pad_template;
   GstAlsaSrc *src;
-  GstCaps *caps;
+  GstCaps *caps, *templ_caps;
 
   src = GST_ALSA_SRC (bsrc);
 
   if (src->handle == NULL) {
     GST_DEBUG_OBJECT (src, "device not open, using template caps");
-    return NULL;                /* base class will get template caps for us */
+    return GST_BASE_SRC_CLASS (parent_class)->get_caps (bsrc, filter);
   }
 
   if (src->cached_caps) {
     GST_LOG_OBJECT (src, "Returning cached caps");
-    return gst_caps_ref (src->cached_caps);
+    if (filter)
+      return gst_caps_intersect_full (filter, src->cached_caps,
+          GST_CAPS_INTERSECT_FIRST);
+    else
+      return gst_caps_ref (src->cached_caps);
   }
 
   element_class = GST_ELEMENT_GET_CLASS (src);
   pad_template = gst_element_class_get_pad_template (element_class, "src");
   g_return_val_if_fail (pad_template != NULL, NULL);
 
+  templ_caps = gst_pad_template_get_caps (pad_template);
+  GST_INFO_OBJECT (src, "template caps %" GST_PTR_FORMAT, templ_caps);
+
   caps = gst_alsa_probe_supported_formats (GST_OBJECT (src), src->handle,
-      gst_pad_template_get_caps (pad_template));
+      templ_caps);
+  gst_caps_unref (templ_caps);
 
   if (caps) {
     src->cached_caps = gst_caps_ref (caps);
@@ -338,14 +294,23 @@ gst_alsasrc_getcaps (GstBaseSrc * bsrc)
 
   GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
 
-  return caps;
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    return intersection;
+  } else {
+    return caps;
+  }
 }
 
 static int
 set_hwparams (GstAlsaSrc * alsa)
 {
   guint rrate;
-  gint err, dir;
+  gint err;
   snd_pcm_hw_params_t *params;
 
   snd_pcm_hw_params_malloc (&params);
@@ -371,12 +336,12 @@ set_hwparams (GstAlsaSrc * alsa)
   if (alsa->buffer_time != -1) {
     /* set the buffer time */
     CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
-            &alsa->buffer_time, &dir), buffer_time);
+            &alsa->buffer_time, NULL), buffer_time);
   }
   if (alsa->period_time != -1) {
     /* set the period time */
     CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
-            &alsa->period_time, &dir), period_time);
+            &alsa->period_time, NULL), period_time);
   }
 
   /* write the parameters to device */
@@ -385,7 +350,7 @@ set_hwparams (GstAlsaSrc * alsa)
   CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
       buffer_size);
 
-  CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
+  CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL),
       period_size);
 
   snd_pcm_hw_params_free (params);
@@ -427,7 +392,8 @@ no_channels:
           g_strdup_printf (_
           ("Could not open device for recording in %d-channel mode"),
           alsa->channels);
-    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err)));
+    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg),
+        ("%s", snd_strerror (err)));
     g_free (msg);
     snd_pcm_hw_params_free (params);
     return err;
@@ -559,25 +525,99 @@ set_sw_params:
 }
 
 static gboolean
-alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
+alsasrc_parse_spec (GstAlsaSrc * alsa, GstAudioRingBufferSpec * spec)
 {
   switch (spec->type) {
-    case GST_BUFTYPE_LINEAR:
-      alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
-          spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
-      break;
-    case GST_BUFTYPE_FLOAT:
-      switch (spec->format) {
-        case GST_FLOAT32_LE:
+    case GST_BUFTYPE_RAW:
+      switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
+        case GST_AUDIO_FORMAT_U8:
+          alsa->format = SND_PCM_FORMAT_U8;
+          break;
+        case GST_AUDIO_FORMAT_S8:
+          alsa->format = SND_PCM_FORMAT_S8;
+          break;
+        case GST_AUDIO_FORMAT_S16LE:
+          alsa->format = SND_PCM_FORMAT_S16_LE;
+          break;
+        case GST_AUDIO_FORMAT_S16BE:
+          alsa->format = SND_PCM_FORMAT_S16_BE;
+          break;
+        case GST_AUDIO_FORMAT_U16LE:
+          alsa->format = SND_PCM_FORMAT_U16_LE;
+          break;
+        case GST_AUDIO_FORMAT_U16BE:
+          alsa->format = SND_PCM_FORMAT_U16_BE;
+          break;
+        case GST_AUDIO_FORMAT_S24_32LE:
+          alsa->format = SND_PCM_FORMAT_S24_LE;
+          break;
+        case GST_AUDIO_FORMAT_S24_32BE:
+          alsa->format = SND_PCM_FORMAT_S24_BE;
+          break;
+        case GST_AUDIO_FORMAT_U24_32LE:
+          alsa->format = SND_PCM_FORMAT_U24_LE;
+          break;
+        case GST_AUDIO_FORMAT_U24_32BE:
+          alsa->format = SND_PCM_FORMAT_U24_BE;
+          break;
+        case GST_AUDIO_FORMAT_S32LE:
+          alsa->format = SND_PCM_FORMAT_S32_LE;
+          break;
+        case GST_AUDIO_FORMAT_S32BE:
+          alsa->format = SND_PCM_FORMAT_S32_BE;
+          break;
+        case GST_AUDIO_FORMAT_U32LE:
+          alsa->format = SND_PCM_FORMAT_U32_LE;
+          break;
+        case GST_AUDIO_FORMAT_U32BE:
+          alsa->format = SND_PCM_FORMAT_U32_BE;
+          break;
+        case GST_AUDIO_FORMAT_S24LE:
+          alsa->format = SND_PCM_FORMAT_S24_3LE;
+          break;
+        case GST_AUDIO_FORMAT_S24BE:
+          alsa->format = SND_PCM_FORMAT_S24_3BE;
+          break;
+        case GST_AUDIO_FORMAT_U24LE:
+          alsa->format = SND_PCM_FORMAT_U24_3LE;
+          break;
+        case GST_AUDIO_FORMAT_U24BE:
+          alsa->format = SND_PCM_FORMAT_U24_3BE;
+          break;
+        case GST_AUDIO_FORMAT_S20LE:
+          alsa->format = SND_PCM_FORMAT_S20_3LE;
+          break;
+        case GST_AUDIO_FORMAT_S20BE:
+          alsa->format = SND_PCM_FORMAT_S20_3BE;
+          break;
+        case GST_AUDIO_FORMAT_U20LE:
+          alsa->format = SND_PCM_FORMAT_U20_3LE;
+          break;
+        case GST_AUDIO_FORMAT_U20BE:
+          alsa->format = SND_PCM_FORMAT_U20_3BE;
+          break;
+        case GST_AUDIO_FORMAT_S18LE:
+          alsa->format = SND_PCM_FORMAT_S18_3LE;
+          break;
+        case GST_AUDIO_FORMAT_S18BE:
+          alsa->format = SND_PCM_FORMAT_S18_3BE;
+          break;
+        case GST_AUDIO_FORMAT_U18LE:
+          alsa->format = SND_PCM_FORMAT_U18_3LE;
+          break;
+        case GST_AUDIO_FORMAT_U18BE:
+          alsa->format = SND_PCM_FORMAT_U18_3BE;
+          break;
+        case GST_AUDIO_FORMAT_F32LE:
           alsa->format = SND_PCM_FORMAT_FLOAT_LE;
           break;
-        case GST_FLOAT32_BE:
+        case GST_AUDIO_FORMAT_F32BE:
           alsa->format = SND_PCM_FORMAT_FLOAT_BE;
           break;
-        case GST_FLOAT64_LE:
+        case GST_AUDIO_FORMAT_F64LE:
           alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
           break;
-        case GST_FLOAT64_BE:
+        case GST_AUDIO_FORMAT_F64BE:
           alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
           break;
         default:
@@ -594,8 +634,8 @@ alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
       goto error;
 
   }
-  alsa->rate = spec->rate;
-  alsa->channels = spec->channels;
+  alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
+  alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
   alsa->buffer_time = spec->buffer_time;
   alsa->period_time = spec->latency_time;
   alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
@@ -644,7 +684,7 @@ open_error:
 }
 
 static gboolean
-gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
+gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
 {
   GstAlsaSrc *alsa;
   gint err;
@@ -660,13 +700,9 @@ gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
   CHECK (set_swparams (alsa), sw_params_failed);
   CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);
 
-  alsa->bytes_per_sample = spec->bytes_per_sample;
-  spec->segsize = alsa->period_size * spec->bytes_per_sample;
+  alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
+  spec->segsize = alsa->period_size * alsa->bpf;
   spec->segtotal = alsa->buffer_size / alsa->period_size;
-  spec->silence_sample[0] = 0;
-  spec->silence_sample[1] = 0;
-  spec->silence_sample[2] = 0;
-  spec->silence_sample[3] = 0;
 
   return TRUE;
 
@@ -707,37 +743,14 @@ static gboolean
 gst_alsasrc_unprepare (GstAudioSrc * asrc)
 {
   GstAlsaSrc *alsa;
-  gint err;
 
   alsa = GST_ALSA_SRC (asrc);
 
-  CHECK (snd_pcm_drop (alsa->handle), drop);
-
-  CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
-
-  CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block);
+  snd_pcm_drop (alsa->handle);
+  snd_pcm_hw_free (alsa->handle);
+  snd_pcm_nonblock (alsa->handle, 1);
 
   return TRUE;
-
-  /* ERRORS */
-drop:
-  {
-    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
-        ("Could not drop samples: %s", snd_strerror (err)));
-    return FALSE;
-  }
-hw_free:
-  {
-    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
-        ("Could not free hw params: %s", snd_strerror (err)));
-    return FALSE;
-  }
-non_block:
-  {
-    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
-        ("Could not set device to nonblocking: %s", snd_strerror (err)));
-    return FALSE;
-  }
 }
 
 static gboolean
@@ -746,6 +759,7 @@ gst_alsasrc_close (GstAudioSrc * asrc)
   GstAlsaSrc *alsa = GST_ALSA_SRC (asrc);
 
   snd_pcm_close (alsa->handle);
+  alsa->handle = NULL;
 
   if (alsa->mixer) {
     gst_alsa_mixer_free (alsa->mixer);
@@ -798,7 +812,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
 
   alsa = GST_ALSA_SRC (asrc);
 
-  cptr = length / alsa->bytes_per_sample;
+  cptr = length / alsa->bpf;
   ptr = data;
 
   GST_ALSA_SRC_LOCK (asrc);
@@ -818,7 +832,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
   }
   GST_ALSA_SRC_UNLOCK (asrc);
 
-  return length - cptr;
+  return length - (cptr * alsa->bpf);
 
 read_error:
   {