Wwise SDK 2022.1.8
By default, the Wwise Sound Engine does all its command processing and audio rendering in a dedicated thread named
AK::EventManager, controlled by the AkPlatformInitSettings::threadLEngine parameters. Calling
AK::SoundEngine::RenderAudio signals the end of a game frame and allows the thread to consume all API commands received since the previous call to
false disables this thread and causes
RenderAudio to run synchronously: processing commands and, if needed, rendering audio. The actual rate of audio output remains controlled by the audio endpoint. If the
RenderAudio call interval is shorter than the buffer period determined by
AkInitSettings::uNumSamplesPerFrame and the output sample rate, some calls to
RenderAudio will skip the audio rendering portion. Conversely, if the
RenderAudio call interval is longer than the output buffer period,
RenderAudio may process more than one buffer at a time, causing a CPU usage spike, and may eventually cause the audio to stutter.
Enabling offline rendering disables asynchronous command processing and audio rendering from the audio thread. The amount of audio rendered per call to
RenderAudio is determined by a positive non-zero value sent to
AK::SoundEngine::SetOfflineRenderingFrameTime. A zero or negative value will force
RenderAudio to process precisely one audio buffer.
Caution: With the audio rendering thread disabled or with offline rendering enabled, synchronous
On Microsoft platforms, due to the use of a single-threaded apartment (STA) concurrency model,
CoInitializeEx() must be called from the same thread that calls
AK::SoundEngine::RenderAudio when setting
Certain AK::SoundEngine::Query functions can cause CPU spikes. To minimize wasted CPU time and ensure optimal performance, we recommend that you follow these guidelines:
By default, the Wwise Sound Engine executes its various audio rendering tasks, or "jobs", on the audio rendering thread in a sequential fashion. These jobs include, but are not limited to, bus and voice processing tasks.
Concurrent execution of these audio jobs can be enabled by specifying a callback that allows the Wwise Sound Engine to request CPU time on game-managed threads. When the game provides an implementation for this callback via
AkJobMgrSettings::fnRequestJobWorker, concurrent execution is enabled in the Wwise Sound Engine.
|Note: When enabling concurrent job execution, some AK::SoundEngine callbacks will be generated from concurrent job worker threads. Additionally, some plug-ins may not be compatible with concurrent job execution.|
To understand how the Sound Engine's Job Manager works, it is important to learn the difference between two important callbacks:
Note: The Wwise Sound Engine expects exactly one call to the worker function for each worker request. For example, if the worker request function is called once to request three workers of type
When the worker request function is defined, the audio rendering thread will behave as follows:
This process can repeat multiple times throughout one audio rendering pass, and the audio rendering thread will attempt to pipeline work as much as possible. For example, when rendering the bus graph, processing time for a given bus will be requested as soon as all inputs have finished processing, and may run independently of other busses. In this way, the Job Manager will always attempt to maximize throughput.
|Note: The worker request function can be called from any thread executing Sound Engine code, and must be implemented in a thread-safe manner.|
The Wwise Sound Engine's Job Manager is designed to work in tandem with existing job schedulers to achieve co-operative multi-tasking. Game engines that already have a job scheduler should implement the worker request function in a way that schedules the execution of the worker function within their existing job system.
When calling the worker function, the game engine's job scheduler can specify a timeout in microseconds. This is to prevent the Sound Engine from taking too much CPU time on the calling thread. Past this timeout, the worker function will stop and request an additional worker if more jobs were available for execution. This allows the execution of other, possibly higher-priority game engine work on this thread.
|Note: Care must be taken when delaying the execution of the worker function or limiting the execution time of Sound Engine work, as this can lead to voice starvation. When integrating Sound Engine jobs into an existing job scheduler, it is recommended to treat audio rendering jobs as high-priority work.|
For game engines that don't already have a job scheduler, a sample implementation of such a scheduler is provided in the SDK samples under
SDK/samples/SoundEngine/Common/AkJobWorkerMgr.[h,cpp]. This sample provides a great starting point for concurrent execution of audio rendering jobs. Additionally, IntegrationDemo provides code demonstrating how this sample implementation can be integrated in an actual end-user application.
Here are a few recommendations on how best to utilize the Job Manager.
AK::MemoryMgr::TermForThreadwhen initializing and terminating the threads, in order to ensure proper initialization and termination of thread-local memory resources. It is also recommended to call
AK::MemoryMgr::TrimForThreadwhen entering a period of inactivity after running the worker function, in order to free up any thread-local memory resources which may not be utilized again in the near future.
AK::SoundEngine::SetJobMgrMaxActiveWorkers. This can be useful to dynamically respond to changes in your title's operating conditions, or to more easily experiment and profile different configurations for multi-threaded work.
The recommendations above must be weighed against the other needs of the game. The Job Manager remains a good way to increase overall throughput of the Sound Engine even if some of these recommendations are not followed.
Running out of memory when allocating a job is considered a critical failure, as the logical flow of audio rendering would be interrupted and unable to resume. This would lead to undefined results and leaks of resources.
To prevent this, the Job Manager allocates slabs of memory that will be kept around and re-used until the Sound Engine is terminated. Most of these slabs are pre-allocated during Sound Engine initialization, but others may be allocated as needed.
You can control the size of the memory slabs, as well as how many are pre-allocated at initialization time, via