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),
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);
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));
}
}
+/**
+ * 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, ×tamp);
+
+ /* 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)
{
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
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 *
element_class->change_state = gst_alsa_src_change_state;
}
+
static void
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)
{
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
}
}
}
+
static GstElementStateReturn
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:
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;
- }
-}