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.
This commit is contained in:
Nirbheek Chauhan 2018-09-11 00:41:59 +05:30
parent 41b7a65b81
commit 1733233060
4 changed files with 76 additions and 0 deletions

View file

@ -56,6 +56,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
@ -216,6 +217,9 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
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);

View file

@ -49,6 +49,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
@ -195,6 +196,9 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
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);

View file

@ -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 @@ __gst_audio_encoded_audio_convert (GstAudioInfo * fmt,
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
}

View file

@ -42,6 +42,9 @@ gboolean __gst_audio_encoded_audio_convert (GstAudioInfo * fmt, gint64 bytes,
gint64 src_value, GstFormat * dest_format,
gint64 * dest_value);
G_GNUC_INTERNAL
gpointer __gst_audio_set_thread_priority (void);
G_END_DECLS
#endif