Skip to content

MacOS fails to elevate thread priority on both capture and replay threads due to large audio buffers #5

@binarybana

Description

@binarybana

Cool project! On my M3 Mac (Sonoma 14.7) I was running into warnings like this at startup (ignore my debugging output since it will become relevant later):

> callme-cli -i 'Yeti Stereo Microphone' -o 'Yeti Stereo Microphone' accept
[....snip....]
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:131:9] audio_buffer_frames = 30720
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:131:9] audio_samplerate_hz = 48000
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:131:9] buffer_frames = 30720
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:139:9] timebase_info.denom = 3
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:139:9] timebase_info.numer = 125
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:139:9] ms2abs = 24000.0
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:155:13] tid = 68099
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:155:13] THREAD_TIME_CONSTRAINT_POLICY = 2
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:155:13] time_constraints = thread_time_constraint_policy {
    period: 15360000,
    computation: 7680000,
    constraint: 15360000,
    preemptible: 1,
}
[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:155:13] THREAD_TIME_CONSTRAINT_POLICY_COUNT!() = 4
2025-03-28T23:53:34.913838Z  WARN callme::audio::playback: failed to set playback thread to realtime priority: AudioThreadPriorityError { message: "thread promotion error: thread_policy_set: time_constraint 4", inner: None }
2025-03-28T23:53:34.977561Z  INFO ep{me=647d9ed3b0}:magicsock:actor: iroh::magicsock: home is now relay https://use1-1.relay.iroh.network./, was None
2025-03-28T23:53:35.019507Z  INFO callme::audio::playback: start playback stream on Yeti Stereo Microphone with AudioFormat { sample_rate: SampleRate(48000), channel_count: 2 }
2025-03-28T23:53:35.019541Z  INFO callme::audio::playback: playback loop start
2025-03-28T23:53:35.938733Z  WARN callme::audio::playback: [tick 45] playback xrun: 1152 of 1920 samples missing (buffered 0) (+ 0 previous)

Mainly the WARN callme::audio::playback: failed to set playback thread to realtime priority bit, which then lead to large numbers of sample missing each loop.

I tracked this down to the large number of audio_buffer_frames that are being passed into audio_thread_priority::promote_current_thread_to_real_time here.

This then turns into a mach OS thread_policy_set call that fails with KERN_INVALID_ARGUMENT. I'm assuming the values are too large (see the extra debug statements in the log above for the playback thread) somehow, because if I replace the first argument (buffer size) in the promote_current_thread_to_real_time call to 0, the call at least succeeds, due to requesting a much smaller number of guaranteed cycles based on the sampling rate with debug data of the resulting constraint policy of:

[/Users/jaknight/src/audio_thread_priority/src/rt_mach.rs:121:9] time_constraints = thread_time_constraint_policy {
    period: 0,
    computation: 120000,
    constraint: 240000,
    preemptible: 1,
}

I'm not sure what the limits are for this call, but the audio coming through seemed okay with the first parameter of 0 on one side (the other used a Windows client which didn't require this workaround), though there were still a few samples missing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions