Component guide

San Andreas Station Pack

Build synchronized Server Radio stations from local tracks, artwork, identifiers, exact durations, and a deterministic program clock.

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 pagesStation Pack
Sections
01 / Overview

Program ownership and synchronization

A Station Pack owns the local station catalog, deterministic order, identifiers, current program, metadata, and timestamps. Radio owns the vehicle, permissions, selection, power, volume, UI, and playback lifecycle; Sound renders the selected local media.

SourceMedia locationSynchronization model
Local GTA RadioGame filesGTA-owned playback.
Satellite RadioExternal live URLShared live stream.
Server RadioStation Pack local filesDeterministic server program clock.
BluetoothPlayer-supplied linkVehicle queue and transport state.

A Server Radio station does not begin when the first player tunes in. With the broadcast clock active, the program is already running and late listeners seek into the current segment.

Do not place local station tracks in Radio's Config.Streams. That table is only for external Satellite Radio URLs; local media belongs to a separately ensured Station Pack.

02 / Setup

Installation and Radio registration

server.cfgcfg
ensure san_andreas_sound
ensure san_andreas_dispatch
ensure san_andreas_station_pack
ensure san_andreas_radio
san_andreas_radio/config.lualua
Config.ServerRadio = {
    Enabled = true,
    AcousticClass = 'server_music',
    VolumeMultiplier = 0.70,
    ExteriorVolumeMultiplier = 0.75,
    Resources = {
        'san_andreas_station_pack'
    }
}
  • Keep the exact san_andreas_station_pack folder name and start it before Radio so the initial catalog is discoverable.
  • Keep fxmanifest.lua, config.lua, server/, audio/, artwork/, and ASSET_PROVENANCE.md together.
  • The release manifest packages files directly beneath audio/ and artwork/. Add manifest patterns if custom media uses subfolders or additional supported extensions.
  • When more than one pack is installed, append each exact folder name to Config.ServerRadio.Resources and keep every station ID unique across packs.
  • The server validates the invoking configured resource and local media prefix; a pack cannot publish another resource's files or take ownership of its stations.
03 / Media

Prepare music, artwork, and durations

AssetSupported release formatsPreparation
Tracks and identifiersMP3, M4A, OGG, WAVUse lowercase ASCII filenames, consistent loudness with headroom, clean edges, and exact final durations.
ArtworkJPG, JPEG, PNGA 3:2 landscape image such as 960x640 fits well; keep important content away from responsive crop edges.
  1. Begin only with media that may be redistributed through the FiveM resource packfile.
  2. Trim unwanted silence and add very short fades where hard edges click.
  3. Keep perceived loudness consistent and preserve headroom; MP3 around 128 kbps at 44.1 or 48 kHz is a practical music balance.
  4. Test the loudest track at maximum managed Radio volume.
  5. Measure the final encoded file, not a source copy from before conversion, and retain the decimal seconds.
  6. Record creator, source, license, modification notes, and required attribution in ASSET_PROVENANCE.md.
Measure final durationshell
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 audio/track-name.mp3
04 / Clock

Configure the broadcast clock

KeyTypeDefaultDescription
StationPackConfig.DebugbooleanfalseAdds station validation and scheduler logging.
StationPackConfig.TickMsnumber250Scheduler update interval.
Broadcast.EnabledbooleantrueEnables the continuous deterministic program clock.
Broadcast.AnchorUnix timestamp1767225600Stable program origin.
Broadcast.Seedinteger9142026Stable deterministic station-order seed.

Keep Anchor and Seed unchanged across normal restarts. The same values let the pack reconstruct the active track and offset rather than restarting from track one. Change either value only when intentionally beginning a different program rotation.

05 / Catalog

Define stations and tracks

san_andreas_station_pack/config.lualua
{
    id = 'SERVER_EXAMPLE_ROCK',
    label = 'Vinewood Rock Works',
    short = 'VRW',
    genre = 'Server-owned rock',
    accent = '#d95f4d',
    artwork = 'artwork/vinewood-rock-works.jpg',
    shuffle = true,
    tracks = {
        {
            id = 'vrw:track-one',
            artist = 'Artist Name',
            title = 'Track Name',
            file = 'audio/track-name.mp3',
            duration = 214.437
        }
    }
}
Station fields
KeyTypeDefaultAccepted valuesRequiredDescription
idstringUp to 64 uppercase letters, digits, underscore, or hyphenYesUnique station identity. A SERVER_ prefix is recommended for clarity.
labelstringYesFull player-facing station name.
shortstringCompact source/display label.
genrestringShort station description.
accent#RRGGBBStation color; invalid values use the pack fallback.
artworkrelative pathSafe JPG, JPEG, or PNG path owned by this pack.
shufflebooleanDeterministic shuffle when true; configured order when false.
tracksarrayYesNon-empty array of validated track entries.
Track fields
KeyTypeDefaultAccepted valuesRequiredDescription
idstringYesUnique inside the station. Globally descriptive IDs are easier to audit.
artiststringOptional but strongly recommended player-facing artist.
titlestringYesPlayer-facing track title.
filerelative pathYesSafe local MP3, M4A, OGG, or WAV path.
durationnumber>= 1 secondYesExact final encoded duration.

Do not reuse an existing track ID for unrelated media unless it should intentionally remain the same logical catalog item. Stable descriptive IDs make revisions and support logs easier to interpret.

06 / Programming

Schedule identifiers and multiple stations

san_andreas_station_pack/config.lualua
Identifiers = {
    Enabled = true,
    EveryTracks = 2,
    Randomize = true,
    Clips = {
        {
            id = 'vrw:station-ident-01',
            artist = 'Vinewood Rock Works',
            title = 'Station Identification',
            file = 'audio/vrw-ident-01.ogg',
            duration = 3.428
        }
    }
}

Identifiers, sweepers, and jingles are normal program segments inserted between songs, not overlays. This keeps every client on one synchronized source.

EveryTracks must be at least one and no greater than the music-track count. Every identifier needs its own ID, metadata, safe local file, and exact duration. Randomize uses deterministic seeded order.

Add more station tables to the same Stations array, or configure multiple pack resources in Radio. Station IDs must be unique across all configured packs; each pack must expose the same public server contract.

07 / Runtime

Synchronization and volume balance

Late-listener pathtext
Radio requests station snapshot
-> receives active track and shared timestamp
-> creates the vehicle sound
-> seeks to the calculated offset
-> fades to the intended volume
  1. Normalize track loudness and retain headroom before changing configuration gain.
  2. Test the loudest track at full managed head-unit volume.
  3. Lower Config.ServerRadio.VolumeMultiplier when local stations overpower Satellite Radio inside the vehicle.
  4. Lower ExteriorVolumeMultiplier when local media overdrives exterior bass or filtering.
  5. Do not raise the global Sound profile to compensate for one quiet file.

For each station, the server derives a deterministic sequence from the track list, shuffle flag, Seed, Anchor, and exact durations. A snapshot identifies the current segment, start time, offset, revision, metadata, and local media URL.

08 / API

Public server API

GetStations

exportServer

Return copied UI-safe station definitions.

Signaturelua
GetStations()
Returns
station definition array

GetSnapshot

exportServer

Return current synchronized source data by station ID.

Signaturelua
GetSnapshot()
Returns
station-source map

GetStation

exportServer

Return one copied station definition or false.

Signaturelua
GetStation(stationId)
Returns
station definition | false

san_andreas_radio:server:stationPackChanged

eventServer

Local server event emitted after the active program segment advances.

Signaturelua
(stationId, source)
ObjectFields
Station definitionid, label, short, genre, accent, artwork, streamed=true, server=true
Current sourcestationId, local url, duration, startedAt, offset, revision, loop=false, syncGroup, track
Track metadataid, artist, title, source='server', kind ('track' or 'identifier')

A custom compatible pack must publish network-safe metadata and browser-playable local https://cfx-nui-... URLs that it owns. It never calls an audio provider or mutates vehicle state.

09 / Operations

Verification, troubleshooting, and distribution

  1. Start Sound, Station Pack, and Radio in order and open the Server Radio source.
  2. Confirm every station's label, description, accent, artwork, artist, and title.
  3. Tune one vehicle, wait at least 20 seconds, then tune a second and compare offsets.
  4. Restart only the Station Pack; unchanged Anchor and Seed should reconstruct the current program.
  5. Listen across several music and identifier boundaries for silence, overlap, clicks, metadata delay, or restart at zero.
  6. Test maximum managed volume inside and outside, then verify radio-off, vehicle deletion, and resource-stop cleanup.
The Server Radio source does not appear.

Likely causes

  • Pack not running before Radio
  • Folder missing from Resources
  • Pack exports invalid

Checks

  1. Check Config.ServerRadio.Enabled and exact name
  2. Inspect pack and Radio consoles

Expected result

Radio discovers every valid configured pack and shows its stations.

Metadata advances but audio is silent.

Likely causes

  • Local file missing or unpackaged
  • Codec unsupported
  • Provider failed

Checks

  1. Check exact path/case and manifest pattern
  2. Inspect Sound diagnostics

Expected result

The local CFX NUI URL starts through the selected provider.

A late listener starts at zero or stations drift after restart.

Likely causes

  • Incorrect duration
  • Anchor or Seed changed
  • Provider seek unavailable

Checks

  1. Measure the final files
  2. Restore stable clock values
  3. Inspect snapshot offset and Sound start

Expected result

All listeners enter the current program offset before and after restarts.

Track boundaries pop or occur early/late.

Likely causes

  • Hard source-file edge
  • Full-scale peak
  • Duration mismatch

Checks

  1. Trim/fade final files
  2. Normalize loudness
  3. Re-measure duration

Expected result

Boundaries are clean and align with metadata.

The client download is excessive.

Likely causes

  • High bitrate or uncompressed media
  • One oversized pack contains optional libraries

Checks

  1. Measure total resource size
  2. Encode efficiently
  3. Split optional formats into separate packs

Expected result

Every connecting client downloads only intentional, practical media.