Playing audio in Spatial SDK apps
Updated: Mar 4, 2026
This document covers playing audio using Android’s or Spatial SDK’s native audio APIs. To learn about best practices that will further enhance your app’s user experience and broaden its audience, see the
design guidelines.
Spatial audio makes sounds appear to come from specific locations in 3D space. When you turn your head, sounds stay in their virtual positions just like in real life. A sound behind you stays behind you, and a sound to your left stays to your left. Spatial SDK provides simple audio playback for background music and UI sounds. It also provides advanced 3D positioned audio for immersive experiences.
Spatial SDK supports specific audio file formats, sample rates, and encoding standards to ensure optimal performance and compatibility across devices.
.wav and .ogg audio files are supported- 3D positioned audio must be mono (single channel)
- Stereo audio is supported for background music and UI sounds
- 48kHz is typically used, but any common multiple of 16kHz should work (for example, 32kHz, 48kHz, 96kHz).
- 44.1kHz audio is not supported at this time.
Signed 16-bit PCM for .wav files is supported.
These format and encoding requirements ensure optimal performance and compatibility across devices. The 48kHz sample rate matches the device’s native audio processing rate, reducing the need for real-time conversion that could impact performance.
Components in Spatial SDK are reusable pieces of functionality that you attach to entities (objects in your 3D scene). The
Audio component makes an entity capable of playing sound from its location in 3D space.
You can add audio components to entities to play spatialized audio for each entity. The file string is parsed by
SceneAudioAsset, as explained below, and the
AudioSystem() plays it.
class Audio(
file: String,
volume: Float = 1.0f,
) : ComponentBase()
Think of SceneAudioAsset as a sound library for your app. Instead of loading the same sound file multiple times (which wastes memory), you load it once into a SceneAudioAsset and then reference it whenever you need to play that sound. This is especially important for sounds you’ll use frequently, like button clicks or notification sounds.
Your scene can have many sounds associated with a single SceneAudioAsset. Use SceneAudioAsset to efficiently reuse audio resources in your application.
public class SceneAudioAsset(filepath: String) {
val canBeSpatialized: Boolean
val duration: Float
}
Here is an example:
val SFX_SELECT = SceneAudioAsset.loadLocalFile("shopping/SFX_Select.wav")
Mono vs. stereo for spatial audio
For 3D positioned audio to work correctly, your audio files must be mono (single channel). Stereo files already contain left/right channel information, which conflicts with the SDK’s ability to position the sound in 3D space around you. Use stereo files only for background music or UI sounds that don’t need positioning.
Play a one-shot sound from a specific position
SceneAudioPlayer gives you ongoing control over positioned audio playback. This is useful for ambient sounds, looping effects, or audio that needs to follow moving objects in your scene.
You can play sounds from a specific origin within your scene, and use the player’s position to determine how it should sound relative to where they are.
public class SceneAudioPlayer(scene: Scene, audioAsset: SceneAudioAsset) {
fun play(position: Vector3, volume: Float = 1.0f, looping: Boolean = false)
fun setPosition(position: Vector3)
fun stop()
}
To play a sound at a specific position, your audio file must support 3D positioning. Check that the canBeSpatialized property is true. If it’s false, the audio will play but won’t come from a specific location in 3D space.
class SpatialAudioActivity : AppSystemActivity() {
override fun onSceneReady() {
super.onSceneReady()
val audioPlayer = SceneAudioPlayer(scene, SceneAudioAsset.loadLocalFile("audio/click.wav"))
val entity = Entity.create(...)
entity?.registerEventListener<ButtonReleaseEventArgs>(ButtonReleaseEventArgs.EVENT_NAME) {
entity, eventArgs ->
val position = entity.getComponent<Transform>().transform.t
when (eventArgs.button) {
ControllerButton.RightTrigger -> audioPlayer.play(position)
ControllerButton.LeftTrigger -> audioPlayer.setPosition(position + Vector3(1.0f, 0.0f, 0.0f))
}
}
}
}
One-shot sound are perfect for immediate audio feedback like button clicks, collision sounds, or notification chimes. They play once and clean up automatically, making them ideal for sounds triggered by user interactions or events where you don’t need ongoing control.
You may need to play a single sound to completion. Spatial SDK supplies simple APIs to allow one-shot sounds to play.
class Scene {
…
fun playSound(soundAsset: SceneAudioAsset, volume: Float)
fun playSound(soundAsset: SceneAudioAsset, position: Vector3, volume: Float)
…
}
The sound will play to completion. You will not be able to cancel the playback early.
Here is an example:
scene.playSound(SceneAudioAsset.loadLocalFile("audio/click.wav"), hitInfo.point, 1f)
class SpatialAudioActivity : AppSystemActivity() {
override fun onSceneReady() {
super.onSceneReady()
val soundAsset = SceneAudioAsset.loadLocalFile("audio/click.wav")
val entity = Entity.create(...)
entity?.registerEventListener<ButtonReleaseEventArgs>(ButtonReleaseEventArgs.EVENT_NAME) {
entity, eventArgs ->
if (eventArgs.button == ControllerButton.RightTrigger ||
eventArgs.button == ControllerButton.LeftTrigger) {
val position = entity.getComponent<Transform>().transform.t
scene.playSound(soundAsset, position, 1.0f)
}
}
}
}
Play a looping background sound
Background sounds create atmosphere and mood in your experience. Unlike positioned audio, background sounds play at a consistent volume regardless of where you look or move. This makes them perfect for ambient music, environmental soundscapes, or narration. The “one at a time” limitation encourages thoughtful audio design. You can smoothly transition between different background tracks as users move through different areas of your experience.
Background sounds are not positioned in 3D space. They play at the same volume no matter where you look or move. Only one background sound can be played at a time.
class Scene {
…
fun playBackgroundSound(soundAsset: SceneAudioAsset, volume: Float, looping: Boolean)
…
}
To turn off the background sound in your app, use the following code:
class Scene {
…
fun stopBackgroundSound()
…
}
Understanding 3D audio positioning
When positioning audio in 3D space, you’ll work with Vector3 coordinates that represent locations in your virtual world. The coordinate system typically follows these conventions:
- X-axis: Left (negative) to Right (positive)
- Y-axis: Down (negative) to Up (positive)
- Z-axis: Backward (negative) to Forward (positive)
Audio positioned closer to the user’s head will sound louder, while distant audio becomes quieter and may have different spatial characteristics. The SDK automatically handles these calculations based on the user’s head position and orientation.