diff --git a/ChangeLog b/ChangeLog index 5629dfb910..7e4b51b998 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2004-06-24 Wim Taymans + + * ext/alsa/gstalsa.c: (gst_alsa_start), (gst_alsa_xrun_recovery): + * ext/alsa/gstalsa.h: + * ext/alsa/gstalsasrc.c: (gst_alsa_src_init), + (gst_alsa_src_update_avail), (gst_alsa_src_loop): + Use alsa trigger_tstamp to get the timestamp of the first + sample in the buffer for more precise sync. Some cleanups. + 2004-06-24 Wim Taymans * gst/audiorate/gstaudiorate.c: (gst_audiorate_link), diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c index c28ac09c76..bdca604997 100644 --- a/ext/alsa/gstalsa.c +++ b/ext/alsa/gstalsa.c @@ -1203,8 +1203,6 @@ gst_alsa_pcm_wait (GstAlsa * this) inline gboolean gst_alsa_start (GstAlsa * this) { - GstClockTime elemnow; - GST_DEBUG ("Setting state to RUNNING"); switch (snd_pcm_state (this->handle)) { @@ -1215,13 +1213,7 @@ gst_alsa_start (GstAlsa * this) ERROR_CHECK (snd_pcm_prepare (this->handle), "error preparing: %s"); case SND_PCM_STATE_SUSPENDED: case SND_PCM_STATE_PREPARED: - /* The strategy to recover the timestamps from the xrun is to take the - * current element time and pretend we just sent all the samples up to - * that time. This will result in an offset discontinuity in the next - * buffer along with the correct timestamp on that buffer, we only - * update the capture timestamps */ - elemnow = gst_element_get_time (GST_ELEMENT (this)); - this->captured = gst_alsa_timestamp_to_samples (this, elemnow); + this->captured = 0; ERROR_CHECK (snd_pcm_start (this->handle), "error starting playback: %s"); break; case SND_PCM_STATE_PAUSED: @@ -1254,6 +1246,11 @@ gst_alsa_xrun_recovery (GstAlsa * this) GST_ERROR_OBJECT (this, "status error: %s", snd_strerror (err)); if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) { + struct timeval now, diff, tstamp; + + gettimeofday (&now, 0); + snd_pcm_status_get_trigger_tstamp (status, &tstamp); + timersub (&now, &tstamp, &diff); /* if we're allowed to recover, ... */ if (this->autorecover) { @@ -1269,8 +1266,12 @@ gst_alsa_xrun_recovery (GstAlsa * this) } /* prepare the device again */ - if ((err = snd_pcm_prepare (this->handle)) < 0) { - GST_ERROR_OBJECT (this, "prepare error: %s", snd_strerror (err)); + if ((err = snd_pcm_drop (this->handle)) < 0) { + GST_ERROR_OBJECT (this, "drop error: %s", snd_strerror (err)); + return FALSE; + } + if ((err = snd_pcm_drain (this->handle)) < 0) { + GST_ERROR_OBJECT (this, "drop error: %s", snd_strerror (err)); return FALSE; } if (!gst_alsa_start (this)) { @@ -1278,8 +1279,10 @@ gst_alsa_xrun_recovery (GstAlsa * this) ("Error starting audio after xrun")); return FALSE; } - GST_DEBUG_OBJECT (this, "XRun!!!! pretending we captured %lld samples", - this->captured); + + GST_DEBUG_OBJECT (this, "XRun!!!! of at least %.3f msecs, " + "pretending we captured %lld samples", + diff.tv_sec * 1000 + diff.tv_usec / 1000.0, this->captured); } else { if (!(gst_alsa_stop_audio (this) && gst_alsa_start_audio (this))) { GST_ELEMENT_ERROR (this, RESOURCE, FAILED, (NULL), diff --git a/ext/alsa/gstalsa.h b/ext/alsa/gstalsa.h index 89036313f4..35f930c13c 100644 --- a/ext/alsa/gstalsa.h +++ b/ext/alsa/gstalsa.h @@ -156,7 +156,6 @@ struct _GstAlsa { /* clocking */ GstAlsaClock * clock; /* our provided clock */ - GstClockTime clock_base; snd_pcm_uframes_t played; /* samples transmitted since last sync This thing actually is our master clock. We will event insert silent samples or diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c index 9fce460269..1b35a7d261 100644 --- a/ext/alsa/gstalsasrc.c +++ b/ext/alsa/gstalsasrc.c @@ -363,13 +363,6 @@ gst_alsa_src_loop (GstElement * element) return; } } - if (this->clock_base == GST_CLOCK_TIME_NONE) { - GstClockTime now; - - now = gst_element_get_time (element); - this->clock_base = gst_alsa_src_get_time (this); - this->captured = gst_alsa_timestamp_to_samples (this, now); - } /* the cast to long is explicitly needed; * with avail = -32 and period_size = 100, avail < period_size is false */ @@ -393,8 +386,18 @@ gst_alsa_src_loop (GstElement * element) { gint outsize; - GstClockTime outtime, outdur, outreal, outideal; - gint64 diff; + GstClockTime outtime, outdur, outreal, outideal, startalsa, outalsa; + gint64 diff, offset; + snd_pcm_status_t *status; + struct timeval tstamp; + int err; + + snd_pcm_status_alloca (&status); + + if ((err = snd_pcm_status (this->handle, status)) < 0) + GST_ERROR_OBJECT (this, "status error: %s", snd_strerror (err)); + + offset = this->captured; /* duration of buffer is just the time of the samples */ outdur = gst_alsa_samples_to_timestamp (this, copied); @@ -403,19 +406,25 @@ gst_alsa_src_loop (GstElement * element) * what is now in the buffer */ outreal = gst_element_get_time (GST_ELEMENT (this)) - outdur; /* ideal time is counting samples */ - outideal = gst_alsa_samples_to_timestamp (this, this->captured); + outideal = gst_alsa_samples_to_timestamp (this, offset); + + snd_pcm_status_get_trigger_tstamp (status, &tstamp); + startalsa = GST_TIMEVAL_TO_TIME (tstamp) - element->base_time; + outalsa = startalsa + outideal; outsize = gst_alsa_samples_to_bytes (this, copied); outtime = GST_CLOCK_TIME_NONE; if (GST_ELEMENT_CLOCK (this)) { if (GST_CLOCK (GST_ALSA (this)->clock) == GST_ELEMENT_CLOCK (this)) { - outtime = outideal; + outtime = outalsa; diff = outideal - outreal; GST_DEBUG_OBJECT (this, "ideal %lld, real %lld, diff %lld\n", outideal, outreal, diff); + offset = gst_alsa_timestamp_to_samples (this, outtime); } else { outtime = outreal; + offset = gst_alsa_timestamp_to_samples (this, outtime); } } @@ -430,8 +439,8 @@ gst_alsa_src_loop (GstElement * element) GST_BUFFER_TIMESTAMP (src->buf[i]) = outtime; GST_BUFFER_DURATION (src->buf[i]) = outdur; - GST_BUFFER_OFFSET (src->buf[i]) = this->captured; - GST_BUFFER_OFFSET_END (src->buf[i]) = this->captured + copied; + GST_BUFFER_OFFSET (src->buf[i]) = offset; + GST_BUFFER_OFFSET_END (src->buf[i]) = offset + copied; buf = src->buf[i]; src->buf[i] = NULL;