Skip to content

Radio Station Framework

Place rs_radio in your resources and ensure it in server.cfg:

ensure rs_radio

The resource requires ox_lib. For legacy FiveM voice, also start the RS-modified pma-voice build. FiveM Enhanced servers using the supported built-in voice API do not require pma-voice.

On legacy servers, use this order in server.cfg:

ensure ox_lib
ensure pma-voice
ensure rs_radio

On supported FiveM Enhanced servers, use:

ensure ox_lib
ensure rs_radio

For legacy voice support, download the RS-modified pma-voice build:

Replace your existing pma-voice folder with it (same resource name) before starting rs_radio. It is stock pma-voice 7.0.1 plus two extra files and a few hooks for the station audience; everything else in pma-voice is unchanged.

If you see this in the server console, you are still on stock pma-voice:

[rs-radio][WARN] ... No such export setStationAudienceSpeakers in resource pma-voice

That is not an error in pma-voice or rs_radio - install the build above and restart. FiveM Enhanced servers using the built-in voice API do not need it.

The modified pma-voice build provides the legacy voice backend for:

  • DJ mic routing
  • cohost monitor/voice routing
  • call-in screening
  • patched live callers
  • station mic participant handling
  • listener ducking behavior

For voice backend selection and Enhanced support, refer to docs/voice-backends.md in the resource archive.

The world playback path is bundled/internalized inside rs_radio.

You do not need to install a separate external xSound resource for the current build in this repository.

The boombox system auto-detects the supported runtime stack.

Supported frameworks:

  • QBCore
  • Qbox
  • ESX

Supported inventories:

  • qb-inventory
  • ox_inventory

Supported target resources:

  • qb-target
  • ox_target

If no supported target resource is running, boombox interaction should be treated as unavailable.

rs_radio uses the configured DJ job for tablet access and boss hiring.

Default job name:

  • dj

Default grades:

  • 0 = Trainee
  • 1 = DJ
  • 2 = Senior DJ
  • 3 = Boss

The boss menu requires grade 3 by default. These values must match:

  • Config.DJJobName
  • Config.DJGrades
  • Config.DJBossGrades

Add the dj job to:

  • resources/[qbx]/qbx_core/shared/jobs.lua

Example:

['dj'] = {
label = 'Radio DJ',
type = 'radio',
defaultDuty = true,
offDutyPay = false,
grades = {
[0] = {
name = 'Trainee',
payment = 25
},
[1] = {
name = 'DJ',
payment = 50
},
[2] = {
name = 'Senior DJ',
payment = 75
},
[3] = {
name = 'Boss',
isboss = true,
bankAuth = true,
payment = 100
},
},
},

After editing jobs, restart qbx_core and rs_radio, or restart the server.

Add the same dj job shape to your QBCore jobs file, commonly:

  • qb-core/shared/jobs.lua

The job key must be lowercase dj, and grade 3 should be marked with isboss = true.

Create the dj job and grades in your ESX jobs database/table or job-management resource.

Minimum requirements:

  • job name: dj
  • grades: 0, 1, 2, 3
  • boss grade: 3

Default item names:

  • radio_boombox
  • radio_walkboy

Expected image assets:

  • radio_boombox.png
  • radio_walkboy.png

This resource auto-detects the runtime stack, but each enabled item still has to exist in your inventory item definitions.

Example:

radio_boombox = {
name = 'radio_boombox',
label = 'Portable Radio',
weight = 2500,
type = 'item',
image = 'radio_boombox.png',
unique = true,
useable = true,
shouldClose = true,
description = 'A portable boombox that can broadcast the station around you.'
},
radio_walkboy = {
name = 'radio_walkboy',
label = 'Walkboy',
weight = 750,
type = 'item',
image = 'radio_walkboy.png',
unique = true,
useable = true,
shouldClose = true,
description = 'A wearable personal radio with headphones.'
},

Qbox servers commonly pair with ox_inventory.

Add an item definition in your ox_inventory item file, commonly:

  • ox_inventory/data/items.lua

Example:

['radio_boombox'] = {
label = 'Portable Radio',
weight = 2500,
stack = false,
close = true,
description = 'A portable boombox that can broadcast the station around you.'
},
['radio_walkboy'] = {
label = 'Walkboy',
weight = 750,
stack = false,
close = true,
consume = 0,
client = {
event = 'rs-radio:client:useWalkboyItem'
},
description = 'A wearable personal radio with headphones.'
},

If your ESX server uses ox_inventory, define the same item there:

  • ox_inventory/data/items.lua

Example:

['radio_boombox'] = {
label = 'Portable Radio',
weight = 2500,
stack = false,
close = true,
description = 'A portable boombox that can broadcast the station around you.'
},
['radio_walkboy'] = {
label = 'Walkboy',
weight = 750,
stack = false,
close = true,
consume = 0,
client = {
event = 'rs-radio:client:useWalkboyItem'
},
description = 'A wearable personal radio with headphones.'
},

If your ESX server uses a different inventory, the exact file depends on that inventory resource.

Minimum expectation for each enabled item:

  • item names must match radio_boombox and radio_walkboy
  • item should be usable
  • images should be radio_boombox.png and radio_walkboy.png
  • item should not stack if your inventory supports unique/non-stackable items
  • The item name in your inventory must match Config.BoomboxItemName unless you change the config.
  • The Walkboy item name must match Config.WalkboyItemName.
  • Inventory examples are install references; edit the item file supplied by your inventory resource.
  • If you change the item name, keep the same value aligned across config.lua and your inventory item definitions.

Static radio props are map/world props, not inventory items. Enable them only on servers that want players to open the listener UI from configured prop models.

In config.lua:

Config.RadioPropTargetsEnabled = true
Config.RadioPropTargets = {
"ex_prop_ex_tv_flat_01",
"xm_prop_x17_tv_flat_01",
"vw_prop_vw_cinema_tv_01",
"prop_tv_flat_01"
}

The player must be near the prop to control it. Config.RadioPropAutoCloseDistance controls when the UI closes, and the server validates the same range with a small buffer.

This feature requires a running target resource:

  • ox_target
  • qb-target

Stations are defined in:

  • config.lua
  • the in-game Station Creator/Admin UI

Fresh installs intentionally start without predefined stations, so every server publishes its own lineup. Existing stations already stored in SQL continue to load and are never deleted by configuration changes.

Most station setup should be done through the Station Creator/Admin UI. That flow handles station identity, branding colors, music, ads, SFX, placement, and review/publish state without requiring server owners to edit JSON by hand.

Open Station Creator:

/radiostationadmin

The command requires the configured radio admin group or ACE permission.

The standard package uses server-provided local .ogg and .mp3 files under songs/. Add audio to the station folders described in songs/README.md and select or publish stations through Station Creator.

Only upload files you own or are properly licensed to use. The package does not include a third-party music catalogue or an external-media add-on.

Shared product ads stay global:

  • data/product_ads.json

Common public commands:

/radiostationadmin
/radioemitterfx
/radiolistenerui
/radiolisten
/radiolisten on
/radiolisten off
/radiocohost add [serverId]
/radiocohost remove [serverId]
/radioacceptcohost
/radiodeclinecohost

Optional command:

/radiotablet

/radiotablet only exists when Config.EnableDJTabletCommand = true.

Notes:

  • /radiostationadmin opens the Station Creator/Admin UI.
  • /radioemitterfx opens the Emitter FX panel for authorized admins.
  • /radiolistenerui and /radiolisten are listener UI shortcuts.
  • Cohost commands are mainly backup/manual workflow; the DJ UI provides the normal invite/accept flow.

If using an external weather authority such as rs_weather or av_weather:

  • keep Config.WeatherAuthorityProvider = "auto" or set it to your provider
  • set Config.WeatherAuthorityResource = "rs_weather" when using rs_weather
  • set Config.WeatherAuthorityResource = "av_weather" when using AV Weather
  • for AV Weather, adjust Config.WeatherAuthorityAvZoneMap if your AV zone names differ from the defaults
  • let the configured weather resource apply world weather
  • let rs_radio only read weather state for radio UI/broadcast purposes

Important:

  • avoid duplicate world weather application
  • when rs_weather is active, rs_radio should behave as a consumer, not a competing weather controller

If you use ox_doorlock, rs_radio can automatically install or update the captured Rebel Radio doors when both ox_doorlock and oxmysql are running.

Config toggle:

  • Config.AutoInstallRebelRadioDoors = true

The auto-installer only inserts missing Rebel Radio rows by name. Existing rows are not deleted or updated.

The repository also includes a manual SQL import:

  • docs/rebel_radio_doors_ox_doorlock.sql

The included doors are locked by default and restricted to:

  • dj grade 0+

Restart ox_doorlock after the auto-install or manual SQL import if any rows were inserted. This is required for double-door entries to rebuild correctly in ox_doorlock.

qb-doorlock does not use the ox_doorlock SQL table, so rs_radio cannot auto-populate it from the database.

If your server uses qb-doorlock, copy the provided entries into your qb-doorlock door config:

  • docs/rebel_radio_doors_qb_doorlock.lua

The entries use:

  • authorizedJobs = { ['dj'] = 0 }
  • locked = true
  • the same north/south front double doors, garage doors, and booth doors captured for Rebel Radio

After adding the entries, restart qb-doorlock.

After installing or updating:

  1. restart the server or ensure rs_radio
  2. confirm the dj job exists in your framework
  3. confirm a grade 3 DJ can open the boss menu at the configured station locations
  4. confirm a hired DJ can open the DJ tablet
  5. confirm listener UI works in a vehicle
  6. confirm Station Creator opens for an admin group user
  7. confirm the server-provided local station audio plays correctly
  8. confirm boombox item flow works if enabled

Before production use, verify:

  • DJ permissions are configured correctly
  • Station Creator/admin tools are restricted to trusted groups or ACE permissions
  • Config.EnableDJTabletCommand is false so DJs use configured station locations
  • DJ job and boss grades exist in your framework
  • boombox item exists for your inventory stack
  • only one weather authority is applying world weather
  • your target/inventory/framework stack matches one of the supported combinations