1818#include " ../../contrib/SimpleLogger/src/simple_logger.hpp"
1919
2020#include < algorithm>
21+ #include < cstdlib>
2122#include < pthread.h>
2223
2324namespace noteahead {
2425
2526RealTimeWorkerPool::RealTimeWorkerPool (size_t workerCount)
2627{
28+ juzzlin::L (" RealTimeWorkerPool" ).info () << " Starting with " << workerCount << " worker thread(s)"
29+ << (workerCount == 0 ? " (serial processing on the audio thread)" : " " );
30+
2731 m_startSemaphores.reserve (workerCount);
2832 m_workers.reserve (workerCount);
2933
@@ -43,7 +47,9 @@ RealTimeWorkerPool::RealTimeWorkerPool(size_t workerCount)
4347 struct sched_param param;
4448 param.sched_priority = 80 ; // High priority for audio
4549 if (pthread_setschedparam (pthread_self (), SCHED_FIFO , ¶m) != 0 ) {
46- juzzlin::L (" RealTimeWorkerPool" ).warning () << " Failed to set RT priority for " << threadName;
50+ juzzlin::L (" RealTimeWorkerPool" ).warning () << " Failed to set RT priority for " << threadName
51+ << " (needs rtprio limits, e.g. the 'audio' group); "
52+ << " audio may stutter under load. Set NOTEAHEAD_AUDIO_WORKERS=0 to disable the pool." ;
4753 }
4854
4955 workerLoop (i);
@@ -117,6 +123,22 @@ void RealTimeWorkerPool::run(size_t taskCount, void * context, TaskCallback call
117123size_t RealTimeWorkerPool::defaultWorkerCount ()
118124{
119125 const auto hardwareThreads = std::thread::hardware_concurrency ();
126+
127+ // Allow overriding the worker count via the environment. NOTEAHEAD_AUDIO_WORKERS=0 disables the
128+ // pool entirely (all device processing runs serially on the audio thread), which avoids the
129+ // worker wakeup latency that can cause stutter when the worker threads cannot obtain real-time
130+ // scheduling. Useful both as a workaround and for diagnosing threading-related audio glitches.
131+ if (const char * env = std::getenv (" NOTEAHEAD_AUDIO_WORKERS" ); env && *env) {
132+ char * end = nullptr ;
133+ const long requested = std::strtol (env, &end, 10 );
134+ if (end != env && requested >= 0 ) {
135+ const auto clamped = std::min<long >(requested, hardwareThreads > 0 ? hardwareThreads : requested);
136+ juzzlin::L (" RealTimeWorkerPool" ).info () << " Worker count overridden via NOTEAHEAD_AUDIO_WORKERS: " << clamped;
137+ return static_cast <size_t >(clamped);
138+ }
139+ juzzlin::L (" RealTimeWorkerPool" ).warning () << " Ignoring invalid NOTEAHEAD_AUDIO_WORKERS value: " << env;
140+ }
141+
120142 if (hardwareThreads <= 1 ) {
121143 return 0 ;
122144 }
0 commit comments