Show / Hide Table of Contents

Class NativeAudio

The most important class, contains static methods that are used to command the native side.

Inheritance
System.Object
NativeAudio
Namespace: E7.Native
Assembly: E7.NativeAudio.dll
Syntax
public static class NativeAudio

Properties

Initialized

Returns true after calling Initialize() successfully, meaning that we have a certain amount of native sources ready for use at native side.

It is able to turn back to false if you call Dispose() to return native sources back to the OS.

Declaration
public static bool Initialized { get; }
Property Value
Type Description
System.Boolean

OnSupportedPlatform

  • If in Editor, it is instantly unsupported (false) no matter what build platform selected.
  • If not in Editor, it is true only on Android and iOS.
Declaration
public static bool OnSupportedPlatform { get; }
Property Value
Type Description
System.Boolean

Methods

Dispose()

[Android] Undo the Initialize(). It doesn't affect any loaded audio, just dispose all the native sources returning them to OS and make them available for other applications.

You still have to unload each audio. Disposing twice is safe, it does nothing.

[iOS] Disposing doesn't work.

[Editor] This is a no-op. It is safe to call and nothing will happen.

Declaration
public static void Dispose()

GetDeviceAudioInformation()

Ask the phone about its audio capabilities.

The returned struct has different properties depending on platform. You should put preprocessor directive (#if UNITY_ANDROID and so on) over the returned object if you are going to access any of its fields. Or else it would be an error if you switch your build platform.

[Editor] Does not work, returns default value of DeviceAudioInformation.

Declaration
public static DeviceAudioInformation GetDeviceAudioInformation()
Returns
Type Description
DeviceAudioInformation

GetNativeSource(Int32)

Get a native source in order to play an audio or control an audio currently played on it. You can keep and cache the returned native source reference and keep using it.

This method is for when you want a specific index of native source you would like to play on.

Declaration
public static NativeSource GetNativeSource(int nativeSourceIndex)
Parameters
Type Name Description
System.Int32 nativeSourceIndex

Specify a zero-indexed native source that you want. If at Initialize() you requested 3, then valid numbers here are : 0, 1, and 2.

If this index turns out to be an invalid index at native side, it has a fallback to round-robin native source selection.

Returns
Type Description
NativeSource

Native source representation you can use it to play audio.

If nativeSourceIndex used was invalid, then this is a result of fallback round-robin native source selection.

Remarks

It checks with the native side if a specified nativeSourceIndex is valid or not before returning a native source interfacing object to you. If not, it has a fallback to round-robin native source selection.

Refer to Selecting native sources on how to strategize your native source index usage depending on your audio.

GetNativeSourceAuto()

Get a native source in order to play an audio or control an audio currently played on it. You can keep and cache the returned native source reference and keep using it.

Unlike GetNativeSource(Int32), this method is for when you just want to play an audio without much care about stopping a previously played audio on any available native source.

It selects a native source by round-robin algorithm, just select the next index from the previous play.

Declaration
public static NativeSource GetNativeSourceAuto()
Returns
Type Description
NativeSource

Native source representation you can use it to play audio resulting from round-robin selection.

Remarks

Refer to Selecting native sources on how to strategize your native source index usage depending on your audio.

GetNativeSourceAuto(INativeSourceSelector)

Get a native source in order to play an audio or control an audio currently played on it. You can keep and cache the returned native source reference and keep using it.

Like GetNativeSource(Int32), this method is for when you want a specific index of native source to play. But unlike that, you can create your own "index returning object" that implements INativeSourceSelector. Making it more systematic for you.

Declaration
public static NativeSource GetNativeSourceAuto(INativeSourceSelector nativeSourceSelector)
Parameters
Type Name Description
INativeSourceSelector nativeSourceSelector
Returns
Type Description
NativeSource

Native source representation you can use it to play audio, resulting from an index that Native Audio got from calling NextNativeSourceIndex() on nativeSourceSelector.

Remarks

You can have internal state inside it if it is a class, you can emulate the default round-robin native source selection, for example.

Refer to Selecting native sources on how to strategize your native source index usage depending on your audio.

GetNativeSourceCount()

Get number of usable native sources. Returns 0 if called before initialization.

[Android] It returns as many as you actually got from initialization. (e.g. if you requested 999 and actually get 15, then this returns 15)

[iOS] It is currently fixed to 15 as that is how OpenAL works. It gives you a set amount of sources.

Declaration
public static int GetNativeSourceCount()
Returns
Type Description
System.Int32
Remarks

This is useful in a case like you want to completely stop all audio played with Native Audio before unloading audio to prevent crash where the play head now play unloaded memory.

Therefore you need to get all native sources and stop each one. With this count you could do so in a for loop.

Initialize()

[iOS] Initializes OpenAL. 15 OpenAL native sources will be allocated all at once. It is not possible to initialize again on iOS. (Nothing will happen)

[Android] Initializes OpenSL ES. 1 OpenSL ES "Engine" and a number of native sources AudioPlayer object (and in turn native AudioTrack) will be allocated all at once.

See Initialize(NativeAudio.InitializationOptions) overload how to customize your initialization.

Declaration
public static void Initialize()
Remarks
  • More about this limit : https://developer.android.com/ndk/guides/audio/opensl/opensl-for-android
  • And my own research here : https://gametorrahod.com/android-native-audio-primer-for-unity-developers/

Initialize(NativeAudio.InitializationOptions)

[iOS] Initializes OpenAL. 15 OpenAL native sources will be allocated all at once. It is not possible to initialize again on iOS. (Nothing will happen)

[Android] Initializes OpenSL ES. 1 OpenSL ES "Engine" and a number of native sources AudioPlayer object (and in turn native AudioTrack) will be allocated all at once.

See Initialize(NativeAudio.InitializationOptions) overload how to customize your initialization.

Declaration
public static void Initialize(NativeAudio.InitializationOptions initializationOptions)
Parameters
Type Name Description
NativeAudio.InitializationOptions initializationOptions

Customize your initialization. Start making it from defaultOptions

Remarks
  • More about this limit : https://developer.android.com/ndk/guides/audio/opensl/opensl-for-android
  • And my own research here : https://gametorrahod.com/android-native-audio-primer-for-unity-developers/
Exceptions
Type Condition
System.NotSupportedException

Thrown when you initialize in Editor or something other than iOS or Android at runtime.

Load(String)

(ADVANCED) Loads an audio from StreamingAssets folder's destination at runtime. Most of the cases you should use the Load(AudioClip) overload instead.

It only supports .wav PCM 16-bit format, stereo or mono, in any sampling rate since it will be resampled to fit the device.

Declaration
public static NativeAudioPointer Load(string streamingAssetsRelativePath)
Parameters
Type Name Description
System.String streamingAssetsRelativePath

If the file is SteamingAssets/Hit.wav use "Hit.wav" (WITH the extension).

Returns
Type Description
NativeAudioPointer

An audio buffer pointer for use with Play(NativeAudioPointer). Get the source from GetNativeSource(Int32)

Exceptions
Type Condition
System.IO.FileLoadException

Thrown when some unexpected exception at native side loading occurs.

Load(String, NativeAudio.LoadOptions)

(ADVANCED) Loads an audio from StreamingAssets folder's destination at runtime. Most of the cases you should use the Load(AudioClip) overload instead.

It only supports .wav PCM 16-bit format, stereo or mono, in any sampling rate since it will be resampled to fit the device.

Declaration
public static NativeAudioPointer Load(string streamingAssetsRelativePath, NativeAudio.LoadOptions loadOptions)
Parameters
Type Name Description
System.String streamingAssetsRelativePath

If the file is SteamingAssets/Hit.wav use "Hit.wav" (WITH the extension).

NativeAudio.LoadOptions loadOptions

Customize your load. Start creating your option from defaultOptions.

Returns
Type Description
NativeAudioPointer

An audio buffer pointer for use with Play(NativeAudioPointer). Get the source from GetNativeSource(Int32)

Exceptions
Type Condition
System.IO.FileLoadException

Thrown when some unexpected exception at native side loading occurs.

Load(AudioClip)

Loads by copying Unity-imported UnityEngine.AudioClip's raw audio memory to native side. You are free to unload the UnityEngine.AudioClip's audio data without affecting what's loaded at the native side after this.

[Editor] This method is a stub and returns null.

Declaration
public static NativeAudioPointer Load(AudioClip audioClip)
Parameters
Type Name Description
UnityEngine.AudioClip audioClip

Hard requirements :

  • Load type MUST be Decompress On Load so Native Audio could read raw PCM byte array from your compressed audio.
  • If you use Load In Background, you must call UnityEngine.AudioClip.LoadAudioData beforehand and ensure that UnityEngine.AudioClip.loadState is UnityEngine.AudioDataLoadState.Loaded before calling Load(AudioClip). Otherwise it would throw an exception. If you are not using UnityEngine.AudioClip.loadInBackground but also not using UnityEngine.AudioClip.preloadAudioData, Native Audio can load for you if not yet loaded.
  • Must not be UnityEngine.AudioClip.ambisonic.
Returns
Type Description
NativeAudioPointer

An audio buffer pointer for use with Play(NativeAudioPointer). Get the source from GetNativeSource(Int32)

Remarks

If you did not Initialize() yet, it will initialize with no NativeAudio.InitializationOptions. You cannot load audio while uninitialized.

Hard requirements :

  • Load type MUST be Decompress On Load so Native Audio could read raw PCM byte array from your compressed audio.
  • If you use Load In Background, you must call UnityEngine.AudioClip.LoadAudioData beforehand and ensure that UnityEngine.AudioClip.loadState is UnityEngine.AudioDataLoadState.Loaded before calling Load(AudioClip). Otherwise it would throw an exception. If you are not using UnityEngine.AudioClip.loadInBackground but also not using UnityEngine.AudioClip.preloadAudioData, Native Audio can load for you if not yet loaded.

It supports all compression format, force to mono, overriding to any sample rate, and quality slider.

[iOS] Loads an audio into OpenAL's output audio buffer. (Max 256) This buffer will be paired to one of 15 OpenAL source when you play it.

[Android] Loads an audio into a short* array at unmanaged native side. This array will be pushed into one of available SLAndroidSimpleBufferQueue when you play it.

The resampling of audio will occur at this moment to match your player's device native rate.

The SLES audio player must be created to match the device rate to enable the special "fast path" audio. What's left is to make our audio compatible with that fast path player, which the resampler will take care of.

You can change the sampling quality of SRC (libsamplerate) library on a per-audio basis with the Load(AudioClip, NativeAudio.LoadOptions) overload.

Exceptions
Type Condition
System.Exception

Thrown when some unexpected exception at native side loading occurs.

System.NotSupportedException

Thrown when you have prohibited settings on your UnityEngine.AudioClip.

System.InvalidOperationException

Thrown when you didn't manually load your UnityEngine.AudioClip when it is not set to load in background.

Load(AudioClip, NativeAudio.LoadOptions)

Loads by copying Unity-imported UnityEngine.AudioClip's raw audio memory to native side. You are free to unload the UnityEngine.AudioClip's audio data without affecting what's loaded at the native side after this.

[Editor] This method is a stub and returns null.

Declaration
public static NativeAudioPointer Load(AudioClip audioClip, NativeAudio.LoadOptions loadOptions)
Parameters
Type Name Description
UnityEngine.AudioClip audioClip

Hard requirements :

  • Load type MUST be Decompress On Load so Native Audio could read raw PCM byte array from your compressed audio.
  • If you use Load In Background, you must call UnityEngine.AudioClip.LoadAudioData beforehand and ensure that UnityEngine.AudioClip.loadState is UnityEngine.AudioDataLoadState.Loaded before calling Load(AudioClip, NativeAudio.LoadOptions). Otherwise it would throw an exception. If you are not using UnityEngine.AudioClip.loadInBackground but also not using UnityEngine.AudioClip.preloadAudioData, Native Audio can load for you if not yet loaded.
  • Must not be UnityEngine.AudioClip.ambisonic.
NativeAudio.LoadOptions loadOptions

Customize your load. Start creating your option from defaultOptions.

Returns
Type Description
NativeAudioPointer

An audio buffer pointer for use with Play(NativeAudioPointer). Get the source from GetNativeSource(Int32)

Remarks

If you did not Initialize() yet, it will initialize with no NativeAudio.InitializationOptions. You cannot load audio while uninitialized.

Hard requirements :

  • Load type MUST be Decompress On Load so Native Audio could read raw PCM byte array from your compressed audio.
  • If you use Load In Background, you must call UnityEngine.AudioClip.LoadAudioData beforehand and ensure that UnityEngine.AudioClip.loadState is UnityEngine.AudioDataLoadState.Loaded before calling Load(AudioClip). Otherwise it would throw an exception. If you are not using UnityEngine.AudioClip.loadInBackground but also not using UnityEngine.AudioClip.preloadAudioData, Native Audio can load for you if not yet loaded.
  • Must not be UnityEngine.AudioClip.ambisonic.

It supports all compression format, force to mono, overriding to any sample rate, and quality slider.

[iOS] Loads an audio into OpenAL's output audio buffer. (Max 256) This buffer will be paired to one of 15 OpenAL source when you play it.

[Android] Loads an audio into a short* array at unmanaged native side. This array will be pushed into one of available SLAndroidSimpleBufferQueue when you play it.

The resampling of audio will occur at this moment to match your player's device native rate.

The SLES audio player must be created to match the device rate to enable the special "fast path" audio. What's left is to make our audio compatible with that fast path player, which the resampler will take care of.

You can change the sampling quality of SRC (libsamplerate) library on a per-audio basis with the Load(AudioClip, NativeAudio.LoadOptions) overload.

Exceptions
Type Condition
System.Exception

Thrown when some unexpected exception at native side loading occurs.

System.NotSupportedException

Thrown when you have prohibited settings on your UnityEngine.AudioClip.

System.InvalidOperationException

Thrown when you didn't manually load your UnityEngine.AudioClip when it is not set to load in background.

SilentAnalyze()

(EXPERIMENTAL) Native Audio will load a small silent wav and perform various stress test for about 1 second. Your player won't be able to hear anything, but recommended to do it when there's no other workload running because it will also measure FPS.

The test will be asynchronous because it has to wait for frame to play the next audio. Yield wait for the result with the returned NativeAudioAnalyzer. This is a component of a new game object created to run a test coroutine on your scene.

If your game is in a yieldable routine, use yield return new WaitUntil( () => analyzer.Analyzed );, it will wait a frame until that is true. If not, you can do a blocking wait with a while loop on analyzer.Analyzed == false.

You must have initialized Native Audio before doing the analysis or else Native Audio will initialize with default options. (Remember you cannot initialize twice to fix initialization options)

By the analysis result you can see if the frame rate drop while using Native Audio or not. I have fixed most of the frame rate drop problem I found. But if there are more obscure devices that drop frame rate, this method can check it at runtime and by the returned result you can stop using Native Audio and return to Unity UnityEngine.AudioSource.

Declaration
public static NativeAudioAnalyzer SilentAnalyze()
Returns
Type Description
NativeAudioAnalyzer
In This Article
Back to top
A Unity plugin by 5argon from Exceed7 Experiments. Problems/suggestions/contact : 5argon@exceed7.com Discord Unity Forum