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 |
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
|
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 |
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 |
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 :
|
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 :
|
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 |