When to stream assets and when not to

The default length that an asset is set to streaming is 10 seconds. I have a lot of looping sounds that are around that length. Meaning that I have certain sounds (like looping hums on enemies) whose variations are 8-10 seconds and 10-12 seconds. By default this results in variations of the same sound having different loading settings. I’m wondering if this is an issue and how I should determine whether these sounds should be streamed or not.

My music files (which are much longer) are all being streamed, but I’m not sure that I’m doing the right thing by having these 8-12 second sounds streamed too.

Whether an asset should be set to stream is a question of resource availability and allocation.

Each currently-playing streaming asset requires constant file I/O (which is to say, access to the disk) and a very small amount of memory; whereas assets with other loading modes require much more memory but only require file I/O when they’re first loaded, and only require these resources once, no matter how many instances of the asset are playing.

File I/O is a very limited resource on most platforms, and is used for many things other than audio. Fortunately, most games load much of their content into memory up-front at the start of new levels and areas, and many users do not run applications that access the disk in the background. This means that there are usually periods when the player’s device is not otherwise loading content from disk, meaning that streaming assets that play in those periods can enjoy uncontested and uninterrupted file I/O. By contrast, a streaming asset that plays while the disk is being accessed regularly by anything else may not be able to access to disk frequently enough to refresh its ring buffer, and so may suffer from buffer starvation. Buffer starvation of a streaming asset manifests as the sound stuttering or stopping entirely.

The streaming loading mode is therefore best used for assets that meet the following conditions:

  • The asset would take up an awkwardly-large amount of memory if fully loaded.
  • Few instances of the asset ever need to be playing at the same time.
  • Few or no other streaming assets ever need to be playing at the same time as the asset.
  • The asset only plays at times when the game does not need to read or write much to the disk on which the asset’s bank is stored.

The first point is why assets longer than ten seconds are set to stream by default, but the other points are all dependent on details of your game’s design that FMOD Studio has no way of knowing about. If you know that a given asset does not meet those criteria, you should set it to not stream.

For example, you’ve mentioned that you have many looping sounds that are likely to play in parallel. Playing a large number of streams (or a large number of instances of the same stream) at the same time is a bad idea, since every concurrently-playing instance of a streaming asset requires constant file I/O for as long as it plays, and forcing a large number of assets to fight for disk access can easily result in one or more of them suffering from buffer starvation.

Music assets, by contrast, are a good choice of asset to make streaming, as such assets tend to be large, and it’s rarely necessary to play more than one or two music assets at a time.

Joseph thank you so much for this detailed answer. That’s cleared things up massively for me!

And would I be correct in thinking that if I have 5 intensities of one music track playing at one time (so mainly hearing one at any time, and max 2 at a time when crossfading between intensities) the muted voices will automatically be virtualized and therefore not requiring any disk I/O?

Yes, you are correct in assuming that. Virtual streams do not require any disk I/O.

I should mention, however, that the need to buffer streams before they can start playing means that they may experience a small yet variable amount of latency when they begin (or when they become non-virtual after being virtualized). This may result in a streaming asset being slightly out of sync with other assets playing at the same time. This usually is irrelevant and unnoticeable when dealing with assets other than music; with music assets, however, there is a chance that the new music track’s percussion could be noticeably out of sync with those of the old track, or in audible phasing. I therefore recommend testing your music thoroughly to check that these issues do not occur or are not noticeable.

Hello all,

I always thought streaming assets worked different way. I thought asset with ‘streaming’ flag would be fully loaded in memory when requested and after the event stops, it would be unloaded. So disk IO is only busy when loading audio data + metadata.

I made some tests which show it’s actually like this and it makes sense - I’m using streaming assets quite a lot and I’m able to hold memory consumption really low even on huge projects. If all those sounds were streaming disk in realtime, it would be a problem for us.

Can someone confirm this?

You are incorrect. As I mentioned above, each stream requires constant disk I/O while it is playing. This is the defining feature of the streaming loading mode.

If you want asset sampledata into memory before playing an event and then unload it afterward, you should instead use the “compressed” or “decompressed” loading mode.

The result of your tests is consistent with how streaming assets work: A streaming asset uses a very small amount of memory, because only a small part of each asset is kept loaded into memory at any given time. This is possible because each stream requires only enough memory to maintain a small ring buffer. Assets are continuously loaded piecemeal from disk into this buffer while the asset is playing, in order to ensure that only a few moments’ worth of sample data are loaded at any given time - and so each playing stream requires constant disk I/O.

You should try playing multiple instances of the same event with streaming assets. If you do, you’ll see that memory consumption scales linearly with the number of event instances, since each streaming asset requires a separate buffer.

By contrast, if you use the “compressed” or “decompressed” loading mode, you’ll see that there’s a significant memory coast associated with the first event instance, but that subsequent instances only consume a tiny amount of memory. This is because loading the whole asset into memory means that multiple different event instances can reference it without needing to have their own individual copies of it.

I can. I’m an employee at Firelight Technologies, and I’ve been helping develop FMOD for over a decade.

In any case, all of the information I’ve mentioned is available in the FMOD Studio User Manual.

2 Likes

Thanks for your answer, Joseph.

I’m aware of different loading modes (in build setting) and if I’d choose streaming, all assets are handled accordingly.

I created blank project with loading mode “compressed” but I marked one asset as “streamed”. In profiler, it works just as you described:


At 0:07 I play event with streamed asset and I can see it really reads from the disk at only slightest memory costs.

But then look at this - I connected to our game via live update and at 0:39 I played event which includes 8 minutes of noise asset marked as streamed. At 0:53 I stopped it and it looks like FMOD allocates memory for the whole asset (1) and then it drops it (2).

Well now I wonder what’s happening. One thing which comes to my mind is that one of our programmers wrote his FMOD implementation for CryEngine from scratch. Is it perhaps possible that his implementation handles streaming assets differently or it is just not possible as it is only handled by FMOD itself?

It is possible that your game’s code specifies FMOD_STUDIO_LOAD_BANK_DECOMPRESS_SAMPLES when loading the bank.

What size are you setting the stream to be with System::setStreamBufferSize? The default is 16384 rawbytes (meaning 32768 actual bytes, as the FMOD Engine aollocates a double buffer), but it’s possible that your game’s code is setting it to a higher value.

Your programmers could also potentially change how streaming assets work in a wide variety of other ways, provided you have a license that allows access to our source code, but it’s hard to imagine why they would do so.

I suppose it may be one of those incidents where a bug became a feature:) Thanks a lot for your answer, I’ll try to reach him and ask him about it, now knowing what we should look for.