Component guide

San Andreas Dispatch

Configure synchronized local call channels, maintain the media catalog safely, connect Radio, and consume the public server contract.

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

Channel and scheduler contract

Dispatch is a server-authoritative local call scheduler. It selects and randomizes MP3 clips, publishes lore-friendly metadata and shared timestamps, and leaves playback to Radio or another consumer.

Channel IDIntended roleIncluded clipsDefault gap
policeState and police dispatch10030-60 seconds
fireFire response10030-60 seconds
emsMedical dispatch10030-60 seconds
serviceCity and utility service10030-60 seconds
airAviation operations10030-60 seconds
marineHarbor and marine operations10030-60 seconds
One channel timelinetext
initial delay
-> choose a randomized clip
-> publish URL, revision, start time, duration, and metadata
-> clip expires
-> randomized silent gap
-> choose the next clip

Each enabled channel owns an independent shuffled deck. Every valid clip is used once before rebuilding the deck; recent-history entries are deferred at the boundary and immediate repeats are avoided.

The expired descriptor remains available during the silent gap. A consumer must compare offset with duration: it can keep the scanner healthy and suppress native chatter without replaying the expired call or falling back to a URL between transmissions.

02 / Setup

Installation and startup verification

  • Keep the exact san_andreas_dispatch folder name.
  • Dispatch itself has no framework, database, or audio-provider dependency.
  • Keep matching MP3 files under audio/<channel> and catalog entries in shared/catalog.lua.
  • Use a consumer such as San Andreas Radio to select recipients and render the descriptor.
  • Start Dispatch before Radio so the first scanner snapshot can use local programming immediately.
server.cfgcfg
ensure san_andreas_sound
ensure san_andreas_dispatch
ensure san_andreas_station_pack
ensure san_andreas_radio
  1. Start Dispatch and watch the server console for catalog errors.
  2. Start Radio and enter a vehicle mapped to each intended channel.
  3. Confirm the scanner HUD shows the correct channel in STANDBY.
  4. Wait for a scheduled call and confirm the state changes to RECEIVING.
  5. Confirm system, talkgroup, destination, and frequency are lore-friendly.
  6. Use a second client and confirm both hear the same call at the same offset.
03 / Configuration

Global and per-channel configuration

KeyTypeDefaultRequiredDescription
Config.DebugbooleanfalseAdds scheduler and validation logging.
Config.InitialDelayMsnumber1000Delay before channels begin after resource start.
Config.NoRepeatHistorynumber6Recent clips deferred when a shuffled deck is rebuilt.
Config.DefaultGap.MinMsnumber30000Default minimum quiet period after a call.
Config.DefaultGap.MaxMsnumber60000Default maximum quiet period after a call.
Config.Channels.<id>.EnabledbooleantrueStops scheduling while retaining files and catalog when false.
Config.Channels.<id>.LabelstringYesServer-side full channel label.
Config.Channels.<id>.MinGapMs / MaxGapMsnumberOptional per-channel values that override the default gap.
PublicMetadata fieldScanner display role
LabelMain channel type, such as Fire Dispatch.
TalkgroupCompact lore-friendly channel identifier.
TalkgroupLabelAgency, destination, or call line.
FrequencyLore-friendly frequency displayed after RX.
SystemNetwork or communications-system name.
One channelsan_andreas_dispatch/config.lualua
Config.Channels.air = {
    Enabled = true,
    Label = 'San Andreas Air Operations',
    PublicMetadata = {
        Label = 'Air Traffic Control',
        Talkgroup = 'LSIA-TWR',
        TalkgroupLabel = 'LSIA Tower',
        Frequency = '119.8000',
        System = 'San Andreas Aviation Authority'
    },
    MinGapMs = 30000,
    MaxGapMs = 60000
}

Public metadata affects player presentation only. It does not replace or erase the source provenance retained in shared/catalog.lua and ATTRIBUTION.md.

04 / Integration

Connect Dispatch to Radio

san_andreas_radio/config.lualua
Config.Dispatch = {
    Enabled = true,
    Resource = 'san_andreas_dispatch',
    ProfileChannels = {
        emergency = 'police',
        fire = 'fire',
        ems = 'ems',
        service = 'service',
        aviation = 'air',
        marine = 'marine'
    }
}
Radio profile setupResult
Mapped profile with Url = ''Local Dispatch only; no web fallback if Dispatch is unavailable.
Mapped profile with a direct UrlLocal Dispatch has priority; the URL is fallback only.
Unmapped profile with a direct UrlExternal stream only.
Unmapped profile with Url = ''No valid scanner audio source.

The mapping key is a Radio scanner profile ID; its value is a Dispatch channel ID. Dispatch never examines vehicles. Vehicle classes, explicit models, disabled models, scanner power, HUD, provider, native scanner suppression, and exterior behavior belong to Radio.

Model-specific profiles are checked before broad vehicle classes. External scanner URLs belong in Radio configuration, never in the local Dispatch catalog.

05 / Media and catalog

Maintain the local call catalog

Treat every replacement as one transaction: media, exact duration, catalog entry, provenance, privacy review, attribution, and acceptance testing must remain aligned.

  1. Confirm that the candidate may be downloaded, hosted, and distributed for the intended release.
  2. Listen from beginning to end. Reject private names, real addresses, phone numbers, plates, medical details, or other inappropriate identifying information.
  3. Trim long silence without cutting words and add very short edge fades when needed.
  4. For speech, MP3 mono at 48 kHz and 64-96 kbps is a practical target. Use lowercase ASCII filenames without spaces.
  5. Measure the final encoded file with ffprobe; never reuse a duration measured before trimming or conversion.
  6. Stage the MP3 and catalog edit outside the active resource, then swap them together.
  7. Update ATTRIBUTION.md and any private audit record, restart Dispatch, check catalog validation, and verify the affected channel in game.
Measure final durationshell
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 state-dispatch-078.mp3
Representative audited entrysan_andreas_dispatch/shared/catalog.lualua
{
    id = 'police_replacement_078',
    file = 'audio/police/state-dispatch-078.mp3',
    duration = 12.736,
    system = 'source-system-id',
    talkgroup = 1,
    talkgroupLabel = 'Source talkgroup',
    description = 'Internal audit description',
    recordedAt = '2026-08-01T12:00:00.000Z',
    sourcePage = 'https://source.example/system/page',
    callId = 'source-call-id'
}
  • Every top-level catalog key must have a matching Config.Channels entry.
  • IDs and file paths must be unique; paths must be normalized, relative, and resolve beneath the resource.
  • Every referenced file must exist, be MP3, and be declared by the manifest; no unreferenced media should remain.
  • Durations must be positive and match the final encoded file.
  • Player-facing lore text comes from Config.Channels.PublicMetadata, not raw catalog provenance.
  • Adding clips must not bypass shuffled-deck and no-repeat behavior.
06 / Extension

Add a new channel

  1. Create a disabled Config.Channels entry with appropriate public metadata and gap settings.
  2. Add the audio/<channel> folder and an aligned Catalog.<channel> table of audited local MP3 entries.
  3. Add the channel ID to CHANNEL_ORDER in san_andreas_dispatch/server/main.lua for the bundled resource.
  4. Add Config.Dispatch.ProfileChannels.<profile> = '<channel>' in Radio and create or adapt the matching scanner profile.
  5. Update automated catalog expectations for IDs, counts, prefixes, metadata, and timing before enabling the channel.
07 / API

Public server API

GetSnapshot

exportServer

Return a map of every bundled channel ID to its current descriptor or false.

Signaturelua
GetSnapshot()
Returns
read-only channel map

GetChannel

exportServer

Return one current descriptor or false.

Signaturelua
GetChannel(channelId)
Returns
descriptor | false

GetCatalogCounts

exportServer

Return raw catalog entry counts by channel ID.

Signaturelua
GetCatalogCounts()
Returns
number map

san_andreas_dispatch:server:transmissionChanged

eventServer

Local server event emitted when a transmission starts, not when it ends.

Signaturelua
(channelId, descriptor)
Descriptor fieldMeaning
kind / channel / channelLabelDispatch identity and public channel label.
clipId / revisionStable catalog item and changing transmission revision.
urlLocal CFX NUI media URL for the active MP3.
duration / startedAt / offsetExact media length and synchronized timing; offset may exceed duration during the silent gap.
loopAlways false for a Dispatch transmission.
label / talkgroup / talkgroupLabel / frequency / systemLore-friendly public scanner metadata.
08 / Operations

Verification, troubleshooting, and privacy

  • Enter one eligible vehicle for every enabled profile and confirm correct standby metadata.
  • Listen to several calls per channel and verify shuffled order, no immediate boundary repeat, exact stop time, and configured quiet gaps.
  • Use two clients on the same channel and compare offsets.
  • Test startup fade, pause, vehicle exit/re-entry, deletion, and independent resource restarts.
  • Confirm Radio suppresses GTA's native scanner only for intended profiles.
A channel never transmits.

Likely causes

  • Channel disabled
  • Empty or invalid catalog
  • Catalog validation error

Checks

  1. Check Enabled, GetCatalogCounts, and the server console
  2. Verify every file/path/duration

Expected result

The channel publishes scheduled descriptors after the initial delay.

Radio uses a fallback URL.

Likely causes

  • Dispatch stopped or disabled
  • Profile unmapped
  • Channel invalid

Checks

  1. Check resource state and Config.Dispatch
  2. Match profile and channel spelling

Expected result

The healthy mapped local descriptor has priority.

Calls repeat immediately or play sequentially.

Likely causes

  • Library too small for history
  • Scheduler deck logic changed
  • Consumer bypasses snapshots

Checks

  1. Compare NoRepeatHistory to clip count
  2. Restore the randomized deck
  3. Consume synchronized descriptors

Expected result

All valid clips cycle through a shuffled deck without an immediate boundary repeat.

A call ends early or late.

Likely causes

  • Catalog duration differs from the final MP3

Checks

  1. Measure the installed encoded file
  2. Update the aligned catalog record

Expected result

Playback stops at the exact catalog duration.

One client hears a different point.

Likely causes

  • The consumer ignored startedAt or offset
  • The provider did not seek after readiness

Checks

  1. Inspect the descriptor and consumer seek path

Expected result

Late listeners enter the current shared offset.

Duplicate calls remain after restart.

Likely causes

  • Duplicate Radio/Sound instances
  • Consumer cleanup failure

Checks

  1. Run one provider and one Radio
  2. Destroy only consumer-owned playback on stop

Expected result

Independent restarts leave one clean playback path.