mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
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:
parent
7face56b42
commit
a48818210d
5 changed files with 99 additions and 35 deletions
13
ChangeLog
13
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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, ×tamp);
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue