alsasrc works now, but it still uses hardcoded caps
authorBenjamin Otte <otte@gnome.org>
Thu, 24 Apr 2003 22:58:33 +0000 (22:58 +0000)
committerBenjamin Otte <otte@gnome.org>
Thu, 24 Apr 2003 22:58:33 +0000 (22:58 +0000)
Original commit message from CVS:
alsasrc works now, but it still uses hardcoded caps

ext/alsa/gstalsa.c
ext/alsa/gstalsa.h

index 3d41041..2520f8d 100644 (file)
@@ -115,7 +115,13 @@ static GstPadTemplate *            gst_alsa_src_pad_factory        (void);
 static GstPadTemplate *                gst_alsa_src_request_pad_factory (void);
 static void                    gst_alsa_src_class_init         (GstAlsaSrcClass *      klass);
 static void                    gst_alsa_src_init               (GstAlsaSrc *           this);
+static int                     gst_alsa_src_mmap               (GstAlsa *              this,
+                                                                snd_pcm_sframes_t *    avail);
+static int                     gst_alsa_src_read               (GstAlsa *              this,
+                                                                snd_pcm_sframes_t *    avail);
 static void                    gst_alsa_src_loop               (GstElement *           element);
+static void                    gst_alsa_src_flush              (GstAlsaSrc *           src);
+static GstElementStateReturn   gst_alsa_src_change_state       (GstElement *           element);
 
 /* GStreamer functions for pads and state changing */
 static GstPad *                        gst_alsa_request_new_pad        (GstElement *           element, 
@@ -868,7 +874,10 @@ gst_alsa_src_class_init (GstAlsaSrcClass *klass)
     src_parent_class = g_type_class_ref (GST_TYPE_ALSA);
 
   alsa_class->stream           = SND_PCM_STREAM_CAPTURE;
+  alsa_class->transmit_mmap    = gst_alsa_src_mmap;
+  alsa_class->transmit_rw      = gst_alsa_src_read;
 
+  element_class->change_state  = gst_alsa_src_change_state;
 }
 static void
 gst_alsa_src_init (GstAlsaSrc *src)
@@ -887,89 +896,207 @@ gst_alsa_src_init (GstAlsaSrc *src)
 
   gst_element_set_loop_function (GST_ELEMENT (this), gst_alsa_src_loop);
 }
+static int
+gst_alsa_src_mmap (GstAlsa *this, snd_pcm_sframes_t *avail)
+{
+  snd_pcm_uframes_t offset;
+  snd_pcm_channel_area_t *dst;
+  const snd_pcm_channel_area_t *src;
+  int i, err, width = snd_pcm_format_physical_width (this->format->format);
+  GstAlsaSrc *alsa_src = GST_ALSA_SRC (this);
+
+  /* areas points to the memory areas that belong to gstreamer. */
+  dst = calloc(this->format->channels, sizeof(snd_pcm_channel_area_t));
+
+  if (((GstElement *) this)->numpads == 1) {
+    /* interleaved */
+    for (i = 0; i < this->format->channels; i++) {
+      dst[i].addr = alsa_src->buf[0]->data;
+      dst[i].first = i * width;
+      dst[i].step = this->format->channels * width;
+    }
+  } else {
+    /* noninterleaved */
+    for (i = 0; i < this->format->channels; i++) {
+      dst[i].addr = alsa_src->buf[i]->data;
+      dst[i].first = 0;
+      dst[i].step = width;
+    }
+  }
+
+  if ((err = snd_pcm_mmap_begin (this->handle, &src, &offset, avail)) < 0) {
+    g_warning ("gstalsa: mmap failed: %s", snd_strerror (err));
+    return -1;
+  }
+  if (*avail > 0 && (err = snd_pcm_areas_copy (dst, 0, src, offset, this->format->channels, *avail, this->format->format)) < 0) {
+    snd_pcm_mmap_commit (this->handle, offset, 0);
+    g_warning ("gstalsa: data copy failed: %s", snd_strerror (err));
+    return -1;
+  }
+  if ((err = snd_pcm_mmap_commit (this->handle, offset, *avail)) < 0) {
+    g_warning ("gstalsa: mmap commit failed: %s", snd_strerror (err));
+    return -1;
+  }
+
+  return err;
+}
+static int
+gst_alsa_src_read (GstAlsa *this, snd_pcm_sframes_t *avail)
+{
+  void *channels[this->format->channels];
+  int err, i;
+  GstAlsaSrc *src = GST_ALSA_SRC (this);
+
+  if (((GstElement *) this)->numpads == 1) {
+    /* interleaved */
+    err = snd_pcm_readi (this->handle, src->buf[0]->data, *avail);
+  } else {
+    /* noninterleaved */
+    for (i = 0; i < this->format->channels; i++) {
+      channels[i] = src->buf[i]->data;
+    }
+    err = snd_pcm_readn (this->handle, channels, *avail);
+  }
+  /* error handling */
+  if (err < 0) {
+    if (err == -EPIPE) {
+      gst_alsa_xrun_recovery (this);
+      return 0;
+    }
+    g_warning ("error on data access: %s", snd_strerror (err));
+  }
+  return err;
+}
+static gboolean
+gst_alsa_src_set_caps (GstAlsaSrc *src)
+{
+  gint i;
+  GstCaps *caps;
+  GstAlsa *this = GST_ALSA (src);
+
+  if (!(this->format = g_new (GstAlsaFormat, 1)))
+    return FALSE;
+  /* FIXME: make this do proper caps nego */
+  this->format->format = SND_PCM_FORMAT_S16;
+  this->format->rate = 44100;
+  this->format->channels = GST_ELEMENT (src)->numpads;
+  GST_DEBUG (GST_CAT_NEGOTIATION, "starting caps negotiation on alsa src");
+  caps = gst_alsa_caps (this->format->format, this->format->rate, this->format->channels);
+  for (i = 0; i < GST_ELEMENT (src)->numpads; i++) {
+    if (gst_pad_try_set_caps (this->pad[i], caps) <= 0) {
+      GST_DEBUG (GST_CAT_NEGOTIATION, "setting caps (%p) in alsasrc (%p) on pad %d failed", caps, this, i);
+      return FALSE;
+    }
+  }
+  
+  if (GST_FLAG_IS_SET (this, GST_ALSA_RUNNING)) gst_alsa_stop_audio (this);
+  if (!gst_alsa_start_audio (this)) {
+    /* FIXME: Try the next format */
+    return FALSE;
+  }
+
+  return TRUE;
+}
+/* we transmit buffers of period_size frames */
 static void
 gst_alsa_src_loop (GstElement *element)
 {
-#if 0
   snd_pcm_sframes_t avail, copied;
-  GstBufferPool *pool = NULL;
-  GstBuffer *buf;
-  GstCaps *caps;
   gint i;
-  GstAlsaPad *pad;
   GstAlsa *this = GST_ALSA (element);
-
-  g_return_if_fail (this != NULL);
+  GstAlsaSrc *src = GST_ALSA_SRC (element);
 
   /* set the caps on all pads */
   if (!this->format) {
-    if (!(this->format = g_new (GstAlsaFormat, 1))) {
-      gst_element_error (element, "No more memory");
-    }
-    /* FIXME: make this settable */
-    this->format->format = SND_PCM_FORMAT_S16;
-    this->format->rate = 44100;
-    this->format->channels = (element->numpads == 1) ? 2 : element->numpads;
-    GST_DEBUG (GST_CAT_NEGOTIATION, "starting caps negotiationgst_alsa_pcm_wait");
-    caps = gst_alsa_caps (this->format->format, this->format->rate, this->format->channels);
-    for (i = 0; i < element->numpads; i++) {
-      if (gst_pad_try_set_caps (this->pads[i].pad, caps) <= 0) {
-        GST_DEBUG (GST_CAT_NEGOTIATION, "setting caps (%p) in alsasrc (%p) on pad %d failed", caps, this, i);
-        return;
-      }
+    if (!gst_alsa_src_set_caps (src)) {
+      gst_element_error (element, "Could not set caps");
+      return;
     }
+    /* get the bufferpool going */
+    if (src->pool)
+      gst_buffer_pool_unref (src->pool);
+    src->pool = gst_buffer_pool_get_default (gst_alsa_samples_to_bytes (this, this->period_size), 
+                                             2 * element->numpads);
   }
 
-src_restart:
-
   while ((avail = gst_alsa_update_avail (this)) < this->period_size) {
-    if (avail == -EPIPE) goto src_restart;
+    if (avail == -EPIPE) continue;
     if (avail < 0) return;
-    if (snd_pcm_state(this->handle) != SND_PCM_STATE_RUNNING) break;
+    if (snd_pcm_state(this->handle) != SND_PCM_STATE_RUNNING) {
+      if (!gst_alsa_start (this))
+       return;
+      continue;
+    };
     /* wait */
     if (gst_alsa_pcm_wait (this) == FALSE)
       return;
   }
-  if (avail > 0) {
-    int width = snd_pcm_format_physical_width (this->format->format);
-    int bytes_per_frame = ( width / 8 ) * (element->numpads == 1 ? this->format->channels : 1);
-    if ((copied = this->transmit (this, &avail)) < 0)
+  g_assert (avail >= this->period_size);
+  /* make sure every pad has a buffer */
+  for (i = 0; i < element->numpads; i++) {
+    if (!src->buf[i]) {
+      src->buf[i] = gst_buffer_new_from_pool (src->pool, 0, 0);
+    }
+  }
+  /* fill buffer with data */
+  if ((copied = this->transmit (this, &avail)) <= 0)
+    return;
+  /* push the buffers out and let them have fun */
+  for (i = 0; i < element->numpads; i++) {
+    if (!src->buf[i])
       return;
-      
-    /* we get the buffer pool once per go round */
-    if (! pool) pool = gst_alsa_src_get_buffer_pool (this->pads[0].pad);
-
-    /* push the data to gstreamer if it's big enough to fill up a buffer. */
-    for (i = 0; i < element->numpads; i++) {
-      pad = &this->pads[i];
-      pad->size += MIN (copied, this->period_size - pad->size);
-
-      if (pad->size >= this->period_size) {
-        g_assert (pad->size <= this->period_size);
-
-        buf = gst_buffer_new_from_pool (pool, 0, 0);
-
-        GST_BUFFER_DATA (buf) = pad->data;
-        GST_BUFFER_SIZE (buf) = this->period_size * bytes_per_frame;
-        GST_BUFFER_MAXSIZE (buf) = this->period_size * bytes_per_frame;
+    if (copied != this->period_size)
+      GST_BUFFER_SIZE (src->buf[i]) = gst_alsa_samples_to_bytes (this, copied);
+    GST_BUFFER_TIMESTAMP (src->buf[i]) = gst_alsa_samples_to_timestamp (this, this->transmitted);
+    gst_pad_push (this->pad[i], src->buf[i]);
+    src->buf[i] = NULL;
+  }
+  this->transmitted += copied;
+}
 
-        gst_pad_push (pad->pad, buf);
+static void
+gst_alsa_src_flush (GstAlsaSrc *src)
+{
+  gint i;
 
-        pad->data = NULL;
-        pad->size = 0;
-      }
+  for (i = 0; i < GST_ELEMENT (src)->numpads; i++) { 
+    if (src->buf[i]) {
+      gst_buffer_unref (src->buf[i]);
+      src->buf[i] = NULL;
     }
-
-    pool = NULL;
   }
+  if (src->pool) {
+    gst_buffer_pool_unref (src->pool);
+    src->pool = NULL;
+  }
+}
+static GstElementStateReturn
+gst_alsa_src_change_state (GstElement *element)
+{
+  GstAlsaSrc *src;
 
-  /* BUG: we start the stream explicitly, autostart doesn't work correctly (alsa 0.9.0rc7) */
-  if (snd_pcm_state(this->handle) == SND_PCM_STATE_PREPARED && snd_pcm_avail_update (this->handle) == 0) {
-    GST_DEBUG (GST_CAT_PLUGIN_INFO, "Explicitly starting capture");
-    snd_pcm_start(this->handle);
+  g_return_val_if_fail (element != NULL, FALSE);
+  src = GST_ALSA_SRC (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+  case GST_STATE_NULL_TO_READY:
+  case GST_STATE_READY_TO_PAUSED:
+  case GST_STATE_PAUSED_TO_PLAYING:
+  case GST_STATE_PLAYING_TO_PAUSED:
+    break;
+  case GST_STATE_PAUSED_TO_READY:
+    gst_alsa_src_flush (src);
+    break;
+  case GST_STATE_READY_TO_NULL:
+    break;
+  default:
+    g_assert_not_reached();
   }
 
-#endif
+  if (GST_ELEMENT_CLASS (sink_parent_class)->change_state)
+    return GST_ELEMENT_CLASS (sink_parent_class)->change_state (element);
+
+  return GST_STATE_SUCCESS;
 }
 
 /*** GSTREAMER PAD / STATE FUNCTIONS*******************************************/
@@ -1455,87 +1582,7 @@ gst_alsa_change_state (GstElement *element)
 }
 
 /*** AUDIO PROCESSING *********************************************************/
-#if 0
-static int
-gst_alsa_do_mmap (GstAlsa *this, snd_pcm_sframes_t *avail)
-{
-  snd_pcm_uframes_t offset;
-  snd_pcm_channel_area_t *dst, *src, *areas;
-  int i, err, width = snd_pcm_format_physical_width (this->format->format);
-
-  /* areas points to the memory areas that belong to gstreamer. */
-  areas = src = dst = calloc(this->format->channels, sizeof(snd_pcm_channel_area_t));
-
-  if (((GstElement *) this)->numpads == 1) {
-    /* interleaved */
-    for (i = 0; i < this->format->channels; i++) {
-      areas[i].addr = this->pads[0].data;
-      areas[i].first = i * width;
-      areas[i].step = this->format->channels * width;
-    }
-  } else {
-    /* noninterleaved */
-    for (i = 0; i < this->format->channels; i++) {
-      areas[i].addr = this->pads[i].data;
-      areas[i].first = 0;
-      areas[i].step = width;
-    }
-  }
-
-  if ((err = snd_pcm_mmap_begin (this->handle, (
-             const snd_pcm_channel_area_t **) (G_OBJECT_TYPE (this) == GST_TYPE_ALSA_SRC ? &src : &dst),
-             &offset, avail)) < 0) {
-    g_warning ("gstalsa: mmap failed: %s", snd_strerror (err));
-    return -1;
-  }
 
-  if ((err = snd_pcm_areas_copy (dst, offset, src, 0, this->format->channels, *avail, this->format->format)) < 0) {
-    snd_pcm_mmap_commit (this->handle, offset, 0);
-    g_warning ("gstalsa: data copy failed: %s", snd_strerror (err));
-    return -1;
-  }
-  if ((err = snd_pcm_mmap_commit (this->handle, offset, *avail)) < 0) {
-    g_warning ("gstalsa: mmap commit failed: %s", snd_strerror (err));
-    return -1;
-  }
-
-  return err;
-}
-static int
-gst_alsa_do_read_write (GstAlsa *this, snd_pcm_sframes_t *avail)
-{
-  void *channels[this->format->channels];
-  int err, i;
-
-  if (((GstElement *) this)->numpads == 1) {
-    /* interleaved */
-    if (G_OBJECT_TYPE (this) == GST_TYPE_ALSA_SRC) {
-      err = snd_pcm_readi (this->handle, this->pads[0].data, *avail);
-    } else {
-      err = snd_pcm_writei (this->handle, this->pads[0].data, *avail);
-    }
-  } else {
-    /* noninterleaved */
-    for (i = 0; i < this->format->channels; i++) {
-      channels[i] = this->pads[i].data;
-    }
-    if (G_OBJECT_TYPE (this) == GST_TYPE_ALSA_SRC) {
-      err = snd_pcm_readn (this->handle, channels, *avail);
-    } else {
-      err = snd_pcm_writen (this->handle, channels, *avail);
-    }
-  }
-  /* error handling */
-  if (err < 0) {
-    if (err == -EPIPE) {
-      gst_alsa_xrun_recovery (this);
-      return 0;
-    }
-    g_warning ("error on data access: %s", snd_strerror (err));
-  }
-  return err;
-}
-#endif
 inline static snd_pcm_sframes_t
 gst_alsa_update_avail (GstAlsa *this)
 {
@@ -1580,9 +1627,9 @@ gst_alsa_pcm_wait (GstAlsa *this)
 inline static gboolean
 gst_alsa_start (GstAlsa *this)
 {
-  gint avail;
+  //gint avail;
 
-  GST_DEBUG (GST_CAT_PLUGIN_INFO, "Starting playback");
+  GST_DEBUG (GST_CAT_PLUGIN_INFO, "Setting state to RUNNING");
 
   switch (snd_pcm_state(this->handle)) {
     case SND_PCM_STATE_XRUN:
@@ -1609,9 +1656,9 @@ gst_alsa_start (GstAlsa *this)
       g_assert_not_reached ();
       break;
   }
-  avail = (gint) gst_alsa_update_avail (this);
+/*  avail = (gint) gst_alsa_update_avail (this);
   if (avail < 0)
-    return FALSE;
+    return FALSE;*/
   gst_alsa_clock_start (this->clock);
   return TRUE;
 }
index 35ec9d3..ce8f7c8 100644 (file)
@@ -160,6 +160,9 @@ struct _GstAlsaSinkClass {
 };
 struct _GstAlsaSrc {
   GstAlsa                      parent;
+
+  GstBuffer *                  buf[GST_ALSA_MAX_CHANNELS];
+  GstBufferPool *              pool;
 };
 struct _GstAlsaSrcClass {
   GstAlsaClass                 parent_class;