fix clock - seeking, xruns etc should be handled correctly now includes bugfix to not play the rest of the audio buff...

Original commit message from CVS:
fix clock - seeking, xruns etc should be handled correctly now
includes bugfix to not play the rest of the audio buffer when going PAUSED => READY
This commit is contained in:
Benjamin Otte 2003-04-18 12:14:04 +00:00
parent 7877428028
commit da25cbb0b3
2 changed files with 42 additions and 18 deletions

View file

@ -970,7 +970,7 @@ gst_alsa_change_state (GstElement *element)
/* if device doesn't know how to pause, we just stop */ /* if device doesn't know how to pause, we just stop */
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_ALSA_RUNNING)) if (GST_FLAG_IS_SET (element, GST_ALSA_RUNNING))
gst_alsa_drain_audio (this); gst_alsa_close_audio (this);
/* clear format and pads */ /* clear format and pads */
g_free (this->format); g_free (this->format);
this->format = NULL; this->format = NULL;
@ -1147,7 +1147,7 @@ gst_alsa_start (GstAlsa *this)
avail = (gint) gst_alsa_update_avail (this); avail = (gint) gst_alsa_update_avail (this);
if (avail < 0) if (avail < 0)
return FALSE; return FALSE;
this->transmitted = this->period_count * this->period_size - avail; //this->transmitted = this->period_count * this->period_size - avail;
gst_alsa_clock_start (this->clock); gst_alsa_clock_start (this->clock);
return TRUE; return TRUE;
} }
@ -1209,7 +1209,8 @@ no_difference:
int samples = MIN (bytes, samplestamp - this->transmitted) * int samples = MIN (bytes, samplestamp - this->transmitted) *
(element->numpads == 1 ? this->format->channels : 1); (element->numpads == 1 ? this->format->channels : 1);
int size = samples * snd_pcm_format_physical_width (this->format->format) / 8; int size = samples * snd_pcm_format_physical_width (this->format->format) / 8;
g_printerr ("Allocating %d bytes (%ld silent samples) now to resync to timestamp\n", size, MIN (bytes, samplestamp - this->transmitted)); g_printerr ("Allocating %d bytes (%ld samples) now to resync: sample %ld expected, but got %ld\n",
size, MIN (bytes, samplestamp - this->transmitted), this->transmitted, samplestamp);
pad->data = g_malloc (size); pad->data = g_malloc (size);
if (!pad->data) { if (!pad->data) {
g_warning ("GstAlsa: error allocating %d bytes, buffers unsynced now.", size); g_warning ("GstAlsa: error allocating %d bytes, buffers unsynced now.", size);
@ -1432,6 +1433,11 @@ gst_alsa_sink_check_event (GstAlsa *this, gint pad_nr, GstEvent *event)
if (pad_nr != 0) if (pad_nr != 0)
break; break;
if (GST_CLOCK_TIME_IS_VALID (this->clock->start_time)) { /* if the clock is running */
g_assert (this->format);
/* adjust the start time */
this->clock->start_time += gst_alsa_samples_to_timestamp (this, this->transmitted);
}
this->transmitted = 0; this->transmitted = 0;
/* FIXME: Notify the clock that we're at offset 0 again */ /* FIXME: Notify the clock that we're at offset 0 again */
break; break;
@ -1445,7 +1451,7 @@ gst_alsa_sink_check_event (GstAlsa *this, gint pad_nr, GstEvent *event)
} }
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
if (!gst_clock_handle_discont (GST_ELEMENT (this)->clock, value)) if (!gst_clock_handle_discont (GST_ELEMENT (this)->clock, value))
g_warning ("GstAlsa: clock couldn't handle discontinuity"); g_printerr ("GstAlsa: clock couldn't handle discontinuity\n");
} }
if (!gst_event_discont_get_value (event, GST_FORMAT_UNITS, &value)) { if (!gst_event_discont_get_value (event, GST_FORMAT_UNITS, &value)) {
if (!gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) { if (!gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) {
@ -1461,10 +1467,13 @@ gst_alsa_sink_check_event (GstAlsa *this, gint pad_nr, GstEvent *event)
value = gst_alsa_bytes_to_samples (this, value); value = gst_alsa_bytes_to_samples (this, value);
} }
} }
if (GST_CLOCK_TIME_IS_VALID (this->clock->start_time)) { /* if the clock is running */
g_assert (this->format);
/* adjust the start time */
this->clock->start_time += gst_alsa_samples_to_timestamp (this, this->transmitted) -
gst_alsa_samples_to_timestamp (this, value);
}
this->transmitted = value; this->transmitted = value;
if (snd_pcm_state (this->handle) == SND_PCM_STATE_RUNNING)
gst_alsa_clock_start (this->clock);
/* flush the current pad */
break; break;
} }
default: default:
@ -1664,7 +1673,10 @@ gst_alsa_drain_audio (GstAlsa *this)
GST_DEBUG (GST_CAT_PLUGIN_INFO, "stopping alsa"); GST_DEBUG (GST_CAT_PLUGIN_INFO, "stopping alsa");
if (this->stream == SND_PCM_STREAM_PLAYBACK) { if (this->stream == SND_PCM_STREAM_PLAYBACK &&
(snd_pcm_state (this->handle) == SND_PCM_STATE_PAUSED ||
snd_pcm_state (this->handle) == SND_PCM_STATE_XRUN ||
snd_pcm_state (this->handle) == SND_PCM_STATE_RUNNING)) {
ERROR_CHECK (snd_pcm_drain (this->handle), ERROR_CHECK (snd_pcm_drain (this->handle),
"couldn't stop and drain buffer: %s"); "couldn't stop and drain buffer: %s");
gst_alsa_clock_stop (this->clock); gst_alsa_clock_stop (this->clock);
@ -1678,12 +1690,14 @@ static gboolean
gst_alsa_stop_audio (GstAlsa *this) gst_alsa_stop_audio (GstAlsa *this)
{ {
g_assert (this != NULL); g_assert (this != NULL);
g_return_val_if_fail (this != NULL, FALSE);
g_return_val_if_fail (this->handle != NULL, FALSE); g_return_val_if_fail (this->handle != NULL, FALSE);
GST_DEBUG (GST_CAT_PLUGIN_INFO, "stopping alsa, skipping pending frames"); GST_DEBUG (GST_CAT_PLUGIN_INFO, "stopping alsa, skipping pending frames");
if (this->stream == SND_PCM_STREAM_PLAYBACK) { if (this->stream == SND_PCM_STREAM_PLAYBACK &&
(snd_pcm_state (this->handle) == SND_PCM_STATE_PAUSED ||
snd_pcm_state (this->handle) == SND_PCM_STATE_XRUN ||
snd_pcm_state (this->handle) == SND_PCM_STATE_RUNNING)) {
ERROR_CHECK (snd_pcm_drop (this->handle), ERROR_CHECK (snd_pcm_drop (this->handle),
"couldn't stop (dropping frames): %s"); "couldn't stop (dropping frames): %s");
gst_alsa_clock_stop (this->clock); gst_alsa_clock_stop (this->clock);
@ -1754,6 +1768,8 @@ static void
gst_alsa_clock_init (GstAlsaClock *clock) gst_alsa_clock_init (GstAlsaClock *clock)
{ {
gst_object_set_name (GST_OBJECT (clock), "GstAlsaClock"); gst_object_set_name (GST_OBJECT (clock), "GstAlsaClock");
clock->start_time = GST_CLOCK_TIME_NONE;
} }
GstAlsaClock* GstAlsaClock*
gst_alsa_clock_new (gchar *name, GstAlsaClockGetTimeFunc get_time, GstAlsa *owner) gst_alsa_clock_new (gchar *name, GstAlsaClockGetTimeFunc get_time, GstAlsa *owner)
@ -1776,28 +1792,36 @@ gst_alsa_clock_start (GstAlsaClock *clock)
GTimeVal timeval; GTimeVal timeval;
g_get_current_time (&timeval); g_get_current_time (&timeval);
g_assert (!GST_CLOCK_TIME_IS_VALID (clock->start_time));
if (clock->owner->format) { if (clock->owner->format) {
clock->adjust = GST_TIMEVAL_TO_TIME (timeval) - clock->get_time (clock->owner); clock->start_time = GST_TIMEVAL_TO_TIME (timeval) + clock->adjust - clock->get_time (clock->owner);
} else { } else {
clock->adjust = GST_TIMEVAL_TO_TIME (timeval); clock->start_time = GST_TIMEVAL_TO_TIME (timeval) + clock->adjust;
} }
} }
void void
gst_alsa_clock_stop (GstAlsaClock *clock) gst_alsa_clock_stop (GstAlsaClock *clock)
{ {
clock->adjust = 0; GTimeVal timeval;
g_get_current_time (&timeval);
g_assert (GST_CLOCK_TIME_IS_VALID (clock->start_time));
clock->adjust += GST_TIMEVAL_TO_TIME (timeval) - clock->start_time - clock->get_time (clock->owner);
clock->start_time = GST_CLOCK_TIME_NONE;
} }
static GstClockTime static GstClockTime
gst_alsa_clock_get_internal_time (GstClock *clock) gst_alsa_clock_get_internal_time (GstClock *clock)
{ {
GstAlsaClock *alsa_clock = GST_ALSA_CLOCK (clock); GstAlsaClock *alsa_clock = GST_ALSA_CLOCK (clock);
if (alsa_clock->adjust) { if (GST_CLOCK_TIME_IS_VALID (alsa_clock->start_time)) {
return alsa_clock->get_time (alsa_clock->owner) + alsa_clock->adjust; return alsa_clock->get_time (alsa_clock->owner) + alsa_clock->start_time;
} else { } else {
GTimeVal timeval; GTimeVal timeval;
g_get_current_time (&timeval); g_get_current_time (&timeval);
return GST_TIMEVAL_TO_TIME (timeval); return GST_TIMEVAL_TO_TIME (timeval) + alsa_clock->adjust;
} }
} }
static guint64 static guint64
@ -1892,7 +1916,6 @@ gst_alsa_timestamp_to_samples (GstAlsa *this, GstClockTime time)
{ {
return (snd_pcm_uframes_t) ((time * this->format->rate + this->format->rate / 2) / GST_SECOND); return (snd_pcm_uframes_t) ((time * this->format->rate + this->format->rate / 2) / GST_SECOND);
} }
/* assumes that this->format != NULL */
static inline GstClockTime static inline GstClockTime
gst_alsa_samples_to_timestamp (GstAlsa *this, snd_pcm_uframes_t samples) gst_alsa_samples_to_timestamp (GstAlsa *this, snd_pcm_uframes_t samples)
{ {

View file

@ -155,7 +155,8 @@ struct _GstAlsaClock {
GstAlsaClockGetTimeFunc get_time; GstAlsaClockGetTimeFunc get_time;
GstAlsa * owner; GstAlsa * owner;
GstClockTimeDiff adjust; /* time_of_clock - time_of_element at sync point */ GstClockTimeDiff adjust; /* adjustment to real clock (recalculated when stopping) */
GstClockTime start_time; /* time when the stream started (NONE when stopped) */
GstClockTime last_unlock; /* time of last unlock request */ GstClockTime last_unlock; /* time of last unlock request */
}; };