Component guide

San Andreas Sound

Configure the positional audio renderer, integrate its native APIs, migrate legacy callers, and diagnose every playback path.

Resource
San Andreas Sound Suite
Version
Sound 1.5.16 · Dispatch 1.0.0 · Radio 1.0.0
Updated
Updated August 21, 2026
Resource GitHub
Browse documentationSan Andreas Sound Suite
Guide pagesSound
Sections
01 / Overview

Renderer responsibility and modes

San Andreas Sound renders caller-owned state. It does not choose stations, schedule Dispatch, grant permissions, or own synchronized vehicle state.

RendererUsed whenCapabilitiesLimitation
webaudioDirect media permits cross-origin sample accessHRTF, distance, gain, bass shelf, low-pass, compression, limiter, and 12-band spectrumThe media host must allow browser CORS access.
htmlDirect media plays but cannot enter Web AudioPlayback, transport, distance-shaped volume, and fallback relationship gainNo HRTF, low-pass, bass shelf, compressor, or analyzer.
youtubeSupported watch, short, embed, or resolved live URLIframe transport, volume, distance-shaped level, and fallback enclosure gainEmbedding may fail; no Web Audio filters, HRTF, or spectrum.
Direct Web Audio graphtext
MediaElementAudioSourceNode
-> GainNode
-> BiquadFilterNode (low shelf)
-> BiquadFilterNode (low pass)
-> DynamicsCompressorNode
-> HRTF panner or direct same-vehicle route
-> shared master limiter

One shared AudioContext is used per client. Listener and active-source transforms are batched; the resource does not create one context or Lua thread per source.

A URL that plays successfully may still use the HTML fallback when CORS prevents Chromium from exposing samples to Web Audio. Inspect diagnostics before treating reduced spatial behavior as a configuration error.

02 / Setup

Installation and core configuration

  1. Keep the exact san_andreas_sound folder name and its config.lua, client, server, web, and manifest files together.
  2. Start Sound before every native caller, Radio, and every resource depending on xsound or interact-sound.
  3. Do not start the original xSound or InteractSound resources while Sound provides their aliases.
  4. Run san_andreas_sound_status in F8, trigger one known sound, and inspect the renderer, started state, context, error, and attachment.
  5. Destroy the test sound or stop its caller and confirm its diagnostic record disappears.
SanAndreasSoundConfig core values in san_andreas_sound/config.lua.
KeyTypeDefaultDescription
PositionUpdateMsnumber50Active listener/source transform batch interval in milliseconds.
IdleUpdateMsnumber500Lower-frequency update interval while no sound is active.
CompletionCheckMsnumber500Natural-end fallback inspection interval.
CompletionGraceMsnumber1500Grace before fallback completion is accepted.
FalloffStartDistancenumber1.5Distance before normal attenuation begins.
DebugbooleanfalseEnables additional development logging.
KeyTypeDefaultDescription
StreamerMode.EnabledbooleantrueExposes the client-local managed-audio mute.
StreamerMode.CommandstringstreamermodeCommand name without a slash.
StreamerMode.PersistbooleantrueStores the local preference between sessions.
StreamerMode.DefaultEnabledbooleanfalseStarts new users muted when true.
StreamerMode.MuteOneShotsbooleantrueIncludes InteractSound-compatible one-shot cues.
Compatibility.XSound.EnabledbooleantruePublishes the supported xSound surface and provider alias.
Compatibility.InteractSound.EnabledbooleantruePublishes the supported InteractSound events and exports.
Compatibility.InteractSound.DefaultVolumenumber0.30One-shot fallback volume when a caller omits it.
Compatibility.InteractSound.MaxDistancenumber300.0Maximum accepted distance for compatibility calls.
Compatibility.InteractSound.ExtensionstringoggSingle extension used by the flat compatibility cue library.
03 / Configuration

Spatial audio and vehicle acoustics

Tune the caller's source level first, then relationship overrides, Sound profile gain, filtering, bass, compression, and finally the limiter. Change one layer at a time.

KeyTypeDefaultDescription
SpatialAudio.EnabledbooleantrueEnables the spatial relationship graph.
SpatialAudio.PanningModelstringHRTFDirectional panning model for compatible sources.
SpatialAudio.DistanceModelstringlinearDistance attenuation curve.
SpatialAudio.RolloffFactornumber1.0Distance rolloff factor.
SpatialAudio.SmoothingMsnumber240Gain and tone ramp duration.
SpatialAudio.RelationshipTransitionMsnumber360Direct/HRTF transition duration when listener relationship changes.
OutputLimiter.ThresholdDbnumber-3.0Final direct-output peak threshold.
OutputLimiter.KneeDbnumber2.0Limiter knee.
OutputLimiter.Rationumber12.0Limiter compression ratio.
OutputLimiter.Attacknumber0.001Limiter attack in seconds.
OutputLimiter.Releasenumber0.10Limiter release in seconds.
Tone.BassFrequencyHznumber400Low-shelf frequency used by relationship shaping.
Tone.CompressortableThreshold -24 dB, knee 18 dB, ratio 2.5, attack 0.012, release 0.25.
KeyTypeDefaultDescription
Cabin.UpdateMsnumber200Roof, door, window, and trunk enclosure cache interval.
Cabin.DoorOpenRationumber0.15Threshold for treating a door as open.
Cabin.DoorExposurenumber0.60How strongly open doors reduce enclosure.
Cabin.WindowExposurenumber0.40How strongly broken/open windows reduce enclosure.
Cabin.TrunkExposurenumber0.35Trunk contribution for sounds that opt in.
Cabin.Sealed.Gainnumber0.65Direct Web Audio sealed-cabin gain.
Cabin.Sealed.FallbackGainnumber0.35Sealed-cabin gain for HTML/YouTube sources that cannot be filtered.
Cabin.Sealed.LowpassHznumber400Sealed-cabin cutoff for compatible media.
Cabin.Sealed.BassGainDbnumber2.0Body-transmission bass shaping.
Occlusion.UpdateMsnumber250Staggered line-of-sight update interval.
Occlusion.ChecksPerTicknumber2Maximum staggered occlusion checks per update.
Relationship profileSpatialBase gainLow-passRole
WorldYes1.010000 HzGeneral positional playback.
InsideNo1.08000 HzSame-vehicle direct route with cabin warmth.
OutsideYes2.01000 HzExterior route; caller exterior trim still applies.
OtherVehicleYes0.752200 HzListener inside a different vehicle.
OccludedBlended0.60400 HzAdditional geometry-blocked shaping.
Acoustic classIntended sourceBehavior
Default or omittedGeneral positional and compatibility callsUses the base cabin and relationship profiles.
musicSatellite Radio and BluetoothMusic-specific cabin and exterior tuning; trunk can opt in.
server_musicLocally hosted Server RadioPeak-controlled profile with reduced exterior bass for hotter local masters.
scannerDispatch, scanner, and voice trafficKeeps communication tone independent from entertainment media.
04 / Client API

Native client API

Entity-attached positional streamclient.lualua
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
local netId = VehToNet(vehicle)
local soundName = ('my_resource:vehicle:%s'):format(netId)

exports.san_andreas_sound:PlayPositional({
    name = soundName,
    url = 'https://media.example.net/authorized-stream.mp3',
    volume = 0.20,
    position = GetEntityCoords(vehicle),
    entityHandle = vehicle,
    entityNetId = netId,
    syncGroup = 'my_resource:station:example',
    acousticClass = 'music',
    trunkAffectsEnclosure = true,
    relationshipOverrides = {
        outside = { volumeMultiplier = 0.18, maxDistance = 18.0 },
        other_vehicle = { volumeMultiplier = 0.18, maxDistance = 18.0 }
    },
    maxDistance = 25.0,
    loop = true,
    playing = true
})
PlayPositional options
KeyTypeDefaultAccepted valuesRequiredDescription
namestringYesStable logical ID. Same-name playback replaces old state without calling the old onPlayEnd callback.
urlstringYesDirect media URL or supported YouTube form.
volumenumber00.0-1.0Source volume intent.
positionvector3 or tableAccepts x/y/z keys or numeric indices.
entityHandleclient entity handleOptional local optimization. Never relay it through the server.
entityNetIdpositive numberNetwork-safe attachment resolved independently by each client.
globalbooleanfalseSelects a non-spatial route. Otherwise provide position or an entity.
maxDistancenumber20>= 0.1Audible radius.
syncGroupstringMaximum 128 charactersProvider hint for sharing matching non-seekable live media.
acousticClassstringSelects an inheriting source-specific acoustic profile.
trunkAffectsEnclosurebooleanOpts this sound into trunk contribution to enclosure.
relationshipOverridestablePer world, inside, outside, or other_vehicle volume and distance overrides.
loopbooleanfalseRepeats compatible media.
playingbooleantrueInitial transport state.
timenumber0Initial nonnegative seek position in seconds.
destroyOnFinishbooleanRemove direct one-shots after natural completion; helper exports infer true for non-looping media.
callback fieldsfunctionsonPlayStart, onPlayEnd, onLoading, onPlayPause, and onPlayResume; client-only.

Case-sensitive Sound client exports

PlayPositional

exportClient

Create or replace a validated named positional or global sound.

Signaturelua
PlayPositional(options)
Returns
boolean; queued locally, not audible confirmation

PlayUrlPos

exportClient

xSound-style positional helper.

Signaturelua
PlayUrlPos(name, url, volume, position, loop, options)
Returns
boolean

PlayUrl

exportClient

Create a global, non-spatial sound.

Signaturelua
PlayUrl(name, url, volume, loop, options)
Returns
boolean

Destroy

exportClient

Stop and remove a sound; explicit destroy calls the current onPlayEnd callback.

Signaturelua
Destroy(name)
Returns
boolean

SetPosition / Position

exportClient

Move a detached source and make it positional.

Signaturelua
SetPosition(name, position)
Returns
boolean

SetEntityNetId

exportClient

Attach or reattach by network ID. Invalid IDs clear an existing attachment.

Signaturelua
SetEntityNetId(name, netId)
Returns
boolean

SetDistance / Distance

exportClient

Set the audible radius, with a 0.1-meter minimum.

Signaturelua
SetDistance(name, meters)
Returns
boolean

SetVolume / setVolume / setVolumeMax

exportClient

Set source volume intent, clamped to 0.0-1.0.

Signaturelua
SetVolume(name, volume)
Returns
boolean

SetTime / setTimeStamp

exportClient

Seek compatible media to a nonnegative time.

Signaturelua
SetTime(name, seconds)
Returns
boolean

SetPlaying

exportClient

Set exact paused/playing transport state.

Signaturelua
SetPlaying(name, playing)
Returns
boolean

Pause / Resume

exportClient

Transport convenience exports.

Signaturelua
Pause(name) / Resume(name)
Returns
boolean

SetSpectrumEnabled

exportClient

Enable local 12-band frames for compatible Web Audio.

Signaturelua
SetSpectrumEnabled(name, enabled)
Returns
boolean

SoundExists

exportClient

Test whether logical sound state exists.

Signaturelua
SoundExists(name)
Returns
boolean

IsReady

exportClient

Read NUI readiness.

Signaturelua
IsReady()
Returns
boolean

GetDiagnostics

exportClient

Return active sound diagnostic records.

Signaturelua
GetDiagnostics()
Returns
map keyed by sound name

SetStreamerMode

exportClient

Set the local managed-audio mute preference.

Signaturelua
SetStreamerMode(enabled)

ToggleStreamerMode

exportClient

Toggle local managed-audio mute.

Signaturelua
ToggleStreamerMode()
Returns
current boolean preference

IsStreamerModeEnabled

exportClient

Read the local preference.

Signaturelua
IsStreamerModeEnabled()
Returns
boolean
05 / Runtime feedback

Callbacks, events, and diagnostics

onPlayStart

callbackClient

Runs after the renderer confirms playback began. Use this when audible-start confirmation matters.

onPlayEnd

callbackClient

Runs after natural completion or explicit Destroy. Same-name replacement does not call the old callback.

onLoading / onPlayPause / onPlayResume

callbackClient

Optional client-only lifecycle callbacks. Functions are not serialized by server relays.

san_andreas_sound:client:playEnded

eventClient

Local integration event emitted for natural completion.

Signaturelua
(name, token)

san_andreas_sound:client:spectrumFrame

eventClient

Local presentation event with twelve normalized values for compatible Web Audio.

Signaturelua
(name, bands)

san_andreas_sound:client:streamerModeChanged

eventClient

Local notification after streamer-mode state changes.

Signaturelua
(enabled)
Diagnostic fieldWhat to verify
rendererwebaudio, html, or youtube; determines available spatial/filter features.
startedTrue only after renderer playback confirmation.
audioContextState / playbackErrorNormally running and without error while compatible audio is active.
profile / acousticClassExpected listener relationship and source class.
enclosure / occludedVehicle sealing and geometry-blocked state.
effective volume / sourceVolume / mutedFinal local shaping versus caller volume and mute state.
entityNetId / resolved entityAttachment exists and resolves locally.
syncGroupMatching live media uses the intended shared transport identity.
06 / Server API

Server relay API

PlayPositional

exportServer

Relay serialized positional playback to a validated client.

Signaturelua
PlayPositional(target, options)
Returns
true after TriggerClientEvent

PlayUrlPos

exportServer

Relay the positional helper.

Signaturelua
PlayUrlPos(target, name, url, volume, position, loop, options)

PlayUrl

exportServer

Relay global playback.

Signaturelua
PlayUrl(target, name, url, volume, loop, options)

Destroy

exportServer

Destroy one named sound on the validated target client.

Signaturelua
Destroy(target, name)

SetPosition / Position

exportServer

Relay a positional update through the native and xSound-compatible aliases.

Signaturelua
SetPosition(target, name, position) / Position(target, name, position)

SetEntityNetId

exportServer

Attach a named sound to a networked entity on the target client.

Signaturelua
SetEntityNetId(target, name, entityNetId)

SetDistance / Distance

exportServer

Relay the audible-distance update through both supported aliases.

Signaturelua
SetDistance(target, name, distance) / Distance(target, name, distance)

SetVolume / setVolume / setVolumeMax

exportServer

Relay volume through the native name or either case-sensitive xSound alias.

Signaturelua
SetVolume(target, name, volume) / setVolume(target, name, volume) / setVolumeMax(target, name, volume)

SetTime / setTimeStamp

exportServer

Relay a playback-position update through the native or xSound-compatible alias.

Signaturelua
SetTime(target, name, seconds) / setTimeStamp(target, name, seconds)

SetPlaying

exportServer

Set the named sound's playing state using an explicit boolean.

Signaturelua
SetPlaying(target, name, playing)

Pause / Resume

exportServer

Relay explicit transport changes.

Signaturelua
Pause(target, name) / Resume(target, name)

The server serializes name, URL, volume, position, entityNetId, syncGroup, acoustic and relationship options, global state, loop, distance, time, playing state, and destroyOnFinish. It cannot serialize callback functions or a client-local entityHandle.

07 / Compatibility

Legacy compatibility contracts

xSound categorySupported names
Playback and mutationPlayUrl, PlayUrlPos, Position, Distance, Destroy, Pause, Resume, setVolume, setVolumeMax, setTimeStamp
InformationgetLink, getPosition, isLooped, getInfo, soundExists, isPlaying, isPaused, getDistance, getVolume, isDynamic, getTimeStamp, getMaxDuration, getAllAudioInfo, isPlayerCloseToAnySound, isPlayerInStreamerMode
Manipulation and callbacksdestroyOnFinish, setSoundLoop, repeatSound, setSoundDynamic, setSoundURL, onPlayStart, onPlayEnd, onLoading, onPlayPause, onPlayResume, fadeIn, fadeOut
Legacy state eventxsound:stateSound accepts play, playpos, position, distance, destroy, pause, resume, volume, timestamp, and destroyOnFinish branches
Completion eventxSound:songStopPlaying(name)

InteractSound compatibility

InteractSound_CL:PlayOnOne

eventClient

Play a non-spatial local one-shot.

Signaturelua
(file, volume)

InteractSound_CL:PlayOnAll

eventClient

Same local behavior after a server broadcast.

Signaturelua
(file, volume)

InteractSound_CL:PlayWithinDistance / PlayWithinDistanceOS

eventClient

Apply a strict distance gate once, then play a non-spatial one-shot.

Signaturelua
(originCoordsOrServerId, maxDistance, file, volume)

InteractSound_SV:PlayOnOne

eventServer

Relay one cue to one target.

Signaturelua
(target, file, volume)

InteractSound_SV:PlayOnSource

eventServer

Relay to the invoking client.

Signaturelua
(file, volume)

InteractSound_SV:PlayOnAll

eventServer

Relay to every client.

Signaturelua
(file, volume)

InteractSound_SV:PlayWithinDistance

eventServer

Relay source position for a client distance gate.

Signaturelua
(maxDistance, file, volume)

PlayOneShot / StopOneShot

exportClient

Available under both canonical and interact-sound resource names.

Signaturelua
PlayOneShot(file, volume) / StopOneShot()
08 / Diagnostics

Performance, verification, and troubleshooting

  • Keep the shared AudioContext and batched transform path; do not create a tight Lua thread per sound.
  • Prefer entity attachment over repeatedly relaying unchanged positions.
  • Enable spectrum only while a display consumes it.
  • Keep occlusion checks staggered and use syncGroup only for matching non-seekable live media.
  • Measure client frame time, NUI memory, stream traffic, simultaneous decoders, and audible stability with multiple nearby vehicles before changing timing defaults.
The export succeeds but nothing is audible.

Likely causes

  • The browser did not start media
  • The URL or codec is blocked
  • The AudioContext is not running

Checks

  1. Run san_andreas_sound_status
  2. Inspect started, renderer, context, URL, and playbackError
  3. Test the exact media in FiveM CEF

Expected result

The active record reports started=true with no playback error.

There is no HRTF, low-pass, or spectrum.

Likely causes

  • CORS forced the HTML renderer
  • The source is YouTube

Checks

  1. Inspect renderer
  2. Use an authorized CORS-compatible direct media endpoint

Expected result

Renderer reports webaudio for the full graph.

The sound is global instead of positional.

Likely causes

  • The caller used PlayUrl
  • No valid position or entity attachment was supplied
  • global=true was set

Checks

  1. Use PlayPositional or PlayUrlPos
  2. Inspect entityNetId and resolved entity

Expected result

Diagnostics show a positional relationship profile.

Doors or trunk do not change enclosure.

Likely causes

  • The source is not attached to a valid vehicle
  • Cabin processing is disabled
  • The trunk was not opted in

Checks

  1. Verify attachment
  2. Confirm Cabin.Enabled
  3. Set trunkAffectsEnclosure=true for music that should use it

Expected result

Enclosure changes cumulatively as openings change.

Compatibility cues are silent.

Likely causes

  • Filename case or extension mismatch
  • The manifest does not package the format
  • The cue is not in the flat sounds directory

Checks

  1. Check web/sounds, Linux case, configured Extension, manifest patterns, and F8

Expected result

The requested local cue resolves through the compatibility path.

Audio duplicates or survives a restart.

Likely causes

  • The original provider is also running
  • A caller owns cleanup too broadly or not at all
  • Temporary diagnostic sounds remain

Checks

  1. Run only one provider
  2. Use resource-prefixed names
  3. Destroy only owned sounds on the caller's resource stop

Expected result

Independent restarts leave no duplicate or orphaned media.