gstaudiosrc/sink: Set audio ringbuffer thread priority
On Windows, the ringbuffer thread function must have the "Pro Audio"
priority set, otherwise it sometimes doesn't get scheduled for
200-300ms, which will immediately cause an underrun unless you set
a very high latency-time and buffer-time.
This has no compile-time deps since it tries to load avrt.dll at
runtime to set the thread priority.
diff --git a/gst-libs/gst/audio/gstaudiosink.c b/gst-libs/gst/audio/gstaudiosink.c
index cc48f7d..cc7b791 100644
--- a/gst-libs/gst/audio/gstaudiosink.c
+++ b/gst-libs/gst/audio/gstaudiosink.c
@@ -53,6 +53,7 @@
#include <gst/audio/audio.h>
#include "gstaudiosink.h"
+#include "gstaudioutilsprivate.h"
GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
#define GST_CAT_DEFAULT gst_audio_sink_debug
@@ -213,6 +214,9 @@
if (writefunc == NULL)
goto no_function;
+ if (G_UNLIKELY (!__gst_audio_set_thread_priority ()))
+ GST_WARNING_OBJECT (sink, "failed to set thread priority");
+
message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
g_value_init (&val, GST_TYPE_G_THREAD);
diff --git a/gst-libs/gst/audio/gstaudiosrc.c b/gst-libs/gst/audio/gstaudiosrc.c
index c3faf8f..008921f 100644
--- a/gst-libs/gst/audio/gstaudiosrc.c
+++ b/gst-libs/gst/audio/gstaudiosrc.c
@@ -46,6 +46,7 @@
#include <gst/audio/audio.h>
#include "gstaudiosrc.h"
+#include "gstaudioutilsprivate.h"
GST_DEBUG_CATEGORY_STATIC (gst_audio_src_debug);
#define GST_CAT_DEFAULT gst_audio_src_debug
@@ -192,6 +193,9 @@
if ((readfunc = csrc->read) == NULL)
goto no_function;
+ if (G_UNLIKELY (!__gst_audio_set_thread_priority ()))
+ GST_WARNING_OBJECT (src, "failed to set thread priority");
+
message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (src));
g_value_init (&val, GST_TYPE_G_THREAD);
diff --git a/gst-libs/gst/audio/gstaudioutilsprivate.c b/gst-libs/gst/audio/gstaudioutilsprivate.c
index 27b056b..cb3935c 100644
--- a/gst-libs/gst/audio/gstaudioutilsprivate.c
+++ b/gst-libs/gst/audio/gstaudioutilsprivate.c
@@ -23,6 +23,10 @@
#include "config.h"
#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
#include <gst/audio/audio.h>
#include "gstaudioutilsprivate.h"
@@ -212,3 +216,64 @@
exit:
return res;
}
+
+#ifdef _WIN32
+/* *INDENT-OFF* */
+static struct
+{
+ HMODULE dll;
+ gboolean tried_loading;
+
+ HANDLE (WINAPI * AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD);
+ BOOL (WINAPI * AvRevertMmThreadCharacteristics) (HANDLE);
+} _gst_audio_avrt_tbl = { 0 };
+/* *INDENT-ON* */
+#endif
+
+static gboolean
+__gst_audio_init_thread_priority (void)
+{
+#ifdef _WIN32
+ if (_gst_audio_avrt_tbl.tried_loading)
+ return _gst_audio_avrt_tbl.dll != NULL;
+
+ if (!_gst_audio_avrt_tbl.dll)
+ _gst_audio_avrt_tbl.dll = LoadLibrary (TEXT ("avrt.dll"));
+
+ if (!_gst_audio_avrt_tbl.dll) {
+ GST_WARNING ("Failed to set thread priority, can't find avrt.dll");
+ _gst_audio_avrt_tbl.tried_loading = TRUE;
+ return FALSE;
+ }
+
+ _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics =
+ GetProcAddress (_gst_audio_avrt_tbl.dll, "AvSetMmThreadCharacteristicsA");
+ _gst_audio_avrt_tbl.AvRevertMmThreadCharacteristics =
+ GetProcAddress (_gst_audio_avrt_tbl.dll,
+ "AvRevertMmThreadCharacteristics");
+
+ _gst_audio_avrt_tbl.tried_loading = TRUE;
+#endif
+
+ return TRUE;
+}
+
+/*
+ * Increases the priority of the thread it's called from
+ */
+gpointer
+__gst_audio_set_thread_priority (void)
+{
+ if (!__gst_audio_init_thread_priority ())
+ return NULL;
+
+#ifdef _WIN32
+ DWORD taskIndex = 0;
+ /* This is only used from ringbuffer thread functions, so we don't need to
+ * ever need to revert the thread priorities. */
+ return _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics (TEXT ("Pro Audio"),
+ &taskIndex);
+#else
+ return NULL;
+#endif
+}
diff --git a/gst-libs/gst/audio/gstaudioutilsprivate.h b/gst-libs/gst/audio/gstaudioutilsprivate.h
index 976765f..b9db8d8 100644
--- a/gst-libs/gst/audio/gstaudioutilsprivate.h
+++ b/gst-libs/gst/audio/gstaudioutilsprivate.h
@@ -42,6 +42,9 @@
gint64 src_value, GstFormat * dest_format,
gint64 * dest_value);
+G_GNUC_INTERNAL
+gpointer __gst_audio_set_thread_priority (void);
+
G_END_DECLS
#endif