diff options
author | yanghuolin <Huolin.Yang@delphi.com> | 2012-11-15 03:31:47 -0500 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2013-01-24 15:34:19 +0100 |
commit | 519f85a43e73efb8f3fb2c7be45226e71149f6c6 (patch) | |
tree | d615ece406d447dbff653138c5d37afb3000eb9c | |
parent | e47288f1738be2cb2cf5868fa944685a898c1cb0 (diff) | |
download | gstreamer-plugins-base-519f85a43e73efb8f3fb2c7be45226e71149f6c6.tar.gz |
alsasink: don't use 100% CPU
The root cause is that alsa-lib is not thread safe for the same handle.
There are two threads in the gstreamer accessing alsa-lib not serilized.
The race condition happens when one thread holds the old framebuffer app_ptr
position in the kernel, another thread advances the framebuffer app_ptr.
when the former thread is scheduled to run again, it overwrites the app_ptr
to old value by copying from kernel.Thus,the app_ptr in the upper
alsa-lib(pcm_rate) become one period size more advanced than the lower
alsa-lib(pcm_hw & kernel).
gstreamer uses noblock and poll method to communicate with the alsa-lib.
The app_ptr unsync situation as described above makes the poll return immediately because
it concludes there is enough space for the ring-buffer via the low-level alsa-lib.
The write function returns immediately because it concludes there is not enough
space for the ring-buffer from the upper-level alsa-lib. Then the loop of poll
and write runs again and again until another period size is available for
ring-buffer.This leads to the cpu 100 problem.
delay_lock is used to avoid the race condition.
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=690937
Conflicts:
ext/alsa/gstalsasink.c
ext/alsa/gstalsasink.h
-rw-r--r-- | ext/alsa/gstalsasink.c | 6 | ||||
-rw-r--r-- | ext/alsa/gstalsasink.h | 5 |
2 files changed, 11 insertions, 0 deletions
diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c index 8682e0502..1600426b7 100644 --- a/ext/alsa/gstalsasink.c +++ b/ext/alsa/gstalsasink.c @@ -150,6 +150,7 @@ gst_alsasink_finalise (GObject * object) g_free (sink->device); g_mutex_free (sink->alsa_lock); + g_mutex_free (sink->delay_lock); g_static_mutex_lock (&output_mutex); --output_ref; @@ -288,6 +289,7 @@ gst_alsasink_init (GstAlsaSink * alsasink, GstAlsaSinkClass * g_class) alsasink->handle = NULL; alsasink->cached_caps = NULL; alsasink->alsa_lock = g_mutex_new (); + alsasink->delay_lock = g_mutex_new (); g_static_mutex_lock (&output_mutex); if (output_ref == 0) { @@ -929,7 +931,9 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) if (err < 0) { GST_DEBUG_OBJECT (asink, "wait error, %d", err); } else { + GST_DELAY_SINK_LOCK (asink); err = snd_pcm_writei (alsa->handle, ptr, cptr); + GST_DELAY_SINK_UNLOCK (asink); } GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr); @@ -966,7 +970,9 @@ gst_alsasink_delay (GstAudioSink * asink) alsa = GST_ALSA_SINK (asink); + GST_DELAY_SINK_LOCK (asink); res = snd_pcm_delay (alsa->handle, &delay); + GST_DELAY_SINK_UNLOCK (asink); if (G_UNLIKELY (res < 0)) { /* on errors, report 0 delay */ GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res); diff --git a/ext/alsa/gstalsasink.h b/ext/alsa/gstalsasink.h index 902dbf77e..c1eea47a3 100644 --- a/ext/alsa/gstalsasink.h +++ b/ext/alsa/gstalsasink.h @@ -43,6 +43,10 @@ typedef struct _GstAlsaSinkClass GstAlsaSinkClass; #define GST_ALSA_SINK_LOCK(obj) (g_mutex_lock (GST_ALSA_SINK_GET_LOCK (obj))) #define GST_ALSA_SINK_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SINK_GET_LOCK (obj))) +#define GST_DELAY_SINK_GET_LOCK(obj) (GST_ALSA_SINK_CAST (obj)->delay_lock) +#define GST_DELAY_SINK_LOCK(obj) (g_mutex_lock (GST_DELAY_SINK_GET_LOCK (obj))) +#define GST_DELAY_SINK_UNLOCK(obj) (g_mutex_unlock (GST_DELAY_SINK_GET_LOCK (obj))) + /** * GstAlsaSink: * @@ -73,6 +77,7 @@ struct _GstAlsaSink { GstCaps *cached_caps; GMutex *alsa_lock; + GMutex *delay_lock; }; struct _GstAlsaSinkClass { |