ext/alsa/: Use alsa trigger_tstamp to get the timestamp of the first sample in the buffer for more precise sync. Some...

Original commit message from CVS:
* 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.
This commit is contained in:
Wim Taymans 2004-06-24 12:53:17 +00:00
parent 796529c197
commit 1bb09c4352
4 changed files with 47 additions and 27 deletions

View file

@ -1,3 +1,12 @@
2004-06-24 Wim Taymans <wim@fluendo.com>
* 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 <wim@fluendo.com> 2004-06-24 Wim Taymans <wim@fluendo.com>
* gst/audiorate/gstaudiorate.c: (gst_audiorate_link), * gst/audiorate/gstaudiorate.c: (gst_audiorate_link),

View file

@ -1203,8 +1203,6 @@ gst_alsa_pcm_wait (GstAlsa * this)
inline gboolean inline gboolean
gst_alsa_start (GstAlsa * this) gst_alsa_start (GstAlsa * this)
{ {
GstClockTime elemnow;
GST_DEBUG ("Setting state to RUNNING"); GST_DEBUG ("Setting state to RUNNING");
switch (snd_pcm_state (this->handle)) { 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"); ERROR_CHECK (snd_pcm_prepare (this->handle), "error preparing: %s");
case SND_PCM_STATE_SUSPENDED: case SND_PCM_STATE_SUSPENDED:
case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_PREPARED:
/* The strategy to recover the timestamps from the xrun is to take the this->captured = 0;
* 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);
ERROR_CHECK (snd_pcm_start (this->handle), "error starting playback: %s"); ERROR_CHECK (snd_pcm_start (this->handle), "error starting playback: %s");
break; break;
case SND_PCM_STATE_PAUSED: 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)); GST_ERROR_OBJECT (this, "status error: %s", snd_strerror (err));
if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) { 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 we're allowed to recover, ... */
if (this->autorecover) { if (this->autorecover) {
@ -1269,8 +1266,12 @@ gst_alsa_xrun_recovery (GstAlsa * this)
} }
/* prepare the device again */ /* prepare the device again */
if ((err = snd_pcm_prepare (this->handle)) < 0) { if ((err = snd_pcm_drop (this->handle)) < 0) {
GST_ERROR_OBJECT (this, "prepare error: %s", snd_strerror (err)); 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; return FALSE;
} }
if (!gst_alsa_start (this)) { if (!gst_alsa_start (this)) {
@ -1278,8 +1279,10 @@ gst_alsa_xrun_recovery (GstAlsa * this)
("Error starting audio after xrun")); ("Error starting audio after xrun"));
return FALSE; 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 { } else {
if (!(gst_alsa_stop_audio (this) && gst_alsa_start_audio (this))) { if (!(gst_alsa_stop_audio (this) && gst_alsa_start_audio (this))) {
GST_ELEMENT_ERROR (this, RESOURCE, FAILED, (NULL), GST_ELEMENT_ERROR (this, RESOURCE, FAILED, (NULL),

View file

@ -156,7 +156,6 @@ struct _GstAlsa {
/* clocking */ /* clocking */
GstAlsaClock * clock; /* our provided clock */ GstAlsaClock * clock; /* our provided clock */
GstClockTime clock_base;
snd_pcm_uframes_t played; /* samples transmitted since last sync snd_pcm_uframes_t played; /* samples transmitted since last sync
This thing actually is our master clock. This thing actually is our master clock.
We will event insert silent samples or We will event insert silent samples or

View file

@ -363,13 +363,6 @@ gst_alsa_src_loop (GstElement * element)
return; 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; /* the cast to long is explicitly needed;
* with avail = -32 and period_size = 100, avail < period_size is false */ * with avail = -32 and period_size = 100, avail < period_size is false */
@ -393,8 +386,18 @@ gst_alsa_src_loop (GstElement * element)
{ {
gint outsize; gint outsize;
GstClockTime outtime, outdur, outreal, outideal; GstClockTime outtime, outdur, outreal, outideal, startalsa, outalsa;
gint64 diff; 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 */ /* duration of buffer is just the time of the samples */
outdur = gst_alsa_samples_to_timestamp (this, copied); outdur = gst_alsa_samples_to_timestamp (this, copied);
@ -403,19 +406,25 @@ gst_alsa_src_loop (GstElement * element)
* what is now in the buffer */ * what is now in the buffer */
outreal = gst_element_get_time (GST_ELEMENT (this)) - outdur; outreal = gst_element_get_time (GST_ELEMENT (this)) - outdur;
/* ideal time is counting samples */ /* 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); outsize = gst_alsa_samples_to_bytes (this, copied);
outtime = GST_CLOCK_TIME_NONE; outtime = GST_CLOCK_TIME_NONE;
if (GST_ELEMENT_CLOCK (this)) { if (GST_ELEMENT_CLOCK (this)) {
if (GST_CLOCK (GST_ALSA (this)->clock) == GST_ELEMENT_CLOCK (this)) { if (GST_CLOCK (GST_ALSA (this)->clock) == GST_ELEMENT_CLOCK (this)) {
outtime = outideal; outtime = outalsa;
diff = outideal - outreal; diff = outideal - outreal;
GST_DEBUG_OBJECT (this, "ideal %lld, real %lld, diff %lld\n", outideal, GST_DEBUG_OBJECT (this, "ideal %lld, real %lld, diff %lld\n", outideal,
outreal, diff); outreal, diff);
offset = gst_alsa_timestamp_to_samples (this, outtime);
} else { } else {
outtime = outreal; 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_TIMESTAMP (src->buf[i]) = outtime;
GST_BUFFER_DURATION (src->buf[i]) = outdur; GST_BUFFER_DURATION (src->buf[i]) = outdur;
GST_BUFFER_OFFSET (src->buf[i]) = this->captured; GST_BUFFER_OFFSET (src->buf[i]) = offset;
GST_BUFFER_OFFSET_END (src->buf[i]) = this->captured + copied; GST_BUFFER_OFFSET_END (src->buf[i]) = offset + copied;
buf = src->buf[i]; buf = src->buf[i];
src->buf[i] = NULL; src->buf[i] = NULL;