mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 14:08:56 +00:00
+ 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:
parent
ca810029cc
commit
85a0755988
1 changed files with 264 additions and 276 deletions
|
@ -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,8 +1024,13 @@ 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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue