Table of Contents

Wwise SDK 2019.2.3
Audiokinetic Stream Manager Initialization Settings

Default Streaming Manager Information

This chapter is specific to the default implementation of the high-level Stream Manager's API.

The initialization settings of the Stream Manager and the AK::StreamMgr::Create() method are specific to Audiokinetic's implementation, and are defined in AkStreamMgrModule.h.

Here is a description of the initialization settings of the default implementation of the Stream Manager. You will certainly have to tweak these settings for your game at some point in order to make best use of I/O and memory resources.

Stream Manager Settings

The AkStreamMgrSettings structure defines the settings needed for the entire Stream Manager. Default values indicated in each subsection are the values returned by AK::StreamMgr::GetDefaultSettings(). These default values may not be adequate for your system. The information contained in I/O Tips, Troubleshooting and Optimization may help you choose optimal values.

Streaming Devices Settings

The AkDeviceSettings structure defines the settings needed for each device, created with AK::CreateDevice(). Default values indicated in each subsection are the values returned by AK::StreamMgr::GetDefaultDeviceSettings(). These default values may not be adequate for your system.

I/O Memory Size

AkDeviceSettings::uIOMemorySize is the total size of the memory reserved for a device’s automatic streaming. The device creates a special memory pool, to which automatic stream I/O data is written. If you don’t plan to use any automatic streams, specify zero. Note, however, that the sound engine uses automatic streams to play streamed audio files. AkDeviceSettings::pIOMemory, AkDeviceSettings::uIOMemoryAlignment and AkDeviceSettings::ePoolAttributes are additional parameters that are passed directly to the pool creation method, AK::MemoryMgr::CreatePool().

Defaults:

Granularity

Granularity is specified by AkDeviceSettings::uGranularity. It defines the standard request size sent to the Low-Level I/O, whether it is sent from a standard stream (sliced operation) or an automatic stream (size of a single stream buffer). Automatic streams use a variable number of buffers, depending on the memory available. The total number of buffers available for automatic streaming is equal to
AkDeviceSettings::uIOMemorySize / AkDeviceSettings::uGranularity.

Tip: To avoid starvation because of memory, streams should be at least double-buffered. Therefore, the I/O memory size should be set to at least
2 * uGranularity * nominal_number_of_streams
Note that the actual number of buffers required per stream is dynamic and depends on stream heuristics and the devices target buffer length (see AkDeviceSettings::fTargetAutoStmBufferLength). The proper way to determine the I/O memory size that is required for your needs is to compute the sum of the throughput required by all your streams in your worst case scenario and multiply it by fTargetAutoStmBufferLength. In practice, it is easier to start with a large value, profile your game with the Wwise profiler, and use the peak value reported for I/O usage in the Streaming Devices tab.

Default: 16 KB

Scheduler Type

The type of streaming device scheduler depends on AkDeviceSettings::uSchedulerTypeFlags. It determines the handshaking mode with the Low-Level I/O. Streaming devices created with AK_SCHEDULER_BLOCKING flag work with AK::StreamMgr::IAkIOHookBlocking, using synchronous handshaking. Streaming devices created with the AK_SCHEDULER_DEFERRED_LINED_UP flag work with AK::StreamMgr::IAkIOHookDeferredBatch, using asynchronous handshaking. Refer to High-Level Devices Specificity for a discussion on high-level device schedulers.

Caution: Using a deferred I/O hook with an AK_SCHEDULER_BLOCKING device and vice-versa results in a run-time crash.

Default: AK_SCHEDULER_BLOCKING

I/O Thread Properties

All high-level devices use a separate thread to post transfer requests to the Low-Level I/O called "AK::IOThread". You can specify properties for this thread by using AkDeviceSettings::threadProperties. AkThreadProperties is defined for each platform in SDK/include/AK/Tools/{Platform name}/AkPlatformFuncs.h. This method typically specifies thread priority and processor.

Tip: The I/O scheduler thread should have a priority above normal because it does not use much of the CPU: it spends most of its time waiting for streams to service, or waiting for the disk controller. However, when it needs to choose a task and post it to the Low-Level I/O, it should be able to do so quickly to maximize the storage device throughput.

Default: Default platform-specific thread properties (as returned by AKPLATFORM::AkGetDefaultThreadProperties()), with a priority equal to AK_THREAD_PRIORITY_ABOVE_NORMAL (defined in AkPlatformFuncs.h).

Target Buffering Length

AkDeviceSettings::fTargetAutoStmBufferLength is a heuristic for a device’s I/O scheduler. It applies to automatic streams only. It specifies the ideal buffering time that should be reached, per stream, in milliseconds. The Stream Manager performs I/O for a given stream until that buffering length is met. The time value translates into buffer size using the stream’s throughput heuristic. For example, a 16-bit stereo sound sampled at 44.1 kHz requires a throughput of 172.3 KB/s. If the target buffer length is set to 380 ms, the target buffer size for this stream will be about 64 KB. With more buffering, streams are less likely to starve. On the other hand, the I/O scheduler will be busier and use more CPU, and a larger amount of memory in the streaming I/O pool. The optimal value depends mainly on the low-level storage device bandwidth and the amount of memory available for streaming. Fast devices should use a smaller buffering length, whereas slower devices, or devices whose throughput has a large standard deviation (due to seeking, for example) should use a larger value. When all automatic streams reach their target buffering length, and there is no pending standard streaming operation, the I/O scheduler becomes idle.

Tip: The ideal target buffering length is proportional to the time at which your low-level device transfers data. Try to specify the lowest value possible without having source starvation notifications appear in the Wwise Profiler, under reasonable conditions, with a sufficiently large I/O memory size. Once this is done, you may reduce the I/O memory size to the peak usage value.

Default: 380 ms.

Maximum Number of Concurrent I/O Transfers

AkDeviceSettings::uMaxConcurrentIO concerns asynchronous low-level devices only (AK_SCHEDULER_DEFERRED_LINED_UP scheduler flag). It is the maximum amount of low-level I/O transfers that the streaming device may post concurrently to the low-level I/O at any given time. When the limit is reached, the I/O thread will stop posting requests to the low-level I/O even if there are streams buffered below their target. You may use this value to safely allocate static arrays of structures that you need to track each pending transfer.

Tip: If you specify 1, you get the same behavior as with a synchronous device (AK_SCHEDULER_BLOCKING scheduler flag), with asynchronous handshaking instead. This can be useful if your I/O manager only exposes an asynchronous API.

You may be tempted to use a large value for this parameter, but there are downsides to this. The streaming device's scheduler posts low-level requests according to the state of each stream at the time it inspects them. If you let it send a lot of requests, and let them remain in the low-level I/O for a long time, the situation is more likely to change in the meantime. For example, streaming sounds may stop, or stop looping. In such cases, these transfers are cancelled and I/O data is flushed upon reception. This may result in a lot of wasted bandwidth.

Large amounts of concurrent requests should only be used with devices whose throughput is not linear with the amount of requests. For example, some DMA controllers can be programmed to process many transfers, but the moment when they complete is mostly independent of the amount of transfers that were programmed.

Default: 8 (ignored by AK_SCHEDULER_BLOCKING schedulers).

Use Stream Cache

AkDeviceSettings::bUseStreamCache determines whether data caching is enabled or not.

Streaming devices support data caching into their streaming pool. When an I/O operation is executed for a memory block, file metadata is attached to it. If the same stream or another instance of the same stream requires a block of data corresponding to the same file at more or less the same position, this block of data will be used directly, thus avoiding a transfer from the low-level I/O.

You must know that critical data structures are preallocated (from the Stream Manager memory pool) when devices are created. Running out of memory at run-time would result in the I/O thread spinning over nothing with a high priority, having disastrous consequences on the game's performances.

With stream data caching, there may be more than one reference for a given memory block. References to memory blocks are an example of such preallocated critical data structures.

By calling AK::SoundEngine::PinEventInStreamCache(), the user can request that certain events have their media "pinned" into stream cache, so that it is ready and can be played with zero latency when needed. If the data is not already in cache when AK::SoundEngine::PinEventInStreamCache() is called, then the data will be streamed in with a low priority automatic stream. The length, in milliseconds, of each media file that is pinned can be customized using the prefetch slider in the Wwise authoring tool. The data will stay in memory until the user releases the media by calling AK::SoundEngine::UnpinEventInStreamCache().

AkDeviceSettings::bUseStreamCache specifies if the device should attempt to reuse IO buffers that have already been streamed from disk. This is particularly useful when streaming small looping sounds. The drawback is a small CPU hit when allocating memory, and a slightly larger memory footprint in the StreamManager pool.

Default: false (caching disabled).