From 90cbd03f3273b9ed088e80a29db0eb8e276a30bd Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 24 Jan 2013 13:25:18 -0600 Subject: [PATCH] Add upstream fix for excessive alsasink CPU usage --- alsa-delay-lock.patch | 91 ++++++++++++++++++++++++++++++++++++ gstreamer1-plugins-base.spec | 7 ++- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 alsa-delay-lock.patch diff --git a/alsa-delay-lock.patch b/alsa-delay-lock.patch new file mode 100644 index 0000000..f378414 --- /dev/null +++ b/alsa-delay-lock.patch @@ -0,0 +1,91 @@ +From 67a7b5a99317ca1f92fb6a88542647aa3ad92c4b Mon Sep 17 00:00:00 2001 +From: yanghuolin +Date: Thu, 15 Nov 2012 08:31:47 +0000 +Subject: 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 +--- +diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c +index 1ef6b91..81731b6 100644 +--- a/ext/alsa/gstalsasink.c ++++ b/ext/alsa/gstalsasink.c +@@ -118,6 +118,7 @@ gst_alsasink_finalise (GObject * object) + + g_free (sink->device); + g_mutex_clear (&sink->alsa_lock); ++ g_mutex_clear (&sink->delay_lock); + + g_mutex_lock (&output_mutex); + --output_ref; +@@ -255,6 +256,7 @@ gst_alsasink_init (GstAlsaSink * alsasink) + alsasink->handle = NULL; + alsasink->cached_caps = NULL; + g_mutex_init (&alsasink->alsa_lock); ++ g_mutex_init (&alsasink->delay_lock); + + g_mutex_lock (&output_mutex); + if (output_ref == 0) { +@@ -1011,7 +1013,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); +@@ -1057,7 +1061,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 3a64a92..8c4c1b0 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 { +-- +cgit v0.9.0.2-2-gbebe diff --git a/gstreamer1-plugins-base.spec b/gstreamer1-plugins-base.spec index 78d914e..e11a432 100644 --- a/gstreamer1-plugins-base.spec +++ b/gstreamer1-plugins-base.spec @@ -2,13 +2,14 @@ Name: gstreamer1-plugins-base Version: 1.0.5 -Release: 2%{?dist} +Release: 3%{?dist} Summary: GStreamer streaming media framework base plugins License: LGPLv2+ URL: http://gstreamer.freedesktop.org/ Source0: http://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-%{version}.tar.xz Patch0: 0001-missing-plugins-Remove-the-mpegaudioversion-field.patch +Patch1: alsa-delay-lock.patch BuildRequires: gstreamer1-devel >= %{version} BuildRequires: gobject-introspection-devel >= 1.31.1 @@ -89,6 +90,7 @@ for the GStreamer Base Plugins library. %prep %setup -q -n gst-plugins-base-%{version} %patch0 -p1 +%patch1 -p1 %build @@ -333,6 +335,9 @@ chrpath --delete $RPM_BUILD_ROOT%{_bindir}/gst-discoverer-1.0 %changelog +* Thu Jan 24 2013 Daniel Drake - 1.0.5-3 +- Add upstream fix for excessive alsasink CPU usage + * Fri Jan 18 2013 Brian Pepple - 1.0.5-2 - Add patch to fix missing mp3 codec discovery. (#680809, #896018)