/*===================================================================================================
AAX_RealTimePerformance.doxygen

Copyright 2020, 2023-2024 Avid Technology, Inc.
All rights reserved.

This file is part of the Avid AAX SDK.

The AAX SDK is subject to commercial or open-source licensing.

By using the AAX SDK, you agree to the terms of both the Avid AAX SDK License
Agreement and Avid Privacy Policy.

AAX SDK License: https://developer.avid.com/aax
Privacy Policy: https://www.avid.com/legal/privacy-policy-statement

Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).

THE AAX SDK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.

===================================================================================================*/

/** @defgroup advancedTopics_RealTimePerformance Real-time performance
	@ingroup AdvancedTopics

	@brief 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.

	\sa \ref troubleshooting_performance

<DIV CLASS="section">
	\section advancedTopics_RealTimePerformance_ThingsNotToDo Things NOT To Do In An Audio Plug-In Render Callback

	\li No unbounded calls/loops
	\li No access to paged memory or files
	\li No system calls
	\li No memory allocations or deallocations
	\li No exceptions
	\li No locks (priority inversions)
	\li No data races
	\li Avoid context switches
	\li No Objective-C or Swift code. These can incur system calls and take locks - see this article for more information.
	\li 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.
	\li 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.

</DIV>

<DIV CLASS="section">
	\section advancedTopics_RealTimePerformance_ThingsToDo Things To Do In An Audio Plug-In Render Callback

	<UL>
		<LI CLASS="Bullet">
			If passing data, always use lock-free FIFOs
			<UL>
				<LI CLASS="Bullet">
					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.
				</LI>
				<LI CLASS="Bullet">
					There is a nice reference implementation for a general-purpose FIFO in the <a href="https://github.com/hogliux/farbot" target="_blank">farbot</a> project
				</LI>
				<LI CLASS="Bullet">
					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
				</LI>
			</UL>
		</LI>
		<LI CLASS="Bullet">
			If sharing small amounts of data (<= 8 bytes), use atomics
			<UL>
				<LI CLASS="Bullet">
					Make a local copy/cache of any atomic values that need to be read multiple times from your render function
				</LI>
				<LI CLASS="Bullet">
					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
				</LI>
			</UL>
		</LI>
		<LI CLASS="Bullet">
			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.
			<UL>
				<LI CLASS="Bullet">
					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
				</LI>
			</UL>
		</LI>
		<LI CLASS="Bullet">
			When sharing larger data, if it is acceptable to access a stale copy of the data, then use a compare-and-exchange loop
			<UL>
				<LI CLASS="Bullet">
					Be careful about memory leaks with this strategy
				</LI>
				<LI CLASS="Bullet">
					See the NonRealtimeMutable template in the <a href="https://github.com/hogliux/farbot" target="_blank">farbot</a> project
				</LI>
			</UL>
		</LI>
	</UL>

</DIV>

<DIV CLASS="section">
	\section advancedTopics_RealTimePerformance_GoodResources Good Resources And Examples

	\li <a href="http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing" target="_blank">Real-time audio programming 101: time waits for nothing</a> by Ross Bencina
	\li <a href="https://atastypixel.com/blog/four-common-mistakes-in-audio-development/" target="_blank">Four common mistakes in audio development</a> by Michael Tyson
	\li <a href="https://github.com/hogliux/farbot" target="_blank">farbot: FAbian's Realtime Box o' Tricks</a> project on GitHub

</DIV>

*/
