Contents

Adding Parallel Real-Time Threads to Audio Workgroups

Optimize the performance of real-time audio threads that run in sync with the I/O thread by adding them to the audio device workgroup.

Overview

If your app creates one or more auxiliary real-time threads that run in sync with the audio server I/O thread, join them to its audio workgroup. Doing so informs the system that these threads are rendering to the same deadline, which helps it optimize performance.

Add Your Threads to the Audio Device Workgroup

Begin by retrieving the audio device’s workgroup, so you can join your threads to it. Retrieve it from the I/O Audio Unit (AUHAL or AURemoteIO) using either the kAudioOutputUnitProperty_OSWorkgroup property for AUv2, or the AUAudioUnit osWorkgroup property for AUv3. In macOS, you can also get it directly from the audio device by using the HAL API. Then, in your real-time thread, call os_workgroup_join to join it to the workgroup, and call os_workgroup_leave when you’ve finished your work, as shown in the example below.

#import <AudioToolbox/AudioToolbox.h>
 
// Get the workgroup from the AUHal.
os_workgroup_t _Nonnull workgroup = auHal.osWorkgroup;

// An opaque join token that the client needs to pass to join and leave a workgroup.
os_workgroup_join_token_s joinToken;

void realtimeThreadFunction(os_workgroup_t workgroup) {
    
    // Join this thread to the workgroup.
    const int result = os_workgroup_join(workgroup, &joinToken);
    if (result == 0) {
        // Success.
    }
    else if (result == EALREADY) {
        // The thread is already part of a workgroup that can't be
        // nested in the the specified workgroup.
        return;
    }
    else if (result == EINVAL) {
        // The workgroup has been canceled.
        return;
    }
    
    // Work cycle.
    while (threadShouldRun) {
        // Typically, wait on a semaphore.
        waitForWork();
        // The controlling thread signaled this thread to stop.
        if (threadShouldRun) {
            performCustomAudioDSPWorkUnit();
            // Typically, signal a semaphore.
            signalWorkComplete();
        }
    }
    
    // Before exiting the thread, leave the workgroup.
    os_workgroup_leave(workgroup, &joinToken);
}

See Also

Essentials