ext/alsa/: Make the xrun code timestamp and offset the buffers correctly. moved the clock to the base class, use alsa...

Original commit message from CVS:
* ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
(gst_alsa_get_time), (gst_alsa_xrun_recovery):
* ext/alsa/gstalsa.h:
* ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
* ext/alsa/gstalsasrc.c: (gst_alsa_src_init), (gst_alsa_src_loop),
(gst_alsa_src_change_state):
* ext/alsa/gstalsasrc.h:
Make the xrun code timestamp and offset the buffers correctly.
moved the clock to the base class, use alsa methods to get time.
Do correct timestamping on outgoing buffers.
This commit is contained in:
Wim Taymans 2004-06-17 14:10:21 +00:00
parent 7face56b42
commit a48818210d
5 changed files with 99 additions and 35 deletions

View file

@ -1,3 +1,16 @@
2004-06-17 Wim Taymans <wim@fluendo.com>
* ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
(gst_alsa_get_time), (gst_alsa_xrun_recovery):
* ext/alsa/gstalsa.h:
* ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
* ext/alsa/gstalsasrc.c: (gst_alsa_src_init), (gst_alsa_src_loop),
(gst_alsa_src_change_state):
* ext/alsa/gstalsasrc.h:
Make the xrun code timestamp and offset the buffers correctly.
moved the clock to the base class, use alsa methods to get time.
Do correct timestamping on outgoing buffers.
2004-06-17 Wim Taymans <wim@fluendo.com>
* gst/audiorate/Makefile.am:

View file

@ -203,6 +203,12 @@ static void
gst_alsa_init (GstAlsa * this)
{
this->device = g_strdup ("default");
g_assert (snd_pcm_status_malloc (&(this->status)) == 0);
this->clock = gst_alsa_clock_new ("alsaclock", gst_alsa_get_time, this);
/* we hold a ref to our clock until we're disposed */
gst_object_ref (GST_OBJECT (this->clock));
gst_object_sink (GST_OBJECT (this->clock));
GST_FLAG_SET (this, GST_ELEMENT_EVENT_AWARE);
GST_FLAG_SET (this, GST_ELEMENT_THREAD_SUGGESTED);
@ -214,6 +220,9 @@ gst_alsa_dispose (GObject * object)
GstAlsa *this = GST_ALSA (object);
g_free (this->device);
this->device = NULL;
snd_pcm_status_free (this->status);
this->status = NULL;
if (this->clock)
gst_object_unparent (GST_OBJECT (this->clock));
@ -310,6 +319,33 @@ gst_alsa_get_property (GObject * object, guint prop_id, GValue * value,
}
}
/**
* ask ALSA for current time using htstamp
* FIXME: This is not very accurate, should use alsa timers instead.
* htstamp seems to use the system clock instead of the hw clock.
*/
GstClockTime
gst_alsa_get_time (GstAlsa * this)
{
int err;
snd_htimestamp_t timestamp;
GstClockTime time;
if ((err = snd_pcm_status (this->handle, this->status)) < 0) {
GST_WARNING_OBJECT (this, "could not get snd_pcm_status");
}
snd_pcm_status_get_htstamp (this->status, &timestamp);
/* time = GST_TIMESPEC_TO_TIME (timestamp); */
time = timestamp.tv_sec * GST_SECOND + timestamp.tv_nsec * GST_NSECOND;
GST_LOG_OBJECT (this, "ALSA reports time of %" GST_TIME_FORMAT,
GST_TIME_ARGS (time));
return time;
}
static const GList *
gst_alsa_probe_get_properties (GstPropertyProbe * probe)
{
@ -1252,6 +1288,10 @@ gst_alsa_xrun_recovery (GstAlsa * this)
GST_INFO_OBJECT (this, "alsa: xrun of at least %.3f msecs",
diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
/* start new timestamps from the current time */
this->transmitted = gst_alsa_timestamp_to_samples (this,
gst_element_get_time (GST_ELEMENT (this)));
/* if we're allowed to recover, ... */
if (this->autorecover) {
/* ... then increase the period size or buffer size / period count to

View file

@ -164,6 +164,7 @@ struct _GstAlsa {
GstClockTime max_discont; /* max difference between current
playback timestamp and buffers timestamps
*/
snd_pcm_status_t *status;
};
struct _GstAlsaClass {
@ -191,6 +192,8 @@ GstCaps * gst_alsa_caps (snd_pcm_format_t format,
gint rate,
gint channels);
GstClockTime gst_alsa_get_time (GstAlsa * this);
/* audio processing functions */
inline snd_pcm_sframes_t gst_alsa_update_avail (GstAlsa * this);
inline gboolean gst_alsa_pcm_wait (GstAlsa * this);

View file

@ -44,8 +44,6 @@ static void gst_alsa_src_loop (GstElement * element);
static void gst_alsa_src_flush (GstAlsaSrc * src);
static GstElementStateReturn gst_alsa_src_change_state (GstElement * element);
static GstClockTime gst_alsa_src_get_time (GstAlsa * this);
static GstAlsa *src_parent_class = NULL;
static GstPadTemplate *
@ -118,6 +116,7 @@ gst_alsa_src_class_init (gpointer g_class, gpointer class_data)
element_class->change_state = gst_alsa_src_change_state;
}
static void
gst_alsa_src_init (GstAlsaSrc * src)
{
@ -128,14 +127,9 @@ gst_alsa_src_init (GstAlsaSrc * src)
gst_pad_set_getcaps_function (this->pad[0], gst_alsa_get_caps);
gst_element_add_pad (GST_ELEMENT (this), this->pad[0]);
this->clock =
gst_alsa_clock_new ("alsasrcclock", gst_alsa_src_get_time, this);
/* we hold a ref to our clock until we're disposed */
gst_object_ref (GST_OBJECT (this->clock));
gst_object_sink (GST_OBJECT (this->clock));
gst_element_set_loop_function (GST_ELEMENT (this), gst_alsa_src_loop);
}
static int
gst_alsa_src_mmap (GstAlsa * this, snd_pcm_sframes_t * avail)
{
@ -359,26 +353,47 @@ gst_alsa_src_loop (GstElement * element)
src->buf[i] =
gst_buffer_new_and_alloc (gst_alsa_samples_to_bytes (this, avail));
}
/* fill buffer with data */
if ((copied = this->transmit (this, &avail)) <= 0)
return;
/* push the buffers out and let them have fun */
for (i = 0; i < element->numpads; i++) {
GstBuffer *buf;
if (!src->buf[i])
return;
if (copied != this->period_size)
GST_BUFFER_SIZE (src->buf[i]) = gst_alsa_samples_to_bytes (this, copied);
GST_BUFFER_TIMESTAMP (src->buf[i]) =
gst_alsa_samples_to_timestamp (this, this->transmitted);
GST_BUFFER_DURATION (src->buf[i]) =
gst_alsa_samples_to_timestamp (this, copied);
buf = src->buf[i];
src->buf[i] = NULL;
gst_pad_push (this->pad[i], GST_DATA (buf));
{
gint outsize;
GstClockTime outtime, outdur;
outsize = gst_alsa_samples_to_bytes (this, copied);
outdur = gst_alsa_samples_to_timestamp (this, copied);
outtime = GST_CLOCK_TIME_NONE;
if (GST_ELEMENT_CLOCK (this)) {
if (GST_CLOCK (GST_ALSA (this)->clock) == GST_ELEMENT_CLOCK (this)) {
outtime = gst_alsa_samples_to_timestamp (this, this->transmitted);
} else {
outtime = gst_element_get_time (GST_ELEMENT (this));
}
}
/* push the buffers out and let them have fun */
for (i = 0; i < element->numpads; i++) {
GstBuffer *buf;
if (!src->buf[i])
return;
if (copied != this->period_size)
GST_BUFFER_SIZE (src->buf[i]) = outsize;
GST_BUFFER_TIMESTAMP (src->buf[i]) = outtime;
GST_BUFFER_DURATION (src->buf[i]) = outdur;
GST_BUFFER_OFFSET (src->buf[i]) = this->transmitted;
GST_BUFFER_OFFSET_END (src->buf[i]) = this->transmitted + copied;
buf = src->buf[i];
src->buf[i] = NULL;
gst_pad_push (this->pad[i], GST_DATA (buf));
}
this->transmitted += copied;
}
this->transmitted += copied;
}
static void
@ -393,6 +408,7 @@ gst_alsa_src_flush (GstAlsaSrc * src)
}
}
}
static GstElementStateReturn
gst_alsa_src_change_state (GstElement * element)
{
@ -404,7 +420,9 @@ gst_alsa_src_change_state (GstElement * element)
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
case GST_STATE_READY_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
@ -421,15 +439,3 @@ gst_alsa_src_change_state (GstElement * element)
return GST_STATE_SUCCESS;
}
static GstClockTime
gst_alsa_src_get_time (GstAlsa * this)
{
snd_pcm_sframes_t delay;
if (snd_pcm_delay (this->handle, &delay) == 0 && this->format) {
return GST_SECOND * (this->transmitted + delay) / this->format->rate;
} else {
return 0;
}
}

View file

@ -38,6 +38,8 @@ typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
struct _GstAlsaSrc {
GstAlsaMixer parent;
GstBuffer *buf[GST_ALSA_MAX_TRACKS];
snd_pcm_status_t *status;
GstClockTime base_time; /* FIXME: move this up ? already present in element ? */
};
struct _GstAlsaSrcClass {