Wwise SDK 2024.1.0
|
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 RenderAudio
.
Setting AkInitSettings::bUseLEngineThread
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 AK::SoundEngine::LoadBank and AK::SoundEngine::UnloadBank API calls must not be made from the same thread as the caller of RenderAudio . This is because these calls may block until an audio buffer is rendered to complete Stop operations and free SoundBank media, which won't happen without a concurrent call to RenderAudio . |
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 AkInitSettings::bUseLEngineThread
to false
.
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 AkJobType_AudioProcessing , and then called again to request two workers of type AkJobType_Generic , then the Sound Engine will expect the game to call the worker function three times with AkJobType_AudioProcessing , and two times with AkJobType_Generic . The calls may be issued in any order, sequentially or concurrently from different threads. |
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::InitForThread
and AK::MemoryMgr::TermForThread
when 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::TrimForThread
when 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.
It is not recommended for Android platform to use more than 2 active worker threads for Job Manager, set with AK::SoundEngine::SetJobMgrMaxActiveWorkers
. A high number of worker threads on Android devices can lead to higher CPU usage with decreased overall sound engine performance.
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 AkInitSettings::settingsJobManager
.
Note: If AK::MemoryMgr::Malloc fails to allocate a new memory slab during rendering, the Job Manager will keep re-trying the allocation until it succeeds. If you observe the Sound Engine hang during low-memory situations, increase the number of pre-allocated slabs in the initialization settings. |
Questions? Problems? Need more info? Contact us, and we can help!
Visit our Support pageRegister your project and we'll help you get started with no strings attached!
Get started with Wwise