+ fixing 100 % cpu usage bug (bug #103658) + cleaning up some of the FIXMEs, mostly bytestream stuff + changing loop ...

Original commit message from CVS:
+ fixing 100 % cpu usage bug (bug #103658)
+ cleaning up some of the FIXMEs, mostly bytestream stuff
+ changing loop to use snd_pcm_wait instead of that poll business
This commit is contained in:
Leif Johnson 2003-01-19 23:23:30 +00:00
parent ca810029cc
commit 85a0755988

View file

@ -57,13 +57,12 @@ static GstPadTemplate *gst_alsa_src_request_pad_factory();
static GstPadTemplate *gst_alsa_sink_pad_factory();
static GstPadTemplate *gst_alsa_sink_request_pad_factory();
static GstPad* gst_alsa_request_new_pad (GstElement *element, GstPadTemplate *templ, const
gchar *name);
static GstPad* gst_alsa_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name);
static void gst_alsa_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_alsa_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static GstElementStateReturn gst_alsa_change_state(GstElement *element);
static GstPadLinkReturn gst_alsa_connect(GstPad *pad, GstCaps *caps);
static GstPadLinkReturn gst_alsa_link(GstPad *pad, GstCaps *caps);
static GstCaps* gst_alsa_caps (GstAlsa *this);
@ -82,9 +81,8 @@ static gboolean gst_alsa_get_channel_addresses (GstAlsa *this);
static void gst_alsa_release_channel_addresses (GstAlsa *this);
static void gst_alsa_sink_silence_on_channel (GstAlsa *this, guint32 chn, guint32 nframes);
static void memset_interleave (char *dst, char val, unsigned int bytes,
unsigned int unit_bytes,
unsigned int skip_bytes);
static void memset_interleave (char *dst, char val, unsigned int bytes, unsigned int unit_bytes, unsigned int skip_bytes);
/* #define _DEBUG */
#ifdef _DEBUG
@ -215,9 +213,12 @@ gst_alsa_src_request_pad_factory(void)
static GstPadTemplate *template = NULL;
if (!template)
template = gst_pad_template_new("src%d", GST_PAD_SRC, GST_PAD_REQUEST,
template =
gst_pad_template_new("src%d", GST_PAD_SRC, GST_PAD_REQUEST,
gst_caps_new("src-request", "audio/raw",
gst_props_new("channels", GST_PROPS_INT(1), NULL)),
gst_props_new("channels",
GST_PROPS_INT(1),
NULL)),
NULL);
return template;
@ -242,9 +243,12 @@ gst_alsa_sink_request_pad_factory(void)
static GstPadTemplate *template = NULL;
if (!template)
template = gst_pad_template_new("sink%d", GST_PAD_SINK, GST_PAD_REQUEST,
template =
gst_pad_template_new("sink%d", GST_PAD_SINK, GST_PAD_REQUEST,
gst_caps_new("sink-request", "audio/raw",
gst_props_new("channels", GST_PROPS_INT(1), NULL)),
gst_props_new("channels",
GST_PROPS_INT(1),
NULL)),
NULL);
return template;
@ -327,7 +331,7 @@ gst_alsa_init(GstAlsa *this)
gst_element_add_pad(GST_ELEMENT(this), GST_ALSA_PAD(this->pads)->pad);
gst_pad_set_link_function(GST_ALSA_PAD(this->pads)->pad, gst_alsa_connect);
gst_pad_set_link_function(GST_ALSA_PAD(this->pads)->pad, gst_alsa_link);
gst_element_set_loop_function(GST_ELEMENT(this), gst_alsa_loop);
}
@ -377,7 +381,7 @@ gst_alsa_request_new_pad (GstElement *element, GstPadTemplate *templ, const gcha
pad->channel = channel;
pad->pad = gst_pad_new_from_template (templ, newname);
gst_element_add_pad (GST_ELEMENT (this), pad->pad);
gst_pad_set_link_function(pad->pad, gst_alsa_connect);
gst_pad_set_link_function(pad->pad, gst_alsa_link);
if (this->data_interleaved && this->pads) {
gst_element_remove_pad (GST_ELEMENT (this), GST_ALSA_PAD(this->pads)->pad);
@ -489,6 +493,7 @@ gst_alsa_change_state(GstElement *element)
{
GstAlsa *this;
guint chn;
GList *l;
g_return_val_if_fail(element != NULL, FALSE);
this = GST_ALSA (element);
@ -496,10 +501,17 @@ gst_alsa_change_state(GstElement *element)
switch (GST_STATE_PENDING(element)) {
case GST_STATE_NULL:
if (GST_FLAG_IS_SET(element, GST_ALSA_RUNNING))
gst_alsa_stop_audio((GstAlsa *)element);
gst_alsa_stop_audio(this);
if (GST_FLAG_IS_SET(element, GST_ALSA_OPEN))
gst_alsa_close_audio((GstAlsa *)element);
/* FIXME: clean up bytestreams, etc */
gst_alsa_close_audio(this);
l = this->pads;
while(l) {
if (GST_ALSA_PAD(l)->bs)
gst_bytestream_destroy(GST_ALSA_PAD(l)->bs);
l = l->next;
}
break;
case GST_STATE_READY:
@ -507,7 +519,7 @@ gst_alsa_change_state(GstElement *element)
case GST_STATE_PAUSED:
if (GST_FLAG_IS_SET(element, GST_ALSA_OPEN) == FALSE)
if (gst_alsa_open_audio((GstAlsa *)element) == FALSE)
if (gst_alsa_open_audio(this) == FALSE)
return GST_STATE_FAILURE;
if (GST_FLAG_IS_SET(element, GST_ALSA_RUNNING)) {
if (this->stream == SND_PCM_STREAM_PLAYBACK) {
@ -521,7 +533,7 @@ gst_alsa_change_state(GstElement *element)
case GST_STATE_PLAYING:
if (GST_FLAG_IS_SET(element, GST_ALSA_RUNNING) == FALSE)
if (gst_alsa_start_audio((GstAlsa *)element) == FALSE)
if (gst_alsa_start_audio(this) == FALSE)
return GST_STATE_FAILURE;
break;
}
@ -753,7 +765,7 @@ gst_alsa_caps (GstAlsa *this)
* Negotiates the caps, "borrowed" from gstosssink.c
*/
GstPadLinkReturn
gst_alsa_connect(GstPad *pad, GstCaps *caps)
gst_alsa_link(GstPad *pad, GstCaps *caps)
{
GstAlsa *this;
gboolean need_mmap;
@ -798,58 +810,39 @@ gst_alsa_connect(GstPad *pad, GstCaps *caps)
return GST_PAD_LINK_DELAYED;
}
/* shamelessly stolen from pbd's audioengine and jack alsa_driver. thanks, paul! */
/* shamelessly stolen from pbd's audioengine and jack alsa_driver. thanks,
paul! */
static void
gst_alsa_loop (GstElement *element)
{
struct pollfd pfd;
gboolean xrun_detected;
guint32 i;
GstAlsa *this = GST_ALSA(element);
g_return_if_fail(this != NULL);
snd_pcm_poll_descriptors (this->handle, &pfd, 1);
if (this->stream == SND_PCM_STREAM_PLAYBACK) {
pfd.events = POLLOUT | POLLERR;
} else {
pfd.events = POLLIN | POLLERR;
}
do {
xrun_detected = FALSE;
if (poll (&pfd, 1, 1000) < 0) {
if (snd_pcm_wait (this->handle, 1000) < 0) {
if (errno == EINTR) {
/* this happens mostly when run
* under gdb, or when exiting due to a signal */
g_print ("EINTR\n");
if (gst_element_interrupt (element))
break;
else
continue;
}
g_warning("poll call failed (%s)", strerror(errno));
g_warning("error waiting for alsa pcm: (%d: %s)", errno, strerror(errno));
return;
}
if (pfd.revents & POLLERR) {
xrun_detected = TRUE;
}
if (pfd.revents == 0) {
g_print ("poll on alsa %s device \"%s\" timed out\n",
this->stream==SND_PCM_STREAM_CAPTURE ? "capture" : "playback",
this->device);
/* timed out, such as when the device is paused */
continue;
}
this->avail = snd_pcm_avail_update (this->handle);
DEBUG ("snd_pcm_avail_update() = %d", (int)this->avail);
if (this->avail < 0) {
if (this->avail == -EPIPE) {
xrun_detected = TRUE;
gst_alsa_xrun_recovery (this);
this->avail = 0;
} else {
g_warning("unknown ALSA avail_update return value (%d)",
(int)this->avail);
@ -857,11 +850,6 @@ gst_alsa_loop (GstElement *element)
}
}
if (xrun_detected) {
gst_alsa_xrun_recovery (this);
this->avail = 0;
}
/* round down to nearest period_frames avail */
this->avail -= this->avail % this->period_frames;
@ -893,7 +881,10 @@ gst_alsa_loop (GstElement *element)
if (this->mmap_open)
gst_alsa_release_channel_addresses(this);
}
gst_element_yield (element);
if (gst_element_interrupt (element))
break;
} while (TRUE);
}
@ -905,7 +896,6 @@ gst_alsa_src_process (GstAlsa *this, snd_pcm_uframes_t frames)
GstAlsaPad *pad = NULL;
GstCaps *caps;
gint unit;
/* gint i=0; */
static gboolean caps_set = FALSE;
@ -915,7 +905,7 @@ gst_alsa_src_process (GstAlsa *this, snd_pcm_uframes_t frames)
l = this->pads;
while (l) {
if (gst_pad_try_set_caps (GST_ALSA_PAD(l)->pad, caps) <= 0) {
g_print ("DANGER WILL ROBINSON!\n");
g_print ("setting caps (%p) in source (%p) failed\n", caps, this);
sleep(1);
return FALSE;
}
@ -928,7 +918,6 @@ gst_alsa_src_process (GstAlsa *this, snd_pcm_uframes_t frames)
unit = this->sample_bytes * (this->data_interleaved ? this->channels : 1);
while (frames) {
/* g_print ("(%d) frames to process: %d\n", i++, frames); */
l = this->pads;
while (l) {
pad = GST_ALSA_PAD(l);
@ -944,8 +933,7 @@ gst_alsa_src_process (GstAlsa *this, snd_pcm_uframes_t frames)
pad->access_addr,
MIN(frames, this->period_frames - pad->offset) * unit);
*/
memcpy(pad->buf + pad->offset * unit,
pad->access_addr,
memcpy(pad->buf + pad->offset * unit, pad->access_addr,
MIN(frames, this->period_frames - pad->offset) * unit);
pad->offset += MIN(frames, this->period_frames - pad->offset);
@ -973,23 +961,26 @@ static gboolean
gst_alsa_sink_process (GstAlsa *this, snd_pcm_uframes_t frames)
{
guint8 *peeked;
guint32 len, avail;
guint32 len, avail, num_peeked;
GstEvent *event = NULL;
GstAlsaPad *alsa_pad;
GList *l;
/* this is necessary because the sample_bytes will change, probably, when
* caps are set, which will occur after the first bytestream_peek. we
* underestimate the amount of data we will need by peeking 'frames' only.
* */
/* FIXME: if 0 < peek_bytes < len, play the peek_bytes */
caps are set, which will occur after the first bytestream_peek. we
underestimate the amount of data we will need by peeking 1 byte only. */
if (!this->sample_bytes) {
if (!GST_ALSA_PAD(this->pads)->bs)
GST_ALSA_PAD(this->pads)->bs = gst_bytestream_new(GST_ALSA_PAD(this->pads)->pad);
alsa_pad = GST_ALSA_PAD(this->pads);
if (gst_bytestream_peek_bytes (GST_ALSA_PAD (this->pads)->bs, &peeked, frames) != frames) {
g_warning("could not make initial pull of %d bytes on pad %s:%s", (int)frames, GST_DEBUG_PAD_NAME(GST_ALSA_PAD(this->pads)->pad));
if (! alsa_pad->bs)
alsa_pad->bs = gst_bytestream_new(alsa_pad->pad);
num_peeked = gst_bytestream_peek_bytes (alsa_pad->bs, &peeked, frames);
if (num_peeked < frames) {
g_warning("could not make initial pull of %d bytes on pad %s:%s",
(int)frames,
GST_DEBUG_PAD_NAME(alsa_pad->pad));
gst_element_set_eos (GST_ELEMENT(this));
return FALSE;
}
@ -1004,18 +995,24 @@ gst_alsa_sink_process (GstAlsa *this, snd_pcm_uframes_t frames)
l = this->pads;
while (l) {
if (!GST_ALSA_PAD(this->pads)->bs)
GST_ALSA_PAD(this->pads)->bs = gst_bytestream_new(GST_ALSA_PAD(this->pads)->pad);
alsa_pad = GST_ALSA_PAD(l);
if (gst_bytestream_peek_bytes(GST_ALSA_PAD(this->pads)->bs, &peeked, len) != len) {
gst_bytestream_get_status(GST_ALSA_PAD(this->pads)->bs, &avail, &event);
if (! alsa_pad->bs)
alsa_pad->bs = gst_bytestream_new(alsa_pad->pad);
num_peeked = gst_bytestream_peek_bytes(alsa_pad->bs, &peeked, len);
if (num_peeked == 0) {
gst_bytestream_get_status(alsa_pad->bs, &avail, &event);
if (event) {
g_warning("got an event on alsasink");
if (GST_EVENT_TYPE(event) == GST_EVENT_EOS) {
/* really, we should just cut this pad out of the graph. let
* me know when this is needed ;)
* also, for sample accuracy etc, we should play avail
* bytes, but hey. */
me know when this is needed ;) */
num_peeked = gst_bytestream_peek_bytes(alsa_pad->bs, &peeked, avail);
if (num_peeked && peeked)
memcpy(alsa_pad->access_addr, peeked, avail);
gst_element_set_eos(GST_ELEMENT(this));
gst_event_unref(event);
return TRUE;
@ -1027,10 +1024,15 @@ gst_alsa_sink_process (GstAlsa *this, snd_pcm_uframes_t frames)
}
}
memcpy(GST_ALSA_PAD(this->pads)->access_addr, peeked, len);
gst_bytestream_flush(GST_ALSA_PAD(this->pads)->bs, len);
if (num_peeked && peeked && alsa_pad->access_addr) {
memcpy(alsa_pad->access_addr, peeked, num_peeked);
gst_bytestream_flush(alsa_pad->bs, num_peeked);
} else {
g_warning ("error while writing %u bytes (peeked into %p) to %p",
num_peeked, peeked, alsa_pad->access_addr);
}
l=l->next;
l = l->next;
}
return TRUE;
@ -1044,15 +1046,9 @@ gst_alsa_xrun_recovery (GstAlsa *this)
snd_pcm_status_alloca(&status);
if (this->stream == SND_PCM_STREAM_CAPTURE) {
if ((res = snd_pcm_status(this->handle, status)) < 0) {
g_warning ("status error: %s", snd_strerror(res));
}
} else {
if ((res = snd_pcm_status(this->handle, status)) < 0) {
g_warning ("status error: %s", snd_strerror(res));
}
}
if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
struct timeval now, diff, tstamp;
@ -1338,15 +1334,9 @@ gst_alsa_stop_audio(GstAlsa *this)
static void
gst_alsa_close_audio(GstAlsa *this)
{
/* gint err; */
g_return_if_fail(this != NULL);
g_return_if_fail(this->handle != NULL);
/* if ((err = snd_pcm_drop (this->handle)) < 0) {
g_warning("channel flush for failed: %s", snd_strerror (err));
return;
} */
snd_pcm_close(this->handle);
this->handle = NULL;
@ -1370,8 +1360,6 @@ gst_alsa_get_channel_addresses (GstAlsa *this)
GST_DEBUG(0, "got %d mmap'd frames", (int)this->avail);
/* g_print ("snd_pcm_mmap_begin() sets avail = %d\n", this->avail); */
l = this->pads;
while (l) {
a = &this->mmap_areas[GST_ALSA_PAD(l)->channel > 0 ?
@ -1383,7 +1371,8 @@ gst_alsa_get_channel_addresses (GstAlsa *this)
for (i=0; i<this->channels; i++) {
a = &this->mmap_areas[i];
this->access_addr[i] = (char *) a->addr + ((a->first + a->step * this->offset) / 8);
this->access_addr[i] = (char *) a->addr + ((a->first + a->step *
this->offset) / 8);
}
this->mmap_open = TRUE;
@ -1432,7 +1421,6 @@ gst_alsa_sink_silence_on_channel (GstAlsa *this, guint32 chn, guint32 nframes)
} else {
memset (this->access_addr[chn], 0, nframes * this->sample_bytes);
}
/* mark_channel_done (chn); */
}
/* taken directly from paul davis' memops.cc */