Use MMCSS to elevate the thread priorities for audio and MIDI threads

use AVRT_PRIORITY_NORMAL for audio threads and AVRT_PRIORITY_HIGH for MIDI
threads
This commit is contained in:
Tim Mayberry 2015-07-30 12:09:43 +10:00
parent e9d00f5cfb
commit acd17a9b53
4 changed files with 78 additions and 1 deletions

View file

@ -37,6 +37,8 @@
#include "i18n.h" #include "i18n.h"
#include "win_utils.h" #include "win_utils.h"
#include "mmcss.h"
#include "debug.h" #include "debug.h"
using namespace ARDOUR; using namespace ARDOUR;
@ -79,6 +81,8 @@ PortAudioBackend::PortAudioBackend (AudioEngine& e, AudioBackendInfo& info)
_instance_name = s_instance_name; _instance_name = s_instance_name;
pthread_mutex_init (&_port_callback_mutex, 0); pthread_mutex_init (&_port_callback_mutex, 0);
mmcss::initialize ();
_pcmio = new PortAudioIO (); _pcmio = new PortAudioIO ();
_midiio = new WinMMEMidiIO (); _midiio = new WinMMEMidiIO ();
} }
@ -87,6 +91,9 @@ PortAudioBackend::~PortAudioBackend ()
{ {
delete _pcmio; _pcmio = 0; delete _pcmio; _pcmio = 0;
delete _midiio; _midiio = 0; delete _midiio; _midiio = 0;
mmcss::deinitialize ();
pthread_mutex_destroy (&_port_callback_mutex); pthread_mutex_destroy (&_port_callback_mutex);
} }
@ -636,7 +643,23 @@ PortAudioBackend::portaudio_process_thread (void *arg)
ThreadData* td = reinterpret_cast<ThreadData*> (arg); ThreadData* td = reinterpret_cast<ThreadData*> (arg);
boost::function<void ()> f = td->f; boost::function<void ()> f = td->f;
delete td; delete td;
#ifdef USE_MMCSS_THREAD_PRIORITIES
HANDLE task_handle;
mmcss::set_thread_characteristics ("Pro Audio", &task_handle);
mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_NORMAL);
#endif
DWORD tid = GetThreadId (GetCurrentThread ());
DEBUG_THREADS (string_compose ("Process Thread Child ID: %1\n", tid));
f (); f ();
#ifdef USE_MMCSS_THREAD_PRIORITIES
mmcss::revert_thread_characteristics (task_handle);
#endif
return 0; return 0;
} }
@ -1308,6 +1331,16 @@ PortAudioBackend::main_process_thread ()
engine.halted_callback("PortAudio I/O error."); engine.halted_callback("PortAudio I/O error.");
} }
#ifdef USE_MMCSS_THREAD_PRIORITIES
HANDLE task_handle;
mmcss::set_thread_characteristics ("Pro Audio", &task_handle);
mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_NORMAL);
#endif
DWORD tid = GetThreadId (GetCurrentThread ());
DEBUG_THREADS (string_compose ("Process Thread Master ID: %1\n", tid));
while (_run) { while (_run) {
if (_freewheeling != _freewheel) { if (_freewheeling != _freewheel) {
@ -1511,6 +1544,11 @@ PortAudioBackend::main_process_thread ()
if (_run) { if (_run) {
engine.halted_callback("PortAudio I/O error."); engine.halted_callback("PortAudio I/O error.");
} }
#ifdef USE_MMCSS_THREAD_PRIORITIES
mmcss::revert_thread_characteristics (task_handle);
#endif
return 0; return 0;
} }

View file

@ -26,6 +26,8 @@
#include "win_utils.h" #include "win_utils.h"
#include "midi_util.h" #include "midi_util.h"
#include "mmcss.h"
#include "debug.h" #include "debug.h"
static const uint32_t MIDI_BUFFER_SIZE = 32768; static const uint32_t MIDI_BUFFER_SIZE = 32768;
@ -175,6 +177,30 @@ WinMMEMidiInputDevice::winmm_input_callback(HMIDIIN handle,
{ {
WinMMEMidiInputDevice* midi_input = (WinMMEMidiInputDevice*)instance; WinMMEMidiInputDevice* midi_input = (WinMMEMidiInputDevice*)instance;
#ifdef USE_MMCSS_THREAD_PRIORITIES
static HANDLE input_thread = GetCurrentThread ();
static bool priority_boosted = false;
if (input_thread != GetCurrentThread ()) {
DWORD otid = GetThreadId (input_thread);
DWORD ntid = GetThreadId (GetCurrentThread ());
// There was a reference on the internet somewhere that it is possible
// for the callback to come from different threads(thread pool) this
// could be problematic but I haven't seen this behaviour yet
DEBUG_THREADS (string_compose (
"WinMME input Thread ID Changed: was %1, now %2\n", otid, ntid));
}
HANDLE task_handle;
if (!priority_boosted) {
mmcss::set_thread_characteristics ("Pro Audio", &task_handle);
mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_HIGH);
priority_boosted = true;
}
#endif
switch (msg) { switch (msg) {
case MIM_OPEN: case MIM_OPEN:
case MIM_CLOSE: case MIM_CLOSE:

View file

@ -27,6 +27,7 @@
#include "win_utils.h" #include "win_utils.h"
#include "midi_util.h" #include "midi_util.h"
#include "mmcss.h"
#include "debug.h" #include "debug.h"
// remove dup with input_device // remove dup with input_device
@ -349,6 +350,13 @@ WinMMEMidiOutputDevice::midi_output_thread ()
DEBUG_MIDI ("WinMMEMidiOut: MIDI output thread started\n"); DEBUG_MIDI ("WinMMEMidiOut: MIDI output thread started\n");
#ifdef USE_MMCSS_THREAD_PRIORITIES
HANDLE task_handle;
mmcss::set_thread_characteristics ("Pro Audio", &task_handle);
mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_HIGH);
#endif
while (!m_thread_quit) { while (!m_thread_quit) {
if (!wait (m_queue_semaphore)) { if (!wait (m_queue_semaphore)) {
break; break;
@ -471,6 +479,10 @@ WinMMEMidiOutputDevice::midi_output_thread ()
#endif #endif
} }
#ifdef USE_MMCSS_THREAD_PRIORITIES
mmcss::revert_thread_characteristics (task_handle);
#endif
m_thread_running = false; m_thread_running = false;
} }

View file

@ -36,5 +36,6 @@ def build(bld):
obj.uselib = ['PORTAUDIO'] obj.uselib = ['PORTAUDIO']
obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends') obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends')
obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"', obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
'ARDOURBACKEND_DLL_EXPORTS' 'ARDOURBACKEND_DLL_EXPORTS',
'USE_MMCSS_THREAD_PRIORITIES'
] ]