Skip to content

Commit 6014a3c

Browse files
committed
set realtime priority for stream threads in alsa and wasapi
implements #939. As someone who doesn't know a whole lot about cpal's inner workings it looks to me like these are the only threads that the library spawns itself, leading me to think these are the only threads that require manual priority changes. However, `audio_thread_priority` claims to also support MacOS, so maybe someone could look into whether that's applicable here?
1 parent 33b8919 commit 6014a3c

File tree

3 files changed

+50
-13
lines changed

3 files changed

+50
-13
lines changed

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ windows = { version = "0.54.0", features = [
3939
"Win32_Media_Multimedia",
4040
"Win32_UI_Shell_PropertiesSystem"
4141
]}
42+
audio_thread_priority = "0.33.0"
4243
asio-sys = { version = "0.2", path = "asio-sys", optional = true }
4344
num-traits = { version = "0.2.6", optional = true }
4445

4546
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd"))'.dependencies]
4647
alsa = "0.9"
4748
libc = "0.2"
49+
audio_thread_priority = "0.33.0"
4850
jack = { version = "0.13.0", optional = true }
4951

5052
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]

src/host/alsa/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
SupportedBufferSize, SupportedStreamConfig, SupportedStreamConfigRange,
1111
SupportedStreamConfigsError,
1212
};
13+
use audio_thread_priority::promote_current_thread_to_real_time;
1314
use std::cell::Cell;
1415
use std::cmp;
1516
use std::convert::TryInto;
@@ -589,6 +590,17 @@ fn input_stream_worker(
589590
error_callback: &mut (dyn FnMut(StreamError) + Send + 'static),
590591
timeout: Option<Duration>,
591592
) {
593+
let buffer_size = if let BufferSize::Fixed(buffer_size) = stream.conf.buffer_size {
594+
buffer_size
595+
} else {
596+
// if the buffer size isn't fixed, let audio_thread_priority choose a sensible default value
597+
0
598+
};
599+
600+
if let Err(err) = promote_current_thread_to_real_time(buffer_size, stream.conf.sample_rate.0) {
601+
eprintln!("Failed to promote audio thread to real-time priority: {err}");
602+
}
603+
592604
let mut ctxt = StreamWorkerContext::new(&timeout);
593605
loop {
594606
let flow =
@@ -640,6 +652,17 @@ fn output_stream_worker(
640652
error_callback: &mut (dyn FnMut(StreamError) + Send + 'static),
641653
timeout: Option<Duration>,
642654
) {
655+
let buffer_size = if let BufferSize::Fixed(buffer_size) = stream.conf.buffer_size {
656+
buffer_size
657+
} else {
658+
// if the buffer size isn't fixed, let audio_thread_priority choose a sensible default value
659+
0
660+
};
661+
662+
if let Err(err) = promote_current_thread_to_real_time(buffer_size, stream.conf.sample_rate.0) {
663+
eprintln!("Failed to promote audio thread to real-time priority: {err}");
664+
}
665+
643666
let mut ctxt = StreamWorkerContext::new(&timeout);
644667
loop {
645668
let flow =

src/host/wasapi/stream.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{
44
BackendSpecificError, Data, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
55
PlayStreamError, SampleFormat, StreamError,
66
};
7+
use audio_thread_priority::promote_current_thread_to_real_time;
78
use std::mem;
89
use std::ptr;
910
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
@@ -269,7 +270,18 @@ fn run_input(
269270
data_callback: &mut dyn FnMut(&Data, &InputCallbackInfo),
270271
error_callback: &mut dyn FnMut(StreamError),
271272
) {
272-
boost_current_thread_priority();
273+
let buffer_size = if let BufferSize::Fixed(buffer_size) = run_ctxt.stream.config.buffer_size {
274+
buffer_size
275+
} else {
276+
// if the buffer size isn't fixed, let audio_thread_priority choose a sensible default value
277+
0
278+
};
279+
280+
if let Err(err) =
281+
promote_current_thread_to_real_time(buffer_size, run_ctxt.stream.config.sample_rate.0)
282+
{
283+
eprintln!("Failed to promote audio thread to real-time priority: {err}");
284+
}
273285

274286
loop {
275287
match process_commands_and_await_signal(&mut run_ctxt, error_callback) {
@@ -298,7 +310,18 @@ fn run_output(
298310
data_callback: &mut dyn FnMut(&mut Data, &OutputCallbackInfo),
299311
error_callback: &mut dyn FnMut(StreamError),
300312
) {
301-
boost_current_thread_priority();
313+
let buffer_size = if let BufferSize::Fixed(buffer_size) = run_ctxt.stream.config.buffer_size {
314+
buffer_size
315+
} else {
316+
// if the buffer size isn't fixed, let audio_thread_priority choose a sensible default value
317+
0
318+
};
319+
320+
if let Err(err) =
321+
promote_current_thread_to_real_time(buffer_size, run_ctxt.stream.config.sample_rate.0)
322+
{
323+
eprintln!("Failed to promote audio thread to real-time priority: {err}");
324+
}
302325

303326
loop {
304327
match process_commands_and_await_signal(&mut run_ctxt, error_callback) {
@@ -322,17 +345,6 @@ fn run_output(
322345
}
323346
}
324347

325-
fn boost_current_thread_priority() {
326-
unsafe {
327-
let thread_id = Threading::GetCurrentThreadId();
328-
329-
let _ = Threading::SetThreadPriority(
330-
HANDLE(thread_id as isize),
331-
Threading::THREAD_PRIORITY_TIME_CRITICAL,
332-
);
333-
}
334-
}
335-
336348
enum ControlFlow {
337349
Break,
338350
Continue,

0 commit comments

Comments
 (0)