| AAX SDK 2.8.0 Avid Audio Extensions Development Kit

- Welcome
- Manual
- Classes
- Files
- Lists
- Support

Loading...
Searching...
No Matches
Real-time performance
AAX SDK Manual » Additional Topics

Guidelines for avoiding audio streaming errors.

This page provides an overview of best practices for avoiding streaming errors and achieving good performance for audio processing on real-time threads.

These recommendations are based on observations we have made when reviewing common Pro Tools streaming errors, especially those caused by plug-ins, as well as on information we have gathered from a number of partners and other experts in the field.

See also
  Plug-In Causes Audio Streaming Errors

# Things NOT To Do In An Audio Plug-In Render Callback

- No unbounded calls/loops
- No access to paged memory or files
- No system calls
- No memory allocations or deallocations
- No exceptions
- No locks (priority inversions)
- No data races
- Avoid context switches
- No Objective-C or Swift code. These can incur system calls and take locks - see this article for more information.
- Do not use the JUCE callAsync() function - it is not real-time safe. As an alternative, you can use a separate dedicated thread that wakes on a timer or the AAX TimerWakeup() method to handle non-real time work.
- Never perform PACE license checks in audio processing thread; always add code annotations to prevent license checks in any code which will be executed from the audio processing callback.

# Things To Do In An Audio Plug-In Render Callback

- If passing data, always use lock-free FIFOs
  - When making data from other parts of the plug-in available to its real-time callback you should always use the AAX packet system; this will ensure thread safety, proper timing of the data delivery with respect to the audio being processed, and optimal real-time thread performance.
  - There is a nice reference implementation for a general-purpose FIFO in the farbot project
  - Lock-free FIFOs are also good for passing data from the real-time thread to a low-priority thread in order to do heavy lifting like writes to disk
- If sharing small amounts of data (<= 8 bytes), use atomics
  - Make a local copy/cache of any atomic values that need to be read multiple times from your render function
  - When using atomics, always make the compiler prove that its implementation is lock-free e.g. using a static_assert that std::atomic<T>::is_always_lock_free
- When sharing larger data, if it is acceptable if the data sometimes cannot be accessed, use a try_lock() in the real-time thread and a lock() in any non-real-time threads.
  - When using this strategy you should use a spin lock, not a std::mutex; std::mutex::unlock() can block in a system call to wake the waiting thread
- When sharing larger data, if it is acceptable to access a stale copy of the data, then use a compare-and-exchange loop
  - Be careful about memory leaks with this strategy
  - See the NonRealtimeMutable template in the farbot project

# Good Resources And Examples

- Real-time audio programming 101: time waits for nothing by Ross Bencina
- Four common mistakes in audio development by Michael Tyson
- farbot: FAbian's Realtime Box o' Tricks project on GitHub

Collaboration diagram for Real-time performance: