ext/alsa/: Make the xrun code timestamp and offset the buffers correctly. moved the...
authorWim Taymans <wim.taymans@gmail.com>
Thu, 17 Jun 2004 14:10:21 +0000 (14:10 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 17 Jun 2004 14:10:21 +0000 (14:10 +0000)
Original commit message from CVS:
* ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
(gst_alsa_get_time), (gst_alsa_xrun_recovery):
* ext/alsa/gstalsa.h:
* ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
* ext/alsa/gstalsasrc.c: (gst_alsa_src_init), (gst_alsa_src_loop),
(gst_alsa_src_change_state):
* ext/alsa/gstalsasrc.h:
Make the xrun code timestamp and offset the buffers correctly.
moved the clock to the base class, use alsa methods to get time.
Do correct timestamping on outgoing buffers.

ChangeLog
ext/alsa/gstalsa.c
ext/alsa/gstalsa.h
ext/alsa/gstalsasrc.c
ext/alsa/gstalsasrc.h

index 4189da6..3400848 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2004-06-17  Wim Taymans  <wim@fluendo.com>
 
+       * ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
+       (gst_alsa_get_time), (gst_alsa_xrun_recovery):
+       * ext/alsa/gstalsa.h:
+       * ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
+       * ext/alsa/gstalsasrc.c: (gst_alsa_src_init), (gst_alsa_src_loop),
+       (gst_alsa_src_change_state):
+       * ext/alsa/gstalsasrc.h:
+       Make the xrun code timestamp and offset the buffers correctly.
+       moved the clock to the base class, use alsa methods to get time.
+       Do correct timestamping on outgoing buffers.
+
+2004-06-17  Wim Taymans  <wim@fluendo.com>
+
        * gst/audiorate/Makefile.am:
        * gst/audiorate/gstaudiorate.c: (gst_audiorate_get_type),
        (gst_audiorate_base_init), (gst_audiorate_class_init),
index e9c2138..ef151b7 100644 (file)
@@ -203,6 +203,12 @@ static void
 gst_alsa_init (GstAlsa * this)
 {
   this->device = g_strdup ("default");
+  g_assert (snd_pcm_status_malloc (&(this->status)) == 0);
+
+  this->clock = gst_alsa_clock_new ("alsaclock", gst_alsa_get_time, this);
+  /* we hold a ref to our clock until we're disposed */
+  gst_object_ref (GST_OBJECT (this->clock));
+  gst_object_sink (GST_OBJECT (this->clock));
 
   GST_FLAG_SET (this, GST_ELEMENT_EVENT_AWARE);
   GST_FLAG_SET (this, GST_ELEMENT_THREAD_SUGGESTED);
@@ -214,6 +220,9 @@ gst_alsa_dispose (GObject * object)
   GstAlsa *this = GST_ALSA (object);
 
   g_free (this->device);
+  this->device = NULL;
+  snd_pcm_status_free (this->status);
+  this->status = NULL;
 
   if (this->clock)
     gst_object_unparent (GST_OBJECT (this->clock));
@@ -310,6 +319,33 @@ gst_alsa_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+/**
+ * ask ALSA for current time using htstamp
+ * FIXME: This is not very accurate, should use alsa timers instead.
+ * htstamp seems to use the system clock instead of the hw clock.
+ */
+GstClockTime
+gst_alsa_get_time (GstAlsa * this)
+{
+  int err;
+  snd_htimestamp_t timestamp;
+  GstClockTime time;
+
+  if ((err = snd_pcm_status (this->handle, this->status)) < 0) {
+    GST_WARNING_OBJECT (this, "could not get snd_pcm_status");
+  }
+
+  snd_pcm_status_get_htstamp (this->status, &timestamp);
+
+  /* time = GST_TIMESPEC_TO_TIME (timestamp); */
+  time = timestamp.tv_sec * GST_SECOND + timestamp.tv_nsec * GST_NSECOND;
+
+  GST_LOG_OBJECT (this, "ALSA reports time of %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time));
+
+  return time;
+}
+
 static const GList *
 gst_alsa_probe_get_properties (GstPropertyProbe * probe)
 {
@@ -1252,6 +1288,10 @@ gst_alsa_xrun_recovery (GstAlsa * this)
     GST_INFO_OBJECT (this, "alsa: xrun of at least %.3f msecs",
         diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
 
+    /* start new timestamps from the current time */
+    this->transmitted = gst_alsa_timestamp_to_samples (this,
+        gst_element_get_time (GST_ELEMENT (this)));
+
     /* if we're allowed to recover, ... */
     if (this->autorecover) {
       /* ... then increase the period size or buffer size / period count to
index b499b66..be7ae1b 100644 (file)
@@ -164,6 +164,7 @@ struct _GstAlsa {
   GstClockTime                 max_discont;    /* max difference between current
                                                   playback timestamp and buffers timestamps
                                                 */
+  snd_pcm_status_t *status;
 };
 
 struct _GstAlsaClass {
@@ -191,6 +192,8 @@ GstCaps *           gst_alsa_caps           (snd_pcm_format_t       format,
                                                 gint                   rate,
                                                 gint                   channels);
 
+GstClockTime                   gst_alsa_get_time       (GstAlsa * this);
+
 /* audio processing functions */
 inline snd_pcm_sframes_t       gst_alsa_update_avail   (GstAlsa * this);
 inline gboolean                        gst_alsa_pcm_wait       (GstAlsa * this);
index db50d04..05703d2 100644 (file)
@@ -44,8 +44,6 @@ 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);
 
-static GstClockTime gst_alsa_src_get_time (GstAlsa * this);
-
 static GstAlsa *src_parent_class = NULL;
 
 static GstPadTemplate *
@@ -118,6 +116,7 @@ gst_alsa_src_class_init (gpointer g_class, gpointer class_data)
 
   element_class->change_state = gst_alsa_src_change_state;
 }
+
 static void
 gst_alsa_src_init (GstAlsaSrc * src)
 {
@@ -128,14 +127,9 @@ gst_alsa_src_init (GstAlsaSrc * src)
   gst_pad_set_getcaps_function (this->pad[0], gst_alsa_get_caps);
   gst_element_add_pad (GST_ELEMENT (this), this->pad[0]);
 
-  this->clock =
-      gst_alsa_clock_new ("alsasrcclock", gst_alsa_src_get_time, this);
-  /* we hold a ref to our clock until we're disposed */
-  gst_object_ref (GST_OBJECT (this->clock));
-  gst_object_sink (GST_OBJECT (this->clock));
-
   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)
 {
@@ -359,26 +353,47 @@ gst_alsa_src_loop (GstElement * element)
     src->buf[i] =
         gst_buffer_new_and_alloc (gst_alsa_samples_to_bytes (this, avail));
   }
+
   /* 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++) {
-    GstBuffer *buf;
 
-    if (!src->buf[i])
-      return;
-    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_BUFFER_DURATION (src->buf[i]) =
-        gst_alsa_samples_to_timestamp (this, copied);
-    buf = src->buf[i];
-    src->buf[i] = NULL;
-    gst_pad_push (this->pad[i], GST_DATA (buf));
+  {
+    gint outsize;
+    GstClockTime outtime, outdur;
+
+    outsize = gst_alsa_samples_to_bytes (this, copied);
+    outdur = gst_alsa_samples_to_timestamp (this, copied);
+    outtime = GST_CLOCK_TIME_NONE;
+
+    if (GST_ELEMENT_CLOCK (this)) {
+      if (GST_CLOCK (GST_ALSA (this)->clock) == GST_ELEMENT_CLOCK (this)) {
+        outtime = gst_alsa_samples_to_timestamp (this, this->transmitted);
+      } else {
+        outtime = gst_element_get_time (GST_ELEMENT (this));
+      }
+    }
+
+    /* push the buffers out and let them have fun */
+    for (i = 0; i < element->numpads; i++) {
+      GstBuffer *buf;
+
+      if (!src->buf[i])
+        return;
+      if (copied != this->period_size)
+        GST_BUFFER_SIZE (src->buf[i]) = outsize;
+
+      GST_BUFFER_TIMESTAMP (src->buf[i]) = outtime;
+      GST_BUFFER_DURATION (src->buf[i]) = outdur;
+      GST_BUFFER_OFFSET (src->buf[i]) = this->transmitted;
+      GST_BUFFER_OFFSET_END (src->buf[i]) = this->transmitted + copied;
+
+      buf = src->buf[i];
+      src->buf[i] = NULL;
+      gst_pad_push (this->pad[i], GST_DATA (buf));
+    }
+    this->transmitted += copied;
   }
-  this->transmitted += copied;
 }
 
 static void
@@ -393,6 +408,7 @@ gst_alsa_src_flush (GstAlsaSrc * src)
     }
   }
 }
+
 static GstElementStateReturn
 gst_alsa_src_change_state (GstElement * element)
 {
@@ -404,7 +420,9 @@ gst_alsa_src_change_state (GstElement * element)
   switch (GST_STATE_TRANSITION (element)) {
     case GST_STATE_NULL_TO_READY:
     case GST_STATE_READY_TO_PAUSED:
+      break;
     case GST_STATE_PAUSED_TO_PLAYING:
+      break;
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
@@ -421,15 +439,3 @@ gst_alsa_src_change_state (GstElement * element)
 
   return GST_STATE_SUCCESS;
 }
-
-static GstClockTime
-gst_alsa_src_get_time (GstAlsa * this)
-{
-  snd_pcm_sframes_t delay;
-
-  if (snd_pcm_delay (this->handle, &delay) == 0 && this->format) {
-    return GST_SECOND * (this->transmitted + delay) / this->format->rate;
-  } else {
-    return 0;
-  }
-}
index 5b4c2b7..d4e72e4 100644 (file)
@@ -38,6 +38,8 @@ typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
 struct _GstAlsaSrc {
   GstAlsaMixer   parent;
   GstBuffer     *buf[GST_ALSA_MAX_TRACKS];
+  snd_pcm_status_t *status;
+  GstClockTime  base_time; /* FIXME: move this up ? already present in element ? */
 };
 
 struct _GstAlsaSrcClass {