/* if device doesn't know how to pause, we just stop */
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_ALSA_RUNNING))
- gst_alsa_drain_audio (this);
+ gst_alsa_close_audio (this);
/* clear format and pads */
g_free (this->format);
this->format = NULL;
avail = (gint) gst_alsa_update_avail (this);
if (avail < 0)
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);
return TRUE;
}
int samples = MIN (bytes, samplestamp - this->transmitted) *
(element->numpads == 1 ? this->format->channels : 1);
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);
if (!pad->data) {
g_warning ("GstAlsa: error allocating %d bytes, buffers unsynced now.", size);
if (pad_nr != 0)
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;
/* FIXME: Notify the clock that we're at offset 0 again */
break;
}
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &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_BYTES, &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;
- if (snd_pcm_state (this->handle) == SND_PCM_STATE_RUNNING)
- gst_alsa_clock_start (this->clock);
- /* flush the current pad */
break;
}
default:
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),
"couldn't stop and drain buffer: %s");
gst_alsa_clock_stop (this->clock);
gst_alsa_stop_audio (GstAlsa *this)
{
g_assert (this != NULL);
- g_return_val_if_fail (this != NULL, FALSE);
g_return_val_if_fail (this->handle != NULL, FALSE);
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),
"couldn't stop (dropping frames): %s");
gst_alsa_clock_stop (this->clock);
gst_alsa_clock_init (GstAlsaClock *clock)
{
gst_object_set_name (GST_OBJECT (clock), "GstAlsaClock");
+
+ clock->start_time = GST_CLOCK_TIME_NONE;
}
GstAlsaClock*
gst_alsa_clock_new (gchar *name, GstAlsaClockGetTimeFunc get_time, GstAlsa *owner)
GTimeVal timeval;
g_get_current_time (&timeval);
+ g_assert (!GST_CLOCK_TIME_IS_VALID (clock->start_time));
+
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 {
- clock->adjust = GST_TIMEVAL_TO_TIME (timeval);
+ clock->start_time = GST_TIMEVAL_TO_TIME (timeval) + clock->adjust;
}
}
void
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
gst_alsa_clock_get_internal_time (GstClock *clock)
{
GstAlsaClock *alsa_clock = GST_ALSA_CLOCK (clock);
- if (alsa_clock->adjust) {
- return alsa_clock->get_time (alsa_clock->owner) + alsa_clock->adjust;
+ if (GST_CLOCK_TIME_IS_VALID (alsa_clock->start_time)) {
+ return alsa_clock->get_time (alsa_clock->owner) + alsa_clock->start_time;
} else {
GTimeVal timeval;
g_get_current_time (&timeval);
- return GST_TIMEVAL_TO_TIME (timeval);
+ return GST_TIMEVAL_TO_TIME (timeval) + alsa_clock->adjust;
}
}
static guint64
{
return (snd_pcm_uframes_t) ((time * this->format->rate + this->format->rate / 2) / GST_SECOND);
}
-/* assumes that this->format != NULL */
static inline GstClockTime
gst_alsa_samples_to_timestamp (GstAlsa *this, snd_pcm_uframes_t samples)
{