mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-31 11:32:38 +00:00
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:
parent
796529c197
commit
1bb09c4352
4 changed files with 47 additions and 27 deletions
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue