It has been a while since I talked about multicore processing issues in plug-ins on MacOS (starting with MacOS 11 “Big Sur”). I was recently reminded that I never posted the details about how I finally managed to solve this issue. It looks like the hints provided in my previous article were not enough for other developers to find out, so here it is! With 5 new major versions of MacOS released without breaking this hack, I guess you can consider it as mostly reliable.
Should You Do It?
As I already said, relying on the private implementation of a feature in someone else’s code is NEVER a good idea. However since there is not other choice here (or let customers “enjoy” degraded performance on MacOS), that’s currently the only way to properly support multicore processing in a real time audio thread when you do not have access to the Core Audio driver directly (typically in a plug-in).
The Trick
So here is the trick: if you have already implemented Apple’s workgroups in your multicore solution, the one piece missing is to get the current workgroup from a processing thread. It is provided by Apple’s own Audio Units framework, but by no other plug-in API (more details in my previous article here).
There is however a way to get it, and you can find out how by looking at Apple’s workgroup implementation on github (we are lucky that this is in the open source part of the system). They have their own private function to get the current workgroup that is used everywhere in the implementation:
static os_workgroup_t
_os_workgroup_get_current(void)
{
return (os_workgroup_t) _dispatch_thread_getspecific(os_workgroup_key);
}
So the current workgroup (if any), is simply a value available from the thread local storage. And the good news is that the os_workgroup_key is a static value that is predefined at build time (the exact value can be found in the private lib dispatch header), so it’s not something that would keep changing over time during a session, like the thread local storage keys you would allocate yourself. Since they have all sorts of predefined values for various uses in this header (and even pre-reserved keys that are not in use yet), it is not likely to change anytime soon (but be aware that it could). It is thus possible to write your own function to get the current workgroup like this:
static os_workgroup_t
my_os_workgroup_get_current(void)
{
return (os_workgroup_t) thread_getspecific(os_workgroup_key);
}
Of course you want to check the OS version (it wasn’t implemented before MacOS 11), and verify that you get what you expect etc. but you get the idea. I have been using this trick since MacOS 11, and it has been working fine ever since (no more audio dropouts with multicore processing). I hope this helps!
Apple, Please…!
Apple audio developers, if you ever come across this blog post, please consider adding a public API to access the current workgroup, it would make things easier and safer for the audio developers community. And I don’t think it is in Apple’s interest to let so many CPU-intensive plug-in have better performance on Windows/Intel: it completely defeats the purpose of owning an Apple Silicon machine for intensive real time processing.
And since you already have your own internal Core Audio API for this (os_workgroup_interval_copy_current_4AudioToolbox), don’t tell me it is not necessary! 😉
Enjoy!
