Skip to content

Radio Station Framework

This file is for server developers who want to integrate another resource with rs_radio.

It intentionally documents only the supported integration surface. Internal playback, emitter routing, station-state internals, and NUI implementation details are not public API.

Legacy servers use the RS-modified pma-voice build for DJ, cohost, caller, monitor, and ducking behavior:

Supported FiveM Enhanced servers use the built-in voice API instead. See docs/voice-backends.md for backend selection and troubleshooting.

  • Let rs_radio own station state.
  • Let rs_radio own vehicle/boombox emitter routing.
  • Use supported events/commands/config instead of mutating internal tables.
  • Treat received state payloads as read-only.
  • Do not call internal audio/runtime exports. They are not part of the customer-facing API.

These are the main client events other resources can use to open or close supported UI flows.

TriggerEvent("rs-radio:openListenerUi")
TriggerEvent("rs-radio:openDjTablet", payload)
TriggerEvent("rs-radio:openStationAdmin")
TriggerEvent("rs-radio:forceCloseDjTablet")

Notes:

  • openListenerUi opens the normal vehicle listener UI path.
  • openDjTablet still respects station context and permissions.
  • openStationAdmin still respects admin/group permissions.
  • forceCloseDjTablet is useful when another scripted scene needs to close the DJ UI safely.

Boombox UI should normally be opened through the boombox item/target flow, because it needs the correct boombox context.

Other resources can listen to these client events for read-only UI or scene awareness.

RegisterNetEvent("rs-radio:updateState", function(state)
-- Read-only station state snapshot.
end)
RegisterNetEvent("rs-radio:listenerVehicleStatus", function(payload)
-- Read-only listener vehicle status.
end)
RegisterNetEvent("rs-radio:boomboxListenerStatus", function(payload)
-- Read-only boombox listener status.
end)
RegisterNetEvent("rs-radio:updateCallQueue", function(queue)
-- Read-only caller queue snapshot.
end)
RegisterNetEvent("rs-radio:activeCall", function(payload)
-- Read-only active call snapshot.
end)
RegisterNetEvent("rs-radio:activeCallEnded", function()
-- Active call ended.
end)
RegisterNetEvent("rs-radio:updateWeather", function(weather)
-- Read-only radio-facing weather snapshot.
end)

These events are intended for displays, scene logic, and lightweight integrations. Do not treat them as permission bypasses or authoritative write paths.

Open the listener UI from another client resource:

TriggerEvent("rs-radio:openListenerUi")

Open the station admin UI from an admin-only interaction:

TriggerEvent("rs-radio:openStationAdmin")

Close the DJ UI when a scripted scene starts:

TriggerEvent("rs-radio:forceCloseDjTablet")

React to station state changes:

RegisterNetEvent("rs-radio:updateState", function(state)
if type(state) ~= "table" then return end
-- Use state for read-only scene/UI behavior.
end)

rs_radio contains internal exports used by the resource itself.

Those exports are not documented as a public integration API and should not be called by third-party resources.

If your project needs a custom integration beyond the events above, request or add a supported wrapper/export intentionally for that use case instead of depending on internal playback primitives.

Most implementation files are internal and may be escrowed in distributed builds. Server owners and third-party resource developers should treat them as protected implementation details, not edit targets.

High-level protected areas:

  • server station state and broadcast logic
  • client world emitter runtime
  • NUI bridge and callback handling
  • browser audio and visualizer implementation
  • cohost/caller/mic routing

Customer-editable areas are documented in:

  • docs/configuration.md
  • docs/installation.md
  • config.lua

Station content and placement should be managed through the Station Creator/Admin UI where possible.

For normal server installs, restart or ensure rs_radio and check the server/F8 console for startup errors.

Maintainer packaging checks are intentionally not part of the public integration API.